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