mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #1805 from fwalch/vim-7.4.399
vim-patch: Port parts of Vim 7.4.399.
This commit is contained in:
commit
04e09ba742
@ -6,6 +6,8 @@
|
||||
// for FILE
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct file_buffer buf_T; // Forward declaration
|
||||
|
||||
// for garray_T
|
||||
#include "nvim/garray.h"
|
||||
// for pos_T, lpos_T and linenr_T
|
||||
@ -16,7 +18,7 @@
|
||||
#include "nvim/iconv.h"
|
||||
// for jump list and tag stack sizes in a buffer and mark types
|
||||
#include "nvim/mark_defs.h"
|
||||
// for u_header_T
|
||||
// for u_header_T; needs buf_T.
|
||||
#include "nvim/undo_defs.h"
|
||||
// for hashtab_T
|
||||
#include "nvim/hashtab.h"
|
||||
@ -80,7 +82,6 @@ typedef struct window_S win_T;
|
||||
typedef struct wininfo_S wininfo_T;
|
||||
typedef struct frame_S frame_T;
|
||||
typedef int scid_T; /* script ID */
|
||||
typedef struct file_buffer buf_T; /* forward declaration */
|
||||
|
||||
// for struct memline (it needs memfile_T)
|
||||
#include "nvim/memline_defs.h"
|
||||
|
@ -91,8 +91,6 @@ typedef struct pointer_entry PTR_EN; /* block/line-count pair */
|
||||
#define PTR_ID (('p' << 8) + 't') /* pointer block id */
|
||||
#define BLOCK0_ID0 'b' /* block 0 id 0 */
|
||||
#define BLOCK0_ID1 '0' /* block 0 id 1 */
|
||||
#define BLOCK0_ID1_C0 'c' /* block 0 id 1 'cm' 0 */
|
||||
#define BLOCK0_ID1_C1 'C' /* block 0 id 1 'cm' 1 */
|
||||
|
||||
/*
|
||||
* pointer to a block, used in a pointer block
|
||||
@ -176,8 +174,7 @@ struct data_block {
|
||||
* variables, because the rest of the swap file is not portable.
|
||||
*/
|
||||
struct block0 {
|
||||
char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
|
||||
* BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
|
||||
char_u b0_id[2]; ///< ID for block 0: BLOCK0_ID0 and BLOCK0_ID1.
|
||||
char_u b0_version[10]; /* Vim version string */
|
||||
char_u b0_page_size[4]; /* number of bytes per page */
|
||||
char_u b0_mtime[4]; /* last modification time of file */
|
||||
@ -619,22 +616,16 @@ void ml_timestamp(buf_T *buf)
|
||||
ml_upd_block0(buf, UB_FNAME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return FAIL when the ID of "b0p" is wrong.
|
||||
*/
|
||||
static int ml_check_b0_id(ZERO_BL *b0p)
|
||||
/// Checks whether the IDs in b0 are valid.
|
||||
static bool ml_check_b0_id(ZERO_BL *b0p)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
if (b0p->b0_id[0] != BLOCK0_ID0
|
||||
|| (b0p->b0_id[1] != BLOCK0_ID1
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C0
|
||||
&& b0p->b0_id[1] != BLOCK0_ID1_C1)
|
||||
)
|
||||
return FAIL;
|
||||
return OK;
|
||||
return b0p->b0_id[0] == BLOCK0_ID0 && b0p->b0_id[1] == BLOCK0_ID1;
|
||||
}
|
||||
|
||||
/// Return true if all strings in b0 are correct (nul-terminated).
|
||||
static bool ml_check_b0_strings(ZERO_BL *b0p) FUNC_ATTR_NONNULL_ALL
|
||||
/// Checks whether all strings in b0 are valid (i.e. nul-terminated).
|
||||
static bool ml_check_b0_strings(ZERO_BL *b0p)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
return (memchr(b0p->b0_version, NUL, 10)
|
||||
&& memchr(b0p->b0_uname, NUL, B0_UNAME_SIZE)
|
||||
|
@ -9,6 +9,7 @@
|
||||
/*
|
||||
* misc2.c: Various functions.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
@ -29,6 +30,7 @@
|
||||
#include "nvim/fileio.h"
|
||||
#include "nvim/fold.h"
|
||||
#include "nvim/getchar.h"
|
||||
#include "nvim/macros.h"
|
||||
#include "nvim/mark.h"
|
||||
#include "nvim/mbyte.h"
|
||||
#include "nvim/memfile.h"
|
||||
@ -459,22 +461,33 @@ char *read_string(FILE *fd, size_t cnt)
|
||||
return (char *)str;
|
||||
}
|
||||
|
||||
/// Write a number to file "fd", MSB first, in "len" bytes.
|
||||
/// @return OK/FAIL.
|
||||
int put_bytes(FILE *fd, uintmax_t number, unsigned int len)
|
||||
/// Writes a number to file "fd", most significant bit first, in "len" bytes.
|
||||
/// @returns false in case of an error.
|
||||
bool put_bytes(FILE *fd, uintmax_t number, size_t len)
|
||||
{
|
||||
for (unsigned int i = len - 1; i < len; --i)
|
||||
if (putc((int)(number >> (i * 8)), fd) == EOF)
|
||||
return FAIL;
|
||||
return OK;
|
||||
assert(len > 0);
|
||||
for (size_t i = len - 1; i < len; i--) {
|
||||
if (putc((int)(number >> (i * 8)), fd) == EOF) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Write time_t to file "fd" in 8 bytes.
|
||||
/// Writes time_t to file "fd" in 8 bytes.
|
||||
void put_time(FILE *fd, time_t time_)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
time_to_bytes(time_, buf);
|
||||
fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd);
|
||||
}
|
||||
|
||||
/// Writes time_t to "buf[8]".
|
||||
void time_to_bytes(time_t time_, uint8_t buf[8])
|
||||
{
|
||||
// time_t can be up to 8 bytes in size, more than uintmax_t in 32 bits
|
||||
// systems, thus we can't use put_bytes() here.
|
||||
for (unsigned int i = 7; i < 8; --i) {
|
||||
putc((int)((uint64_t)time_ >> (i * 8)), fd);
|
||||
for (size_t i = 7, bufi = 0; bufi < 8; i--, bufi++) {
|
||||
buf[bufi] = (uint8_t)((uint64_t)time_ >> (i * 8));
|
||||
}
|
||||
}
|
||||
|
660
src/nvim/undo.c
660
src/nvim/undo.c
@ -713,143 +713,159 @@ static void u_free_uhp(u_header_T *uhp)
|
||||
free(uhp);
|
||||
}
|
||||
|
||||
static int serialize_header(FILE *fp, buf_T *buf, char_u *hash)
|
||||
/// Writes the header.
|
||||
/// @returns false in case of an error.
|
||||
static bool serialize_header(bufinfo_T *bi, char_u *hash)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
/* Start writing, first the magic marker and undo info version. */
|
||||
if (fwrite(UF_START_MAGIC, UF_START_MAGIC_LEN, 1, fp) != 1)
|
||||
return FAIL;
|
||||
buf_T *buf = bi->bi_buf;
|
||||
FILE *fp = bi->bi_fp;
|
||||
|
||||
put_bytes(fp, UF_VERSION, 2);
|
||||
|
||||
/* Write a hash of the buffer text, so that we can verify it is still the
|
||||
* same when reading the buffer text. */
|
||||
if (fwrite(hash, UNDO_HASH_SIZE, 1, fp) != 1)
|
||||
return FAIL;
|
||||
|
||||
/* buffer-specific data */
|
||||
put_bytes(fp, (uintmax_t)buf->b_ml.ml_line_count, 4);
|
||||
size_t len = buf->b_u_line_ptr ? STRLEN(buf->b_u_line_ptr) : 0;
|
||||
put_bytes(fp, len, 4);
|
||||
if (len > 0 && fwrite(buf->b_u_line_ptr, len, 1, fp) != 1)
|
||||
return FAIL;
|
||||
put_bytes(fp, (uintmax_t)buf->b_u_line_lnum, 4);
|
||||
put_bytes(fp, (uintmax_t)buf->b_u_line_colnr, 4);
|
||||
|
||||
/* Undo structures header data */
|
||||
put_header_ptr(fp, buf->b_u_oldhead);
|
||||
put_header_ptr(fp, buf->b_u_newhead);
|
||||
put_header_ptr(fp, buf->b_u_curhead);
|
||||
|
||||
put_bytes(fp, (uintmax_t)buf->b_u_numhead, 4);
|
||||
put_bytes(fp, (uintmax_t)buf->b_u_seq_last, 4);
|
||||
put_bytes(fp, (uintmax_t)buf->b_u_seq_cur, 4);
|
||||
put_time(fp, buf->b_u_time_cur);
|
||||
|
||||
/* Optional fields. */
|
||||
putc(4, fp);
|
||||
putc(UF_LAST_SAVE_NR, fp);
|
||||
put_bytes(fp, (uintmax_t)buf->b_u_save_nr_last, 4);
|
||||
|
||||
putc(0, fp); /* end marker */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int serialize_uhp(FILE *fp, buf_T *buf, u_header_T *uhp)
|
||||
{
|
||||
if (put_bytes(fp, UF_HEADER_MAGIC, 2) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
put_header_ptr(fp, uhp->uh_next.ptr);
|
||||
put_header_ptr(fp, uhp->uh_prev.ptr);
|
||||
put_header_ptr(fp, uhp->uh_alt_next.ptr);
|
||||
put_header_ptr(fp, uhp->uh_alt_prev.ptr);
|
||||
put_bytes(fp, (uintmax_t)uhp->uh_seq, 4);
|
||||
serialize_pos(uhp->uh_cursor, fp);
|
||||
put_bytes(fp, (uintmax_t)uhp->uh_cursor_vcol, 4);
|
||||
put_bytes(fp, (uintmax_t)uhp->uh_flags, 2);
|
||||
/* Assume NMARKS will stay the same. */
|
||||
for (size_t i = 0; i < NMARKS; ++i)
|
||||
serialize_pos(uhp->uh_namedm[i], fp);
|
||||
serialize_visualinfo(&uhp->uh_visual, fp);
|
||||
put_time(fp, uhp->uh_time);
|
||||
|
||||
/* Optional fields. */
|
||||
putc(4, fp);
|
||||
putc(UHP_SAVE_NR, fp);
|
||||
put_bytes(fp, (uintmax_t)uhp->uh_save_nr, 4);
|
||||
|
||||
putc(0, fp); /* end marker */
|
||||
|
||||
/* Write all the entries. */
|
||||
for (u_entry_T *uep = uhp->uh_entry; uep; uep = uep->ue_next) {
|
||||
put_bytes(fp, UF_ENTRY_MAGIC, 2);
|
||||
if (serialize_uep(fp, buf, uep) == FAIL)
|
||||
return FAIL;
|
||||
// Start writing, first the magic marker and undo info version.
|
||||
if (fwrite(UF_START_MAGIC, UF_START_MAGIC_LEN, 1, fp) != 1) {
|
||||
return false;
|
||||
}
|
||||
put_bytes(fp, UF_ENTRY_END_MAGIC, 2);
|
||||
return OK;
|
||||
|
||||
undo_write_bytes(bi, UF_VERSION, 2);
|
||||
|
||||
// Write a hash of the buffer text, so that we can verify it is
|
||||
// still the same when reading the buffer text.
|
||||
if (!undo_write(bi, hash, UNDO_HASH_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write buffer-specific data.
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_ml.ml_line_count, 4);
|
||||
size_t len = buf->b_u_line_ptr ? STRLEN(buf->b_u_line_ptr) : 0;
|
||||
undo_write_bytes(bi, len, 4);
|
||||
if (len > 0 && !undo_write(bi, buf->b_u_line_ptr, len)) {
|
||||
return false;
|
||||
}
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_u_line_lnum, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_u_line_colnr, 4);
|
||||
|
||||
// Write undo structures header data.
|
||||
put_header_ptr(bi, buf->b_u_oldhead);
|
||||
put_header_ptr(bi, buf->b_u_newhead);
|
||||
put_header_ptr(bi, buf->b_u_curhead);
|
||||
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_u_numhead, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_u_seq_last, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_u_seq_cur, 4);
|
||||
uint8_t time_buf[8];
|
||||
time_to_bytes(buf->b_u_time_cur, time_buf);
|
||||
undo_write(bi, time_buf, sizeof(time_buf));
|
||||
|
||||
// Write optional fields.
|
||||
undo_write_bytes(bi, 4, 1);
|
||||
undo_write_bytes(bi, UF_LAST_SAVE_NR, 1);
|
||||
undo_write_bytes(bi, (uintmax_t)buf->b_u_save_nr_last, 4);
|
||||
|
||||
// Write end marker.
|
||||
undo_write_bytes(bi, 0, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u_header_T *unserialize_uhp(FILE *fp, char_u *file_name)
|
||||
static bool serialize_uhp(bufinfo_T *bi, u_header_T *uhp)
|
||||
{
|
||||
u_header_T *uhp;
|
||||
int i;
|
||||
u_entry_T *uep, *last_uep;
|
||||
int c;
|
||||
int error;
|
||||
if (!undo_write_bytes(bi, (uintmax_t)UF_HEADER_MAGIC, 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uhp = xmalloc(sizeof(u_header_T));
|
||||
put_header_ptr(bi, uhp->uh_next.ptr);
|
||||
put_header_ptr(bi, uhp->uh_prev.ptr);
|
||||
put_header_ptr(bi, uhp->uh_alt_next.ptr);
|
||||
put_header_ptr(bi, uhp->uh_alt_prev.ptr);
|
||||
undo_write_bytes(bi, (uintmax_t)uhp->uh_seq, 4);
|
||||
serialize_pos(bi, uhp->uh_cursor);
|
||||
undo_write_bytes(bi, (uintmax_t)uhp->uh_cursor_vcol, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)uhp->uh_flags, 2);
|
||||
// Assume NMARKS will stay the same.
|
||||
for (size_t i = 0; i < (size_t)NMARKS; i++) {
|
||||
serialize_pos(bi, uhp->uh_namedm[i]);
|
||||
}
|
||||
serialize_visualinfo(bi, &uhp->uh_visual);
|
||||
uint8_t time_buf[8];
|
||||
time_to_bytes(uhp->uh_time, time_buf);
|
||||
undo_write(bi, time_buf, sizeof(time_buf));
|
||||
|
||||
// Write optional fields.
|
||||
undo_write_bytes(bi, 4, 1);
|
||||
undo_write_bytes(bi, UHP_SAVE_NR, 1);
|
||||
undo_write_bytes(bi, (uintmax_t)uhp->uh_save_nr, 4);
|
||||
|
||||
// Write end marker.
|
||||
undo_write_bytes(bi, 0, 1);
|
||||
|
||||
// Write all the entries.
|
||||
for (u_entry_T *uep = uhp->uh_entry; uep; uep = uep->ue_next) {
|
||||
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
|
||||
if (!serialize_uep(bi, uep)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_END_MAGIC, 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static u_header_T *unserialize_uhp(bufinfo_T *bi, char_u *file_name)
|
||||
{
|
||||
u_header_T *uhp = xmalloc(sizeof(u_header_T));
|
||||
memset(uhp, 0, sizeof(u_header_T));
|
||||
#ifdef U_DEBUG
|
||||
uhp->uh_magic = UH_MAGIC;
|
||||
#endif
|
||||
uhp->uh_next.seq = get4c(fp);
|
||||
uhp->uh_prev.seq = get4c(fp);
|
||||
uhp->uh_alt_next.seq = get4c(fp);
|
||||
uhp->uh_alt_prev.seq = get4c(fp);
|
||||
uhp->uh_seq = get4c(fp);
|
||||
uhp->uh_next.seq = undo_read_4c(bi);
|
||||
uhp->uh_prev.seq = undo_read_4c(bi);
|
||||
uhp->uh_alt_next.seq = undo_read_4c(bi);
|
||||
uhp->uh_alt_prev.seq = undo_read_4c(bi);
|
||||
uhp->uh_seq = undo_read_4c(bi);
|
||||
if (uhp->uh_seq <= 0) {
|
||||
corruption_error("uh_seq", file_name);
|
||||
free(uhp);
|
||||
return NULL;
|
||||
}
|
||||
unserialize_pos(&uhp->uh_cursor, fp);
|
||||
uhp->uh_cursor_vcol = get4c(fp);
|
||||
uhp->uh_flags = get2c(fp);
|
||||
for (i = 0; i < NMARKS; ++i)
|
||||
unserialize_pos(&uhp->uh_namedm[i], fp);
|
||||
unserialize_visualinfo(&uhp->uh_visual, fp);
|
||||
uhp->uh_time = get8ctime(fp);
|
||||
unserialize_pos(bi, &uhp->uh_cursor);
|
||||
uhp->uh_cursor_vcol = undo_read_4c(bi);
|
||||
uhp->uh_flags = undo_read_2c(bi);
|
||||
for (size_t i = 0; i < (size_t)NMARKS; i++) {
|
||||
unserialize_pos(bi, &uhp->uh_namedm[i]);
|
||||
}
|
||||
unserialize_visualinfo(bi, &uhp->uh_visual);
|
||||
uhp->uh_time = undo_read_time(bi);
|
||||
|
||||
/* Optional fields. */
|
||||
// Unserialize optional fields.
|
||||
for (;; ) {
|
||||
int len = getc(fp);
|
||||
int what;
|
||||
int len = undo_read_byte(bi);
|
||||
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
break;
|
||||
what = getc(fp);
|
||||
}
|
||||
int what = undo_read_byte(bi);
|
||||
switch (what) {
|
||||
case UHP_SAVE_NR:
|
||||
uhp->uh_save_nr = get4c(fp);
|
||||
uhp->uh_save_nr = undo_read_4c(bi);
|
||||
break;
|
||||
default:
|
||||
/* field not supported, skip */
|
||||
while (--len >= 0)
|
||||
(void)getc(fp);
|
||||
// Field not supported, skip it.
|
||||
while (--len >= 0) {
|
||||
(void)undo_read_byte(bi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unserialize the uep list. */
|
||||
last_uep = NULL;
|
||||
while ((c = get2c(fp)) == UF_ENTRY_MAGIC) {
|
||||
error = FALSE;
|
||||
uep = unserialize_uep(fp, &error, file_name);
|
||||
if (last_uep == NULL)
|
||||
// Unserialize the uep list.
|
||||
u_entry_T *last_uep = NULL;
|
||||
int c;
|
||||
while ((c = undo_read_2c(bi)) == UF_ENTRY_MAGIC) {
|
||||
bool error = false;
|
||||
u_entry_T *uep = unserialize_uep(bi, &error, file_name);
|
||||
if (last_uep == NULL) {
|
||||
uhp->uh_entry = uep;
|
||||
else
|
||||
} else {
|
||||
last_uep->ue_next = uep;
|
||||
}
|
||||
last_uep = uep;
|
||||
if (uep == NULL || error) {
|
||||
u_free_uhp(uhp);
|
||||
@ -865,59 +881,60 @@ static u_header_T *unserialize_uhp(FILE *fp, char_u *file_name)
|
||||
return uhp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize "uep" to "fp".
|
||||
*/
|
||||
static int serialize_uep(FILE *fp, buf_T *buf, u_entry_T *uep)
|
||||
/// Serializes "uep".
|
||||
///
|
||||
/// @returns false in case of an error.
|
||||
static bool serialize_uep(bufinfo_T *bi, u_entry_T *uep)
|
||||
{
|
||||
put_bytes(fp, (uintmax_t)uep->ue_top, 4);
|
||||
put_bytes(fp, (uintmax_t)uep->ue_bot, 4);
|
||||
put_bytes(fp, (uintmax_t)uep->ue_lcount, 4);
|
||||
put_bytes(fp, (uintmax_t)uep->ue_size, 4);
|
||||
for (size_t i = 0; i < (size_t)uep->ue_size; ++i) {
|
||||
undo_write_bytes(bi, (uintmax_t)uep->ue_top, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)uep->ue_bot, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)uep->ue_lcount, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)uep->ue_size, 4);
|
||||
|
||||
for (size_t i = 0; i < (size_t)uep->ue_size; i++) {
|
||||
size_t len = STRLEN(uep->ue_array[i]);
|
||||
if (put_bytes(fp, len, 4) == FAIL)
|
||||
return FAIL;
|
||||
if (len > 0 && fwrite(uep->ue_array[i], len, 1, fp) != 1)
|
||||
return FAIL;
|
||||
if (!undo_write_bytes(bi, len, 4)) {
|
||||
return false;
|
||||
}
|
||||
return OK;
|
||||
if (len > 0 && !undo_write(bi, uep->ue_array[i], len)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static u_entry_T *unserialize_uep(FILE *fp, int *error, char_u *file_name)
|
||||
static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error, char_u *file_name)
|
||||
{
|
||||
int i;
|
||||
u_entry_T *uep;
|
||||
char_u **array;
|
||||
char_u *line;
|
||||
int line_len;
|
||||
|
||||
uep = xmalloc(sizeof(u_entry_T));
|
||||
u_entry_T *uep = xmalloc(sizeof(u_entry_T));
|
||||
memset(uep, 0, sizeof(u_entry_T));
|
||||
#ifdef U_DEBUG
|
||||
uep->ue_magic = UE_MAGIC;
|
||||
#endif
|
||||
uep->ue_top = get4c(fp);
|
||||
uep->ue_bot = get4c(fp);
|
||||
uep->ue_lcount = get4c(fp);
|
||||
uep->ue_size = get4c(fp);
|
||||
uep->ue_top = undo_read_4c(bi);
|
||||
uep->ue_bot = undo_read_4c(bi);
|
||||
uep->ue_lcount = undo_read_4c(bi);
|
||||
uep->ue_size = undo_read_4c(bi);
|
||||
|
||||
char_u **array;
|
||||
if (uep->ue_size > 0) {
|
||||
array = xmalloc(sizeof(char_u *) * (size_t)uep->ue_size);
|
||||
memset(array, 0, sizeof(char_u *) * (size_t)uep->ue_size);
|
||||
} else
|
||||
} else {
|
||||
array = NULL;
|
||||
}
|
||||
uep->ue_array = array;
|
||||
|
||||
for (i = 0; i < uep->ue_size; ++i) {
|
||||
line_len = get4c(fp);
|
||||
if (line_len >= 0)
|
||||
line = READ_STRING(fp, line_len);
|
||||
else {
|
||||
for (size_t i = 0; i < (size_t)uep->ue_size; i++) {
|
||||
int line_len = undo_read_4c(bi);
|
||||
char_u *line;
|
||||
if (line_len >= 0) {
|
||||
line = undo_read_string(bi, (size_t)line_len);
|
||||
} else {
|
||||
line = NULL;
|
||||
corruption_error("line length", file_name);
|
||||
}
|
||||
if (line == NULL) {
|
||||
*error = TRUE;
|
||||
*error = true;
|
||||
return uep;
|
||||
}
|
||||
array[i] = line;
|
||||
@ -925,61 +942,47 @@ static u_entry_T *unserialize_uep(FILE *fp, int *error, char_u *file_name)
|
||||
return uep;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize "pos" to "fp".
|
||||
*/
|
||||
static void serialize_pos(pos_T pos, FILE *fp)
|
||||
/// Serializes "pos".
|
||||
static void serialize_pos(bufinfo_T *bi, pos_T pos)
|
||||
{
|
||||
put_bytes(fp, (uintmax_t)pos.lnum, 4);
|
||||
put_bytes(fp, (uintmax_t)pos.col, 4);
|
||||
put_bytes(fp, (uintmax_t)pos.coladd, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)pos.lnum, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)pos.col, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)pos.coladd, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unserialize the pos_T at the current position in fp.
|
||||
*/
|
||||
static void unserialize_pos(pos_T *pos, FILE *fp)
|
||||
/// Unserializes the pos_T at the current position.
|
||||
static void unserialize_pos(bufinfo_T *bi, pos_T *pos)
|
||||
{
|
||||
pos->lnum = get4c(fp);
|
||||
if (pos->lnum < 0)
|
||||
pos->lnum = undo_read_4c(bi);
|
||||
if (pos->lnum < 0) {
|
||||
pos->lnum = 0;
|
||||
pos->col = get4c(fp);
|
||||
if (pos->col < 0)
|
||||
}
|
||||
pos->col = undo_read_4c(bi);
|
||||
if (pos->col < 0) {
|
||||
pos->col = 0;
|
||||
pos->coladd = get4c(fp);
|
||||
if (pos->coladd < 0)
|
||||
}
|
||||
pos->coladd = undo_read_4c(bi);
|
||||
if (pos->coladd < 0) {
|
||||
pos->coladd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize "info" to "fp".
|
||||
*/
|
||||
static void serialize_visualinfo(visualinfo_T *info, FILE *fp)
|
||||
/// Serializes "info".
|
||||
static void serialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
|
||||
{
|
||||
serialize_pos(info->vi_start, fp);
|
||||
serialize_pos(info->vi_end, fp);
|
||||
put_bytes(fp, (uintmax_t)info->vi_mode, 4);
|
||||
put_bytes(fp, (uintmax_t)info->vi_curswant, 4);
|
||||
serialize_pos(bi, info->vi_start);
|
||||
serialize_pos(bi, info->vi_end);
|
||||
undo_write_bytes(bi, (uintmax_t)info->vi_mode, 4);
|
||||
undo_write_bytes(bi, (uintmax_t)info->vi_curswant, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unserialize the visualinfo_T at the current position in fp.
|
||||
*/
|
||||
static void unserialize_visualinfo(visualinfo_T *info, FILE *fp)
|
||||
/// Unserializes the visualinfo_T at the current position.
|
||||
static void unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
|
||||
{
|
||||
unserialize_pos(&info->vi_start, fp);
|
||||
unserialize_pos(&info->vi_end, fp);
|
||||
info->vi_mode = get4c(fp);
|
||||
info->vi_curswant = get4c(fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the pointer to an undo header. Instead of writing the pointer itself
|
||||
* we use the sequence number of the header. This is converted back to
|
||||
* pointers when reading. */
|
||||
static void put_header_ptr(FILE *fp, u_header_T *uhp)
|
||||
{
|
||||
put_bytes(fp, (uintmax_t)(uhp != NULL ? uhp->uh_seq : 0), 4);
|
||||
unserialize_pos(bi, &info->vi_start);
|
||||
unserialize_pos(bi, &info->vi_end);
|
||||
info->vi_mode = undo_read_4c(bi);
|
||||
info->vi_curswant = undo_read_4c(bi);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1003,6 +1006,7 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
|
||||
FILE *fp = NULL;
|
||||
int perm;
|
||||
bool write_ok = false;
|
||||
bufinfo_T bi;
|
||||
|
||||
if (name == NULL) {
|
||||
file_name = u_get_undo_file_name(buf->b_ffname, FALSE);
|
||||
@ -1134,8 +1138,11 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
|
||||
/*
|
||||
* Write the header.
|
||||
*/
|
||||
if (serialize_header(fp, buf, hash) == FAIL)
|
||||
bi.bi_buf = buf;
|
||||
bi.bi_fp = fp;
|
||||
if (!serialize_header(&bi, hash)) {
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iteratively serialize UHPs and their UEPs from the top down.
|
||||
@ -1149,9 +1156,10 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
|
||||
#ifdef U_DEBUG
|
||||
++headers_written;
|
||||
#endif
|
||||
if (serialize_uhp(fp, buf, uhp) == FAIL)
|
||||
if (!serialize_uhp(&bi, uhp)) {
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now walk through the tree - algorithm from undo_time(). */
|
||||
if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark)
|
||||
@ -1168,8 +1176,9 @@ void u_write_undo(char_u *name, int forceit, buf_T *buf, char_u *hash)
|
||||
uhp = uhp->uh_next.ptr;
|
||||
}
|
||||
|
||||
if (put_bytes(fp, UF_HEADER_END_MAGIC, 2) == OK)
|
||||
if (undo_write_bytes(&bi, (uintmax_t)UF_HEADER_END_MAGIC, 2)) {
|
||||
write_ok = true;
|
||||
}
|
||||
#ifdef U_DEBUG
|
||||
if (headers_written != buf->b_u_numhead) {
|
||||
EMSGN("Written %" PRId64 " headers, ...", headers_written);
|
||||
@ -1198,47 +1207,27 @@ theend:
|
||||
free(file_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the undo tree from an undo file.
|
||||
* If "name" is not NULL use it as the undo file name. This also means being
|
||||
* a bit more verbose.
|
||||
* Otherwise use curbuf->b_ffname to generate the undo file name.
|
||||
* "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
|
||||
*/
|
||||
/// Loads the undo tree from an undo file.
|
||||
/// If "name" is not NULL use it as the undo file name. This also means being
|
||||
/// a bit more verbose.
|
||||
/// Otherwise use curbuf->b_ffname to generate the undo file name.
|
||||
/// "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
|
||||
void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
|
||||
FUNC_ATTR_NONNULL_ARG(2)
|
||||
{
|
||||
char_u *file_name;
|
||||
FILE *fp;
|
||||
long version, str_len;
|
||||
char_u *line_ptr = NULL;
|
||||
linenr_T line_lnum;
|
||||
colnr_T line_colnr;
|
||||
linenr_T line_count;
|
||||
int num_head = 0;
|
||||
long old_header_seq, new_header_seq, cur_header_seq;
|
||||
long seq_last, seq_cur;
|
||||
long last_save_nr = 0;
|
||||
short old_idx = -1, new_idx = -1, cur_idx = -1;
|
||||
long num_read_uhps = 0;
|
||||
time_t seq_time;
|
||||
int i, j;
|
||||
int c;
|
||||
u_header_T *uhp;
|
||||
u_header_T **uhp_table = NULL;
|
||||
char_u read_hash[UNDO_HASH_SIZE];
|
||||
char_u magic_buf[UF_START_MAGIC_LEN];
|
||||
#ifdef U_DEBUG
|
||||
int *uhp_table_used;
|
||||
#endif
|
||||
char_u *line_ptr = NULL;
|
||||
|
||||
char_u *file_name;
|
||||
if (name == NULL) {
|
||||
file_name = u_get_undo_file_name(curbuf->b_ffname, TRUE);
|
||||
if (file_name == NULL)
|
||||
if (file_name == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UNIX
|
||||
/* For safety we only read an undo file if the owner is equal to the
|
||||
* owner of the text file or equal to the current user. */
|
||||
// For safety we only read an undo file if the owner is equal to the
|
||||
// owner of the text file or equal to the current user.
|
||||
FileInfo file_info_orig;
|
||||
FileInfo file_info_undo;
|
||||
if (os_fileinfo((char *)orig_name, &file_info_orig)
|
||||
@ -1254,8 +1243,9 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
} else {
|
||||
file_name = name;
|
||||
}
|
||||
|
||||
if (p_verbose > 0) {
|
||||
verbose_enter();
|
||||
@ -1263,103 +1253,120 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
|
||||
verbose_leave();
|
||||
}
|
||||
|
||||
fp = mch_fopen((char *)file_name, "r");
|
||||
FILE *fp = mch_fopen((char *)file_name, "r");
|
||||
if (fp == NULL) {
|
||||
if (name != NULL || p_verbose > 0)
|
||||
if (name != NULL || p_verbose > 0) {
|
||||
EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the undo file header.
|
||||
*/
|
||||
bufinfo_T bi;
|
||||
bi.bi_buf = curbuf;
|
||||
bi.bi_fp = fp;
|
||||
|
||||
// Read the undo file header.
|
||||
char_u magic_buf[UF_START_MAGIC_LEN];
|
||||
if (fread(magic_buf, UF_START_MAGIC_LEN, 1, fp) != 1
|
||||
|| memcmp(magic_buf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) {
|
||||
EMSG2(_("E823: Not an undo file: %s"), file_name);
|
||||
goto error;
|
||||
}
|
||||
version = get2c(fp);
|
||||
int version = get2c(fp);
|
||||
if (version != UF_VERSION) {
|
||||
EMSG2(_("E824: Incompatible undo file: %s"), file_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fread(read_hash, UNDO_HASH_SIZE, 1, fp) != 1) {
|
||||
char_u read_hash[UNDO_HASH_SIZE];
|
||||
if (!undo_read(&bi, read_hash, UNDO_HASH_SIZE)) {
|
||||
corruption_error("hash", file_name);
|
||||
goto error;
|
||||
}
|
||||
line_count = (linenr_T)get4c(fp);
|
||||
linenr_T line_count = (linenr_T)undo_read_4c(&bi);
|
||||
if (memcmp(hash, read_hash, UNDO_HASH_SIZE) != 0
|
||||
|| line_count != curbuf->b_ml.ml_line_count) {
|
||||
if (p_verbose > 0 || name != NULL) {
|
||||
if (name == NULL)
|
||||
if (name == NULL) {
|
||||
verbose_enter();
|
||||
}
|
||||
give_warning((char_u *)
|
||||
_("File contents changed, cannot use undo info"), true);
|
||||
if (name == NULL)
|
||||
if (name == NULL) {
|
||||
verbose_leave();
|
||||
}
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Read undo data for "U" command. */
|
||||
str_len = get4c(fp);
|
||||
if (str_len < 0)
|
||||
// Read undo data for "U" command.
|
||||
int str_len = undo_read_4c(&bi);
|
||||
if (str_len < 0) {
|
||||
goto error;
|
||||
if (str_len > 0)
|
||||
line_ptr = READ_STRING(fp, str_len);
|
||||
line_lnum = (linenr_T)get4c(fp);
|
||||
line_colnr = (colnr_T)get4c(fp);
|
||||
}
|
||||
|
||||
if (str_len > 0) {
|
||||
line_ptr = undo_read_string(&bi, (size_t)str_len);
|
||||
}
|
||||
linenr_T line_lnum = (linenr_T)undo_read_4c(&bi);
|
||||
colnr_T line_colnr = (colnr_T)undo_read_4c(&bi);
|
||||
if (line_lnum < 0 || line_colnr < 0) {
|
||||
corruption_error("line lnum/col", file_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Begin general undo data */
|
||||
old_header_seq = get4c(fp);
|
||||
new_header_seq = get4c(fp);
|
||||
cur_header_seq = get4c(fp);
|
||||
num_head = get4c(fp);
|
||||
seq_last = get4c(fp);
|
||||
seq_cur = get4c(fp);
|
||||
seq_time = get8ctime(fp);
|
||||
// Begin general undo data
|
||||
int old_header_seq = undo_read_4c(&bi);
|
||||
int new_header_seq = undo_read_4c(&bi);
|
||||
int cur_header_seq = undo_read_4c(&bi);
|
||||
int num_head = undo_read_4c(&bi);
|
||||
int seq_last = undo_read_4c(&bi);
|
||||
int seq_cur = undo_read_4c(&bi);
|
||||
time_t seq_time = undo_read_time(&bi);
|
||||
|
||||
/* Optional header fields. */
|
||||
// Optional header fields.
|
||||
long last_save_nr = 0;
|
||||
for (;; ) {
|
||||
int len = getc(fp);
|
||||
int what;
|
||||
int len = undo_read_byte(&bi);
|
||||
|
||||
if (len == 0 || len == EOF)
|
||||
if (len == 0 || len == EOF) {
|
||||
break;
|
||||
what = getc(fp);
|
||||
}
|
||||
int what = undo_read_byte(&bi);
|
||||
switch (what) {
|
||||
case UF_LAST_SAVE_NR:
|
||||
last_save_nr = get4c(fp);
|
||||
last_save_nr = undo_read_4c(&bi);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* field not supported, skip */
|
||||
while (--len >= 0)
|
||||
(void)getc(fp);
|
||||
// field not supported, skip
|
||||
while (--len >= 0) {
|
||||
(void)undo_read_byte(&bi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* uhp_table will store the freshly created undo headers we allocate
|
||||
* until we insert them into curbuf. The table remains sorted by the
|
||||
* sequence numbers of the headers.
|
||||
* When there are no headers uhp_table is NULL. */
|
||||
// uhp_table will store the freshly created undo headers we allocate
|
||||
// until we insert them into curbuf. The table remains sorted by the
|
||||
// sequence numbers of the headers.
|
||||
// When there are no headers uhp_table is NULL.
|
||||
if (num_head > 0) {
|
||||
uhp_table = xmalloc((size_t)num_head * sizeof(u_header_T *));
|
||||
}
|
||||
|
||||
while ((c = get2c(fp)) == UF_HEADER_MAGIC) {
|
||||
long num_read_uhps = 0;
|
||||
|
||||
int c;
|
||||
while ((c = undo_read_2c(&bi)) == UF_HEADER_MAGIC) {
|
||||
if (num_read_uhps >= num_head) {
|
||||
corruption_error("num_head too small", file_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
uhp = unserialize_uhp(fp, file_name);
|
||||
if (uhp == NULL)
|
||||
u_header_T *uhp = unserialize_uhp(&bi, file_name);
|
||||
if (uhp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
uhp_table[num_read_uhps++] = uhp;
|
||||
}
|
||||
|
||||
@ -1374,54 +1381,61 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
|
||||
|
||||
#ifdef U_DEBUG
|
||||
size_t amount = num_head * sizeof(int) + 1;
|
||||
uhp_table_used = xmalloc(amount);
|
||||
int *uhp_table_used = xmalloc(amount);
|
||||
memset(uhp_table_used, 0, amount);
|
||||
# define SET_FLAG(j) ++ uhp_table_used[j]
|
||||
#else
|
||||
# define SET_FLAG(j)
|
||||
#endif
|
||||
|
||||
/* We have put all of the headers into a table. Now we iterate through the
|
||||
* table and swizzle each sequence number we have stored in uh_*_seq into
|
||||
* a pointer corresponding to the header with that sequence number. */
|
||||
for (i = 0; i < num_head; i++) {
|
||||
uhp = uhp_table[i];
|
||||
if (uhp == NULL)
|
||||
// We have put all of the headers into a table. Now we iterate through the
|
||||
// table and swizzle each sequence number we have stored in uh_*_seq into
|
||||
// a pointer corresponding to the header with that sequence number.
|
||||
short old_idx = -1, new_idx = -1, cur_idx = -1;
|
||||
for (int i = 0; i < num_head; i++) {
|
||||
u_header_T *uhp = uhp_table[i];
|
||||
if (uhp == NULL) {
|
||||
continue;
|
||||
for (j = 0; j < num_head; j++)
|
||||
}
|
||||
for (int j = 0; j < num_head; j++) {
|
||||
if (uhp_table[j] != NULL && i != j
|
||||
&& uhp_table[i]->uh_seq == uhp_table[j]->uh_seq) {
|
||||
corruption_error("duplicate uh_seq", file_name);
|
||||
goto error;
|
||||
}
|
||||
for (j = 0; j < num_head; j++)
|
||||
}
|
||||
for (int j = 0; j < num_head; j++) {
|
||||
if (uhp_table[j] != NULL
|
||||
&& uhp_table[j]->uh_seq == uhp->uh_next.seq) {
|
||||
uhp->uh_next.ptr = uhp_table[j];
|
||||
SET_FLAG(j);
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < num_head; j++)
|
||||
}
|
||||
for (int j = 0; j < num_head; j++) {
|
||||
if (uhp_table[j] != NULL
|
||||
&& uhp_table[j]->uh_seq == uhp->uh_prev.seq) {
|
||||
uhp->uh_prev.ptr = uhp_table[j];
|
||||
SET_FLAG(j);
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < num_head; j++)
|
||||
}
|
||||
for (int j = 0; j < num_head; j++) {
|
||||
if (uhp_table[j] != NULL
|
||||
&& uhp_table[j]->uh_seq == uhp->uh_alt_next.seq) {
|
||||
uhp->uh_alt_next.ptr = uhp_table[j];
|
||||
SET_FLAG(j);
|
||||
break;
|
||||
}
|
||||
for (j = 0; j < num_head; j++)
|
||||
}
|
||||
for (int j = 0; j < num_head; j++) {
|
||||
if (uhp_table[j] != NULL
|
||||
&& uhp_table[j]->uh_seq == uhp->uh_alt_prev.seq) {
|
||||
uhp->uh_alt_prev.ptr = uhp_table[j];
|
||||
SET_FLAG(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (old_header_seq > 0 && old_idx < 0 && uhp->uh_seq == old_header_seq) {
|
||||
assert(i <= SHRT_MAX);
|
||||
old_idx = (short)i;
|
||||
@ -1439,8 +1453,8 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we have read the undo info successfully, free the current undo
|
||||
* info and use the info from the file. */
|
||||
// Now that we have read the undo info successfully, free the current undo
|
||||
// info and use the info from the file.
|
||||
u_blockfree(curbuf);
|
||||
curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx];
|
||||
curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx];
|
||||
@ -1459,35 +1473,117 @@ void u_read_undo(char_u *name, char_u *hash, char_u *orig_name)
|
||||
free(uhp_table);
|
||||
|
||||
#ifdef U_DEBUG
|
||||
for (i = 0; i < num_head; ++i)
|
||||
if (uhp_table_used[i] == 0)
|
||||
for (int i = 0; i < num_head; i++) {
|
||||
if (uhp_table_used[i] == 0) {
|
||||
EMSGN("uhp_table entry %" PRId64 " not used, leaking memory", i);
|
||||
}
|
||||
}
|
||||
free(uhp_table_used);
|
||||
u_check(TRUE);
|
||||
#endif
|
||||
|
||||
if (name != NULL)
|
||||
if (name != NULL) {
|
||||
smsg((char_u *)_("Finished reading undo file %s"), file_name);
|
||||
}
|
||||
goto theend;
|
||||
|
||||
error:
|
||||
free(line_ptr);
|
||||
if (uhp_table != NULL) {
|
||||
for (i = 0; i < num_read_uhps; i++)
|
||||
if (uhp_table[i] != NULL)
|
||||
for (long i = 0; i < num_read_uhps; i++)
|
||||
if (uhp_table[i] != NULL) {
|
||||
u_free_uhp(uhp_table[i]);
|
||||
}
|
||||
free(uhp_table);
|
||||
}
|
||||
|
||||
theend:
|
||||
if (fp != NULL)
|
||||
if (fp != NULL) {
|
||||
fclose(fp);
|
||||
if (file_name != name)
|
||||
}
|
||||
if (file_name != name) {
|
||||
free(file_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a sequence of bytes to the undo file.
|
||||
///
|
||||
/// @returns false in case of an error.
|
||||
static bool undo_write(bufinfo_T *bi, uint8_t *ptr, size_t len)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
return fwrite(ptr, len, 1, bi->bi_fp) == 1;
|
||||
}
|
||||
|
||||
/// Writes a number, most significant bit first, in "len" bytes.
|
||||
///
|
||||
/// Must match with undo_read_?c() functions.
|
||||
///
|
||||
/// @returns false in case of an error.
|
||||
static bool undo_write_bytes(bufinfo_T *bi, uintmax_t nr, size_t len)
|
||||
{
|
||||
assert(len > 0);
|
||||
uint8_t buf[8];
|
||||
for (size_t i = len - 1, bufi = 0; bufi < len; i--, bufi++) {
|
||||
buf[bufi] = (uint8_t)(nr >> (i * 8));
|
||||
}
|
||||
return undo_write(bi, buf, len);
|
||||
}
|
||||
|
||||
/// Writes the pointer to an undo header.
|
||||
///
|
||||
/// Instead of writing the pointer itself, we use the sequence
|
||||
/// number of the header. This is converted back to pointers
|
||||
/// when reading.
|
||||
static void put_header_ptr(bufinfo_T *bi, u_header_T *uhp)
|
||||
{
|
||||
assert(uhp == NULL || uhp->uh_seq >= 0);
|
||||
undo_write_bytes(bi, (uint64_t)(uhp != NULL ? uhp->uh_seq : 0), 4);
|
||||
}
|
||||
|
||||
static int undo_read_4c(bufinfo_T *bi)
|
||||
{
|
||||
return get4c(bi->bi_fp);
|
||||
}
|
||||
|
||||
static int undo_read_2c(bufinfo_T *bi)
|
||||
{
|
||||
return get2c(bi->bi_fp);
|
||||
}
|
||||
|
||||
static int undo_read_byte(bufinfo_T *bi)
|
||||
{
|
||||
return getc(bi->bi_fp);
|
||||
}
|
||||
|
||||
static time_t undo_read_time(bufinfo_T *bi)
|
||||
{
|
||||
return get8ctime(bi->bi_fp);
|
||||
}
|
||||
|
||||
/// Reads "buffer[size]" from the undo file.
|
||||
///
|
||||
/// @returns false in case of an error.
|
||||
static bool undo_read(bufinfo_T *bi, uint8_t *buffer, size_t size)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
return fread(buffer, size, 1, bi->bi_fp) == 1;
|
||||
}
|
||||
|
||||
/// Reads a string of length "len" from "bi->bi_fd" and appends a zero to it.
|
||||
///
|
||||
/// @param len can be zero to allocate an empty line.
|
||||
///
|
||||
/// @returns a pointer to allocated memory or NULL in case of an error.
|
||||
static uint8_t *undo_read_string(bufinfo_T *bi, size_t len)
|
||||
{
|
||||
uint8_t *ptr = xmallocz(len);
|
||||
if (len > 0 && !undo_read(bi, ptr, len)) {
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* If 'cpoptions' contains 'u': Undo the previous undo or redo (vi compatible).
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <time.h> // for time_t
|
||||
|
||||
#include "nvim/pos.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
|
||||
/* Structure to store info about the Visual area. */
|
||||
typedef struct {
|
||||
@ -67,4 +68,10 @@ struct u_header {
|
||||
#define UH_CHANGED 0x01 /* b_changed flag before undo/after redo */
|
||||
#define UH_EMPTYBUF 0x02 /* buffer was empty */
|
||||
|
||||
/// Structure passed around between undofile functions.
|
||||
typedef struct {
|
||||
buf_T *bi_buf;
|
||||
FILE *bi_fp;
|
||||
} bufinfo_T;
|
||||
|
||||
#endif // NVIM_UNDO_DEFS_H
|
||||
|
Loading…
Reference in New Issue
Block a user