1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4#include <stdlib.h>
5#include <stddef.h>
6#include <stdbool.h>
7#include <string.h>
8#include <inttypes.h>
9#include <errno.h>
10#include <assert.h>
11
12#include <msgpack.h>
13#include <uv.h>
14
15#include "nvim/os/os.h"
16#include "nvim/os/time.h"
17#include "nvim/vim.h"
18#include "nvim/pos.h"
19#include "nvim/ascii.h"
20#include "nvim/shada.h"
21#include "nvim/message.h"
22#include "nvim/globals.h"
23#include "nvim/memory.h"
24#include "nvim/mark.h"
25#include "nvim/macros.h"
26#include "nvim/ops.h"
27#include "nvim/garray.h"
28#include "nvim/option.h"
29#include "nvim/msgpack_rpc/helpers.h"
30#include "nvim/api/private/defs.h"
31#include "nvim/api/private/helpers.h"
32#include "nvim/buffer.h"
33#include "nvim/buffer_defs.h"
34#include "nvim/ex_docmd.h"
35#include "nvim/ex_getln.h"
36#include "nvim/search.h"
37#include "nvim/regexp.h"
38#include "nvim/eval/typval.h"
39#include "nvim/version.h"
40#include "nvim/path.h"
41#include "nvim/fileio.h"
42#include "nvim/os/fileio.h"
43#include "nvim/strings.h"
44#include "nvim/quickfix.h"
45#include "nvim/eval/encode.h"
46#include "nvim/eval/decode.h"
47#include "nvim/lib/khash.h"
48#include "nvim/lib/kvec.h"
49
50#ifdef HAVE_BE64TOH
51# define _BSD_SOURCE 1
52# define _DEFAULT_SOURCE 1
53# include ENDIAN_INCLUDE_FILE
54#endif
55
56// Note: when using bufset hash pointers are intentionally casted to uintptr_t
57// and not to khint32_t or khint64_t: this way compiler must give a warning
58// (-Wconversion) when types change.
59#ifdef ARCH_32
60KHASH_SET_INIT_INT(bufset)
61#elif defined(ARCH_64)
62KHASH_SET_INIT_INT64(bufset)
63#else
64# error Not a 64- or 32-bit architecture
65#endif
66KHASH_MAP_INIT_STR(fnamebufs, buf_T *)
67KHASH_SET_INIT_STR(strset)
68
69#define copy_option_part(src, dest, ...) \
70 ((char *) copy_option_part((char_u **) src, (char_u *) dest, __VA_ARGS__))
71#define find_shada_parameter(...) \
72 ((const char *) find_shada_parameter(__VA_ARGS__))
73#define home_replace_save(a, b) \
74 ((char *)home_replace_save(a, (char_u *)b))
75#define home_replace(a, b, c, d, e) \
76 home_replace(a, (char_u *)b, (char_u *)c, d, e)
77#define vim_rename(a, b) \
78 (vim_rename((char_u *)a, (char_u *)b))
79#define mb_strnicmp(a, b, c) \
80 (mb_strnicmp((char_u *)a, (char_u *)b, c))
81#define path_try_shorten_fname(b) \
82 ((char *)path_try_shorten_fname((char_u *)b))
83#define buflist_new(ffname, sfname, ...) \
84 (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
85#define os_isdir(f) (os_isdir((char_u *) f))
86#define regtilde(s, m) ((char *) regtilde((char_u *) s, m))
87#define path_tail_with_sep(f) ((char *) path_tail_with_sep((char_u *)f))
88
89#define SEARCH_KEY_MAGIC "sm"
90#define SEARCH_KEY_SMARTCASE "sc"
91#define SEARCH_KEY_HAS_LINE_OFFSET "sl"
92#define SEARCH_KEY_PLACE_CURSOR_AT_END "se"
93#define SEARCH_KEY_IS_LAST_USED "su"
94#define SEARCH_KEY_IS_SUBSTITUTE_PATTERN "ss"
95#define SEARCH_KEY_HIGHLIGHTED "sh"
96#define SEARCH_KEY_OFFSET "so"
97#define SEARCH_KEY_PAT "sp"
98#define SEARCH_KEY_BACKWARD "sb"
99
100#define REG_KEY_TYPE "rt"
101#define REG_KEY_WIDTH "rw"
102#define REG_KEY_CONTENTS "rc"
103#define REG_KEY_UNNAMED "ru"
104
105#define KEY_LNUM "l"
106#define KEY_COL "c"
107#define KEY_FILE "f"
108#define KEY_NAME_CHAR "n"
109
110// Error messages formerly used by viminfo code:
111// E136: viminfo: Too many errors, skipping rest of file
112// E137: Viminfo file is not writable: %s
113// E138: Can't write viminfo file %s!
114// E195: Cannot open ShaDa file for reading
115// E574: Unknown register type %d
116// E575: Illegal starting char
117// E576: Missing '>'
118// E577: Illegal register name
119// E886: Can't rename viminfo file to %s!
120// E929: Too many viminfo temp files, like %s!
121// Now only six of them are used:
122// E137: ShaDa file is not writeable (for pre-open checks)
123// E929: All %s.tmp.X files exist, cannot write ShaDa file!
124// RCERR (E576) for critical read errors.
125// RNERR (E136) for various errors when renaming.
126// RERR (E575) for various errors inside read ShaDa file.
127// SERR (E886) for various “system” errors (always contains output of
128// strerror)
129// WERR (E574) for various ignorable write errors
130
131/// Common prefix for all errors inside ShaDa file
132///
133/// I.e. errors occurred while parsing, but not system errors occurred while
134/// reading.
135#define RERR "E575: "
136
137/// Common prefix for critical read errors
138///
139/// I.e. errors that make shada_read_next_item return kSDReadStatusNotShaDa.
140#define RCERR "E576: "
141
142/// Common prefix for all “system” errors
143#define SERR "E886: "
144
145/// Common prefix for all “rename” errors
146#define RNERR "E136: "
147
148/// Common prefix for all ignorable “write” errors
149#define WERR "E574: "
150
151/// Callback function for add_search_pattern
152typedef void (*SearchPatternGetter)(SearchPattern *);
153
154/// Possible ShaDa entry types
155///
156/// @warning Enum values are part of the API and must not be altered.
157///
158/// All values that are not in enum are ignored.
159typedef enum {
160 kSDItemUnknown = -1, ///< Unknown item.
161 kSDItemMissing = 0, ///< Missing value. Should never appear in a file.
162 kSDItemHeader = 1, ///< Header. Present for debugging purposes.
163 kSDItemSearchPattern = 2, ///< Last search pattern (*not* history item).
164 ///< Comes from user searches (e.g. when typing
165 ///< "/pat") or :substitute command calls.
166 kSDItemSubString = 3, ///< Last substitute replacement string.
167 kSDItemHistoryEntry = 4, ///< History item.
168 kSDItemRegister = 5, ///< Register.
169 kSDItemVariable = 6, ///< Global variable.
170 kSDItemGlobalMark = 7, ///< Global mark definition.
171 kSDItemJump = 8, ///< Item from jump list.
172 kSDItemBufferList = 9, ///< Buffer list.
173 kSDItemLocalMark = 10, ///< Buffer-local mark.
174 kSDItemChange = 11, ///< Item from buffer change list.
175#define SHADA_LAST_ENTRY ((uint64_t) kSDItemChange)
176} ShadaEntryType;
177
178/// Possible results when reading ShaDa file
179typedef enum {
180 kSDReadStatusSuccess, ///< Reading was successfull.
181 kSDReadStatusFinished, ///< Nothing more to read.
182 kSDReadStatusReadError, ///< Failed to read from file.
183 kSDReadStatusNotShaDa, ///< Input is most likely not a ShaDa file.
184 kSDReadStatusMalformed, ///< Error in the currently read item.
185} ShaDaReadResult;
186
187/// Possible results of shada_write function.
188typedef enum {
189 kSDWriteSuccessfull, ///< Writing was successfull.
190 kSDWriteReadNotShada, ///< Writing was successfull, but when reading it
191 ///< attempted to read file that did not look like
192 ///< a ShaDa file.
193 kSDWriteFailed, ///< Writing was not successfull (e.g. because there
194 ///< was no space left on device).
195 kSDWriteIgnError, ///< Writing resulted in a error which can be ignored
196 ///< (e.g. when trying to dump a function reference or
197 ///< self-referencing container in a variable).
198} ShaDaWriteResult;
199
200/// Flags for shada_read_next_item
201enum SRNIFlags {
202 kSDReadHeader = (1 << kSDItemHeader), ///< Determines whether header should
203 ///< be read (it is usually ignored).
204 kSDReadUndisableableData = (
205 (1 << kSDItemSearchPattern)
206 | (1 << kSDItemSubString)
207 | (1 << kSDItemJump)), ///< Data reading which cannot be disabled by
208 ///< &shada or other options except for disabling
209 ///< reading ShaDa as a whole.
210 kSDReadRegisters = (1 << kSDItemRegister), ///< Determines whether registers
211 ///< should be read (may only be
212 ///< disabled when writing, but
213 ///< not when reading).
214 kSDReadHistory = (1 << kSDItemHistoryEntry), ///< Determines whether history
215 ///< should be read (can only be
216 ///< disabled by &history).
217 kSDReadVariables = (1 << kSDItemVariable), ///< Determines whether variables
218 ///< should be read (disabled by
219 ///< removing ! from &shada).
220 kSDReadBufferList = (1 << kSDItemBufferList), ///< Determines whether buffer
221 ///< list should be read
222 ///< (disabled by removing
223 ///< % entry from &shada).
224 kSDReadUnknown = (1 << (SHADA_LAST_ENTRY + 1)), ///< Determines whether
225 ///< unknown items should be
226 ///< read (usually disabled).
227 kSDReadGlobalMarks = (1 << kSDItemGlobalMark), ///< Determines whether global
228 ///< marks should be read. Can
229 ///< only be disabled by
230 ///< having f0 in &shada when
231 ///< writing.
232 kSDReadLocalMarks = (1 << kSDItemLocalMark), ///< Determines whether local
233 ///< marks should be read. Can
234 ///< only be disabled by
235 ///< disabling &shada or putting
236 ///< '0 there. Is also used for
237 ///< v:oldfiles.
238 kSDReadChanges = (1 << kSDItemChange), ///< Determines whether change list
239 ///< should be read. Can only be
240 ///< disabled by disabling &shada or
241 ///< putting '0 there.
242};
243// Note: SRNIFlags enum name was created only to make it possible to reference
244// it. This name is not actually used anywhere outside of the documentation.
245
246/// Structure defining a single ShaDa file entry
247typedef struct {
248 ShadaEntryType type;
249 Timestamp timestamp;
250 union {
251 Dictionary header;
252 struct shada_filemark {
253 char name;
254 pos_T mark;
255 char *fname;
256 dict_T *additional_data;
257 } filemark;
258 struct search_pattern {
259 bool magic;
260 bool smartcase;
261 bool has_line_offset;
262 bool place_cursor_at_end;
263 int64_t offset;
264 bool is_last_used;
265 bool is_substitute_pattern;
266 bool highlighted;
267 bool search_backward;
268 char *pat;
269 dict_T *additional_data;
270 } search_pattern;
271 struct history_item {
272 uint8_t histtype;
273 char *string;
274 char sep;
275 list_T *additional_elements;
276 } history_item;
277 struct reg { // yankreg_T
278 char name;
279 MotionType type;
280 char **contents;
281 bool is_unnamed;
282 size_t contents_size;
283 size_t width;
284 dict_T *additional_data;
285 } reg;
286 struct global_var {
287 char *name;
288 typval_T value;
289 list_T *additional_elements;
290 } global_var;
291 struct {
292 uint64_t type;
293 char *contents;
294 size_t size;
295 } unknown_item;
296 struct sub_string {
297 char *sub;
298 list_T *additional_elements;
299 } sub_string;
300 struct buffer_list {
301 size_t size;
302 struct buffer_list_buffer {
303 pos_T pos;
304 char *fname;
305 dict_T *additional_data;
306 } *buffers;
307 } buffer_list;
308 } data;
309} ShadaEntry;
310
311struct hm_llist_entry;
312
313/// One entry in sized linked list
314typedef struct hm_llist_entry {
315 ShadaEntry data; ///< Entry data.
316 bool can_free_entry; ///< True if data can be freed.
317 struct hm_llist_entry *next; ///< Pointer to next entry or NULL.
318 struct hm_llist_entry *prev; ///< Pointer to previous entry or NULL.
319} HMLListEntry;
320
321KHASH_MAP_INIT_STR(hmll_entries, HMLListEntry *)
322
323/// Sized linked list structure for history merger
324typedef struct {
325 HMLListEntry *entries; ///< Pointer to the start of the allocated array of
326 ///< entries.
327 HMLListEntry *first; ///< First entry in the list (is not necessary start
328 ///< of the array) or NULL.
329 HMLListEntry *last; ///< Last entry in the list or NULL.
330 HMLListEntry *free_entry; ///< Last free entry removed by hmll_remove.
331 HMLListEntry *last_free_entry; ///< Last unused element in entries array.
332 size_t size; ///< Number of allocated entries.
333 size_t num_entries; ///< Number of entries already used.
334 khash_t(hmll_entries) contained_entries; ///< Hash mapping all history entry
335 ///< strings to corresponding entry
336 ///< pointers.
337} HMLList;
338
339typedef struct {
340 HMLList hmll;
341 bool do_merge;
342 bool reading;
343 const void *iter;
344 ShadaEntry last_hist_entry;
345 uint8_t history_type;
346} HistoryMergerState;
347
348/// ShadaEntry structure that knows whether it should be freed
349typedef struct {
350 ShadaEntry data; ///< ShadaEntry data.
351 bool can_free_entry; ///< True if entry can be freed.
352} PossiblyFreedShadaEntry;
353
354/// Structure that holds one file marks.
355typedef struct {
356 PossiblyFreedShadaEntry marks[NLOCALMARKS]; ///< All file marks.
357 PossiblyFreedShadaEntry changes[JUMPLISTSIZE]; ///< All file changes.
358 size_t changes_size; ///< Number of changes occupied.
359 ShadaEntry *additional_marks; ///< All marks with unknown names.
360 size_t additional_marks_size; ///< Size of the additional_marks array.
361 Timestamp greatest_timestamp; ///< Greatest timestamp among marks.
362} FileMarks;
363
364KHASH_MAP_INIT_STR(file_marks, FileMarks)
365
366/// State structure used by shada_write
367///
368/// Before actually writing most of the data is read to this structure.
369typedef struct {
370 HistoryMergerState hms[HIST_COUNT]; ///< Structures for history merging.
371 PossiblyFreedShadaEntry global_marks[NMARKS]; ///< Named global marks.
372 PossiblyFreedShadaEntry numbered_marks[EXTRA_MARKS]; ///< Numbered marks.
373 PossiblyFreedShadaEntry registers[NUM_SAVED_REGISTERS]; ///< All registers.
374 PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; ///< All dumped jumps.
375 size_t jumps_size; ///< Number of jumps occupied.
376 PossiblyFreedShadaEntry search_pattern; ///< Last search pattern.
377 PossiblyFreedShadaEntry sub_search_pattern; ///< Last s/ search pattern.
378 PossiblyFreedShadaEntry replacement; ///< Last s// replacement string.
379 khash_t(strset) dumped_variables; ///< Names of already dumped variables.
380 khash_t(file_marks) file_marks; ///< All file marks.
381} WriteMergerState;
382
383struct sd_read_def;
384
385/// Function used to close files defined by ShaDaReadDef
386typedef void (*ShaDaReadCloser)(struct sd_read_def *const sd_reader)
387 REAL_FATTR_NONNULL_ALL;
388
389/// Function used to read ShaDa files
390typedef ptrdiff_t (*ShaDaFileReader)(struct sd_read_def *const sd_reader,
391 void *const dest,
392 const size_t size)
393 REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
394
395/// Function used to skip in ShaDa files
396typedef int (*ShaDaFileSkipper)(struct sd_read_def *const sd_reader,
397 const size_t offset)
398 REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
399
400/// Structure containing necessary pointers for reading ShaDa files
401typedef struct sd_read_def {
402 ShaDaFileReader read; ///< Reader function.
403 ShaDaReadCloser close; ///< Close function.
404 ShaDaFileSkipper skip; ///< Function used to skip some bytes.
405 void *cookie; ///< Data describing object read from.
406 bool eof; ///< True if reader reached end of file.
407 const char *error; ///< Error message in case of error.
408 uintmax_t fpos; ///< Current position (amount of bytes read since
409 ///< reader structure initialization). May overflow.
410} ShaDaReadDef;
411
412struct sd_write_def;
413
414/// Function used to close files defined by ShaDaWriteDef
415typedef void (*ShaDaWriteCloser)(struct sd_write_def *const sd_writer)
416 REAL_FATTR_NONNULL_ALL;
417
418/// Function used to write ShaDa files
419typedef ptrdiff_t (*ShaDaFileWriter)(struct sd_write_def *const sd_writer,
420 const void *const src,
421 const size_t size)
422 REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
423
424/// Structure containing necessary pointers for writing ShaDa files
425typedef struct sd_write_def {
426 ShaDaFileWriter write; ///< Writer function.
427 ShaDaWriteCloser close; ///< Close function.
428 void *cookie; ///< Data describing object written to.
429 const char *error; ///< Error message in case of error.
430} ShaDaWriteDef;
431
432#ifdef INCLUDE_GENERATED_DECLARATIONS
433# include "shada.c.generated.h"
434#endif
435
436#define DEF_SDE(name, attr, ...) \
437 [kSDItem##name] = { \
438 .timestamp = 0, \
439 .type = kSDItem##name, \
440 .data = { \
441 .attr = { __VA_ARGS__ } \
442 } \
443 }
444#define DEFAULT_POS { 1, 0, 0 }
445static const pos_T default_pos = DEFAULT_POS;
446static const ShadaEntry sd_default_values[] = {
447 [kSDItemMissing] = { .type = kSDItemMissing, .timestamp = 0 },
448 DEF_SDE(Header, header, .size = 0),
449 DEF_SDE(SearchPattern, search_pattern,
450 .magic = true,
451 .smartcase = false,
452 .has_line_offset = false,
453 .place_cursor_at_end = false,
454 .offset = 0,
455 .is_last_used = true,
456 .is_substitute_pattern = false,
457 .highlighted = false,
458 .search_backward = false,
459 .pat = NULL,
460 .additional_data = NULL),
461 DEF_SDE(SubString, sub_string, .sub = NULL, .additional_elements = NULL),
462 DEF_SDE(HistoryEntry, history_item,
463 .histtype = HIST_CMD,
464 .string = NULL,
465 .sep = NUL,
466 .additional_elements = NULL),
467 DEF_SDE(Register, reg,
468 .name = NUL,
469 .type = kMTCharWise,
470 .contents = NULL,
471 .contents_size = 0,
472 .is_unnamed = false,
473 .width = 0,
474 .additional_data = NULL),
475 DEF_SDE(Variable, global_var,
476 .name = NULL,
477 .value = {
478 .v_type = VAR_UNKNOWN,
479 .vval = { .v_string = NULL }
480 },
481 .additional_elements = NULL),
482 DEF_SDE(GlobalMark, filemark,
483 .name = '"',
484 .mark = DEFAULT_POS,
485 .fname = NULL,
486 .additional_data = NULL),
487 DEF_SDE(Jump, filemark,
488 .name = NUL,
489 .mark = DEFAULT_POS,
490 .fname = NULL,
491 .additional_data = NULL),
492 DEF_SDE(BufferList, buffer_list,
493 .size = 0,
494 .buffers = NULL),
495 DEF_SDE(LocalMark, filemark,
496 .name = '"',
497 .mark = DEFAULT_POS,
498 .fname = NULL,
499 .additional_data = NULL),
500 DEF_SDE(Change, filemark,
501 .name = NUL,
502 .mark = DEFAULT_POS,
503 .fname = NULL,
504 .additional_data = NULL),
505};
506#undef DEFAULT_POS
507#undef DEF_SDE
508
509/// Initialize new linked list
510///
511/// @param[out] hmll List to initialize.
512/// @param[in] size Maximum size of the list.
513static inline void hmll_init(HMLList *const hmll, const size_t size)
514 FUNC_ATTR_NONNULL_ALL
515{
516 *hmll = (HMLList) {
517 .entries = xcalloc(size, sizeof(hmll->entries[0])),
518 .first = NULL,
519 .last = NULL,
520 .free_entry = NULL,
521 .size = size,
522 .num_entries = 0,
523 .contained_entries = KHASH_EMPTY_TABLE(hmll_entries),
524 };
525 hmll->last_free_entry = hmll->entries;
526}
527
528/// Iterate over HMLList in forward direction
529///
530/// @param hmll Pointer to the list.
531/// @param cur_entry Name of the variable to iterate over.
532/// @param code Code to execute on each iteration.
533///
534/// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`).
535#define HMLL_FORALL(hmll, cur_entry, code) \
536 for (HMLListEntry *cur_entry = (hmll)->first; cur_entry != NULL; \
537 cur_entry = cur_entry->next) { \
538 code \
539 } \
540
541/// Remove entry from the linked list
542///
543/// @param hmll List to remove from.
544/// @param hmll_entry Entry to remove.
545static inline void hmll_remove(HMLList *const hmll,
546 HMLListEntry *const hmll_entry)
547 FUNC_ATTR_NONNULL_ALL
548{
549 if (hmll_entry == hmll->last_free_entry - 1) {
550 hmll->last_free_entry--;
551 } else {
552 assert(hmll->free_entry == NULL);
553 hmll->free_entry = hmll_entry;
554 }
555 const khiter_t k = kh_get(hmll_entries, &hmll->contained_entries,
556 hmll_entry->data.data.history_item.string);
557 assert(k != kh_end(&hmll->contained_entries));
558 kh_del(hmll_entries, &hmll->contained_entries, k);
559 if (hmll_entry->next == NULL) {
560 hmll->last = hmll_entry->prev;
561 } else {
562 hmll_entry->next->prev = hmll_entry->prev;
563 }
564 if (hmll_entry->prev == NULL) {
565 hmll->first = hmll_entry->next;
566 } else {
567 hmll_entry->prev->next = hmll_entry->next;
568 }
569 hmll->num_entries--;
570 if (hmll_entry->can_free_entry) {
571 shada_free_shada_entry(&hmll_entry->data);
572 }
573}
574
575
576/// Insert entry to the linked list
577///
578/// @param[out] hmll List to insert to.
579/// @param[in] hmll_entry Entry to insert after or NULL if it is needed
580/// to insert at the first entry.
581/// @param[in] data Data to insert.
582/// @param[in] can_free_entry True if data can be freed.
583static inline void hmll_insert(HMLList *const hmll,
584 HMLListEntry *hmll_entry,
585 const ShadaEntry data,
586 const bool can_free_entry)
587 FUNC_ATTR_NONNULL_ARG(1)
588{
589 if (hmll->num_entries == hmll->size) {
590 if (hmll_entry == hmll->first) {
591 hmll_entry = NULL;
592 }
593 assert(hmll->first != NULL);
594 hmll_remove(hmll, hmll->first);
595 }
596 HMLListEntry *target_entry;
597 if (hmll->free_entry == NULL) {
598 assert((size_t) (hmll->last_free_entry - hmll->entries)
599 == hmll->num_entries);
600 target_entry = hmll->last_free_entry++;
601 } else {
602 assert((size_t) (hmll->last_free_entry - hmll->entries) - 1
603 == hmll->num_entries);
604 target_entry = hmll->free_entry;
605 hmll->free_entry = NULL;
606 }
607 target_entry->data = data;
608 target_entry->can_free_entry = can_free_entry;
609 int kh_ret;
610 const khiter_t k = kh_put(hmll_entries, &hmll->contained_entries,
611 data.data.history_item.string, &kh_ret);
612 if (kh_ret > 0) {
613 kh_val(&hmll->contained_entries, k) = target_entry;
614 }
615 hmll->num_entries++;
616 target_entry->prev = hmll_entry;
617 if (hmll_entry == NULL) {
618 target_entry->next = hmll->first;
619 hmll->first = target_entry;
620 } else {
621 target_entry->next = hmll_entry->next;
622 hmll_entry->next = target_entry;
623 }
624 if (target_entry->next == NULL) {
625 hmll->last = target_entry;
626 } else {
627 target_entry->next->prev = target_entry;
628 }
629}
630
631/// Iterate over HMLList in backward direction
632///
633/// @param hmll Pointer to the list.
634/// @param cur_entry Name of the variable to iterate over, must be already
635/// defined.
636/// @param code Code to execute on each iteration.
637///
638/// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`).
639#define HMLL_ITER_BACK(hmll, cur_entry, code) \
640 for (cur_entry = (hmll)->last; cur_entry != NULL; \
641 cur_entry = cur_entry->prev) { \
642 code \
643 }
644
645/// Free linked list
646///
647/// @param[in] hmll List to free.
648static inline void hmll_dealloc(HMLList *const hmll)
649 FUNC_ATTR_NONNULL_ALL
650{
651 kh_dealloc(hmll_entries, &hmll->contained_entries);
652 xfree(hmll->entries);
653}
654
655/// Wrapper for reading from file descriptors
656///
657/// @return -1 or number of bytes read.
658static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest,
659 const size_t size)
660 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
661{
662 const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size);
663 sd_reader->eof = file_eof(sd_reader->cookie);
664 if (ret < 0) {
665 sd_reader->error = os_strerror((int)ret);
666 return -1;
667 }
668 sd_reader->fpos += (size_t)ret;
669 return ret;
670}
671
672/// Read one character
673static int read_char(ShaDaReadDef *const sd_reader)
674 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
675{
676 uint8_t ret;
677 ptrdiff_t read_bytes = sd_reader->read(sd_reader, &ret, 1);
678 if (read_bytes != 1) {
679 return EOF;
680 }
681 return (int) ret;
682}
683
684/// Wrapper for writing to file descriptors
685///
686/// @return -1 or number of bytes written.
687static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer,
688 const void *const dest,
689 const size_t size)
690 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
691{
692 const ptrdiff_t ret = file_write(sd_writer->cookie, dest, size);
693 if (ret < 0) {
694 sd_writer->error = os_strerror((int)ret);
695 return -1;
696 }
697 return ret;
698}
699
700/// Wrapper for closing file descriptors opened for reading
701static void close_sd_reader(ShaDaReadDef *const sd_reader)
702 FUNC_ATTR_NONNULL_ALL
703{
704 close_file(sd_reader->cookie);
705}
706
707/// Wrapper for closing file descriptors opened for writing
708static void close_sd_writer(ShaDaWriteDef *const sd_writer)
709 FUNC_ATTR_NONNULL_ALL
710{
711 close_file(sd_writer->cookie);
712}
713
714/// Wrapper for read that reads to IObuff and ignores bytes read
715///
716/// Used for skipping.
717///
718/// @param[in,out] sd_reader File read.
719/// @param[in] offset Amount of bytes to skip.
720///
721/// @return FAIL in case of failure, OK in case of success. May set
722/// sd_reader->eof or sd_reader->error.
723static int sd_reader_skip_read(ShaDaReadDef *const sd_reader,
724 const size_t offset)
725 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
726{
727 const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset);
728 if (skip_bytes < 0) {
729 sd_reader->error = os_strerror((int)skip_bytes);
730 return FAIL;
731 } else if (skip_bytes != (ptrdiff_t)offset) {
732 assert(skip_bytes < (ptrdiff_t)offset);
733 sd_reader->eof = file_eof(sd_reader->cookie);
734 if (!sd_reader->eof) {
735 sd_reader->error = _("too few bytes read");
736 }
737 return FAIL;
738 }
739 sd_reader->fpos += (size_t)skip_bytes;
740 return OK;
741}
742
743/// Wrapper for read that can be used when lseek cannot be used
744///
745/// E.g. when trying to read from a pipe.
746///
747/// @param[in,out] sd_reader File read.
748/// @param[in] offset Amount of bytes to skip.
749///
750/// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or
751/// kSDReadStatusSuccess.
752static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
753 const size_t offset)
754 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
755{
756 if (sd_reader->skip(sd_reader, offset) != OK) {
757 if (sd_reader->error != NULL) {
758 emsgf(_(SERR "System error while skipping in ShaDa file: %s"),
759 sd_reader->error);
760 return kSDReadStatusReadError;
761 } else if (sd_reader->eof) {
762 emsgf(_(RCERR "Error while reading ShaDa file: "
763 "last entry specified that it occupies %" PRIu64 " bytes, "
764 "but file ended earlier"),
765 (uint64_t) offset);
766 return kSDReadStatusNotShaDa;
767 }
768 assert(false);
769 }
770 return kSDReadStatusSuccess;
771}
772
773/// Open ShaDa file for reading
774///
775/// @param[in] fname File name to open.
776/// @param[out] sd_reader Location where reader structure will be saved.
777///
778/// @return libuv error in case of error, 0 otherwise.
779static int open_shada_file_for_reading(const char *const fname,
780 ShaDaReadDef *sd_reader)
781 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
782{
783 int error;
784
785 *sd_reader = (ShaDaReadDef) {
786 .read = &read_file,
787 .close = &close_sd_reader,
788 .skip = &sd_reader_skip_read,
789 .error = NULL,
790 .eof = false,
791 .fpos = 0,
792 .cookie = file_open_new(&error, fname, kFileReadOnly, 0),
793 };
794 if (sd_reader->cookie == NULL) {
795 return error;
796 }
797
798 assert(STRCMP(p_enc, "utf-8") == 0);
799
800 return 0;
801}
802
803/// Wrapper for closing file descriptors
804static void close_file(void *cookie)
805{
806 const int error = file_free(cookie, !!p_fs);
807 if (error != 0) {
808 emsgf(_(SERR "System error while closing ShaDa file: %s"),
809 os_strerror(error));
810 }
811}
812
813/// Check whether buffer is in the given set
814///
815/// @param[in] set Set to check within.
816/// @param[in] buf Buffer to find.
817///
818/// @return true or false.
819static inline bool in_bufset(const khash_t(bufset) *const set, const buf_T *buf)
820 FUNC_ATTR_PURE
821{
822 return kh_get(bufset, set, (uintptr_t) buf) != kh_end(set);
823}
824
825/// Check whether string is in the given set
826///
827/// @param[in] set Set to check within.
828/// @param[in] buf Buffer to find.
829///
830/// @return true or false.
831static inline bool in_strset(const khash_t(strset) *const set, char *str)
832 FUNC_ATTR_PURE
833{
834 return kh_get(strset, set, str) != kh_end(set);
835}
836
837/// Msgpack callback for writing to ShaDaWriteDef*
838static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
839{
840 ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *) data;
841 ptrdiff_t written_bytes = sd_writer->write(sd_writer, buf, len);
842 if (written_bytes == -1) {
843 emsgf(_(SERR "System error while writing ShaDa file: %s"),
844 sd_writer->error);
845 return -1;
846 }
847 return 0;
848}
849
850/// Check whether writing to shada file was disabled ("-i NONE" or "--clean").
851///
852/// @return true if it was disabled, false otherwise.
853static bool shada_disabled(void)
854 FUNC_ATTR_PURE
855{
856 return strequal(p_shadafile, "NONE");
857}
858
859/// Read ShaDa file
860///
861/// @param[in] file File to read or NULL to use default name.
862/// @param[in] flags Flags, see ShaDaReadFileFlags enum.
863///
864/// @return FAIL if reading failed for some reason and OK otherwise.
865static int shada_read_file(const char *const file, const int flags)
866 FUNC_ATTR_WARN_UNUSED_RESULT
867{
868 if (shada_disabled()) {
869 return FAIL;
870 }
871
872 char *const fname = shada_filename(file);
873
874 ShaDaReadDef sd_reader;
875 const int of_ret = open_shada_file_for_reading(fname, &sd_reader);
876
877 if (p_verbose > 0) {
878 verbose_enter();
879 smsg(_("Reading ShaDa file \"%s\"%s%s%s%s"),
880 fname,
881 (flags & kShaDaWantInfo) ? _(" info") : "",
882 (flags & kShaDaWantMarks) ? _(" marks") : "",
883 (flags & kShaDaGetOldfiles) ? _(" oldfiles") : "",
884 of_ret != 0 ? _(" FAILED") : "");
885 verbose_leave();
886 }
887
888 if (of_ret != 0) {
889 if (of_ret != UV_ENOENT || (flags & kShaDaMissingError)) {
890 emsgf(_(SERR "System error while opening ShaDa file %s for reading: %s"),
891 fname, os_strerror(of_ret));
892 }
893 xfree(fname);
894 return FAIL;
895 }
896 xfree(fname);
897
898 shada_read(&sd_reader, flags);
899 sd_reader.close(&sd_reader);
900
901 return OK;
902}
903
904/// Wrapper for hist_iter() function which produces ShadaEntry values
905///
906/// @param[in] iter Current iteration state.
907/// @param[in] history_type Type of the history (HIST_*).
908/// @param[in] zero If true, then item is removed from instance
909/// memory upon reading.
910/// @param[out] hist Location where iteration results should be saved.
911///
912/// @return Next iteration state.
913static const void *shada_hist_iter(const void *const iter,
914 const uint8_t history_type,
915 const bool zero,
916 ShadaEntry *const hist)
917 FUNC_ATTR_NONNULL_ARG(4) FUNC_ATTR_WARN_UNUSED_RESULT
918{
919 histentry_T hist_he;
920 const void *const ret = hist_iter(iter, history_type, zero, &hist_he);
921 if (hist_he.hisstr == NULL) {
922 *hist = (ShadaEntry) { .type = kSDItemMissing };
923 } else {
924 *hist = (ShadaEntry) {
925 .type = kSDItemHistoryEntry,
926 .timestamp = hist_he.timestamp,
927 .data = {
928 .history_item = {
929 .histtype = history_type,
930 .string = (char *) hist_he.hisstr,
931 .sep = (char) (history_type == HIST_SEARCH
932 ? (char) hist_he.hisstr[STRLEN(hist_he.hisstr) + 1]
933 : 0),
934 .additional_elements = hist_he.additional_elements,
935 }
936 }
937 };
938 }
939 return ret;
940}
941
942/// Insert history entry
943///
944/// Inserts history entry at the end of the ring buffer (may insert earlier
945/// according to the timestamp). If entry was already in the ring buffer
946/// existing entry will be removed unless it has greater timestamp.
947///
948/// Before the new entry entries from the current Neovim history will be
949/// inserted unless `do_iter` argument is false.
950///
951/// @param[in,out] hms_p Ring buffer and associated structures.
952/// @param[in] entry Inserted entry.
953/// @param[in] do_iter Determines whether Neovim own history should
954/// be used. Must be true only if inserting
955/// entry from current Neovim history.
956/// @param[in] can_free_entry True if entry can be freed.
957static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
958 const bool do_iter, const bool can_free_entry)
959 FUNC_ATTR_NONNULL_ALL
960{
961 if (do_iter) {
962 while (hms_p->last_hist_entry.type != kSDItemMissing
963 && hms_p->last_hist_entry.timestamp < entry.timestamp) {
964 hms_insert(hms_p, hms_p->last_hist_entry, false, hms_p->reading);
965 if (hms_p->iter == NULL) {
966 hms_p->last_hist_entry.type = kSDItemMissing;
967 break;
968 }
969 hms_p->iter = shada_hist_iter(hms_p->iter, hms_p->history_type,
970 hms_p->reading, &hms_p->last_hist_entry);
971 }
972 }
973 HMLList *const hmll = &hms_p->hmll;
974 const khiter_t k = kh_get(hmll_entries, &hms_p->hmll.contained_entries,
975 entry.data.history_item.string);
976 if (k != kh_end(&hmll->contained_entries)) {
977 HMLListEntry *const existing_entry = kh_val(&hmll->contained_entries, k);
978 if (entry.timestamp > existing_entry->data.timestamp) {
979 hmll_remove(hmll, existing_entry);
980 } else if (!do_iter && entry.timestamp == existing_entry->data.timestamp) {
981 // Prefer entry from the current Neovim instance.
982 if (existing_entry->can_free_entry) {
983 shada_free_shada_entry(&existing_entry->data);
984 }
985 existing_entry->data = entry;
986 existing_entry->can_free_entry = can_free_entry;
987 // Previous key was freed above, as part of freeing the ShaDa entry.
988 kh_key(&hmll->contained_entries, k) = entry.data.history_item.string;
989 return;
990 } else {
991 return;
992 }
993 }
994 HMLListEntry *insert_after;
995 HMLL_ITER_BACK(hmll, insert_after, {
996 if (insert_after->data.timestamp <= entry.timestamp) {
997 break;
998 }
999 })
1000 hmll_insert(hmll, insert_after, entry, can_free_entry);
1001}
1002
1003/// Initialize the history merger
1004///
1005/// @param[out] hms_p Structure to be initialized.
1006/// @param[in] history_type History type (one of HIST_\* values).
1007/// @param[in] num_elements Number of elements in the result.
1008/// @param[in] do_merge Prepare structure for merging elements.
1009/// @param[in] reading If true, then merger is reading history for use
1010/// in Neovim.
1011static inline void hms_init(HistoryMergerState *const hms_p,
1012 const uint8_t history_type,
1013 const size_t num_elements,
1014 const bool do_merge,
1015 const bool reading)
1016 FUNC_ATTR_NONNULL_ALL
1017{
1018 hmll_init(&hms_p->hmll, num_elements);
1019 hms_p->do_merge = do_merge;
1020 hms_p->reading = reading;
1021 hms_p->iter = shada_hist_iter(NULL, history_type, hms_p->reading,
1022 &hms_p->last_hist_entry);
1023 hms_p->history_type = history_type;
1024}
1025
1026/// Merge in all remaining Neovim own history entries
1027///
1028/// @param[in,out] hms_p Merger structure into which history should be
1029/// inserted.
1030static inline void hms_insert_whole_neovim_history(
1031 HistoryMergerState *const hms_p)
1032 FUNC_ATTR_NONNULL_ALL
1033{
1034 while (hms_p->last_hist_entry.type != kSDItemMissing) {
1035 hms_insert(hms_p, hms_p->last_hist_entry, false, hms_p->reading);
1036 if (hms_p->iter == NULL) {
1037 break;
1038 }
1039 hms_p->iter = shada_hist_iter(hms_p->iter, hms_p->history_type,
1040 hms_p->reading, &hms_p->last_hist_entry);
1041 }
1042}
1043
1044/// Convert merger structure to Neovim internal structure for history
1045///
1046/// @param[in] hms_p Converted merger structure.
1047/// @param[out] hist_array Array with the results.
1048/// @param[out] new_hisidx New last history entry index.
1049/// @param[out] new_hisnum Amount of history items in merger structure.
1050static inline void hms_to_he_array(const HistoryMergerState *const hms_p,
1051 histentry_T *const hist_array,
1052 int *const new_hisidx,
1053 int *const new_hisnum)
1054 FUNC_ATTR_NONNULL_ALL
1055{
1056 histentry_T *hist = hist_array;
1057 HMLL_FORALL(&hms_p->hmll, cur_entry, {
1058 hist->timestamp = cur_entry->data.timestamp;
1059 hist->hisnum = (int) (hist - hist_array) + 1;
1060 hist->hisstr = (char_u *) cur_entry->data.data.history_item.string;
1061 hist->additional_elements =
1062 cur_entry->data.data.history_item.additional_elements;
1063 hist++;
1064 })
1065 *new_hisnum = (int) (hist - hist_array);
1066 *new_hisidx = *new_hisnum - 1;
1067}
1068
1069/// Free history merger structure
1070///
1071/// @param[in] hms_p Structure to be freed.
1072static inline void hms_dealloc(HistoryMergerState *const hms_p)
1073 FUNC_ATTR_NONNULL_ALL
1074{
1075 hmll_dealloc(&hms_p->hmll);
1076}
1077
1078/// Iterate over all history entries in history merger, in order
1079///
1080/// @param[in] hms_p Merger structure to iterate over.
1081/// @param[out] cur_entry Name of the iterator variable.
1082/// @param code Code to execute on each iteration.
1083///
1084/// @return for cycle header. Use `HMS_ITER(hms_p, cur_entry) {body}`.
1085#define HMS_ITER(hms_p, cur_entry, code) \
1086 HMLL_FORALL(&((hms_p)->hmll), cur_entry, code)
1087
1088/// Find buffer for given buffer name (cached)
1089///
1090/// @param[in,out] fname_bufs Cache containing fname to buffer mapping.
1091/// @param[in] fname File name to find.
1092///
1093/// @return Pointer to the buffer or NULL.
1094static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs,
1095 const char *const fname)
1096 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
1097{
1098 int kh_ret;
1099 khint_t k = kh_put(fnamebufs, fname_bufs, fname, &kh_ret);
1100 if (!kh_ret) {
1101 return kh_val(fname_bufs, k);
1102 }
1103 kh_key(fname_bufs, k) = xstrdup(fname);
1104 FOR_ALL_BUFFERS(buf) {
1105 if (buf->b_ffname != NULL) {
1106 if (fnamecmp(fname, buf->b_ffname) == 0) {
1107 kh_val(fname_bufs, k) = buf;
1108 return buf;
1109 }
1110 }
1111 }
1112 kh_val(fname_bufs, k) = NULL;
1113 return NULL;
1114}
1115
1116/// Compare two marks
1117static inline bool marks_equal(const pos_T a, const pos_T b)
1118{
1119 return (a.lnum == b.lnum) && (a.col == b.col);
1120}
1121
1122#define MERGE_JUMPS(jumps_size, jumps, jumps_type, timestamp_attr, mark_attr, \
1123 entry, fname_cond, free_func, fin_func, \
1124 idxadj_func, afterfree_func) \
1125 do { \
1126 const int jl_len = (int) jumps_size; \
1127 int i; \
1128 for (i = jl_len; i > 0; i--) { \
1129 const jumps_type jl_entry = jumps[i - 1]; \
1130 if (jl_entry.timestamp_attr <= entry.timestamp) { \
1131 if (marks_equal(jl_entry.mark_attr, entry.data.filemark.mark) \
1132 && fname_cond) { \
1133 i = -1; \
1134 } \
1135 break; \
1136 } \
1137 } \
1138 if (i > 0) { \
1139 if (jl_len == JUMPLISTSIZE) { \
1140 free_func(jumps[0]); \
1141 i--; \
1142 if (i > 0) { \
1143 memmove(&jumps[0], &jumps[1], sizeof(jumps[1]) * (size_t) i); \
1144 } \
1145 } else if (i != jl_len) { \
1146 memmove(&jumps[i + 1], &jumps[i], \
1147 sizeof(jumps[0]) * (size_t) (jl_len - i)); \
1148 } \
1149 } else if (i == 0) { \
1150 if (jl_len == JUMPLISTSIZE) { \
1151 i = -1; \
1152 } else if (jl_len > 0) { \
1153 memmove(&jumps[1], &jumps[0], sizeof(jumps[0]) * (size_t) jl_len); \
1154 } \
1155 } \
1156 if (i != -1) { \
1157 jumps[i] = fin_func(entry); \
1158 if (jl_len < JUMPLISTSIZE) { \
1159 jumps_size++; \
1160 } \
1161 idxadj_func(i); \
1162 } else { \
1163 shada_free_shada_entry(&entry); \
1164 afterfree_func(entry); \
1165 } \
1166 } while (0)
1167
1168/// Read data from ShaDa file
1169///
1170/// @param[in] sd_reader Structure containing file reader definition.
1171/// @param[in] flags What to read, see ShaDaReadFileFlags enum.
1172static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
1173 FUNC_ATTR_NONNULL_ALL
1174{
1175 list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES);
1176 const bool force = flags & kShaDaForceit;
1177 const bool get_old_files = (flags & (kShaDaGetOldfiles | kShaDaForceit)
1178 && (force || tv_list_len(oldfiles_list) == 0));
1179 const bool want_marks = flags & kShaDaWantMarks;
1180 const unsigned srni_flags = (unsigned) (
1181 (flags & kShaDaWantInfo
1182 ? (kSDReadUndisableableData
1183 | kSDReadRegisters
1184 | kSDReadGlobalMarks
1185 | (p_hi ? kSDReadHistory : 0)
1186 | (find_shada_parameter('!') != NULL
1187 ? kSDReadVariables
1188 : 0)
1189 | (find_shada_parameter('%') != NULL
1190 && ARGCOUNT == 0
1191 ? kSDReadBufferList
1192 : 0))
1193 : 0)
1194 | (want_marks && get_shada_parameter('\'') > 0
1195 ? kSDReadLocalMarks | kSDReadChanges
1196 : 0)
1197 | (get_old_files
1198 ? kSDReadLocalMarks
1199 : 0));
1200 if (srni_flags == 0) {
1201 // Nothing to do.
1202 return;
1203 }
1204 HistoryMergerState hms[HIST_COUNT];
1205 if (srni_flags & kSDReadHistory) {
1206 for (uint8_t i = 0; i < HIST_COUNT; i++) {
1207 hms_init(&hms[i], i, (size_t) p_hi, true, true);
1208 }
1209 }
1210 ShadaEntry cur_entry;
1211 khash_t(bufset) cl_bufs = KHASH_EMPTY_TABLE(bufset);
1212 khash_t(fnamebufs) fname_bufs = KHASH_EMPTY_TABLE(fnamebufs);
1213 khash_t(strset) oldfiles_set = KHASH_EMPTY_TABLE(strset);
1214 if (get_old_files && (oldfiles_list == NULL || force)) {
1215 oldfiles_list = tv_list_alloc(kListLenUnknown);
1216 set_vim_var_list(VV_OLDFILES, oldfiles_list);
1217 }
1218 ShaDaReadResult srni_ret;
1219 while ((srni_ret = shada_read_next_item(sd_reader, &cur_entry, srni_flags, 0))
1220 != kSDReadStatusFinished) {
1221 switch (srni_ret) {
1222 case kSDReadStatusSuccess: {
1223 break;
1224 }
1225 case kSDReadStatusFinished: {
1226 // Should be handled by the while condition.
1227 assert(false);
1228 }
1229 case kSDReadStatusNotShaDa:
1230 case kSDReadStatusReadError: {
1231 goto shada_read_main_cycle_end;
1232 }
1233 case kSDReadStatusMalformed: {
1234 continue;
1235 }
1236 }
1237 switch (cur_entry.type) {
1238 case kSDItemMissing: {
1239 assert(false);
1240 }
1241 case kSDItemUnknown: {
1242 break;
1243 }
1244 case kSDItemHeader: {
1245 shada_free_shada_entry(&cur_entry);
1246 break;
1247 }
1248 case kSDItemSearchPattern: {
1249 if (!force) {
1250 SearchPattern pat;
1251 (cur_entry.data.search_pattern.is_substitute_pattern
1252 ? &get_substitute_pattern
1253 : &get_search_pattern)(&pat);
1254 if (pat.pat != NULL && pat.timestamp >= cur_entry.timestamp) {
1255 shada_free_shada_entry(&cur_entry);
1256 break;
1257 }
1258 }
1259 (cur_entry.data.search_pattern.is_substitute_pattern
1260 ? &set_substitute_pattern
1261 : &set_search_pattern)((SearchPattern) {
1262 .magic = cur_entry.data.search_pattern.magic,
1263 .no_scs = !cur_entry.data.search_pattern.smartcase,
1264 .off = {
1265 .dir = cur_entry.data.search_pattern.search_backward ? '?' : '/',
1266 .line = cur_entry.data.search_pattern.has_line_offset,
1267 .end = cur_entry.data.search_pattern.place_cursor_at_end,
1268 .off = cur_entry.data.search_pattern.offset,
1269 },
1270 .pat = (char_u *) cur_entry.data.search_pattern.pat,
1271 .additional_data = cur_entry.data.search_pattern.additional_data,
1272 .timestamp = cur_entry.timestamp,
1273 });
1274 if (cur_entry.data.search_pattern.is_last_used) {
1275 set_last_used_pattern(
1276 cur_entry.data.search_pattern.is_substitute_pattern);
1277 set_no_hlsearch(!cur_entry.data.search_pattern.highlighted);
1278 }
1279 // Do not free shada entry: its allocated memory was saved above.
1280 break;
1281 }
1282 case kSDItemSubString: {
1283 if (!force) {
1284 SubReplacementString sub;
1285 sub_get_replacement(&sub);
1286 if (sub.sub != NULL && sub.timestamp >= cur_entry.timestamp) {
1287 shada_free_shada_entry(&cur_entry);
1288 break;
1289 }
1290 }
1291 sub_set_replacement((SubReplacementString) {
1292 .sub = cur_entry.data.sub_string.sub,
1293 .timestamp = cur_entry.timestamp,
1294 .additional_elements = cur_entry.data.sub_string.additional_elements,
1295 });
1296 // Without using regtilde and without / &cpo flag previous substitute
1297 // string is close to useless: you can only use it with :& or :~ and
1298 // that’s all because s//~ is not available until the first call to
1299 // regtilde. Vim was not calling this for some reason.
1300 (void) regtilde(cur_entry.data.sub_string.sub, p_magic);
1301 // Do not free shada entry: its allocated memory was saved above.
1302 break;
1303 }
1304 case kSDItemHistoryEntry: {
1305 if (cur_entry.data.history_item.histtype >= HIST_COUNT) {
1306 shada_free_shada_entry(&cur_entry);
1307 break;
1308 }
1309 hms_insert(hms + cur_entry.data.history_item.histtype, cur_entry, true,
1310 true);
1311 // Do not free shada entry: its allocated memory was saved above.
1312 break;
1313 }
1314 case kSDItemRegister: {
1315 if (cur_entry.data.reg.type != kMTCharWise
1316 && cur_entry.data.reg.type != kMTLineWise
1317 && cur_entry.data.reg.type != kMTBlockWise) {
1318 shada_free_shada_entry(&cur_entry);
1319 break;
1320 }
1321 if (!force) {
1322 const yankreg_T *const reg = op_reg_get(cur_entry.data.reg.name);
1323 if (reg == NULL || reg->timestamp >= cur_entry.timestamp) {
1324 shada_free_shada_entry(&cur_entry);
1325 break;
1326 }
1327 }
1328 if (!op_reg_set(cur_entry.data.reg.name, (yankreg_T) {
1329 .y_array = (char_u **)cur_entry.data.reg.contents,
1330 .y_size = cur_entry.data.reg.contents_size,
1331 .y_type = cur_entry.data.reg.type,
1332 .y_width = (colnr_T) cur_entry.data.reg.width,
1333 .timestamp = cur_entry.timestamp,
1334 .additional_data = cur_entry.data.reg.additional_data,
1335 }, cur_entry.data.reg.is_unnamed)) {
1336 shada_free_shada_entry(&cur_entry);
1337 }
1338 // Do not free shada entry: its allocated memory was saved above.
1339 break;
1340 }
1341 case kSDItemVariable: {
1342 var_set_global(cur_entry.data.global_var.name,
1343 cur_entry.data.global_var.value);
1344 cur_entry.data.global_var.value.v_type = VAR_UNKNOWN;
1345 shada_free_shada_entry(&cur_entry);
1346 break;
1347 }
1348 case kSDItemJump:
1349 case kSDItemGlobalMark: {
1350 buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
1351 if (buf != NULL) {
1352 XFREE_CLEAR(cur_entry.data.filemark.fname);
1353 }
1354 xfmark_T fm = (xfmark_T) {
1355 .fname = (char_u *) (buf == NULL
1356 ? cur_entry.data.filemark.fname
1357 : NULL),
1358 .fmark = {
1359 .mark = cur_entry.data.filemark.mark,
1360 .fnum = (buf == NULL ? 0 : buf->b_fnum),
1361 .timestamp = cur_entry.timestamp,
1362 .additional_data = cur_entry.data.filemark.additional_data,
1363 },
1364 };
1365 if (cur_entry.type == kSDItemGlobalMark) {
1366 if (!mark_set_global(cur_entry.data.filemark.name, fm, !force)) {
1367 shada_free_shada_entry(&cur_entry);
1368 break;
1369 }
1370 } else {
1371#define SDE_TO_XFMARK(entry) fm
1372#define ADJUST_IDX(i) \
1373 if (curwin->w_jumplistidx >= i \
1374 && curwin->w_jumplistidx + 1 <= curwin->w_jumplistlen) { \
1375 curwin->w_jumplistidx++; \
1376 }
1377#define DUMMY_AFTERFREE(entry)
1378 MERGE_JUMPS(curwin->w_jumplistlen, curwin->w_jumplist, xfmark_T,
1379 fmark.timestamp, fmark.mark, cur_entry,
1380 (buf == NULL
1381 ? (jl_entry.fname != NULL
1382 && STRCMP(fm.fname, jl_entry.fname) == 0)
1383 : fm.fmark.fnum == jl_entry.fmark.fnum),
1384 free_xfmark, SDE_TO_XFMARK, ADJUST_IDX, DUMMY_AFTERFREE);
1385#undef SDE_TO_XFMARK
1386#undef ADJUST_IDX
1387#undef DUMMY_AFTERFREE
1388 }
1389 // Do not free shada entry: its allocated memory was saved above.
1390 break;
1391 }
1392 case kSDItemBufferList: {
1393 for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) {
1394 char *const sfname = path_try_shorten_fname(
1395 cur_entry.data.buffer_list.buffers[i].fname);
1396 buf_T *const buf = buflist_new(
1397 cur_entry.data.buffer_list.buffers[i].fname, sfname, 0,
1398 BLN_LISTED);
1399 if (buf != NULL) {
1400 RESET_FMARK(&buf->b_last_cursor,
1401 cur_entry.data.buffer_list.buffers[i].pos, 0);
1402 buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum,
1403 buf->b_last_cursor.mark.col, false);
1404 buf->additional_data =
1405 cur_entry.data.buffer_list.buffers[i].additional_data;
1406 cur_entry.data.buffer_list.buffers[i].additional_data = NULL;
1407 }
1408 }
1409 shada_free_shada_entry(&cur_entry);
1410 break;
1411 }
1412 case kSDItemChange:
1413 case kSDItemLocalMark: {
1414 if (get_old_files && !in_strset(&oldfiles_set,
1415 cur_entry.data.filemark.fname)) {
1416 char *fname = cur_entry.data.filemark.fname;
1417 if (want_marks) {
1418 // Do not bother with allocating memory for the string if already
1419 // allocated string from cur_entry can be used. It cannot be used if
1420 // want_marks is set because this way it may be used for a mark.
1421 fname = xstrdup(fname);
1422 }
1423 int kh_ret;
1424 (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
1425 tv_list_append_allocated_string(oldfiles_list, fname);
1426 if (!want_marks) {
1427 // Avoid free because this string was already used.
1428 cur_entry.data.filemark.fname = NULL;
1429 }
1430 }
1431 if (!want_marks) {
1432 shada_free_shada_entry(&cur_entry);
1433 break;
1434 }
1435 buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
1436 if (buf == NULL) {
1437 shada_free_shada_entry(&cur_entry);
1438 break;
1439 }
1440 const fmark_T fm = (fmark_T) {
1441 .mark = cur_entry.data.filemark.mark,
1442 .fnum = 0,
1443 .timestamp = cur_entry.timestamp,
1444 .additional_data = cur_entry.data.filemark.additional_data,
1445 };
1446 if (cur_entry.type == kSDItemLocalMark) {
1447 if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) {
1448 shada_free_shada_entry(&cur_entry);
1449 break;
1450 }
1451 } else {
1452 int kh_ret;
1453 (void) kh_put(bufset, &cl_bufs, (uintptr_t) buf, &kh_ret);
1454#define SDE_TO_FMARK(entry) fm
1455#define AFTERFREE(entry) (entry).data.filemark.fname = NULL
1456#define DUMMY_IDX_ADJ(i)
1457 MERGE_JUMPS(buf->b_changelistlen, buf->b_changelist, fmark_T,
1458 timestamp, mark, cur_entry, true,
1459 free_fmark, SDE_TO_FMARK, DUMMY_IDX_ADJ, AFTERFREE);
1460#undef SDE_TO_FMARK
1461#undef AFTERFREE
1462#undef DUMMY_IDX_ADJ
1463 }
1464 // Do not free shada entry: except for fname, its allocated memory (i.e.
1465 // additional_data attribute contents if non-NULL) was saved above.
1466 xfree(cur_entry.data.filemark.fname);
1467 break;
1468 }
1469 }
1470 }
1471shada_read_main_cycle_end:
1472 // Warning: shada_hist_iter returns ShadaEntry elements which use strings from
1473 // original history list. This means that once such entry is removed
1474 // from the history Neovim array will no longer be valid. To reduce
1475 // amount of memory allocations ShaDa file reader allocates enough
1476 // memory for the history string itself and separator character which
1477 // may be assigned right away.
1478 if (srni_flags & kSDReadHistory) {
1479 for (uint8_t i = 0; i < HIST_COUNT; i++) {
1480 hms_insert_whole_neovim_history(&hms[i]);
1481 clr_history(i);
1482 int *new_hisidx;
1483 int *new_hisnum;
1484 histentry_T *hist = hist_get_array(i, &new_hisidx, &new_hisnum);
1485 if (hist != NULL) {
1486 hms_to_he_array(&hms[i], hist, new_hisidx, new_hisnum);
1487 }
1488 hms_dealloc(&hms[i]);
1489 }
1490 }
1491 if (cl_bufs.n_occupied) {
1492 FOR_ALL_TAB_WINDOWS(tp, wp) {
1493 (void) tp;
1494 if (in_bufset(&cl_bufs, wp->w_buffer)) {
1495 wp->w_changelistidx = wp->w_buffer->b_changelistlen;
1496 }
1497 }
1498 }
1499 kh_dealloc(bufset, &cl_bufs);
1500 const char *key;
1501 kh_foreach_key(&fname_bufs, key, {
1502 xfree((void *) key);
1503 })
1504 kh_dealloc(fnamebufs, &fname_bufs);
1505 kh_dealloc(strset, &oldfiles_set);
1506}
1507
1508/// Default shada file location: cached path
1509static char *default_shada_file = NULL;
1510
1511/// Get the default ShaDa file
1512static const char *shada_get_default_file(void)
1513 FUNC_ATTR_WARN_UNUSED_RESULT
1514{
1515 if (default_shada_file == NULL) {
1516 char *shada_dir = stdpaths_user_data_subpath("shada", 0, false);
1517 default_shada_file = concat_fnames_realloc(shada_dir, "main.shada", true);
1518 }
1519 return default_shada_file;
1520}
1521
1522/// Get the ShaDa file name to use
1523///
1524/// If "file" is given and not empty, use it (has already been expanded by
1525/// cmdline functions). Otherwise use "-i file_name", value from 'shada' or the
1526/// default, and expand environment variables.
1527///
1528/// @param[in] file Forced file name or NULL.
1529///
1530/// @return An allocated string containing shada file name.
1531static char *shada_filename(const char *file)
1532 FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
1533{
1534 if (file == NULL || *file == NUL) {
1535 if (p_shadafile != NULL && *p_shadafile != NUL) {
1536 file = p_shadafile;
1537 } else {
1538 if ((file = find_shada_parameter('n')) == NULL || *file == NUL) {
1539 file = shada_get_default_file();
1540 }
1541 // XXX It used to be one level lower, so that whatever is in
1542 // `p_shadafile` was expanded. I intentionally moved it here
1543 // because various expansions must have already be done by the shell.
1544 // If shell is not performing them then they should be done in main.c
1545 // where arguments are parsed, *not here*.
1546 expand_env((char_u *)file, &(NameBuff[0]), MAXPATHL);
1547 file = (const char *) &(NameBuff[0]);
1548 }
1549 }
1550 return xstrdup(file);
1551}
1552
1553#define PACK_STATIC_STR(s) \
1554 do { \
1555 msgpack_pack_str(spacker, sizeof(s) - 1); \
1556 msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \
1557 } while (0)
1558#define PACK_STRING(s) \
1559 do { \
1560 const String s_ = (s); \
1561 msgpack_pack_str(spacker, s_.size); \
1562 if (s_.size) { \
1563 msgpack_pack_str_body(spacker, s_.data, s_.size); \
1564 } \
1565 } while (0)
1566#define PACK_BIN(s) \
1567 do { \
1568 const String s_ = (s); \
1569 msgpack_pack_bin(spacker, s_.size); \
1570 if (s_.size > 0) { \
1571 msgpack_pack_bin_body(spacker, s_.data, s_.size); \
1572 } \
1573 } while (0)
1574
1575/// Write single ShaDa entry
1576///
1577/// @param[in] packer Packer used to write entry.
1578/// @param[in] entry Entry written.
1579/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
1580/// restrictions.
1581///
1582/// @return kSDWriteSuccessfull, kSDWriteFailed or kSDWriteIgnError.
1583static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
1584 ShadaEntry entry,
1585 const size_t max_kbyte)
1586 FUNC_ATTR_NONNULL_ALL
1587{
1588 ShaDaWriteResult ret = kSDWriteFailed;
1589 msgpack_sbuffer sbuf;
1590 msgpack_sbuffer_init(&sbuf);
1591 msgpack_packer *spacker = msgpack_packer_new(&sbuf, &msgpack_sbuffer_write);
1592#define DUMP_ADDITIONAL_ELEMENTS(src, what) \
1593 do { \
1594 if ((src) != NULL) { \
1595 TV_LIST_ITER((src), li, { \
1596 if (encode_vim_to_msgpack(spacker, TV_LIST_ITEM_TV(li), \
1597 _("additional elements of ShaDa " what)) \
1598 == FAIL) { \
1599 goto shada_pack_entry_error; \
1600 } \
1601 }); \
1602 } \
1603 } while (0)
1604#define DUMP_ADDITIONAL_DATA(src, what) \
1605 do { \
1606 dict_T *const d = (src); \
1607 if (d != NULL) { \
1608 size_t todo = d->dv_hashtab.ht_used; \
1609 for (const hashitem_T *hi= d->dv_hashtab.ht_array; todo; hi++) { \
1610 if (!HASHITEM_EMPTY(hi)) { \
1611 todo--; \
1612 dictitem_T *const di = TV_DICT_HI2DI(hi); \
1613 const size_t key_len = strlen((const char *)hi->hi_key); \
1614 msgpack_pack_str(spacker, key_len); \
1615 msgpack_pack_str_body(spacker, (const char *)hi->hi_key, key_len); \
1616 if (encode_vim_to_msgpack(spacker, &di->di_tv, \
1617 _("additional data of ShaDa " what)) \
1618 == FAIL) { \
1619 goto shada_pack_entry_error; \
1620 } \
1621 } \
1622 } \
1623 } \
1624 } while (0)
1625#define CHECK_DEFAULT(entry, attr) \
1626 (sd_default_values[entry.type].data.attr == entry.data.attr)
1627#define ONE_IF_NOT_DEFAULT(entry, attr) \
1628 ((size_t) (!CHECK_DEFAULT(entry, attr)))
1629 switch (entry.type) {
1630 case kSDItemMissing: {
1631 assert(false);
1632 }
1633 case kSDItemUnknown: {
1634 if (spacker->callback(spacker->data, entry.data.unknown_item.contents,
1635 (unsigned) entry.data.unknown_item.size) == -1) {
1636 goto shada_pack_entry_error;
1637 }
1638 break;
1639 }
1640 case kSDItemHistoryEntry: {
1641 const bool is_hist_search =
1642 entry.data.history_item.histtype == HIST_SEARCH;
1643 const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)(
1644 tv_list_len(entry.data.history_item.additional_elements));
1645 msgpack_pack_array(spacker, arr_size);
1646 msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
1647 PACK_BIN(cstr_as_string(entry.data.history_item.string));
1648 if (is_hist_search) {
1649 msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep);
1650 }
1651 DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
1652 "history entry item");
1653 break;
1654 }
1655 case kSDItemVariable: {
1656 const size_t arr_size = 2 + (size_t)(
1657 tv_list_len(entry.data.global_var.additional_elements));
1658 msgpack_pack_array(spacker, arr_size);
1659 const String varname = cstr_as_string(entry.data.global_var.name);
1660 PACK_BIN(varname);
1661 char vardesc[256] = "variable g:";
1662 memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
1663 varname.size + 1);
1664 if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
1665 == FAIL) {
1666 ret = kSDWriteIgnError;
1667 EMSG2(_(WERR "Failed to write variable %s"),
1668 entry.data.global_var.name);
1669 goto shada_pack_entry_error;
1670 }
1671 DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
1672 "variable item");
1673 break;
1674 }
1675 case kSDItemSubString: {
1676 const size_t arr_size = 1 + (size_t)(
1677 tv_list_len(entry.data.sub_string.additional_elements));
1678 msgpack_pack_array(spacker, arr_size);
1679 PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
1680 DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
1681 "sub string item");
1682 break;
1683 }
1684 case kSDItemSearchPattern: {
1685 const size_t map_size = (size_t) (
1686 1 // Search pattern is always present
1687 + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic)
1688 + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used)
1689 + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase)
1690 + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset)
1691 + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end)
1692 + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_substitute_pattern)
1693 + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted)
1694 + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset)
1695 + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward)
1696 // finally, additional data:
1697 + (size_t) (
1698 entry.data.search_pattern.additional_data
1699 ? entry.data.search_pattern.additional_data->dv_hashtab.ht_used
1700 : 0));
1701 msgpack_pack_map(spacker, map_size);
1702 PACK_STATIC_STR(SEARCH_KEY_PAT);
1703 PACK_BIN(cstr_as_string(entry.data.search_pattern.pat));
1704#define PACK_BOOL(entry, name, attr) \
1705 do { \
1706 if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \
1707 PACK_STATIC_STR(name); \
1708 if (sd_default_values[entry.type].data.search_pattern.attr) { \
1709 msgpack_pack_false(spacker); \
1710 } else { \
1711 msgpack_pack_true(spacker); \
1712 } \
1713 } \
1714 } while (0)
1715 PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic);
1716 PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used);
1717 PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase);
1718 PACK_BOOL(entry, SEARCH_KEY_HAS_LINE_OFFSET, has_line_offset);
1719 PACK_BOOL(entry, SEARCH_KEY_PLACE_CURSOR_AT_END, place_cursor_at_end);
1720 PACK_BOOL(entry, SEARCH_KEY_IS_SUBSTITUTE_PATTERN, is_substitute_pattern);
1721 PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted);
1722 PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward);
1723 if (!CHECK_DEFAULT(entry, search_pattern.offset)) {
1724 PACK_STATIC_STR(SEARCH_KEY_OFFSET);
1725 msgpack_pack_int64(spacker, entry.data.search_pattern.offset);
1726 }
1727#undef PACK_BOOL
1728 DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
1729 "search pattern item");
1730 break;
1731 }
1732 case kSDItemChange:
1733 case kSDItemGlobalMark:
1734 case kSDItemLocalMark:
1735 case kSDItemJump: {
1736 const size_t map_size = (size_t) (
1737 1 // File name
1738 + ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum)
1739 + ONE_IF_NOT_DEFAULT(entry, filemark.mark.col)
1740 + ONE_IF_NOT_DEFAULT(entry, filemark.name)
1741 // Additional entries, if any:
1742 + (size_t) (
1743 entry.data.filemark.additional_data == NULL
1744 ? 0
1745 : entry.data.filemark.additional_data->dv_hashtab.ht_used));
1746 msgpack_pack_map(spacker, map_size);
1747 PACK_STATIC_STR(KEY_FILE);
1748 PACK_BIN(cstr_as_string(entry.data.filemark.fname));
1749 if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) {
1750 PACK_STATIC_STR(KEY_LNUM);
1751 msgpack_pack_long(spacker, entry.data.filemark.mark.lnum);
1752 }
1753 if (!CHECK_DEFAULT(entry, filemark.mark.col)) {
1754 PACK_STATIC_STR(KEY_COL);
1755 msgpack_pack_long(spacker, entry.data.filemark.mark.col);
1756 }
1757 assert(entry.type == kSDItemJump || entry.type == kSDItemChange
1758 ? CHECK_DEFAULT(entry, filemark.name)
1759 : true);
1760 if (!CHECK_DEFAULT(entry, filemark.name)) {
1761 PACK_STATIC_STR(KEY_NAME_CHAR);
1762 msgpack_pack_uint8(spacker, (uint8_t) entry.data.filemark.name);
1763 }
1764 DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
1765 "mark (change, jump, global or local) item");
1766 break;
1767 }
1768 case kSDItemRegister: {
1769 const size_t map_size = (size_t) (
1770 2 // Register contents and name
1771 + ONE_IF_NOT_DEFAULT(entry, reg.type)
1772 + ONE_IF_NOT_DEFAULT(entry, reg.width)
1773 + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed)
1774 // Additional entries, if any:
1775 + (size_t) (entry.data.reg.additional_data == NULL
1776 ? 0
1777 : entry.data.reg.additional_data->dv_hashtab.ht_used));
1778 msgpack_pack_map(spacker, map_size);
1779 PACK_STATIC_STR(REG_KEY_CONTENTS);
1780 msgpack_pack_array(spacker, entry.data.reg.contents_size);
1781 for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
1782 PACK_BIN(cstr_as_string(entry.data.reg.contents[i]));
1783 }
1784 PACK_STATIC_STR(KEY_NAME_CHAR);
1785 msgpack_pack_char(spacker, entry.data.reg.name);
1786 if (!CHECK_DEFAULT(entry, reg.type)) {
1787 PACK_STATIC_STR(REG_KEY_TYPE);
1788 msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type);
1789 }
1790 if (!CHECK_DEFAULT(entry, reg.width)) {
1791 PACK_STATIC_STR(REG_KEY_WIDTH);
1792 msgpack_pack_uint64(spacker, (uint64_t) entry.data.reg.width);
1793 }
1794 if (!CHECK_DEFAULT(entry, reg.is_unnamed)) {
1795 PACK_STATIC_STR(REG_KEY_UNNAMED);
1796 if (entry.data.reg.is_unnamed) {
1797 msgpack_pack_true(spacker);
1798 } else {
1799 msgpack_pack_false(spacker);
1800 }
1801 }
1802 DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
1803 break;
1804 }
1805 case kSDItemBufferList: {
1806 msgpack_pack_array(spacker, entry.data.buffer_list.size);
1807 for (size_t i = 0; i < entry.data.buffer_list.size; i++) {
1808 const size_t map_size = (size_t) (
1809 1 // Buffer name
1810 + (size_t) (entry.data.buffer_list.buffers[i].pos.lnum
1811 != default_pos.lnum)
1812 + (size_t) (entry.data.buffer_list.buffers[i].pos.col
1813 != default_pos.col)
1814 // Additional entries, if any:
1815 + (size_t) (
1816 entry.data.buffer_list.buffers[i].additional_data == NULL
1817 ? 0
1818 : (entry.data.buffer_list.buffers[i].additional_data
1819 ->dv_hashtab.ht_used)));
1820 msgpack_pack_map(spacker, map_size);
1821 PACK_STATIC_STR(KEY_FILE);
1822 PACK_BIN(cstr_as_string(entry.data.buffer_list.buffers[i].fname));
1823 if (entry.data.buffer_list.buffers[i].pos.lnum != 1) {
1824 PACK_STATIC_STR(KEY_LNUM);
1825 msgpack_pack_uint64(
1826 spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.lnum);
1827 }
1828 if (entry.data.buffer_list.buffers[i].pos.col != 0) {
1829 PACK_STATIC_STR(KEY_COL);
1830 msgpack_pack_uint64(
1831 spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.col);
1832 }
1833 DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
1834 "buffer list subitem");
1835 }
1836 break;
1837 }
1838 case kSDItemHeader: {
1839 msgpack_pack_map(spacker, entry.data.header.size);
1840 for (size_t i = 0; i < entry.data.header.size; i++) {
1841 PACK_STRING(entry.data.header.items[i].key);
1842 const Object obj = entry.data.header.items[i].value;
1843 switch (obj.type) {
1844 case kObjectTypeString: {
1845 PACK_BIN(obj.data.string);
1846 break;
1847 }
1848 case kObjectTypeInteger: {
1849 msgpack_pack_int64(spacker, (int64_t) obj.data.integer);
1850 break;
1851 }
1852 default: {
1853 assert(false);
1854 }
1855 }
1856 }
1857 break;
1858 }
1859 }
1860#undef CHECK_DEFAULT
1861#undef ONE_IF_NOT_DEFAULT
1862 if (!max_kbyte || sbuf.size <= max_kbyte * 1024) {
1863 if (entry.type == kSDItemUnknown) {
1864 if (msgpack_pack_uint64(packer, entry.data.unknown_item.type) == -1) {
1865 goto shada_pack_entry_error;
1866 }
1867 } else {
1868 if (msgpack_pack_uint64(packer, (uint64_t) entry.type) == -1) {
1869 goto shada_pack_entry_error;
1870 }
1871 }
1872 if (msgpack_pack_uint64(packer, (uint64_t) entry.timestamp) == -1) {
1873 goto shada_pack_entry_error;
1874 }
1875 if (sbuf.size > 0) {
1876 if ((msgpack_pack_uint64(packer, (uint64_t) sbuf.size) == -1)
1877 || (packer->callback(packer->data, sbuf.data,
1878 (unsigned) sbuf.size) == -1)) {
1879 goto shada_pack_entry_error;
1880 }
1881 }
1882 }
1883 msgpack_packer_free(spacker);
1884 msgpack_sbuffer_destroy(&sbuf);
1885 return kSDWriteSuccessfull;
1886shada_pack_entry_error:
1887 msgpack_packer_free(spacker);
1888 msgpack_sbuffer_destroy(&sbuf);
1889 return ret;
1890}
1891#undef PACK_STRING
1892
1893/// Write single ShaDa entry and free it afterwards
1894///
1895/// Will not free if entry could not be freed.
1896///
1897/// @param[in] packer Packer used to write entry.
1898/// @param[in] entry Entry written.
1899/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
1900/// restrictions.
1901static inline ShaDaWriteResult shada_pack_pfreed_entry(
1902 msgpack_packer *const packer, PossiblyFreedShadaEntry entry,
1903 const size_t max_kbyte)
1904 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
1905{
1906 ShaDaWriteResult ret = kSDWriteSuccessfull;
1907 ret = shada_pack_entry(packer, entry.data, max_kbyte);
1908 if (entry.can_free_entry) {
1909 shada_free_shada_entry(&entry.data);
1910 }
1911 return ret;
1912}
1913
1914/// Compare two FileMarks structure to order them by greatest_timestamp
1915///
1916/// Order is reversed: structure with greatest greatest_timestamp comes first.
1917/// Function signature is compatible with qsort.
1918static int compare_file_marks(const void *a, const void *b)
1919 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
1920{
1921 const FileMarks *const *const a_fms = a;
1922 const FileMarks *const *const b_fms = b;
1923 return ((*a_fms)->greatest_timestamp == (*b_fms)->greatest_timestamp
1924 ? 0
1925 : ((*a_fms)->greatest_timestamp > (*b_fms)->greatest_timestamp
1926 ? -1
1927 : 1));
1928}
1929
1930/// Parse msgpack object that has given length
1931///
1932/// @param[in] sd_reader Structure containing file reader definition.
1933/// @param[in] length Object length.
1934/// @param[out] ret_unpacked Location where read result should be saved. If
1935/// NULL then unpacked data will be freed. Must be
1936/// NULL if `ret_buf` is NULL.
1937/// @param[out] ret_buf Buffer containing parsed string.
1938///
1939/// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or
1940/// kSDReadStatusSuccess.
1941static inline ShaDaReadResult shada_parse_msgpack(
1942 ShaDaReadDef *const sd_reader, const size_t length,
1943 msgpack_unpacked *ret_unpacked, char **const ret_buf)
1944 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
1945{
1946 const uintmax_t initial_fpos = sd_reader->fpos;
1947 char *const buf = xmalloc(length);
1948
1949 const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length);
1950 if (fl_ret != kSDReadStatusSuccess) {
1951 xfree(buf);
1952 return fl_ret;
1953 }
1954 bool did_try_to_free = false;
1955shada_parse_msgpack_read_next: {}
1956 size_t off = 0;
1957 msgpack_unpacked unpacked;
1958 msgpack_unpacked_init(&unpacked);
1959 const msgpack_unpack_return result =
1960 msgpack_unpack_next(&unpacked, buf, length, &off);
1961 ShaDaReadResult ret = kSDReadStatusSuccess;
1962 switch (result) {
1963 case MSGPACK_UNPACK_SUCCESS: {
1964 if (off < length) {
1965 goto shada_parse_msgpack_extra_bytes;
1966 }
1967 break;
1968 }
1969 case MSGPACK_UNPACK_PARSE_ERROR: {
1970 emsgf(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
1971 "at position %" PRIu64),
1972 (uint64_t) initial_fpos);
1973 ret = kSDReadStatusNotShaDa;
1974 break;
1975 }
1976 case MSGPACK_UNPACK_NOMEM_ERROR: {
1977 if (!did_try_to_free) {
1978 did_try_to_free = true;
1979 try_to_free_memory();
1980 goto shada_parse_msgpack_read_next;
1981 }
1982 EMSG(_(e_outofmem));
1983 ret = kSDReadStatusReadError;
1984 break;
1985 }
1986 case MSGPACK_UNPACK_CONTINUE: {
1987 emsgf(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
1988 "at position %" PRIu64),
1989 (uint64_t) initial_fpos);
1990 ret = kSDReadStatusNotShaDa;
1991 break;
1992 }
1993 case MSGPACK_UNPACK_EXTRA_BYTES: {
1994shada_parse_msgpack_extra_bytes:
1995 emsgf(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
1996 "at position %" PRIu64),
1997 (uint64_t) initial_fpos);
1998 ret = kSDReadStatusNotShaDa;
1999 break;
2000 }
2001 }
2002 if (ret_buf != NULL && ret == kSDReadStatusSuccess) {
2003 if (ret_unpacked == NULL) {
2004 msgpack_unpacked_destroy(&unpacked);
2005 } else {
2006 *ret_unpacked = unpacked;
2007 }
2008 *ret_buf = buf;
2009 } else {
2010 assert(ret_buf == NULL || ret != kSDReadStatusSuccess);
2011 msgpack_unpacked_destroy(&unpacked);
2012 xfree(buf);
2013 }
2014 return ret;
2015}
2016
2017/// Format shada entry for debugging purposes
2018///
2019/// @param[in] entry ShaDa entry to format.
2020///
2021/// @return string representing ShaDa entry in a static buffer.
2022static const char *shada_format_entry(const ShadaEntry entry)
2023 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
2024{
2025 static char ret[1024];
2026 ret[0] = 0;
2027 vim_snprintf(S_LEN(ret), "%s", "[ ] ts=%" PRIu64 " ");
2028 // ^ Space for `can_free_entry`
2029 switch (entry.type) {
2030 case kSDItemMissing: {
2031 vim_snprintf_add(S_LEN(ret), "Missing");
2032 break;
2033 }
2034 case kSDItemHeader: {
2035 vim_snprintf_add(S_LEN(ret), "Header { TODO }");
2036 break;
2037 }
2038 case kSDItemBufferList: {
2039 vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
2040 break;
2041 }
2042 case kSDItemUnknown: {
2043 vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
2044 break;
2045 }
2046 case kSDItemSearchPattern: {
2047 vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
2048 break;
2049 }
2050 case kSDItemSubString: {
2051 vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
2052 break;
2053 }
2054 case kSDItemHistoryEntry: {
2055 vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
2056 break;
2057 }
2058 case kSDItemRegister: {
2059 vim_snprintf_add(S_LEN(ret), "Register { TODO }");
2060 break;
2061 }
2062 case kSDItemVariable: {
2063 vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
2064 break;
2065 }
2066#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
2067 do { \
2068 typval_T ad_tv = { \
2069 .v_type = VAR_DICT, \
2070 .vval.v_dict = entry.data.filemark.additional_data \
2071 }; \
2072 size_t ad_len; \
2073 char *const ad = encode_tv2string(&ad_tv, &ad_len); \
2074 vim_snprintf_add( \
2075 S_LEN(ret), \
2076 entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
2077 "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
2078 "ad={%p:[%zu]%.64s} }", \
2079 name_fmt_arg, \
2080 strlen(entry.data.filemark.fname), \
2081 entry.data.filemark.fname, \
2082 entry.data.filemark.mark.lnum, \
2083 entry.data.filemark.mark.col, \
2084 entry.data.filemark.mark.coladd, \
2085 (void *)entry.data.filemark.additional_data, \
2086 ad_len, \
2087 ad); \
2088 } while (0)
2089 case kSDItemGlobalMark: {
2090 FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
2091 break;
2092 }
2093 case kSDItemChange: {
2094 FORMAT_MARK_ENTRY("Change", "%s", "");
2095 break;
2096 }
2097 case kSDItemLocalMark: {
2098 FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
2099 break;
2100 }
2101 case kSDItemJump: {
2102 FORMAT_MARK_ENTRY("Jump", "%s", "");
2103 break;
2104 }
2105#undef FORMAT_MARK_ENTRY
2106 }
2107 return ret;
2108}
2109
2110/// Format possibly freed shada entry for debugging purposes
2111///
2112/// @param[in] entry ShaDa entry to format.
2113///
2114/// @return string representing ShaDa entry in a static buffer.
2115static const char *shada_format_pfreed_entry(
2116 const PossiblyFreedShadaEntry pfs_entry)
2117 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
2118{
2119 char *ret = (char *)shada_format_entry(pfs_entry.data);
2120 ret[1] = (pfs_entry.can_free_entry ? 'T' : 'F');
2121 return ret;
2122}
2123
2124/// Read and merge in ShaDa file, used when writing
2125///
2126/// @param[in] sd_reader Structure containing file reader definition.
2127/// @param[in] srni_flags Flags determining what to read.
2128/// @param[in] max_kbyte Maximum size of one element.
2129/// @param[in,out] ret_wms Location where results are saved.
2130/// @param[out] packer MessagePack packer for entries which are not
2131/// merged.
2132static inline ShaDaWriteResult shada_read_when_writing(
2133 ShaDaReadDef *const sd_reader, const unsigned srni_flags,
2134 const size_t max_kbyte, WriteMergerState *const wms,
2135 msgpack_packer *const packer)
2136 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
2137{
2138 ShaDaWriteResult ret = kSDWriteSuccessfull;
2139 ShadaEntry entry;
2140 ShaDaReadResult srni_ret;
2141 while ((srni_ret = shada_read_next_item(sd_reader, &entry, srni_flags,
2142 max_kbyte))
2143 != kSDReadStatusFinished) {
2144 switch (srni_ret) {
2145 case kSDReadStatusSuccess: {
2146 break;
2147 }
2148 case kSDReadStatusFinished: {
2149 // Should be handled by the while condition.
2150 assert(false);
2151 }
2152 case kSDReadStatusNotShaDa: {
2153 ret = kSDWriteReadNotShada;
2154 FALLTHROUGH;
2155 }
2156 case kSDReadStatusReadError: {
2157 return ret;
2158 }
2159 case kSDReadStatusMalformed: {
2160 continue;
2161 }
2162 }
2163#define COMPARE_WITH_ENTRY(wms_entry_, entry) \
2164 do { \
2165 PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
2166 if (wms_entry->data.type != kSDItemMissing) { \
2167 if (wms_entry->data.timestamp >= (entry).timestamp) { \
2168 shada_free_shada_entry(&(entry)); \
2169 break; \
2170 } \
2171 if (wms_entry->can_free_entry) { \
2172 shada_free_shada_entry(&wms_entry->data); \
2173 } \
2174 } \
2175 *wms_entry = pfs_entry; \
2176 } while (0)
2177 const PossiblyFreedShadaEntry pfs_entry = {
2178 .can_free_entry = true,
2179 .data = entry,
2180 };
2181 switch (entry.type) {
2182 case kSDItemMissing: {
2183 break;
2184 }
2185 case kSDItemHeader:
2186 case kSDItemBufferList: {
2187 assert(false);
2188 }
2189 case kSDItemUnknown: {
2190 ret = shada_pack_entry(packer, entry, 0);
2191 shada_free_shada_entry(&entry);
2192 break;
2193 }
2194 case kSDItemSearchPattern: {
2195 COMPARE_WITH_ENTRY((entry.data.search_pattern.is_substitute_pattern
2196 ? &wms->sub_search_pattern
2197 : &wms->search_pattern), entry);
2198 break;
2199 }
2200 case kSDItemSubString: {
2201 COMPARE_WITH_ENTRY(&wms->replacement, entry);
2202 break;
2203 }
2204 case kSDItemHistoryEntry: {
2205 if (entry.data.history_item.histtype >= HIST_COUNT) {
2206 ret = shada_pack_entry(packer, entry, 0);
2207 shada_free_shada_entry(&entry);
2208 break;
2209 }
2210 hms_insert(&wms->hms[entry.data.history_item.histtype], entry, true,
2211 true);
2212 break;
2213 }
2214 case kSDItemRegister: {
2215 const int idx = op_reg_index(entry.data.reg.name);
2216 if (idx < 0) {
2217 ret = shada_pack_entry(packer, entry, 0);
2218 shada_free_shada_entry(&entry);
2219 break;
2220 }
2221 COMPARE_WITH_ENTRY(&wms->registers[idx], entry);
2222 break;
2223 }
2224 case kSDItemVariable: {
2225 if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
2226 ret = shada_pack_entry(packer, entry, 0);
2227 }
2228 shada_free_shada_entry(&entry);
2229 break;
2230 }
2231 case kSDItemGlobalMark: {
2232 if (ascii_isdigit(entry.data.filemark.name)) {
2233 bool processed_mark = false;
2234 // Completely ignore numbered mark names, make a list sorted by
2235 // timestamp.
2236 for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
2237 ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
2238 if (wms_entry.type != kSDItemGlobalMark) {
2239 continue;
2240 }
2241 // Ignore duplicates.
2242 if (wms_entry.timestamp == entry.timestamp
2243 && (wms_entry.data.filemark.additional_data == NULL
2244 && entry.data.filemark.additional_data == NULL)
2245 && marks_equal(wms_entry.data.filemark.mark,
2246 entry.data.filemark.mark)
2247 && strcmp(wms_entry.data.filemark.fname,
2248 entry.data.filemark.fname) == 0) {
2249 shada_free_shada_entry(&entry);
2250 processed_mark = true;
2251 break;
2252 }
2253 if (wms_entry.timestamp >= entry.timestamp) {
2254 processed_mark = true;
2255 if (i < ARRAY_SIZE(wms->numbered_marks)) {
2256 replace_numbered_mark(wms, i, pfs_entry);
2257 } else {
2258 shada_free_shada_entry(&entry);
2259 }
2260 break;
2261 }
2262 }
2263 if (!processed_mark) {
2264 replace_numbered_mark(wms, 0, pfs_entry);
2265 }
2266 } else {
2267 const int idx = mark_global_index(entry.data.filemark.name);
2268 if (idx < 0) {
2269 ret = shada_pack_entry(packer, entry, 0);
2270 shada_free_shada_entry(&entry);
2271 break;
2272 }
2273 COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
2274 }
2275 break;
2276 }
2277 case kSDItemChange:
2278 case kSDItemLocalMark: {
2279 if (shada_removable(entry.data.filemark.fname)) {
2280 shada_free_shada_entry(&entry);
2281 break;
2282 }
2283 const char *const fname = (const char *) entry.data.filemark.fname;
2284 khiter_t k;
2285 int kh_ret;
2286 k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
2287 FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
2288 if (kh_ret > 0) {
2289 memset(filemarks, 0, sizeof(*filemarks));
2290 }
2291 if (entry.timestamp > filemarks->greatest_timestamp) {
2292 filemarks->greatest_timestamp = entry.timestamp;
2293 }
2294 if (entry.type == kSDItemLocalMark) {
2295 const int idx = mark_local_index(entry.data.filemark.name);
2296 if (idx < 0) {
2297 filemarks->additional_marks = xrealloc(
2298 filemarks->additional_marks,
2299 (++filemarks->additional_marks_size
2300 * sizeof(filemarks->additional_marks[0])));
2301 filemarks->additional_marks[filemarks->additional_marks_size - 1] =
2302 entry;
2303 } else {
2304 PossiblyFreedShadaEntry *const wms_entry = &filemarks->marks[idx];
2305 if (wms_entry->data.type != kSDItemMissing) {
2306 if (wms_entry->data.timestamp >= entry.timestamp) {
2307 shada_free_shada_entry(&entry);
2308 break;
2309 }
2310 if (wms_entry->can_free_entry) {
2311 if (kh_key(&wms->file_marks, k)
2312 == wms_entry->data.data.filemark.fname) {
2313 kh_key(&wms->file_marks, k) = entry.data.filemark.fname;
2314 }
2315 shada_free_shada_entry(&wms_entry->data);
2316 }
2317 }
2318 *wms_entry = pfs_entry;
2319 }
2320 } else {
2321#define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \
2322 do { \
2323 if (entry.can_free_entry) { \
2324 shada_free_shada_entry(&entry.data); \
2325 } \
2326 } while (0)
2327#define SDE_TO_PFSDE(entry) \
2328 ((PossiblyFreedShadaEntry) { .can_free_entry = true, .data = entry })
2329#define AFTERFREE_DUMMY(entry)
2330#define DUMMY_IDX_ADJ(i)
2331 MERGE_JUMPS(filemarks->changes_size, filemarks->changes,
2332 PossiblyFreedShadaEntry, data.timestamp,
2333 data.data.filemark.mark, entry, true,
2334 FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
2335 DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
2336 }
2337 break;
2338 }
2339 case kSDItemJump: {
2340 MERGE_JUMPS(wms->jumps_size, wms->jumps, PossiblyFreedShadaEntry,
2341 data.timestamp, data.data.filemark.mark, entry,
2342 strcmp(jl_entry.data.data.filemark.fname,
2343 entry.data.filemark.fname) == 0,
2344 FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
2345 DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
2346#undef FREE_POSSIBLY_FREED_SHADA_ENTRY
2347#undef SDE_TO_PFSDE
2348#undef DUMMY_IDX_ADJ
2349#undef AFTERFREE_DUMMY
2350 break;
2351 }
2352 }
2353 }
2354#undef COMPARE_WITH_ENTRY
2355 return ret;
2356}
2357
2358/// Check whether buffer should be ignored
2359///
2360/// @param[in] buf buf_T* to check.
2361/// @param[in] removable_bufs Cache of buffers ignored due to their location.
2362///
2363/// @return true or false.
2364static inline bool ignore_buf(const buf_T *const buf,
2365 khash_t(bufset) *const removable_bufs)
2366 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
2367{
2368 return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
2369 || bt_terminal(buf) || in_bufset(removable_bufs, buf));
2370}
2371
2372/// Get list of buffers to write to the shada file
2373///
2374/// @param[in] removable_bufs Buffers which are ignored
2375///
2376/// @return ShadaEntry List of buffers to save, kSDItemBufferList entry.
2377static inline ShadaEntry shada_get_buflist(
2378 khash_t(bufset) *const removable_bufs)
2379 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
2380{
2381 int max_bufs = get_shada_parameter('%');
2382 size_t buf_count = 0;
2383 FOR_ALL_BUFFERS(buf) {
2384 if (!ignore_buf(buf, removable_bufs)
2385 && (max_bufs < 0 || buf_count < (size_t)max_bufs)) {
2386 buf_count++;
2387 }
2388 }
2389
2390 ShadaEntry buflist_entry = (ShadaEntry) {
2391 .type = kSDItemBufferList,
2392 .timestamp = os_time(),
2393 .data = {
2394 .buffer_list = {
2395 .size = buf_count,
2396 .buffers = xmalloc(buf_count
2397 * sizeof(*buflist_entry.data.buffer_list.buffers)),
2398 },
2399 },
2400 };
2401 size_t i = 0;
2402 FOR_ALL_BUFFERS(buf) {
2403 if (ignore_buf(buf, removable_bufs)) {
2404 continue;
2405 }
2406 if (i >= buf_count) {
2407 break;
2408 }
2409 buflist_entry.data.buffer_list.buffers[i] = (struct buffer_list_buffer) {
2410 .pos = buf->b_last_cursor.mark,
2411 .fname = (char *)buf->b_ffname,
2412 .additional_data = buf->additional_data,
2413 };
2414 i++;
2415 }
2416
2417 return buflist_entry;
2418}
2419
2420/// Save search pattern to PossiblyFreedShadaEntry
2421///
2422/// @param[out] ret_pse Location where result will be saved.
2423/// @param[in] get_pattern Function used to get pattern.
2424/// @param[in] is_substitute_pattern True if pattern in question is substitute
2425/// pattern. Also controls whether some
2426/// fields should be initialized to default
2427/// or values from get_pattern.
2428/// @param[in] search_last_used Result of search_was_last_used().
2429/// @param[in] search_highlighted True if search pattern was highlighted by
2430/// &hlsearch and this information should be
2431/// saved.
2432static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
2433 const SearchPatternGetter get_pattern,
2434 const bool is_substitute_pattern,
2435 const bool search_last_used,
2436 const bool search_highlighted)
2437 FUNC_ATTR_ALWAYS_INLINE
2438{
2439 const ShadaEntry defaults = sd_default_values[kSDItemSearchPattern];
2440 SearchPattern pat;
2441 get_pattern(&pat);
2442 if (pat.pat != NULL) {
2443 *ret_pse = (PossiblyFreedShadaEntry) {
2444 .can_free_entry = false,
2445 .data = {
2446 .type = kSDItemSearchPattern,
2447 .timestamp = pat.timestamp,
2448 .data = {
2449 .search_pattern = {
2450 .magic = pat.magic,
2451 .smartcase = !pat.no_scs,
2452 .has_line_offset = (is_substitute_pattern
2453 ? defaults.data.search_pattern.has_line_offset
2454 : pat.off.line),
2455 .place_cursor_at_end = (
2456 is_substitute_pattern
2457 ? defaults.data.search_pattern.place_cursor_at_end
2458 : pat.off.end),
2459 .offset = (is_substitute_pattern
2460 ? defaults.data.search_pattern.offset
2461 : pat.off.off),
2462 .is_last_used = (is_substitute_pattern ^ search_last_used),
2463 .is_substitute_pattern = is_substitute_pattern,
2464 .highlighted = ((is_substitute_pattern ^ search_last_used)
2465 && search_highlighted),
2466 .pat = (char *)pat.pat,
2467 .additional_data = pat.additional_data,
2468 .search_backward = (!is_substitute_pattern && pat.off.dir == '?'),
2469 }
2470 }
2471 }
2472 };
2473 }
2474}
2475
2476/// Initialize registers for writing to the ShaDa file
2477///
2478/// @param[in] wms The WriteMergerState used when writing.
2479/// @param[in] max_reg_lines The maximum number of register lines.
2480static inline void shada_initialize_registers(WriteMergerState *const wms,
2481 int max_reg_lines)
2482 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
2483{
2484 const void *reg_iter = NULL;
2485 const bool limit_reg_lines = max_reg_lines >= 0;
2486 do {
2487 yankreg_T reg;
2488 char name = NUL;
2489 bool is_unnamed = false;
2490 reg_iter = op_global_reg_iter(reg_iter, &name, &reg, &is_unnamed);
2491 if (name == NUL) {
2492 break;
2493 }
2494 if (limit_reg_lines && reg.y_size > (size_t)max_reg_lines) {
2495 continue;
2496 }
2497 wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) {
2498 .can_free_entry = false,
2499 .data = {
2500 .type = kSDItemRegister,
2501 .timestamp = reg.timestamp,
2502 .data = {
2503 .reg = {
2504 .contents = (char **)reg.y_array,
2505 .contents_size = (size_t)reg.y_size,
2506 .type = reg.y_type,
2507 .width = (size_t)(reg.y_type == kMTBlockWise ? reg.y_width : 0),
2508 .additional_data = reg.additional_data,
2509 .name = name,
2510 .is_unnamed = is_unnamed,
2511 }
2512 }
2513 }
2514 };
2515 } while (reg_iter != NULL);
2516}
2517
2518/// Replace numbered mark in WriteMergerState
2519///
2520/// Frees the last mark, moves (including adjusting mark names) marks from idx
2521/// to the last-but-one one and saves the new mark at given index.
2522///
2523/// @param[out] wms Merger state to adjust.
2524/// @param[in] idx Index at which new mark should be placed.
2525/// @param[in] entry New mark.
2526static inline void replace_numbered_mark(WriteMergerState *const wms,
2527 const size_t idx,
2528 const PossiblyFreedShadaEntry entry)
2529 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
2530{
2531 if (ARRAY_LAST_ENTRY(wms->numbered_marks).can_free_entry) {
2532 shada_free_shada_entry(&ARRAY_LAST_ENTRY(wms->numbered_marks).data);
2533 }
2534 for (size_t i = idx; i < ARRAY_SIZE(wms->numbered_marks) - 1; i++) {
2535 if (wms->numbered_marks[i].data.type == kSDItemGlobalMark) {
2536 wms->numbered_marks[i].data.data.filemark.name = (char)('0' + (int)i + 1);
2537 }
2538 }
2539 memmove(wms->numbered_marks + idx + 1, wms->numbered_marks + idx,
2540 sizeof(wms->numbered_marks[0])
2541 * (ARRAY_SIZE(wms->numbered_marks) - 1 - idx));
2542 wms->numbered_marks[idx] = entry;
2543 wms->numbered_marks[idx].data.data.filemark.name = (char)('0' + (int)idx);
2544}
2545
2546/// Find buffers ignored due to their location.
2547///
2548/// @param[out] removable_bufs Cache of buffers ignored due to their location.
2549static inline void find_removable_bufs(khash_t(bufset) *removable_bufs)
2550{
2551 FOR_ALL_BUFFERS(buf) {
2552 if (buf->b_ffname != NULL && shada_removable((char *)buf->b_ffname)) {
2553 int kh_ret;
2554 (void)kh_put(bufset, removable_bufs, (uintptr_t)buf, &kh_ret);
2555 }
2556 }
2557}
2558
2559/// Write ShaDa file
2560///
2561/// @param[in] sd_writer Structure containing file writer definition.
2562/// @param[in] sd_reader Structure containing file reader definition. If it is
2563/// not NULL then contents of this file will be merged
2564/// with current Neovim runtime.
2565static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
2566 ShaDaReadDef *const sd_reader)
2567 FUNC_ATTR_NONNULL_ARG(1)
2568{
2569 ShaDaWriteResult ret = kSDWriteSuccessfull;
2570 int max_kbyte_i = get_shada_parameter('s');
2571 if (max_kbyte_i < 0) {
2572 max_kbyte_i = 10;
2573 }
2574 if (max_kbyte_i == 0) {
2575 return ret;
2576 }
2577
2578 WriteMergerState *const wms = xcalloc(1, sizeof(*wms));
2579 bool dump_one_history[HIST_COUNT];
2580 const bool dump_global_vars = (find_shada_parameter('!') != NULL);
2581 int max_reg_lines = get_shada_parameter('<');
2582 if (max_reg_lines < 0) {
2583 max_reg_lines = get_shada_parameter('"');
2584 }
2585 const bool dump_registers = (max_reg_lines != 0);
2586 khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
2587 const size_t max_kbyte = (size_t) max_kbyte_i;
2588 const size_t num_marked_files = (size_t) get_shada_parameter('\'');
2589 const bool dump_global_marks = get_shada_parameter('f') != 0;
2590 bool dump_history = false;
2591
2592 // Initialize history merger
2593 for (uint8_t i = 0; i < HIST_COUNT; i++) {
2594 long num_saved = get_shada_parameter(hist_type2char(i));
2595 if (num_saved == -1) {
2596 num_saved = p_hi;
2597 }
2598 if (num_saved > 0) {
2599 dump_history = true;
2600 dump_one_history[i] = true;
2601 hms_init(&wms->hms[i], i, (size_t) num_saved, sd_reader != NULL, false);
2602 } else {
2603 dump_one_history[i] = false;
2604 }
2605 }
2606
2607 const unsigned srni_flags = (unsigned) (
2608 kSDReadUndisableableData
2609 | kSDReadUnknown
2610 | (dump_history ? kSDReadHistory : 0)
2611 | (dump_registers ? kSDReadRegisters : 0)
2612 | (dump_global_vars ? kSDReadVariables : 0)
2613 | (dump_global_marks ? kSDReadGlobalMarks : 0)
2614 | (num_marked_files ? kSDReadLocalMarks | kSDReadChanges : 0));
2615
2616 msgpack_packer *const packer = msgpack_packer_new(sd_writer,
2617 &msgpack_sd_writer_write);
2618
2619 // Set b_last_cursor for all the buffers that have a window.
2620 //
2621 // It is needed to correctly save '"' mark on exit. Has a side effect of
2622 // setting '"' mark in all windows on :wshada to the current cursor
2623 // position (basically what :wviminfo used to do).
2624 FOR_ALL_TAB_WINDOWS(tp, wp) {
2625 set_last_cursor(wp);
2626 }
2627
2628 find_removable_bufs(&removable_bufs);
2629
2630 // Write header
2631 if (shada_pack_entry(packer, (ShadaEntry) {
2632 .type = kSDItemHeader,
2633 .timestamp = os_time(),
2634 .data = {
2635 .header = {
2636 .size = 5,
2637 .capacity = 5,
2638 .items = ((KeyValuePair[]) {
2639 { STATIC_CSTR_AS_STRING("generator"),
2640 STRING_OBJ(STATIC_CSTR_AS_STRING("nvim")) },
2641 { STATIC_CSTR_AS_STRING("version"),
2642 STRING_OBJ(cstr_as_string(longVersion)) },
2643 { STATIC_CSTR_AS_STRING("max_kbyte"),
2644 INTEGER_OBJ((Integer) max_kbyte) },
2645 { STATIC_CSTR_AS_STRING("pid"),
2646 INTEGER_OBJ((Integer) os_get_pid()) },
2647 { STATIC_CSTR_AS_STRING("encoding"),
2648 STRING_OBJ(cstr_as_string((char *) p_enc)) },
2649 }),
2650 }
2651 }
2652 }, 0) == kSDWriteFailed) {
2653 ret = kSDWriteFailed;
2654 goto shada_write_exit;
2655 }
2656
2657 // Write buffer list
2658 if (find_shada_parameter('%') != NULL) {
2659 ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs);
2660 if (shada_pack_entry(packer, buflist_entry, 0) == kSDWriteFailed) {
2661 xfree(buflist_entry.data.buffer_list.buffers);
2662 ret = kSDWriteFailed;
2663 goto shada_write_exit;
2664 }
2665 xfree(buflist_entry.data.buffer_list.buffers);
2666 }
2667
2668 // Write some of the variables
2669 if (dump_global_vars) {
2670 const void *var_iter = NULL;
2671 const Timestamp cur_timestamp = os_time();
2672 do {
2673 typval_T vartv;
2674 const char *name = NULL;
2675 var_iter = var_shada_iter(var_iter, &name, &vartv, VAR_FLAVOUR_SHADA);
2676 if (name == NULL) {
2677 break;
2678 }
2679 typval_T tgttv;
2680 tv_copy(&vartv, &tgttv);
2681 ShaDaWriteResult spe_ret;
2682 if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) {
2683 .type = kSDItemVariable,
2684 .timestamp = cur_timestamp,
2685 .data = {
2686 .global_var = {
2687 .name = (char *) name,
2688 .value = tgttv,
2689 .additional_elements = NULL,
2690 }
2691 }
2692 }, max_kbyte)) == kSDWriteFailed) {
2693 tv_clear(&vartv);
2694 tv_clear(&tgttv);
2695 ret = kSDWriteFailed;
2696 goto shada_write_exit;
2697 }
2698 tv_clear(&vartv);
2699 tv_clear(&tgttv);
2700 if (spe_ret == kSDWriteSuccessfull) {
2701 int kh_ret;
2702 (void) kh_put(strset, &wms->dumped_variables, name, &kh_ret);
2703 }
2704 } while (var_iter != NULL);
2705 }
2706
2707 // Initialize jump list
2708 setpcmark();
2709 cleanup_jumplist(curwin, false);
2710 wms->jumps_size = shada_init_jumps(wms->jumps, &removable_bufs);
2711
2712 const bool search_highlighted = !(no_hlsearch
2713 || find_shada_parameter('h') != NULL);
2714 const bool search_last_used = search_was_last_used();
2715
2716 // Initialize search pattern
2717 add_search_pattern(&wms->search_pattern, &get_search_pattern, false,
2718 search_last_used, search_highlighted);
2719
2720 // Initialize substitute search pattern
2721 add_search_pattern(&wms->sub_search_pattern, &get_substitute_pattern, true,
2722 search_last_used, search_highlighted);
2723
2724 // Initialize substitute replacement string
2725 {
2726 SubReplacementString sub;
2727 sub_get_replacement(&sub);
2728 wms->replacement = (PossiblyFreedShadaEntry) {
2729 .can_free_entry = false,
2730 .data = {
2731 .type = kSDItemSubString,
2732 .timestamp = sub.timestamp,
2733 .data = {
2734 .sub_string = {
2735 .sub = (char *) sub.sub,
2736 .additional_elements = sub.additional_elements,
2737 }
2738 }
2739 }
2740 };
2741 }
2742
2743 // Initialize global marks
2744 if (dump_global_marks) {
2745 const void *global_mark_iter = NULL;
2746 size_t digit_mark_idx = 0;
2747 do {
2748 char name = NUL;
2749 xfmark_T fm;
2750 global_mark_iter = mark_global_iter(global_mark_iter, &name, &fm);
2751 if (name == NUL) {
2752 break;
2753 }
2754 const char *fname;
2755 if (fm.fmark.fnum == 0) {
2756 assert(fm.fname != NULL);
2757 if (shada_removable((const char *) fm.fname)) {
2758 continue;
2759 }
2760 fname = (const char *) fm.fname;
2761 } else {
2762 const buf_T *const buf = buflist_findnr(fm.fmark.fnum);
2763 if (buf == NULL || buf->b_ffname == NULL
2764 || in_bufset(&removable_bufs, buf)) {
2765 continue;
2766 }
2767 fname = (const char *) buf->b_ffname;
2768 }
2769 const PossiblyFreedShadaEntry pf_entry = {
2770 .can_free_entry = false,
2771 .data = {
2772 .type = kSDItemGlobalMark,
2773 .timestamp = fm.fmark.timestamp,
2774 .data = {
2775 .filemark = {
2776 .mark = fm.fmark.mark,
2777 .name = name,
2778 .additional_data = fm.fmark.additional_data,
2779 .fname = (char *)fname,
2780 }
2781 }
2782 },
2783 };
2784 if (ascii_isdigit(name)) {
2785 replace_numbered_mark(wms, digit_mark_idx++, pf_entry);
2786 } else {
2787 wms->global_marks[mark_global_index(name)] = pf_entry;
2788 }
2789 } while (global_mark_iter != NULL);
2790 }
2791
2792 // Initialize registers
2793 if (dump_registers) {
2794 shada_initialize_registers(wms, max_reg_lines);
2795 }
2796
2797 // Initialize buffers
2798 if (num_marked_files > 0) {
2799 FOR_ALL_BUFFERS(buf) {
2800 if (buf->b_ffname == NULL || in_bufset(&removable_bufs, buf)) {
2801 continue;
2802 }
2803 const void *local_marks_iter = NULL;
2804 const char *const fname = (const char *) buf->b_ffname;
2805 khiter_t k;
2806 int kh_ret;
2807 k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
2808 FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
2809 if (kh_ret > 0) {
2810 memset(filemarks, 0, sizeof(*filemarks));
2811 }
2812 do {
2813 fmark_T fm;
2814 char name = NUL;
2815 local_marks_iter = mark_buffer_iter(local_marks_iter, buf, &name, &fm);
2816 if (name == NUL) {
2817 break;
2818 }
2819 filemarks->marks[mark_local_index(name)] = (PossiblyFreedShadaEntry) {
2820 .can_free_entry = false,
2821 .data = {
2822 .type = kSDItemLocalMark,
2823 .timestamp = fm.timestamp,
2824 .data = {
2825 .filemark = {
2826 .mark = fm.mark,
2827 .name = name,
2828 .fname = (char *) fname,
2829 .additional_data = fm.additional_data,
2830 }
2831 }
2832 }
2833 };
2834 if (fm.timestamp > filemarks->greatest_timestamp) {
2835 filemarks->greatest_timestamp = fm.timestamp;
2836 }
2837 } while (local_marks_iter != NULL);
2838 for (int i = 0; i < buf->b_changelistlen; i++) {
2839 const fmark_T fm = buf->b_changelist[i];
2840 filemarks->changes[i] = (PossiblyFreedShadaEntry) {
2841 .can_free_entry = false,
2842 .data = {
2843 .type = kSDItemChange,
2844 .timestamp = fm.timestamp,
2845 .data = {
2846 .filemark = {
2847 .mark = fm.mark,
2848 .fname = (char *) fname,
2849 .additional_data = fm.additional_data,
2850 }
2851 }
2852 }
2853 };
2854 if (fm.timestamp > filemarks->greatest_timestamp) {
2855 filemarks->greatest_timestamp = fm.timestamp;
2856 }
2857 }
2858 filemarks->changes_size = (size_t) buf->b_changelistlen;
2859 }
2860 }
2861
2862 if (sd_reader != NULL) {
2863 const ShaDaWriteResult srww_ret = shada_read_when_writing(
2864 sd_reader, srni_flags, max_kbyte, wms, packer);
2865 if (srww_ret != kSDWriteSuccessfull) {
2866 ret = srww_ret;
2867 }
2868 }
2869
2870 // Update numbered marks: '0' should be replaced with the current position,
2871 // '9' should be removed and all other marks shifted.
2872 if (!ignore_buf(curbuf, &removable_bufs) && curwin->w_cursor.lnum != 0) {
2873 replace_numbered_mark(wms, 0, (PossiblyFreedShadaEntry) {
2874 .can_free_entry = false,
2875 .data = {
2876 .type = kSDItemGlobalMark,
2877 .timestamp = os_time(),
2878 .data = {
2879 .filemark = {
2880 .mark = curwin->w_cursor,
2881 .name = '0',
2882 .additional_data = NULL,
2883 .fname = (char *)curbuf->b_ffname,
2884 }
2885 }
2886 },
2887 });
2888 }
2889
2890 // Write the rest
2891#define PACK_WMS_ARRAY(wms_array) \
2892 do { \
2893 for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \
2894 if (wms_array[i_].data.type != kSDItemMissing) { \
2895 if (shada_pack_pfreed_entry(packer, wms_array[i_], max_kbyte) \
2896 == kSDWriteFailed) { \
2897 ret = kSDWriteFailed; \
2898 goto shada_write_exit; \
2899 } \
2900 } \
2901 } \
2902 } while (0)
2903 PACK_WMS_ARRAY(wms->global_marks);
2904 PACK_WMS_ARRAY(wms->numbered_marks);
2905 PACK_WMS_ARRAY(wms->registers);
2906 for (size_t i = 0; i < wms->jumps_size; i++) {
2907 if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte)
2908 == kSDWriteFailed) {
2909 ret = kSDWriteFailed;
2910 goto shada_write_exit;
2911 }
2912 }
2913#define PACK_WMS_ENTRY(wms_entry) \
2914 do { \
2915 if (wms_entry.data.type != kSDItemMissing) { \
2916 if (shada_pack_pfreed_entry(packer, wms_entry, max_kbyte) \
2917 == kSDWriteFailed) { \
2918 ret = kSDWriteFailed; \
2919 goto shada_write_exit; \
2920 } \
2921 } \
2922 } while (0)
2923 PACK_WMS_ENTRY(wms->search_pattern);
2924 PACK_WMS_ENTRY(wms->sub_search_pattern);
2925 PACK_WMS_ENTRY(wms->replacement);
2926#undef PACK_WMS_ENTRY
2927
2928 const size_t file_markss_size = kh_size(&wms->file_marks);
2929 FileMarks **const all_file_markss =
2930 xmalloc(file_markss_size * sizeof(*all_file_markss));
2931 FileMarks **cur_file_marks = all_file_markss;
2932 for (khint_t i = kh_begin(&wms->file_marks); i != kh_end(&wms->file_marks);
2933 i++) {
2934 if (kh_exist(&wms->file_marks, i)) {
2935 *cur_file_marks++ = &kh_val(&wms->file_marks, i);
2936 }
2937 }
2938 qsort((void *) all_file_markss, file_markss_size, sizeof(*all_file_markss),
2939 &compare_file_marks);
2940 const size_t file_markss_to_dump = MIN(num_marked_files, file_markss_size);
2941 for (size_t i = 0; i < file_markss_to_dump; i++) {
2942 PACK_WMS_ARRAY(all_file_markss[i]->marks);
2943 for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) {
2944 if (shada_pack_pfreed_entry(packer, all_file_markss[i]->changes[j],
2945 max_kbyte) == kSDWriteFailed) {
2946 ret = kSDWriteFailed;
2947 goto shada_write_exit;
2948 }
2949 }
2950 for (size_t j = 0; j < all_file_markss[i]->additional_marks_size; j++) {
2951 if (shada_pack_entry(packer, all_file_markss[i]->additional_marks[j],
2952 0) == kSDWriteFailed) {
2953 shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]);
2954 ret = kSDWriteFailed;
2955 goto shada_write_exit;
2956 }
2957 shada_free_shada_entry(&all_file_markss[i]->additional_marks[j]);
2958 }
2959 xfree(all_file_markss[i]->additional_marks);
2960 }
2961 xfree(all_file_markss);
2962#undef PACK_WMS_ARRAY
2963
2964 if (dump_history) {
2965 for (size_t i = 0; i < HIST_COUNT; i++) {
2966 if (dump_one_history[i]) {
2967 hms_insert_whole_neovim_history(&wms->hms[i]);
2968 HMS_ITER(&wms->hms[i], cur_entry, {
2969 if (shada_pack_pfreed_entry(
2970 packer, (PossiblyFreedShadaEntry) {
2971 .data = cur_entry->data,
2972 .can_free_entry = cur_entry->can_free_entry,
2973 }, max_kbyte) == kSDWriteFailed) {
2974 ret = kSDWriteFailed;
2975 break;
2976 }
2977 })
2978 if (ret == kSDWriteFailed) {
2979 goto shada_write_exit;
2980 }
2981 }
2982 }
2983 }
2984
2985shada_write_exit:
2986 for (size_t i = 0; i < HIST_COUNT; i++) {
2987 if (dump_one_history[i]) {
2988 hms_dealloc(&wms->hms[i]);
2989 }
2990 }
2991 kh_dealloc(file_marks, &wms->file_marks);
2992 kh_dealloc(bufset, &removable_bufs);
2993 msgpack_packer_free(packer);
2994 kh_dealloc(strset, &wms->dumped_variables);
2995 xfree(wms);
2996 return ret;
2997}
2998
2999#undef IGNORE_BUF
3000#undef PACK_STATIC_STR
3001
3002/// Write ShaDa file to a given location
3003///
3004/// @param[in] fname File to write to. If it is NULL or empty then default
3005/// location is used.
3006/// @param[in] nomerge If true then old file is ignored.
3007///
3008/// @return OK if writing was successfull, FAIL otherwise.
3009int shada_write_file(const char *const file, bool nomerge)
3010{
3011 if (shada_disabled()) {
3012 return FAIL;
3013 }
3014
3015 char *const fname = shada_filename(file);
3016 char *tempname = NULL;
3017 ShaDaWriteDef sd_writer = {
3018 .write = &write_file,
3019 .close = &close_sd_writer,
3020 .error = NULL,
3021 };
3022 ShaDaReadDef sd_reader = { .close = NULL };
3023
3024 if (!nomerge) {
3025 int error;
3026 if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) {
3027 if (error != UV_ENOENT) {
3028 emsgf(_(SERR "System error while opening ShaDa file %s for reading "
3029 "to merge before writing it: %s"),
3030 fname, os_strerror(error));
3031 // Try writing the file even if opening it emerged any issues besides
3032 // file not existing: maybe writing will succeed nevertheless.
3033 }
3034 nomerge = true;
3035 goto shada_write_file_nomerge;
3036 }
3037 tempname = modname(fname, ".tmp.a", false);
3038 if (tempname == NULL) {
3039 nomerge = true;
3040 goto shada_write_file_nomerge;
3041 }
3042
3043 // Save permissions from the original file, with modifications:
3044 int perm = (int) os_getperm(fname);
3045 perm = (perm >= 0) ? ((perm & 0777) | 0600) : 0600;
3046 // ^3 ^1 ^2 ^2,3
3047 // 1: Strip SUID bit if any.
3048 // 2: Make sure that user can always read and write the result.
3049 // 3: If somebody happened to delete the file after it was opened for
3050 // reading use u=rw permissions.
3051shada_write_file_open: {}
3052 sd_writer.cookie = file_open_new(
3053 &error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
3054 if (sd_writer.cookie == NULL) {
3055 if (error == UV_EEXIST || error == UV_ELOOP) {
3056 // File already exists, try another name
3057 char *const wp = tempname + strlen(tempname) - 1;
3058 if (*wp == 'z') {
3059 // Tried names from .tmp.a to .tmp.z, all failed. Something must be
3060 // wrong then.
3061 EMSG2(_("E138: All %s.tmp.X files exist, cannot write ShaDa file!"),
3062 fname);
3063 xfree(fname);
3064 xfree(tempname);
3065 assert(sd_reader.close != NULL);
3066 sd_reader.close(&sd_reader);
3067 return FAIL;
3068 } else {
3069 (*wp)++;
3070 goto shada_write_file_open;
3071 }
3072 } else {
3073 emsgf(_(SERR "System error while opening temporary ShaDa file %s "
3074 "for writing: %s"), tempname, os_strerror(error));
3075 }
3076 }
3077 }
3078 if (nomerge) {
3079shada_write_file_nomerge: {}
3080 char *const tail = path_tail_with_sep(fname);
3081 if (tail != fname) {
3082 const char tail_save = *tail;
3083 *tail = NUL;
3084 if (!os_isdir(fname)) {
3085 int ret;
3086 char *failed_dir;
3087 if ((ret = os_mkdir_recurse(fname, 0700, &failed_dir)) != 0) {
3088 EMSG3(_(SERR "Failed to create directory %s "
3089 "for writing ShaDa file: %s"),
3090 failed_dir, os_strerror(ret));
3091 xfree(fname);
3092 xfree(failed_dir);
3093 return FAIL;
3094 }
3095 }
3096 *tail = tail_save;
3097 }
3098 int error;
3099 sd_writer.cookie = file_open_new(&error, fname, kFileCreate|kFileTruncate,
3100 0600);
3101 if (sd_writer.cookie == NULL) {
3102 emsgf(_(SERR "System error while opening ShaDa file %s for writing: %s"),
3103 fname, os_strerror(error));
3104 }
3105 }
3106
3107 if (sd_writer.cookie == NULL) {
3108 xfree(fname);
3109 xfree(tempname);
3110 if (sd_reader.cookie != NULL) {
3111 sd_reader.close(&sd_reader);
3112 }
3113 return FAIL;
3114 }
3115
3116 if (p_verbose > 0) {
3117 verbose_enter();
3118 smsg(_("Writing ShaDa file \"%s\""), fname);
3119 verbose_leave();
3120 }
3121
3122 const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge
3123 ? NULL
3124 : &sd_reader));
3125 assert(sw_ret != kSDWriteIgnError);
3126 if (!nomerge) {
3127 sd_reader.close(&sd_reader);
3128 bool did_remove = false;
3129 if (sw_ret == kSDWriteSuccessfull) {
3130#ifdef UNIX
3131 // For Unix we check the owner of the file. It's not very nice to
3132 // overwrite a user’s viminfo file after a "su root", with a
3133 // viminfo file that the user can't read.
3134 FileInfo old_info;
3135 if (os_fileinfo((char *)fname, &old_info)) {
3136 if (getuid() == ROOT_UID) {
3137 if (old_info.stat.st_uid != ROOT_UID
3138 || old_info.stat.st_gid != getgid()) {
3139 const uv_uid_t old_uid = (uv_uid_t)old_info.stat.st_uid;
3140 const uv_gid_t old_gid = (uv_gid_t)old_info.stat.st_gid;
3141 const int fchown_ret = os_fchown(file_fd(sd_writer.cookie),
3142 old_uid, old_gid);
3143 if (fchown_ret != 0) {
3144 EMSG3(_(RNERR "Failed setting uid and gid for file %s: %s"),
3145 tempname, os_strerror(fchown_ret));
3146 goto shada_write_file_did_not_remove;
3147 }
3148 }
3149 } else if (!(old_info.stat.st_uid == getuid()
3150 ? (old_info.stat.st_mode & 0200)
3151 : (old_info.stat.st_gid == getgid()
3152 ? (old_info.stat.st_mode & 0020)
3153 : (old_info.stat.st_mode & 0002)))) {
3154 EMSG2(_("E137: ShaDa file is not writable: %s"), fname);
3155 goto shada_write_file_did_not_remove;
3156 }
3157 }
3158#endif
3159 if (vim_rename(tempname, fname) == -1) {
3160 EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"),
3161 tempname, fname);
3162 } else {
3163 did_remove = true;
3164 os_remove(tempname);
3165 }
3166 } else {
3167 if (sw_ret == kSDWriteReadNotShada) {
3168 EMSG3(_(RNERR "Did not rename %s because %s "
3169 "does not look like a ShaDa file"), tempname, fname);
3170 } else {
3171 EMSG3(_(RNERR "Did not rename %s to %s because there were errors "
3172 "during writing it"), tempname, fname);
3173 }
3174 }
3175 if (!did_remove) {
3176#ifdef UNIX
3177shada_write_file_did_not_remove:
3178#endif
3179 EMSG3(_(RNERR "Do not forget to remove %s or rename it manually to %s."),
3180 tempname, fname);
3181 }
3182 xfree(tempname);
3183 }
3184 sd_writer.close(&sd_writer);
3185
3186 xfree(fname);
3187 return OK;
3188}
3189
3190/// Read marks information from ShaDa file
3191///
3192/// @return OK in case of success, FAIL otherwise.
3193int shada_read_marks(void)
3194{
3195 return shada_read_file(NULL, kShaDaWantMarks);
3196}
3197
3198/// Read all information from ShaDa file
3199///
3200/// @param[in] fname File to write to. If it is NULL or empty then default
3201/// @param[in] forceit If true, use forced reading (prioritize file contents
3202/// over current Neovim state).
3203/// @param[in] missing_ok If true, do not error out when file is missing.
3204///
3205/// @return OK in case of success, FAIL otherwise.
3206int shada_read_everything(const char *const fname, const bool forceit,
3207 const bool missing_ok)
3208{
3209 return shada_read_file(fname,
3210 kShaDaWantInfo|kShaDaWantMarks|kShaDaGetOldfiles
3211 |(forceit?kShaDaForceit:0)
3212 |(missing_ok?0:kShaDaMissingError));
3213}
3214
3215static void shada_free_shada_entry(ShadaEntry *const entry)
3216{
3217 if (entry == NULL) {
3218 return;
3219 }
3220 switch (entry->type) {
3221 case kSDItemMissing: {
3222 break;
3223 }
3224 case kSDItemUnknown: {
3225 xfree(entry->data.unknown_item.contents);
3226 break;
3227 }
3228 case kSDItemHeader: {
3229 api_free_dictionary(entry->data.header);
3230 break;
3231 }
3232 case kSDItemChange:
3233 case kSDItemJump:
3234 case kSDItemGlobalMark:
3235 case kSDItemLocalMark: {
3236 tv_dict_unref(entry->data.filemark.additional_data);
3237 xfree(entry->data.filemark.fname);
3238 break;
3239 }
3240 case kSDItemSearchPattern: {
3241 tv_dict_unref(entry->data.search_pattern.additional_data);
3242 xfree(entry->data.search_pattern.pat);
3243 break;
3244 }
3245 case kSDItemRegister: {
3246 tv_dict_unref(entry->data.reg.additional_data);
3247 for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
3248 xfree(entry->data.reg.contents[i]);
3249 }
3250 xfree(entry->data.reg.contents);
3251 break;
3252 }
3253 case kSDItemHistoryEntry: {
3254 tv_list_unref(entry->data.history_item.additional_elements);
3255 xfree(entry->data.history_item.string);
3256 break;
3257 }
3258 case kSDItemVariable: {
3259 tv_list_unref(entry->data.global_var.additional_elements);
3260 xfree(entry->data.global_var.name);
3261 tv_clear(&entry->data.global_var.value);
3262 break;
3263 }
3264 case kSDItemSubString: {
3265 tv_list_unref(entry->data.sub_string.additional_elements);
3266 xfree(entry->data.sub_string.sub);
3267 break;
3268 }
3269 case kSDItemBufferList: {
3270 for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
3271 xfree(entry->data.buffer_list.buffers[i].fname);
3272 tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
3273 }
3274 xfree(entry->data.buffer_list.buffers);
3275 break;
3276 }
3277 }
3278}
3279
3280#ifndef HAVE_BE64TOH
3281static inline uint64_t be64toh(uint64_t big_endian_64_bits)
3282{
3283#ifdef ORDER_BIG_ENDIAN
3284 return big_endian_64_bits;
3285#else
3286 // It may appear that when !defined(ORDER_BIG_ENDIAN) actual order is big
3287 // endian. This variant is suboptimal, but it works regardless of actual
3288 // order.
3289 uint8_t *buf = (uint8_t *) &big_endian_64_bits;
3290 uint64_t ret = 0;
3291 for (size_t i = 8; i; i--) {
3292 ret |= ((uint64_t) buf[i - 1]) << ((8 - i) * 8);
3293 }
3294 return ret;
3295#endif
3296}
3297#endif
3298
3299/// Read given number of bytes into given buffer, display error if needed
3300///
3301/// @param[in] sd_reader Structure containing file reader definition.
3302/// @param[out] buffer Where to save the results.
3303/// @param[in] length How many bytes should be read.
3304///
3305/// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if
3306/// there were not enough bytes to read or kSDReadStatusReadError if
3307/// there was some error while reading.
3308static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
3309 char *const buffer,
3310 const size_t length)
3311 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
3312{
3313 const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length);
3314
3315 if (read_bytes != (ptrdiff_t)length) {
3316 if (sd_reader->error != NULL) {
3317 emsgf(_(SERR "System error while reading ShaDa file: %s"),
3318 sd_reader->error);
3319 return kSDReadStatusReadError;
3320 } else {
3321 emsgf(_(RCERR "Error while reading ShaDa file: "
3322 "last entry specified that it occupies %" PRIu64 " bytes, "
3323 "but file ended earlier"),
3324 (uint64_t)length);
3325 return kSDReadStatusNotShaDa;
3326 }
3327 }
3328 return kSDReadStatusSuccess;
3329}
3330
3331/// Read next unsigned integer from file
3332///
3333/// Errors out if the result is not an unsigned integer.
3334///
3335/// Unlike msgpack own function this one works with `FILE *` and reads *exactly*
3336/// as much bytes as needed, making it possible to avoid both maintaining own
3337/// buffer and calling `fseek`.
3338///
3339/// One byte from file stream is always consumed, even if it is not correct.
3340///
3341/// @param[in] sd_reader Structure containing file reader definition.
3342/// @param[out] result Location where result is saved.
3343///
3344/// @return kSDReadStatusSuccess if reading was successfull,
3345/// kSDReadStatusNotShaDa if there were not enough bytes to read or
3346/// kSDReadStatusReadError if reading failed for whatever reason.
3347static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
3348 const int first_char,
3349 uint64_t *const result)
3350 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
3351{
3352 const uintmax_t fpos = sd_reader->fpos - 1;
3353
3354 if (first_char == EOF) {
3355 if (sd_reader->error) {
3356 emsgf(_(SERR "System error while reading integer from ShaDa file: %s"),
3357 sd_reader->error);
3358 return kSDReadStatusReadError;
3359 } else if (sd_reader->eof) {
3360 emsgf(_(RCERR "Error while reading ShaDa file: "
3361 "expected positive integer at position %" PRIu64
3362 ", but got nothing"),
3363 (uint64_t) fpos);
3364 return kSDReadStatusNotShaDa;
3365 }
3366 }
3367
3368 if (~first_char & 0x80) {
3369 // Positive fixnum
3370 *result = (uint64_t) ((uint8_t) first_char);
3371 } else {
3372 size_t length = 0;
3373 switch (first_char) {
3374 case 0xCC: { // uint8
3375 length = 1;
3376 break;
3377 }
3378 case 0xCD: { // uint16
3379 length = 2;
3380 break;
3381 }
3382 case 0xCE: { // uint32
3383 length = 4;
3384 break;
3385 }
3386 case 0xCF: { // uint64
3387 length = 8;
3388 break;
3389 }
3390 default: {
3391 emsgf(_(RCERR "Error while reading ShaDa file: "
3392 "expected positive integer at position %" PRIu64),
3393 (uint64_t) fpos);
3394 return kSDReadStatusNotShaDa;
3395 }
3396 }
3397 uint64_t buf = 0;
3398 char *buf_u8 = (char *) &buf;
3399 ShaDaReadResult fl_ret;
3400 if ((fl_ret = fread_len(sd_reader, &(buf_u8[sizeof(buf)-length]), length))
3401 != kSDReadStatusSuccess) {
3402 return fl_ret;
3403 }
3404 *result = be64toh(buf);
3405 }
3406 return kSDReadStatusSuccess;
3407}
3408
3409#define READERR(entry_name, error_desc) \
3410 RERR "Error while reading ShaDa file: " \
3411 entry_name " entry at position %" PRIu64 " " \
3412 error_desc
3413#define CHECK_KEY(key, expected) ( \
3414 key.via.str.size == sizeof(expected) - 1 \
3415 && STRNCMP(key.via.str.ptr, expected, sizeof(expected) - 1) == 0)
3416#define CLEAR_GA_AND_ERROR_OUT(ga) \
3417 do { \
3418 ga_clear(&ga); \
3419 goto shada_read_next_item_error; \
3420 } while (0)
3421#define ID(s) s
3422#define BINDUP(b) xmemdupz(b.ptr, b.size)
3423#define TOINT(s) ((int) (s))
3424#define TOLONG(s) ((long) (s))
3425#define TOCHAR(s) ((char) (s))
3426#define TOU8(s) ((uint8_t) (s))
3427#define TOSIZE(s) ((size_t) (s))
3428#define CHECKED_ENTRY(condition, error_desc, entry_name, obj, tgt, attr, \
3429 proc) \
3430 do { \
3431 if (!(condition)) { \
3432 emsgf(_(READERR(entry_name, error_desc)), initial_fpos); \
3433 CLEAR_GA_AND_ERROR_OUT(ad_ga); \
3434 } \
3435 tgt = proc(obj.via.attr); \
3436 } while (0)
3437#define CHECK_KEY_IS_STR(un, entry_name) \
3438 if (un.data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \
3439 emsgf(_(READERR(entry_name, "has key which is not a string")), \
3440 initial_fpos); \
3441 CLEAR_GA_AND_ERROR_OUT(ad_ga); \
3442 } else if (un.data.via.map.ptr[i].key.via.str.size == 0) { \
3443 emsgf(_(READERR(entry_name, "has empty key")), initial_fpos); \
3444 CLEAR_GA_AND_ERROR_OUT(ad_ga); \
3445 }
3446#define CHECKED_KEY(un, entry_name, name, error_desc, tgt, condition, attr, \
3447 proc) \
3448 else if (CHECK_KEY( /* NOLINT(readability/braces) */ \
3449 un.data.via.map.ptr[i].key, name)) { \
3450 CHECKED_ENTRY( \
3451 condition, "has " name " key value " error_desc, \
3452 entry_name, un.data.via.map.ptr[i].val, \
3453 tgt, attr, proc); \
3454 }
3455#define TYPED_KEY(un, entry_name, name, type_name, tgt, objtype, attr, proc) \
3456 CHECKED_KEY( \
3457 un, entry_name, name, "which is not " type_name, tgt, \
3458 un.data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \
3459 attr, proc)
3460#define BOOLEAN_KEY(un, entry_name, name, tgt) \
3461 TYPED_KEY(un, entry_name, name, "a boolean", tgt, BOOLEAN, boolean, ID)
3462#define STRING_KEY(un, entry_name, name, tgt) \
3463 TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, BINDUP)
3464#define CONVERTED_STRING_KEY(un, entry_name, name, tgt) \
3465 TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, \
3466 BIN_CONVERTED)
3467#define INT_KEY(un, entry_name, name, tgt, proc) \
3468 CHECKED_KEY( \
3469 un, entry_name, name, "which is not an integer", tgt, \
3470 ((un.data.via.map.ptr[i].val.type \
3471 == MSGPACK_OBJECT_POSITIVE_INTEGER) \
3472 || (un.data.via.map.ptr[i].val.type \
3473 == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \
3474 i64, proc)
3475#define INTEGER_KEY(un, entry_name, name, tgt) \
3476 INT_KEY(un, entry_name, name, tgt, TOINT)
3477#define LONG_KEY(un, entry_name, name, tgt) \
3478 INT_KEY(un, entry_name, name, tgt, TOLONG)
3479#define ADDITIONAL_KEY(un) \
3480 else { /* NOLINT(readability/braces) */ \
3481 ga_grow(&ad_ga, 1); \
3482 memcpy(((char *)ad_ga.ga_data) + ((size_t)ad_ga.ga_len \
3483 * sizeof(*un.data.via.map.ptr)), \
3484 un.data.via.map.ptr + i, \
3485 sizeof(*un.data.via.map.ptr)); \
3486 ad_ga.ga_len++; \
3487 }
3488#define CONVERTED(str, len) (xmemdupz((str), (len)))
3489#define BIN_CONVERTED(b) CONVERTED(b.ptr, b.size)
3490#define SET_ADDITIONAL_DATA(tgt, name) \
3491 do { \
3492 if (ad_ga.ga_len) { \
3493 msgpack_object obj = { \
3494 .type = MSGPACK_OBJECT_MAP, \
3495 .via = { \
3496 .map = { \
3497 .size = (uint32_t) ad_ga.ga_len, \
3498 .ptr = ad_ga.ga_data, \
3499 } \
3500 } \
3501 }; \
3502 typval_T adtv; \
3503 if (msgpack_to_vim(obj, &adtv) == FAIL \
3504 || adtv.v_type != VAR_DICT) { \
3505 emsgf(_(READERR(name, \
3506 "cannot be converted to a VimL dictionary")), \
3507 initial_fpos); \
3508 ga_clear(&ad_ga); \
3509 tv_clear(&adtv); \
3510 goto shada_read_next_item_error; \
3511 } \
3512 tgt = adtv.vval.v_dict; \
3513 } \
3514 ga_clear(&ad_ga); \
3515 } while (0)
3516#define SET_ADDITIONAL_ELEMENTS(src, src_maxsize, tgt, name) \
3517 do { \
3518 if ((src).size > (size_t) (src_maxsize)) { \
3519 msgpack_object obj = { \
3520 .type = MSGPACK_OBJECT_ARRAY, \
3521 .via = { \
3522 .array = { \
3523 .size = ((src).size - (uint32_t) (src_maxsize)), \
3524 .ptr = (src).ptr + (src_maxsize), \
3525 } \
3526 } \
3527 }; \
3528 typval_T aetv; \
3529 if (msgpack_to_vim(obj, &aetv) == FAIL) { \
3530 emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
3531 initial_fpos); \
3532 tv_clear(&aetv); \
3533 goto shada_read_next_item_error; \
3534 } \
3535 assert(aetv.v_type == VAR_LIST); \
3536 (tgt) = aetv.vval.v_list; \
3537 } \
3538 } while (0)
3539
3540/// Iterate over shada file contents
3541///
3542/// @param[in] sd_reader Structure containing file reader definition.
3543/// @param[out] entry Address where next entry contents will be saved.
3544/// @param[in] flags Flags, determining whether and which items should be
3545/// skipped (see SRNIFlags enum).
3546/// @param[in] max_kbyte If non-zero, skip reading entries which have length
3547/// greater then given.
3548///
3549/// @return Any value from ShaDaReadResult enum.
3550static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader,
3551 ShadaEntry *const entry,
3552 const unsigned flags,
3553 const size_t max_kbyte)
3554 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
3555{
3556 ShaDaReadResult ret = kSDReadStatusMalformed;
3557shada_read_next_item_start:
3558 // Set entry type to kSDItemMissing and also make sure that all pointers in
3559 // data union are NULL so they are safe to xfree(). This is needed in case
3560 // somebody calls goto shada_read_next_item_error before anything is set in
3561 // the switch.
3562 memset(entry, 0, sizeof(*entry));
3563 if (sd_reader->eof) {
3564 return kSDReadStatusFinished;
3565 }
3566
3567 // First: manually unpack type, timestamp and length.
3568 // This is needed to avoid both seeking and having to maintain a buffer.
3569 uint64_t type_u64 = (uint64_t) kSDItemMissing;
3570 uint64_t timestamp_u64;
3571 uint64_t length_u64;
3572
3573 const uint64_t initial_fpos = (uint64_t) sd_reader->fpos;
3574 const int first_char = read_char(sd_reader);
3575 if (first_char == EOF && sd_reader->eof) {
3576 return kSDReadStatusFinished;
3577 }
3578
3579 ShaDaReadResult mru_ret;
3580 if (((mru_ret = msgpack_read_uint64(sd_reader, first_char, &type_u64))
3581 != kSDReadStatusSuccess)
3582 || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader),
3583 &timestamp_u64))
3584 != kSDReadStatusSuccess)
3585 || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader),
3586 &length_u64))
3587 != kSDReadStatusSuccess)) {
3588 return mru_ret;
3589 }
3590
3591 if (length_u64 > PTRDIFF_MAX) {
3592 emsgf(_(RCERR "Error while reading ShaDa file: "
3593 "there is an item at position %" PRIu64 " "
3594 "that is stated to be too long"),
3595 initial_fpos);
3596 return kSDReadStatusNotShaDa;
3597 }
3598
3599 const size_t length = (size_t)length_u64;
3600 entry->timestamp = (Timestamp)timestamp_u64;
3601
3602 if (type_u64 == 0) {
3603 // kSDItemUnknown cannot possibly pass that far because it is -1 and that
3604 // will fail in msgpack_read_uint64. But kSDItemMissing may and it will
3605 // otherwise be skipped because (1 << 0) will never appear in flags.
3606 emsgf(_(RCERR "Error while reading ShaDa file: "
3607 "there is an item at position %" PRIu64 " "
3608 "that must not be there: Missing items are "
3609 "for internal uses only"),
3610 initial_fpos);
3611 return kSDReadStatusNotShaDa;
3612 }
3613
3614 if ((type_u64 > SHADA_LAST_ENTRY
3615 ? !(flags & kSDReadUnknown)
3616 : !((unsigned) (1 << type_u64) & flags))
3617 || (max_kbyte && length > max_kbyte * 1024)) {
3618 // First entry is unknown or equal to "\n" (10)? Most likely this means that
3619 // current file is not a ShaDa file because first item should normally be
3620 // a header (excluding tests where first item is tested item). Check this by
3621 // parsing entry contents: in non-ShaDa files this will most likely result
3622 // in incomplete MessagePack string.
3623 if (initial_fpos == 0
3624 && (type_u64 == '\n' || type_u64 > SHADA_LAST_ENTRY)) {
3625 const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length,
3626 NULL, NULL);
3627 if (spm_ret != kSDReadStatusSuccess) {
3628 return spm_ret;
3629 }
3630 } else {
3631 const ShaDaReadResult srs_ret = sd_reader_skip(sd_reader, length);
3632 if (srs_ret != kSDReadStatusSuccess) {
3633 return srs_ret;
3634 }
3635 }
3636 goto shada_read_next_item_start;
3637 }
3638
3639 if (type_u64 > SHADA_LAST_ENTRY) {
3640 entry->type = kSDItemUnknown;
3641 entry->data.unknown_item.size = length;
3642 entry->data.unknown_item.type = type_u64;
3643 if (initial_fpos == 0) {
3644 const ShaDaReadResult spm_ret = shada_parse_msgpack(
3645 sd_reader, length, NULL, &entry->data.unknown_item.contents);
3646 if (spm_ret != kSDReadStatusSuccess) {
3647 entry->type = kSDItemMissing;
3648 }
3649 return spm_ret;
3650 } else {
3651 entry->data.unknown_item.contents = xmalloc(length);
3652 const ShaDaReadResult fl_ret = fread_len(
3653 sd_reader, entry->data.unknown_item.contents, length);
3654 if (fl_ret != kSDReadStatusSuccess) {
3655 shada_free_shada_entry(entry);
3656 entry->type = kSDItemMissing;
3657 }
3658 return fl_ret;
3659 }
3660 }
3661
3662 msgpack_unpacked unpacked;
3663 char *buf = NULL;
3664
3665 const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length,
3666 &unpacked, &buf);
3667 if (spm_ret != kSDReadStatusSuccess) {
3668 ret = spm_ret;
3669 goto shada_read_next_item_error;
3670 }
3671 ret = kSDReadStatusMalformed;
3672 entry->data = sd_default_values[type_u64].data;
3673 switch ((ShadaEntryType) type_u64) {
3674 case kSDItemHeader: {
3675 if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
3676 emsgf(_(READERR("header", "is not a dictionary")), initial_fpos);
3677 goto shada_read_next_item_error;
3678 }
3679 break;
3680 }
3681 case kSDItemSearchPattern: {
3682 if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
3683 emsgf(_(READERR("search pattern", "is not a dictionary")),
3684 initial_fpos);
3685 goto shada_read_next_item_error;
3686 }
3687 garray_T ad_ga;
3688 ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
3689 for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
3690 CHECK_KEY_IS_STR(unpacked, "search pattern")
3691 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC,
3692 entry->data.search_pattern.magic)
3693 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE,
3694 entry->data.search_pattern.smartcase)
3695 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET,
3696 entry->data.search_pattern.has_line_offset)
3697 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END,
3698 entry->data.search_pattern.place_cursor_at_end)
3699 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED,
3700 entry->data.search_pattern.is_last_used)
3701 BOOLEAN_KEY(unpacked, "search pattern",
3702 SEARCH_KEY_IS_SUBSTITUTE_PATTERN,
3703 entry->data.search_pattern.is_substitute_pattern)
3704 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED,
3705 entry->data.search_pattern.highlighted)
3706 BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD,
3707 entry->data.search_pattern.search_backward)
3708 INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET,
3709 entry->data.search_pattern.offset)
3710 CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT,
3711 entry->data.search_pattern.pat)
3712 ADDITIONAL_KEY(unpacked)
3713 }
3714 if (entry->data.search_pattern.pat == NULL) {
3715 emsgf(_(READERR("search pattern", "has no pattern")), initial_fpos);
3716 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3717 }
3718 SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
3719 "search pattern");
3720 break;
3721 }
3722 case kSDItemChange:
3723 case kSDItemJump:
3724 case kSDItemGlobalMark:
3725 case kSDItemLocalMark: {
3726 if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
3727 emsgf(_(READERR("mark", "is not a dictionary")), initial_fpos);
3728 goto shada_read_next_item_error;
3729 }
3730 garray_T ad_ga;
3731 ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
3732 for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
3733 CHECK_KEY_IS_STR(unpacked, "mark")
3734 if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
3735 if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
3736 emsgf(_(READERR("mark", "has n key which is only valid for "
3737 "local and global mark entries")), initial_fpos);
3738 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3739 }
3740 CHECKED_ENTRY(
3741 (unpacked.data.via.map.ptr[i].val.type
3742 == MSGPACK_OBJECT_POSITIVE_INTEGER),
3743 "has n key value which is not an unsigned integer",
3744 "mark", unpacked.data.via.map.ptr[i].val,
3745 entry->data.filemark.name, u64, TOCHAR);
3746 }
3747 LONG_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum)
3748 INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col)
3749 STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname)
3750 ADDITIONAL_KEY(unpacked)
3751 }
3752 if (entry->data.filemark.fname == NULL) {
3753 emsgf(_(READERR("mark", "is missing file name")), initial_fpos);
3754 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3755 }
3756 if (entry->data.filemark.mark.lnum <= 0) {
3757 emsgf(_(READERR("mark", "has invalid line number")), initial_fpos);
3758 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3759 }
3760 if (entry->data.filemark.mark.col < 0) {
3761 emsgf(_(READERR("mark", "has invalid column number")), initial_fpos);
3762 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3763 }
3764 SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
3765 break;
3766 }
3767 case kSDItemRegister: {
3768 if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
3769 emsgf(_(READERR("register", "is not a dictionary")), initial_fpos);
3770 goto shada_read_next_item_error;
3771 }
3772 garray_T ad_ga;
3773 ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
3774 for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
3775 CHECK_KEY_IS_STR(unpacked, "register")
3776 if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
3777 REG_KEY_CONTENTS)) {
3778 if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
3779 emsgf(_(READERR("register",
3780 "has " REG_KEY_CONTENTS
3781 " key with non-array value")),
3782 initial_fpos);
3783 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3784 }
3785 if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
3786 emsgf(_(READERR("register",
3787 "has " REG_KEY_CONTENTS " key with empty array")),
3788 initial_fpos);
3789 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3790 }
3791 const msgpack_object_array arr =
3792 unpacked.data.via.map.ptr[i].val.via.array;
3793 for (size_t j = 0; j < arr.size; j++) {
3794 if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) {
3795 emsgf(_(READERR("register", "has " REG_KEY_CONTENTS " array "
3796 "with non-binary value")), initial_fpos);
3797 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3798 }
3799 }
3800 entry->data.reg.contents_size = arr.size;
3801 entry->data.reg.contents = xmalloc(arr.size * sizeof(char *));
3802 for (size_t j = 0; j < arr.size; j++) {
3803 entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin);
3804 }
3805 }
3806 BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED,
3807 entry->data.reg.is_unnamed)
3808 TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer",
3809 entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8)
3810 TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer",
3811 entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR)
3812 TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer",
3813 entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
3814 ADDITIONAL_KEY(unpacked)
3815 }
3816 if (entry->data.reg.contents == NULL) {
3817 emsgf(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
3818 initial_fpos);
3819 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3820 }
3821 SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register");
3822 break;
3823 }
3824 case kSDItemHistoryEntry: {
3825 if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
3826 emsgf(_(READERR("history", "is not an array")), initial_fpos);
3827 goto shada_read_next_item_error;
3828 }
3829 if (unpacked.data.via.array.size < 2) {
3830 emsgf(_(READERR("history", "does not have enough elements")),
3831 initial_fpos);
3832 goto shada_read_next_item_error;
3833 }
3834 if (unpacked.data.via.array.ptr[0].type
3835 != MSGPACK_OBJECT_POSITIVE_INTEGER) {
3836 emsgf(_(READERR("history", "has wrong history type type")),
3837 initial_fpos);
3838 goto shada_read_next_item_error;
3839 }
3840 if (unpacked.data.via.array.ptr[1].type
3841 != MSGPACK_OBJECT_BIN) {
3842 emsgf(_(READERR("history", "has wrong history string type")),
3843 initial_fpos);
3844 goto shada_read_next_item_error;
3845 }
3846 if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
3847 unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
3848 emsgf(_(READERR("history", "contains string with zero byte inside")),
3849 initial_fpos);
3850 goto shada_read_next_item_error;
3851 }
3852 entry->data.history_item.histtype =
3853 (uint8_t) unpacked.data.via.array.ptr[0].via.u64;
3854 const bool is_hist_search =
3855 entry->data.history_item.histtype == HIST_SEARCH;
3856 if (is_hist_search) {
3857 if (unpacked.data.via.array.size < 3) {
3858 emsgf(_(READERR("search history",
3859 "does not have separator character")), initial_fpos);
3860 goto shada_read_next_item_error;
3861 }
3862 if (unpacked.data.via.array.ptr[2].type
3863 != MSGPACK_OBJECT_POSITIVE_INTEGER) {
3864 emsgf(_(READERR("search history",
3865 "has wrong history separator type")), initial_fpos);
3866 goto shada_read_next_item_error;
3867 }
3868 entry->data.history_item.sep =
3869 (char) unpacked.data.via.array.ptr[2].via.u64;
3870 }
3871 size_t strsize;
3872 strsize = (
3873 unpacked.data.via.array.ptr[1].via.bin.size
3874 + 1 // Zero byte
3875 + 1); // Separator character
3876 entry->data.history_item.string = xmalloc(strsize);
3877 memcpy(entry->data.history_item.string,
3878 unpacked.data.via.array.ptr[1].via.bin.ptr,
3879 unpacked.data.via.array.ptr[1].via.bin.size);
3880 entry->data.history_item.string[strsize - 2] = 0;
3881 entry->data.history_item.string[strsize - 1] =
3882 entry->data.history_item.sep;
3883 SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search),
3884 entry->data.history_item.additional_elements,
3885 "history");
3886 break;
3887 }
3888 case kSDItemVariable: {
3889 if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
3890 emsgf(_(READERR("variable", "is not an array")), initial_fpos);
3891 goto shada_read_next_item_error;
3892 }
3893 if (unpacked.data.via.array.size < 2) {
3894 emsgf(_(READERR("variable", "does not have enough elements")),
3895 initial_fpos);
3896 goto shada_read_next_item_error;
3897 }
3898 if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
3899 emsgf(_(READERR("variable", "has wrong variable name type")),
3900 initial_fpos);
3901 goto shada_read_next_item_error;
3902 }
3903 entry->data.global_var.name =
3904 xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr,
3905 unpacked.data.via.array.ptr[0].via.bin.size);
3906 if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
3907 &(entry->data.global_var.value)) == FAIL) {
3908 emsgf(_(READERR("variable", "has value that cannot "
3909 "be converted to the VimL value")), initial_fpos);
3910 goto shada_read_next_item_error;
3911 }
3912 SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
3913 entry->data.global_var.additional_elements,
3914 "variable");
3915 break;
3916 }
3917 case kSDItemSubString: {
3918 if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
3919 emsgf(_(READERR("sub string", "is not an array")), initial_fpos);
3920 goto shada_read_next_item_error;
3921 }
3922 if (unpacked.data.via.array.size < 1) {
3923 emsgf(_(READERR("sub string", "does not have enough elements")),
3924 initial_fpos);
3925 goto shada_read_next_item_error;
3926 }
3927 if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
3928 emsgf(_(READERR("sub string", "has wrong sub string type")),
3929 initial_fpos);
3930 goto shada_read_next_item_error;
3931 }
3932 entry->data.sub_string.sub =
3933 BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin);
3934 SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1,
3935 entry->data.sub_string.additional_elements,
3936 "sub string");
3937 break;
3938 }
3939 case kSDItemBufferList: {
3940 if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
3941 emsgf(_(READERR("buffer list", "is not an array")), initial_fpos);
3942 goto shada_read_next_item_error;
3943 }
3944 if (unpacked.data.via.array.size == 0) {
3945 break;
3946 }
3947 entry->data.buffer_list.buffers =
3948 xcalloc(unpacked.data.via.array.size,
3949 sizeof(*entry->data.buffer_list.buffers));
3950 for (size_t i = 0; i < unpacked.data.via.array.size; i++) {
3951 entry->data.buffer_list.size++;
3952 msgpack_unpacked unpacked_2 = (msgpack_unpacked) {
3953 .data = unpacked.data.via.array.ptr[i],
3954 };
3955 {
3956 if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) {
3957 emsgf(_(RERR "Error while reading ShaDa file: "
3958 "buffer list at position %" PRIu64 " "
3959 "contains entry that is not a dictionary"),
3960 initial_fpos);
3961 goto shada_read_next_item_error;
3962 }
3963 entry->data.buffer_list.buffers[i].pos = default_pos;
3964 garray_T ad_ga;
3965 ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1);
3966 {
3967 // XXX: Temporarily reassign `i` because the macros depend on it.
3968 const size_t j = i;
3969 {
3970 for (i = 0; i < unpacked_2.data.via.map.size; i++) { // -V535
3971 CHECK_KEY_IS_STR(unpacked_2, "buffer list entry")
3972 LONG_KEY(unpacked_2, "buffer list entry", KEY_LNUM,
3973 entry->data.buffer_list.buffers[j].pos.lnum)
3974 INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL,
3975 entry->data.buffer_list.buffers[j].pos.col)
3976 STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE,
3977 entry->data.buffer_list.buffers[j].fname)
3978 ADDITIONAL_KEY(unpacked_2)
3979 }
3980 }
3981 i = j; // XXX: Restore `i`.
3982 }
3983 if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
3984 emsgf(_(RERR "Error while reading ShaDa file: "
3985 "buffer list at position %" PRIu64 " "
3986 "contains entry with invalid line number"),
3987 initial_fpos);
3988 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3989 }
3990 if (entry->data.buffer_list.buffers[i].pos.col < 0) {
3991 emsgf(_(RERR "Error while reading ShaDa file: "
3992 "buffer list at position %" PRIu64 " "
3993 "contains entry with invalid column number"),
3994 initial_fpos);
3995 CLEAR_GA_AND_ERROR_OUT(ad_ga);
3996 }
3997 if (entry->data.buffer_list.buffers[i].fname == NULL) {
3998 emsgf(_(RERR "Error while reading ShaDa file: "
3999 "buffer list at position %" PRIu64 " "
4000 "contains entry that does not have a file name"),
4001 initial_fpos);
4002 CLEAR_GA_AND_ERROR_OUT(ad_ga);
4003 }
4004 SET_ADDITIONAL_DATA(
4005 entry->data.buffer_list.buffers[i].additional_data,
4006 "buffer list entry");
4007 }
4008 }
4009 break;
4010 }
4011 case kSDItemMissing:
4012 case kSDItemUnknown: {
4013 assert(false);
4014 }
4015 }
4016 entry->type = (ShadaEntryType) type_u64;
4017 ret = kSDReadStatusSuccess;
4018shada_read_next_item_end:
4019 if (buf != NULL) {
4020 msgpack_unpacked_destroy(&unpacked);
4021 xfree(buf);
4022 }
4023 return ret;
4024shada_read_next_item_error:
4025 entry->type = (ShadaEntryType) type_u64;
4026 shada_free_shada_entry(entry);
4027 entry->type = kSDItemMissing;
4028 goto shada_read_next_item_end;
4029}
4030#undef BIN_CONVERTED
4031#undef CONVERTED
4032#undef CHECK_KEY
4033#undef BOOLEAN_KEY
4034#undef CONVERTED_STRING_KEY
4035#undef STRING_KEY
4036#undef ADDITIONAL_KEY
4037#undef ID
4038#undef BINDUP
4039#undef TOCHAR
4040#undef TOINT
4041#undef TOLONG
4042#undef TYPED_KEY
4043#undef INT_KEY
4044#undef INTEGER_KEY
4045#undef LONG_KEY
4046#undef TOU8
4047#undef TOSIZE
4048#undef SET_ADDITIONAL_DATA
4049#undef SET_ADDITIONAL_ELEMENTS
4050#undef CLEAR_GA_AND_ERROR_OUT
4051
4052/// Check whether "name" is on removable media (according to 'shada')
4053///
4054/// @param[in] name Checked name.
4055///
4056/// @return True if it is, false otherwise.
4057static bool shada_removable(const char *name)
4058 FUNC_ATTR_WARN_UNUSED_RESULT
4059{
4060 char *p;
4061 char part[MAXPATHL + 1];
4062 bool retval = false;
4063
4064 char *new_name = home_replace_save(NULL, name);
4065 for (p = (char *) p_shada; *p; ) {
4066 (void) copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
4067 if (part[0] == 'r') {
4068 home_replace(NULL, part + 1, NameBuff, MAXPATHL, true);
4069 size_t n = STRLEN(NameBuff);
4070 if (mb_strnicmp(NameBuff, new_name, n) == 0) {
4071 retval = true;
4072 break;
4073 }
4074 }
4075 }
4076 xfree(new_name);
4077 return retval;
4078}
4079
4080/// Initialize ShaDa jumplist entries.
4081///
4082/// @param[in,out] jumps Array of ShaDa entries to set.
4083/// @param[in] removable_bufs Cache of buffers ignored due to their
4084/// location.
4085///
4086/// @return number of jumplist entries
4087static inline size_t shada_init_jumps(
4088 PossiblyFreedShadaEntry *jumps, khash_t(bufset) *const removable_bufs)
4089{
4090 if (!curwin->w_jumplistlen) {
4091 return 0;
4092 }
4093
4094 size_t jumps_size = 0;
4095 const void *jump_iter = NULL;
4096
4097 do {
4098 xfmark_T fm;
4099 jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm);
4100
4101 if (fm.fmark.mark.lnum == 0) {
4102 iemsgf("ShaDa: mark lnum zero (ji:%p, js:%p, len:%i)",
4103 (void *)jump_iter, (void *)&curwin->w_jumplist[0],
4104 curwin->w_jumplistlen);
4105 continue;
4106 }
4107 const buf_T *const buf = (fm.fmark.fnum == 0
4108 ? NULL
4109 : buflist_findnr(fm.fmark.fnum));
4110 if (buf != NULL
4111 ? in_bufset(removable_bufs, buf)
4112 : fm.fmark.fnum != 0) {
4113 continue;
4114 }
4115 const char *const fname = (char *) (fm.fmark.fnum == 0
4116 ? (fm.fname == NULL ? NULL : fm.fname)
4117 : buf->b_ffname);
4118 if (fname == NULL) {
4119 continue;
4120 }
4121 jumps[jumps_size++] = (PossiblyFreedShadaEntry) {
4122 .can_free_entry = false,
4123 .data = {
4124 .type = kSDItemJump,
4125 .timestamp = fm.fmark.timestamp,
4126 .data = {
4127 .filemark = {
4128 .name = NUL,
4129 .mark = fm.fmark.mark,
4130 .fname = (char *) fname,
4131 .additional_data = fm.fmark.additional_data,
4132 }
4133 }
4134 }
4135 };
4136 } while (jump_iter != NULL);
4137 return jumps_size;
4138}
4139
4140/// Write registers ShaDa entries in given msgpack_sbuffer.
4141///
4142/// @param[in] sbuf target msgpack_sbuffer to write to.
4143void shada_encode_regs(msgpack_sbuffer *const sbuf)
4144 FUNC_ATTR_NONNULL_ALL
4145{
4146 WriteMergerState *const wms = xcalloc(1, sizeof(*wms));
4147 shada_initialize_registers(wms, -1);
4148 msgpack_packer packer;
4149 msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
4150 for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) {
4151 if (wms->registers[i].data.type == kSDItemRegister) {
4152 if (kSDWriteFailed
4153 == shada_pack_pfreed_entry(&packer, wms->registers[i], 0)) {
4154 abort();
4155 }
4156 }
4157 }
4158 xfree(wms);
4159}
4160
4161/// Write jumplist ShaDa entries in given msgpack_sbuffer.
4162///
4163/// @param[in] sbuf target msgpack_sbuffer to write to.
4164void shada_encode_jumps(msgpack_sbuffer *const sbuf)
4165 FUNC_ATTR_NONNULL_ALL
4166{
4167 khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
4168 find_removable_bufs(&removable_bufs);
4169 PossiblyFreedShadaEntry jumps[JUMPLISTSIZE];
4170 cleanup_jumplist(curwin, true);
4171 size_t jumps_size = shada_init_jumps(jumps, &removable_bufs);
4172 msgpack_packer packer;
4173 msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
4174 for (size_t i = 0; i < jumps_size; i++) {
4175 if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) {
4176 abort();
4177 }
4178 }
4179}
4180
4181/// Write buffer list ShaDa entry in given msgpack_sbuffer.
4182///
4183/// @param[in] sbuf target msgpack_sbuffer to write to.
4184void shada_encode_buflist(msgpack_sbuffer *const sbuf)
4185 FUNC_ATTR_NONNULL_ALL
4186{
4187 khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
4188 find_removable_bufs(&removable_bufs);
4189 ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs);
4190 msgpack_packer packer;
4191 msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
4192 if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) {
4193 abort();
4194 }
4195 xfree(buflist_entry.data.buffer_list.buffers);
4196}
4197
4198/// Write global variables ShaDa entries in given msgpack_sbuffer.
4199///
4200/// @param[in] sbuf target msgpack_sbuffer to write to.
4201void shada_encode_gvars(msgpack_sbuffer *const sbuf)
4202 FUNC_ATTR_NONNULL_ALL
4203{
4204 msgpack_packer packer;
4205 msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
4206 const void *var_iter = NULL;
4207 const Timestamp cur_timestamp = os_time();
4208 do {
4209 typval_T vartv;
4210 const char *name = NULL;
4211 var_iter = var_shada_iter(
4212 var_iter, &name, &vartv,
4213 VAR_FLAVOUR_DEFAULT | VAR_FLAVOUR_SESSION | VAR_FLAVOUR_SHADA);
4214 if (name == NULL) {
4215 break;
4216 }
4217 if (vartv.v_type != VAR_FUNC && vartv.v_type != VAR_PARTIAL) {
4218 typval_T tgttv;
4219 tv_copy(&vartv, &tgttv);
4220 ShaDaWriteResult r = shada_pack_entry(&packer, (ShadaEntry) {
4221 .type = kSDItemVariable,
4222 .timestamp = cur_timestamp,
4223 .data = {
4224 .global_var = {
4225 .name = (char *)name,
4226 .value = tgttv,
4227 .additional_elements = NULL,
4228 }
4229 }
4230 }, 0);
4231 if (kSDWriteFailed == r) {
4232 abort();
4233 }
4234 tv_clear(&tgttv);
4235 }
4236 tv_clear(&vartv);
4237 } while (var_iter != NULL);
4238}
4239
4240/// Wrapper for reading from msgpack_sbuffer.
4241///
4242/// @return number of bytes read.
4243static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest,
4244 const size_t size)
4245 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
4246{
4247 msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
4248 const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos);
4249 if (bytes_read < size) {
4250 sd_reader->eof = true;
4251 }
4252 memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read);
4253 sd_reader->fpos += bytes_read;
4254 return (ptrdiff_t)bytes_read;
4255}
4256
4257/// Wrapper for read that ignores bytes read from msgpack_sbuffer.
4258///
4259/// Used for skipping.
4260///
4261/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer.
4262/// @param[in] offset Amount of bytes to skip.
4263///
4264/// @return FAIL in case of failure, OK in case of success. May set
4265/// sd_reader->eof.
4266static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader,
4267 const size_t offset)
4268 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
4269{
4270 msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
4271 assert(sbuf->size >= sd_reader->fpos);
4272 const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos);
4273 if (skip_bytes < offset) {
4274 sd_reader->eof = true;
4275 return FAIL;
4276 }
4277 sd_reader->fpos += offset;
4278 return OK;
4279}
4280
4281/// Prepare ShaDaReadDef with msgpack_sbuffer for reading.
4282///
4283/// @param[in] sbuf msgpack_sbuffer to read from.
4284/// @param[out] sd_reader Location where reader structure will be saved.
4285static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf,
4286 ShaDaReadDef *sd_reader)
4287 FUNC_ATTR_NONNULL_ALL
4288{
4289 *sd_reader = (ShaDaReadDef) {
4290 .read = &read_sbuf,
4291 .close = NULL,
4292 .skip = &sd_sbuf_reader_skip_read,
4293 .error = NULL,
4294 .eof = false,
4295 .fpos = 0,
4296 .cookie = (void *)sbuf,
4297 };
4298}
4299
4300/// Read ShaDa from msgpack_sbuffer.
4301///
4302/// @param[in] file msgpack_sbuffer to read from.
4303/// @param[in] flags Flags, see ShaDaReadFileFlags enum.
4304void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags)
4305 FUNC_ATTR_NONNULL_ALL
4306{
4307 assert(sbuf != NULL);
4308 if (sbuf->data == NULL) {
4309 return;
4310 }
4311 ShaDaReadDef sd_reader;
4312 open_shada_sbuf_for_reading(sbuf, &sd_reader);
4313 shada_read(&sd_reader, flags);
4314}
4315