#define CHECK(c, s)
#include "vim.h"
#ifndef UNIX
# include <time.h>
#endif
#if defined(SASC) || defined(__amigaos4__)
# include <proto/dos.h>
#endif
typedef struct block0 ZERO_BL;
typedef struct pointer_block PTR_BL;
typedef struct data_block DATA_BL;
typedef struct pointer_entry PTR_EN;
#define DATA_ID (('d' << 8) + 'a')
#define PTR_ID (('p' << 8) + 't')
#define BLOCK0_ID0 'b'
#define BLOCK0_ID1 '0'
#define BLOCK0_ID1_C0 'c'
#define BLOCK0_ID1_C1 'C'
#define BLOCK0_ID1_C2 'd'
#if defined(FEAT_CRYPT)
static int id1_codes[] = {
BLOCK0_ID1_C0,
BLOCK0_ID1_C1,
BLOCK0_ID1_C2,
};
#endif
struct pointer_entry
{
blocknr_T pe_bnum;
linenr_T pe_line_count;
linenr_T pe_old_lnum;
int pe_page_count;
};
struct pointer_block
{
short_u pb_id;
short_u pb_count;
short_u pb_count_max;
PTR_EN pb_pointer[1];
};
struct data_block
{
short_u db_id;
unsigned db_free;
unsigned db_txt_start;
unsigned db_txt_end;
linenr_T db_line_count;
unsigned db_index[1];
};
#define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
#define DB_INDEX_MASK (~DB_MARKED)
#define INDEX_SIZE (sizeof(unsigned))
#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE)
#define B0_FNAME_SIZE_ORG 900
#define B0_FNAME_SIZE_NOCRYPT 898
#define B0_FNAME_SIZE_CRYPT 890
#define B0_UNAME_SIZE 40
#define B0_HNAME_SIZE 40
#define B0_MAGIC_LONG 0x30313233L
#define B0_MAGIC_INT 0x20212223L
#define B0_MAGIC_SHORT 0x10111213L
#define B0_MAGIC_CHAR 0x55
struct block0
{
char_u b0_id[2];
char_u b0_version[10];
char_u b0_page_size[4];
char_u b0_mtime[4];
char_u b0_ino[4];
char_u b0_pid[4];
char_u b0_uname[B0_UNAME_SIZE];
char_u b0_hname[B0_HNAME_SIZE];
char_u b0_fname[B0_FNAME_SIZE_ORG];
long b0_magic_long;
int b0_magic_int;
short b0_magic_short;
char_u b0_magic_char;
};
#define B0_DIRTY 0x55
#define b0_dirty b0_fname[B0_FNAME_SIZE_ORG - 1]
#define b0_flags b0_fname[B0_FNAME_SIZE_ORG - 2]
#define b0_seed b0_fname[B0_FNAME_SIZE_ORG - 2 - MF_SEED_LEN]
#define B0_FF_MASK 3
#define B0_SAME_DIR 4
#define B0_HAS_FENC 8
#define STACK_INCR 5
static linenr_T lowest_marked = 0;
#define ML_DELETE 0x11
#define ML_INSERT 0x12
#define ML_FIND 0x13
#define ML_FLUSH 0x02
#define ML_SIMPLE(x) (x & 0x10)
typedef enum {
UB_FNAME = 0
, UB_SAME_DIR
, UB_CRYPT
} upd_block0_T;
#ifdef FEAT_CRYPT
static void ml_set_mfp_crypt(buf_T *buf);
static void ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p);
#endif
static int ml_check_b0_id(ZERO_BL *b0p);
static void ml_upd_block0(buf_T *buf, upd_block0_T what);
static void set_b0_fname(ZERO_BL *, buf_T *buf);
static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf);
#ifdef FEAT_MBYTE
static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf);
#endif
static time_t swapfile_info(char_u *);
static int recov_file_names(char_u **, char_u *, int prepend_dot);
static int ml_append_int(buf_T *, linenr_T, char_u *, colnr_T, int, int);
static int ml_delete_int(buf_T *, linenr_T, int);
static char_u *findswapname(buf_T *, char_u **, char_u *);
static void ml_flush_line(buf_T *);
static bhdr_T *ml_new_data(memfile_T *, int, int);
static bhdr_T *ml_new_ptr(memfile_T *);
static bhdr_T *ml_find_line(buf_T *, linenr_T, int);
static int ml_add_stack(buf_T *);
static void ml_lineadd(buf_T *, int);
static int b0_magic_wrong(ZERO_BL *);
#ifdef CHECK_INODE
static int fnamecmp_ino(char_u *, char_u *, long);
#endif
static void long_to_char(long, char_u *);
static long char_to_long(char_u *);
#if defined(UNIX) || defined(WIN3264)
static char_u *make_percent_swname(char_u *dir, char_u *name);
#endif
#ifdef FEAT_CRYPT
static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading);
#endif
#ifdef FEAT_BYTEOFF
static void ml_updatechunk(buf_T *buf, long line, long len, int updtype);
#endif
int
ml_open(buf_T *buf)
{
memfile_T *mfp;
bhdr_T *hp = NULL;
ZERO_BL *b0p;
PTR_BL *pp;
DATA_BL *dp;
buf->b_ml.ml_stack_size = 0;
buf->b_ml.ml_stack = NULL;
buf->b_ml.ml_stack_top = 0;
buf->b_ml.ml_locked = NULL;
buf->b_ml.ml_line_lnum = 0;
#ifdef FEAT_BYTEOFF
buf->b_ml.ml_chunksize = NULL;
#endif
if (cmdmod.noswapfile)
buf->b_p_swf = FALSE;
if (p_uc && buf->b_p_swf)
buf->b_may_swap = TRUE;
else
buf->b_may_swap = FALSE;
mfp = mf_open(NULL, 0);
if (mfp == NULL)
goto error;
buf->b_ml.ml_mfp = mfp;
#ifdef FEAT_CRYPT
mfp->mf_buffer = buf;
#endif
buf->b_ml.ml_flags = ML_EMPTY;
buf->b_ml.ml_line_count = 1;
#ifdef FEAT_LINEBREAK
curwin->w_nrwidth_line_count = 0;
#endif
if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
goto error;
if (hp->bh_bnum != 0)
{
IEMSG(_("E298: Didn't get block nr 0?"));
goto error;
}
b0p = (ZERO_BL *)(hp->bh_data);
b0p->b0_id[0] = BLOCK0_ID0;
b0p->b0_id[1] = BLOCK0_ID1;
b0p->b0_magic_long = (long)B0_MAGIC_LONG;
b0p->b0_magic_int = (int)B0_MAGIC_INT;
b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
b0p->b0_magic_char = B0_MAGIC_CHAR;
STRNCPY(b0p->b0_version, "VIM ", 4);
STRNCPY(b0p->b0_version + 4, Version, 6);
long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
#ifdef FEAT_SPELL
if (!buf->b_spell)
#endif
{
b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
b0p->b0_flags = get_fileformat(buf) + 1;
set_b0_fname(b0p, buf);
(void)get_user_name(b0p->b0_uname, B0_UNAME_SIZE);
b0p->b0_uname[B0_UNAME_SIZE - 1] = NUL;
mch_get_host_name(b0p->b0_hname, B0_HNAME_SIZE);
b0p->b0_hname[B0_HNAME_SIZE - 1] = NUL;
long_to_char(mch_get_pid(), b0p->b0_pid);
#ifdef FEAT_CRYPT
ml_set_b0_crypt(buf, b0p);
#endif
}
mf_put(mfp, hp, TRUE, FALSE);
if (!buf->b_help && !B_SPELL(buf))
(void)mf_sync(mfp, 0);
if ((hp = ml_new_ptr(mfp)) == NULL)
goto error;
if (hp->bh_bnum != 1)
{
IEMSG(_("E298: Didn't get block nr 1?"));
goto error;
}
pp = (PTR_BL *)(hp->bh_data);
pp->pb_count = 1;
pp->pb_pointer[0].pe_bnum = 2;
pp->pb_pointer[0].pe_page_count = 1;
pp->pb_pointer[0].pe_old_lnum = 1;
pp->pb_pointer[0].pe_line_count = 1;
mf_put(mfp, hp, TRUE, FALSE);
if ((hp = ml_new_data(mfp, FALSE, 1)) == NULL)
goto error;
if (hp->bh_bnum != 2)
{
IEMSG(_("E298: Didn't get block nr 2?"));
goto error;
}
dp = (DATA_BL *)(hp->bh_data);
dp->db_index[0] = --dp->db_txt_start;
dp->db_free -= 1 + INDEX_SIZE;
dp->db_line_count = 1;
*((char_u *)dp + dp->db_txt_start) = NUL;
return OK;
error:
if (mfp != NULL)
{
if (hp)
mf_put(mfp, hp, FALSE, FALSE);
mf_close(mfp, TRUE);
}
buf->b_ml.ml_mfp = NULL;
return FAIL;
}
#if defined(FEAT_CRYPT) || defined(PROTO)
static void
ml_set_mfp_crypt(buf_T *buf)
{
if (*buf->b_p_key != NUL)
{
int method_nr = crypt_get_method_nr(buf);
if (method_nr > CRYPT_M_ZIP)
{
sha2_seed(buf->b_ml.ml_mfp->mf_seed, MF_SEED_LEN, NULL, 0);
}
}
}
static void
ml_set_b0_crypt(buf_T *buf, ZERO_BL *b0p)
{
if (*buf->b_p_key == NUL)
b0p->b0_id[1] = BLOCK0_ID1;
else
{
int method_nr = crypt_get_method_nr(buf);
b0p->b0_id[1] = id1_codes[method_nr];
if (method_nr > CRYPT_M_ZIP)
{
sha2_seed(&b0p->b0_seed, MF_SEED_LEN, NULL, 0);
mch_memmove(buf->b_ml.ml_mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
}
}
}
void
ml_set_crypt_key(
buf_T *buf,
char_u *old_key,
char_u *old_cm)
{
memfile_T *mfp = buf->b_ml.ml_mfp;
bhdr_T *hp;
int page_count;
int idx;
long error;
infoptr_T *ip;
PTR_BL *pp;
DATA_BL *dp;
blocknr_T bnum;
int top;
int old_method;
if (mfp == NULL)
return;
old_method = crypt_method_nr_from_name(old_cm);
{
char_u *new_key = buf->b_p_key;
char_u *new_buf_cm = buf->b_p_cm;
buf->b_p_key = old_key;
buf->b_p_cm = old_cm;
ml_preserve(buf, FALSE);
buf->b_p_key = new_key;
buf->b_p_cm = new_buf_cm;
}
mfp->mf_old_key = old_key;
mfp->mf_old_cm = old_method;
if (old_method > 0 && *old_key != NUL)
mch_memmove(mfp->mf_old_seed, mfp->mf_seed, MF_SEED_LEN);
ml_upd_block0(buf, UB_CRYPT);
if (mfp->mf_infile_count > 2)
{
ml_flush_line(buf);
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
hp = NULL;
bnum = 1;
page_count = 1;
idx = 0;
error = 0;
buf->b_ml.ml_stack_top = 0;
vim_free(buf->b_ml.ml_stack);
buf->b_ml.ml_stack = NULL;
buf->b_ml.ml_stack_size = 0;
for ( ; !got_int; line_breakcheck())
{
if (hp != NULL)
mf_put(mfp, hp, FALSE, FALSE);
if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
{
if (bnum == 1)
break;
++error;
}
else
{
pp = (PTR_BL *)(hp->bh_data);
if (pp->pb_id == PTR_ID)
{
if (pp->pb_count == 0)
{
++error;
}
else if (idx < (int)pp->pb_count)
{
if (pp->pb_pointer[idx].pe_bnum < 0)
{
++idx;
continue;
}
if ((top = ml_add_stack(buf)) < 0)
{
++error;
break;
}
ip = &(buf->b_ml.ml_stack[top]);
ip->ip_bnum = bnum;
ip->ip_index = idx;
bnum = pp->pb_pointer[idx].pe_bnum;
page_count = pp->pb_pointer[idx].pe_page_count;
idx = 0;
continue;
}
}
else
{
dp = (DATA_BL *)(hp->bh_data);
if (dp->db_id != DATA_ID)
++error;
else
{
mf_put(mfp, hp, TRUE, FALSE);
hp = NULL;
}
}
}
if (buf->b_ml.ml_stack_top == 0)
break;
ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
bnum = ip->ip_bnum;
idx = ip->ip_index + 1;
page_count = 1;
}
if (hp != NULL)
mf_put(mfp, hp, FALSE, FALSE);
if (error > 0)
EMSG(_("E843: Error while updating swap file crypt"));
}
mfp->mf_old_key = NULL;
}
#endif
void
ml_setname(buf_T *buf)
{
int success = FALSE;
memfile_T *mfp;
char_u *fname;
char_u *dirp;
#if defined(MSWIN)
char_u *p;
#endif
mfp = buf->b_ml.ml_mfp;
if (mfp->mf_fd < 0)
{
if (p_uc != 0 && !cmdmod.noswapfile)
ml_open_file(buf);
return;
}
dirp = p_dir;
for (;;)
{
if (*dirp == NUL)
break;
fname = findswapname(buf, &dirp, mfp->mf_fname);
if (dirp == NULL)
break;
if (fname == NULL)
continue;
#if defined(MSWIN)
p = FullName_save(fname, FALSE);
vim_free(fname);
fname = p;
if (fname == NULL)
continue;
#endif
if (fnamecmp(fname, mfp->mf_fname) == 0)
{
vim_free(fname);
success = TRUE;
break;
}
if (mfp->mf_fd >= 0)
{
close(mfp->mf_fd);
mfp->mf_fd = -1;
}
if (vim_rename(mfp->mf_fname, fname) == 0)
{
success = TRUE;
vim_free(mfp->mf_fname);
mfp->mf_fname = fname;
vim_free(mfp->mf_ffname);
#if defined(MSWIN)
mfp->mf_ffname = NULL;
#else
mf_set_ffname(mfp);
#endif
ml_upd_block0(buf, UB_SAME_DIR);
break;
}
vim_free(fname);
}
if (mfp->mf_fd == -1)
{
mfp->mf_fd = mch_open((char *)mfp->mf_fname, O_RDWR | O_EXTRA, 0);
if (mfp->mf_fd < 0)
{
EMSG(_("E301: Oops, lost the swap file!!!"));
return;
}
#ifdef HAVE_FD_CLOEXEC
{
int fdflags = fcntl(mfp->mf_fd, F_GETFD);
if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
(void)fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
}
#endif
}
if (!success)
EMSG(_("E302: Could not rename swap file"));
}
void
ml_open_files(void)
{
buf_T *buf;
FOR_ALL_BUFFERS(buf)
if (!buf->b_p_ro || buf->b_changed)
ml_open_file(buf);
}
void
ml_open_file(buf_T *buf)
{
memfile_T *mfp;
char_u *fname;
char_u *dirp;
mfp = buf->b_ml.ml_mfp;
if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile)
return;
#ifdef FEAT_SPELL
if (buf->b_spell)
{
fname = vim_tempname('s', FALSE);
if (fname != NULL)
(void)mf_open_file(mfp, fname);
buf->b_may_swap = FALSE;
return;
}
#endif
dirp = p_dir;
for (;;)
{
if (*dirp == NUL)
break;
fname = findswapname(buf, &dirp, NULL);
if (dirp == NULL)
break;
if (fname == NULL)
continue;
if (mf_open_file(mfp, fname) == OK)
{
#if defined(MSWIN)
mf_fullname(mfp);
#endif
ml_upd_block0(buf, UB_SAME_DIR);
if (mf_sync(mfp, MFS_ZERO) == OK)
{
mf_set_dirty(mfp);
break;
}
mf_close_file(buf, FALSE);
}
}
if (mfp->mf_fname == NULL)
{
need_wait_return = TRUE;
++no_wait_return;
(void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
--no_wait_return;
}
buf->b_may_swap = FALSE;
}
void
check_need_swap(
int newfile)
{
if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
ml_open_file(curbuf);
}
void
ml_close(buf_T *buf, int del_file)
{
if (buf->b_ml.ml_mfp == NULL)
return;
mf_close(buf->b_ml.ml_mfp, del_file);
if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
vim_free(buf->b_ml.ml_line_ptr);
vim_free(buf->b_ml.ml_stack);
#ifdef FEAT_BYTEOFF
vim_free(buf->b_ml.ml_chunksize);
buf->b_ml.ml_chunksize = NULL;
#endif
buf->b_ml.ml_mfp = NULL;
buf->b_flags &= ~BF_RECOVERED;
}
void
ml_close_all(int del_file)
{
buf_T *buf;
FOR_ALL_BUFFERS(buf)
ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0
|| vim_strchr(p_cpo, CPO_PRESERVE) == NULL));
#ifdef FEAT_SPELL
spell_delete_wordlist();
#endif
#ifdef TEMPDIRNAMES
vim_deltempdir();
#endif
}
void
ml_close_notmod(void)
{
buf_T *buf;
FOR_ALL_BUFFERS(buf)
if (!bufIsChanged(buf))
ml_close(buf, TRUE);
}
void
ml_timestamp(buf_T *buf)
{
ml_upd_block0(buf, UB_FNAME);
}
static int
ml_check_b0_id(ZERO_BL *b0p)
{
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
&& b0p->b0_id[1] != BLOCK0_ID1_C2)
)
return FAIL;
return OK;
}
static void
ml_upd_block0(buf_T *buf, upd_block0_T what)
{
memfile_T *mfp;
bhdr_T *hp;
ZERO_BL *b0p;
mfp = buf->b_ml.ml_mfp;
if (mfp == NULL)
return;
hp = mf_get(mfp, (blocknr_T)0, 1);
if (hp == NULL)
{
#ifdef FEAT_CRYPT
if (what == UB_CRYPT)
ml_set_mfp_crypt(buf);
#endif
return;
}
b0p = (ZERO_BL *)(hp->bh_data);
if (ml_check_b0_id(b0p) == FAIL)
IEMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
else
{
if (what == UB_FNAME)
set_b0_fname(b0p, buf);
#ifdef FEAT_CRYPT
else if (what == UB_CRYPT)
ml_set_b0_crypt(buf, b0p);
#endif
else
set_b0_dir_flag(b0p, buf);
}
mf_put(mfp, hp, TRUE, FALSE);
}
static void
set_b0_fname(ZERO_BL *b0p, buf_T *buf)
{
stat_T st;
if (buf->b_ffname == NULL)
b0p->b0_fname[0] = NUL;
else
{
#if defined(MSWIN) || defined(AMIGA)
vim_strncpy(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE_CRYPT - 1);
# ifdef BACKSLASH_IN_FILENAME
forward_slash(b0p->b0_fname);
# endif
#else
size_t flen, ulen;
char_u uname[B0_UNAME_SIZE];
home_replace(NULL, buf->b_ffname, b0p->b0_fname,
B0_FNAME_SIZE_CRYPT, TRUE);
if (b0p->b0_fname[0] == '~')
{
flen = STRLEN(b0p->b0_fname);
if (get_user_name(uname, B0_UNAME_SIZE) == FAIL
|| (ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE_CRYPT - 1)
vim_strncpy(b0p->b0_fname, buf->b_ffname,
B0_FNAME_SIZE_CRYPT - 1);
else
{
mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
mch_memmove(b0p->b0_fname + 1, uname, ulen);
}
}
#endif
if (mch_stat((char *)buf->b_ffname, &st) >= 0)
{
long_to_char((long)st.st_mtime, b0p->b0_mtime);
#ifdef CHECK_INODE
long_to_char((long)st.st_ino, b0p->b0_ino);
#endif
buf_store_time(buf, &st, buf->b_ffname);
buf->b_mtime_read = buf->b_mtime;
}
else
{
long_to_char(0L, b0p->b0_mtime);
#ifdef CHECK_INODE
long_to_char(0L, b0p->b0_ino);
#endif
buf->b_mtime = 0;
buf->b_mtime_read = 0;
buf->b_orig_size = 0;
buf->b_orig_mode = 0;
}
}
#ifdef FEAT_MBYTE
add_b0_fenc(b0p, curbuf);
#endif
}
static void
set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
{
if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
b0p->b0_flags |= B0_SAME_DIR;
else
b0p->b0_flags &= ~B0_SAME_DIR;
}
#ifdef FEAT_MBYTE
static void
add_b0_fenc(
ZERO_BL *b0p,
buf_T *buf)
{
int n;
int size = B0_FNAME_SIZE_NOCRYPT;
# ifdef FEAT_CRYPT
if (*buf->b_p_key != NUL)
size = B0_FNAME_SIZE_CRYPT;
# endif
n = (int)STRLEN(buf->b_p_fenc);
if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
b0p->b0_flags &= ~B0_HAS_FENC;
else
{
mch_memmove((char *)b0p->b0_fname + size - n,
(char *)buf->b_p_fenc, (size_t)n);
*(b0p->b0_fname + size - n - 1) = NUL;
b0p->b0_flags |= B0_HAS_FENC;
}
}
#endif
void
ml_recover(void)
{
buf_T *buf = NULL;
memfile_T *mfp = NULL;
char_u *fname;
char_u *fname_used = NULL;
bhdr_T *hp = NULL;
ZERO_BL *b0p;
int b0_ff;
char_u *b0_fenc = NULL;
#ifdef FEAT_CRYPT
int b0_cm = -1;
#endif
PTR_BL *pp;
DATA_BL *dp;
infoptr_T *ip;
blocknr_T bnum;
int page_count;
stat_T org_stat, swp_stat;
int len;
int directly;
linenr_T lnum;
char_u *p;
int i;
long error;
int cannot_open;
linenr_T line_count;
int has_error;
int idx;
int top;
int txt_start;
off_T size;
int called_from_main;
int serious_error = TRUE;
long mtime;
int attr;
int orig_file_status = NOTDONE;
recoverymode = TRUE;
called_from_main = (curbuf->b_ml.ml_mfp == NULL);
attr = HL_ATTR(HLF_E);
fname = curbuf->b_fname;
if (fname == NULL)
fname = (char_u *)"";
len = (int)STRLEN(fname);
if (len >= 4 &&
#if defined(VMS)
STRNICMP(fname + len - 4, "_s", 2)
#else
STRNICMP(fname + len - 4, ".s", 2)
#endif
== 0
&& vim_strchr((char_u *)"UVWuvw", fname[len - 2]) != NULL
&& ASCII_ISALPHA(fname[len - 1]))
{
directly = TRUE;
fname_used = vim_strsave(fname);
}
else
{
directly = FALSE;
len = recover_names(fname, FALSE, 0, NULL);
if (len == 0)
{
EMSG2(_("E305: No swap file found for %s"), fname);
goto theend;
}
if (len == 1)
i = 1;
else
{
(void)recover_names(fname, TRUE, 0, NULL);
msg_putchar('\n');
MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
i = get_number(FALSE, NULL);
if (i < 1 || i > len)
goto theend;
}
(void)recover_names(fname, FALSE, i, &fname_used);
}
if (fname_used == NULL)
goto theend;
if (called_from_main && ml_open(curbuf) == FAIL)
getout(1);
buf = (buf_T *)alloc((unsigned)sizeof(buf_T));
if (buf == NULL)
goto theend;
buf->b_ml.ml_stack_size = 0;
buf->b_ml.ml_stack = NULL;
buf->b_ml.ml_stack_top = 0;
buf->b_ml.ml_line_lnum = 0;
buf->b_ml.ml_locked = NULL;
buf->b_ml.ml_flags = 0;
#ifdef FEAT_CRYPT
buf->b_p_key = empty_option;
buf->b_p_cm = empty_option;
#endif
p = vim_strsave(fname_used);
mfp = mf_open(fname_used, O_RDONLY);
fname_used = p;
if (mfp == NULL || mfp->mf_fd < 0)
{
if (fname_used != NULL)
EMSG2(_("E306: Cannot open %s"), fname_used);
goto theend;
}
buf->b_ml.ml_mfp = mfp;
#ifdef FEAT_CRYPT
mfp->mf_buffer = buf;
#endif
mfp->mf_page_size = MIN_SWAP_PAGE_SIZE;
if ((hp = mf_get(mfp, (blocknr_T)0, 1)) == NULL)
{
msg_start();
MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
MSG_PUTS_ATTR(_("\nMaybe no changes were made or Vim did not update the swap file."),
attr | MSG_HIST);
msg_end();
goto theend;
}
b0p = (ZERO_BL *)(hp->bh_data);
if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
{
msg_start();
msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
MSG_HIST);
MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
msg_end();
goto theend;
}
if (ml_check_b0_id(b0p) == FAIL)
{
EMSG2(_("E307: %s does not look like a Vim swap file"), mfp->mf_fname);
goto theend;
}
if (b0_magic_wrong(b0p))
{
msg_start();
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
#if defined(MSWIN)
if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
attr | MSG_HIST);
else
#endif
MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
attr | MSG_HIST);
MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
b0p->b0_fname[0] = NUL;
MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
msg_end();
goto theend;
}
#ifdef FEAT_CRYPT
for (i = 0; i < (int)(sizeof(id1_codes) / sizeof(int)); ++i)
if (id1_codes[i] == b0p->b0_id[1])
b0_cm = i;
if (b0_cm > 0)
mch_memmove(mfp->mf_seed, &b0p->b0_seed, MF_SEED_LEN);
crypt_set_cm_option(buf, b0_cm < 0 ? 0 : b0_cm);
#else
if (b0p->b0_id[1] != BLOCK0_ID1)
{
EMSG2(_("E833: %s is encrypted and this version of Vim does not support encryption"), mfp->mf_fname);
goto theend;
}
#endif
if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
{
unsigned previous_page_size = mfp->mf_page_size;
mf_new_page_size(mfp, (unsigned)char_to_long(b0p->b0_page_size));
if (mfp->mf_page_size < previous_page_size)
{
msg_start();
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
MSG_PUTS_ATTR(_(" has been damaged (page size is smaller than minimum value).\n"),
attr | MSG_HIST);
msg_end();
goto theend;
}
if ((size = vim_lseek(mfp->mf_fd, (off_T)0L, SEEK_END)) <= 0)
mfp->mf_blocknr_max = 0;
else
mfp->mf_blocknr_max = (blocknr_T)(size / mfp->mf_page_size);
mfp->mf_infile_count = mfp->mf_blocknr_max;
p = alloc(mfp->mf_page_size);
if (p == NULL)
goto theend;
mch_memmove(p, hp->bh_data, previous_page_size);
vim_free(hp->bh_data);
hp->bh_data = p;
b0p = (ZERO_BL *)(hp->bh_data);
}
if (directly)
{
expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
if (setfname(curbuf, NameBuff, NULL, TRUE) == FAIL)
goto theend;
}
home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
smsg((char_u *)_("Using swap file \"%s\""), NameBuff);
if (buf_spname(curbuf) != NULL)
vim_strncpy(NameBuff, buf_spname(curbuf), MAXPATHL - 1);
else
home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
smsg((char_u *)_("Original file \"%s\""), NameBuff);
msg_putchar('\n');
mtime = char_to_long(b0p->b0_mtime);
if (curbuf->b_ffname != NULL
&& mch_stat((char *)curbuf->b_ffname, &org_stat) != -1
&& ((mch_stat((char *)mfp->mf_fname, &swp_stat) != -1
&& org_stat.st_mtime > swp_stat.st_mtime)
|| org_stat.st_mtime != mtime))
{
EMSG(_("E308: Warning: Original file may have been changed"));
}
out_flush();
b0_ff = (b0p->b0_flags & B0_FF_MASK);
if (b0p->b0_flags & B0_HAS_FENC)
{
int fnsize = B0_FNAME_SIZE_NOCRYPT;
#ifdef FEAT_CRYPT
if (b0p->b0_id[1] != BLOCK0_ID1)
fnsize = B0_FNAME_SIZE_CRYPT;
#endif
for (p = b0p->b0_fname + fnsize; p > b0p->b0_fname && p[-1] != NUL; --p)
;
b0_fenc = vim_strnsave(p, (int)(b0p->b0_fname + fnsize - p));
}
mf_put(mfp, hp, FALSE, FALSE);
hp = NULL;
while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
ml_delete((linenr_T)1, FALSE);
if (curbuf->b_ffname != NULL)
orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
(linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
#ifdef FEAT_CRYPT
if (b0_cm >= 0)
{
if (*curbuf->b_p_key != NUL)
{
smsg((char_u *)_("Swap file is encrypted: \"%s\""), fname_used);
MSG_PUTS(_("\nIf you entered a new crypt key but did not write the text file,"));
MSG_PUTS(_("\nenter the new crypt key."));
MSG_PUTS(_("\nIf you wrote the text file after changing the crypt key press enter"));
MSG_PUTS(_("\nto use the same key for text file and swap file"));
}
else
smsg((char_u *)_(need_key_msg), fname_used);
buf->b_p_key = crypt_get_key(FALSE, FALSE);
if (buf->b_p_key == NULL)
buf->b_p_key = curbuf->b_p_key;
else if (*buf->b_p_key == NUL)
{
vim_free(buf->b_p_key);
buf->b_p_key = curbuf->b_p_key;
}
if (buf->b_p_key == NULL)
buf->b_p_key = empty_option;
}
#endif
if (b0_ff != 0)
set_fileformat(b0_ff - 1, OPT_LOCAL);
if (b0_fenc != NULL)
{
set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL);
vim_free(b0_fenc);
}
unchanged(curbuf, TRUE);
bnum = 1;
page_count = 1;
lnum = 0;
line_count = 0;
idx = 0;
error = 0;
buf->b_ml.ml_stack_top = 0;
buf->b_ml.ml_stack = NULL;
buf->b_ml.ml_stack_size = 0;
if (curbuf->b_ffname == NULL)
cannot_open = TRUE;
else
cannot_open = FALSE;
serious_error = FALSE;
for ( ; !got_int; line_breakcheck())
{
if (hp != NULL)
mf_put(mfp, hp, FALSE, FALSE);
if ((hp = mf_get(mfp, (blocknr_T)bnum, page_count)) == NULL)
{
if (bnum == 1)
{
EMSG2(_("E309: Unable to read block 1 from %s"), mfp->mf_fname);
goto theend;
}
++error;
ml_append(lnum++, (char_u *)_("???MANY LINES MISSING"),
(colnr_T)0, TRUE);
}
else
{
pp = (PTR_BL *)(hp->bh_data);
if (pp->pb_id == PTR_ID)
{
if (idx == 0 && line_count != 0)
{
for (i = 0; i < (int)pp->pb_count; ++i)
line_count -= pp->pb_pointer[i].pe_line_count;
if (line_count != 0)
{
++error;
ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
(colnr_T)0, TRUE);
}
}
if (pp->pb_count == 0)
{
ml_append(lnum++, (char_u *)_("???EMPTY BLOCK"),
(colnr_T)0, TRUE);
++error;
}
else if (idx < (int)pp->pb_count)
{
if (pp->pb_pointer[idx].pe_bnum < 0)
{
if (!cannot_open)
{
line_count = pp->pb_pointer[idx].pe_line_count;
if (readfile(curbuf->b_ffname, NULL, lnum,
pp->pb_pointer[idx].pe_old_lnum - 1,
line_count, NULL, 0) != OK)
cannot_open = TRUE;
else
lnum += line_count;
}
if (cannot_open)
{
++error;
ml_append(lnum++, (char_u *)_("???LINES MISSING"),
(colnr_T)0, TRUE);
}
++idx;
continue;
}
if ((top = ml_add_stack(buf)) < 0)
{
++error;
break;
}
ip = &(buf->b_ml.ml_stack[top]);
ip->ip_bnum = bnum;
ip->ip_index = idx;
bnum = pp->pb_pointer[idx].pe_bnum;
line_count = pp->pb_pointer[idx].pe_line_count;
page_count = pp->pb_pointer[idx].pe_page_count;
idx = 0;
continue;
}
}
else
{
dp = (DATA_BL *)(hp->bh_data);
if (dp->db_id != DATA_ID)
{
if (bnum == 1)
{
EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
mfp->mf_fname);
goto theend;
}
++error;
ml_append(lnum++, (char_u *)_("???BLOCK MISSING"),
(colnr_T)0, TRUE);
}
else
{
has_error = FALSE;
if (page_count * mfp->mf_page_size != dp->db_txt_end)
{
ml_append(lnum++, (char_u *)_("??? from here until ???END lines may be messed up"),
(colnr_T)0, TRUE);
++error;
has_error = TRUE;
dp->db_txt_end = page_count * mfp->mf_page_size;
}
*((char_u *)dp + dp->db_txt_end - 1) = NUL;
if (line_count != dp->db_line_count)
{
ml_append(lnum++, (char_u *)_("??? from here until ???END lines may have been inserted/deleted"),
(colnr_T)0, TRUE);
++error;
has_error = TRUE;
}
for (i = 0; i < dp->db_line_count; ++i)
{
txt_start = (dp->db_index[i] & DB_INDEX_MASK);
if (txt_start <= (int)HEADER_SIZE
|| txt_start >= (int)dp->db_txt_end)
{
p = (char_u *)"???";
++error;
}
else
p = (char_u *)dp + txt_start;
ml_append(lnum++, p, (colnr_T)0, TRUE);
}
if (has_error)
ml_append(lnum++, (char_u *)_("???END"),
(colnr_T)0, TRUE);
}
}
}
if (buf->b_ml.ml_stack_top == 0)
break;
ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
bnum = ip->ip_bnum;
idx = ip->ip_index + 1;
page_count = 1;
}
if (orig_file_status != OK || curbuf->b_ml.ml_line_count != lnum * 2 + 1)
{
if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL))
{
changed_int();
++CHANGEDTICK(curbuf);
}
}
else
{
for (idx = 1; idx <= lnum; ++idx)
{
p = vim_strsave(ml_get(idx));
i = STRCMP(p, ml_get(idx + lnum));
vim_free(p);
if (i != 0)
{
changed_int();
++CHANGEDTICK(curbuf);
break;
}
}
}
while (curbuf->b_ml.ml_line_count > lnum
&& !(curbuf->b_ml.ml_flags & ML_EMPTY))
ml_delete(curbuf->b_ml.ml_line_count, FALSE);
curbuf->b_flags |= BF_RECOVERED;
recoverymode = FALSE;
if (got_int)
EMSG(_("E311: Recovery Interrupted"));
else if (error)
{
++no_wait_return;
MSG(">>>>>>>>>>>>>");
EMSG(_("E312: Errors detected while recovering; look for lines starting with ???"));
--no_wait_return;
MSG(_("See \":help E312\" for more information."));
MSG(">>>>>>>>>>>>>");
}
else
{
if (curbuf->b_changed)
{
MSG(_("Recovery completed. You should check if everything is OK."));
MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
MSG_PUTS(_("and run diff with the original file to check for changes)"));
}
else
MSG(_("Recovery completed. Buffer contents equals file contents."));
if (vim_strchr(p_cpo, CPO_PRESERVE) == NULL)
MSG_PUTS(_("\nYou may want to delete the .swp file now.\n\n"));
cmdline_row = msg_row;
}
#ifdef FEAT_CRYPT
if (*buf->b_p_key != NUL && STRCMP(curbuf->b_p_key, buf->b_p_key) != 0)
{
MSG_PUTS(_("Using crypt key from swap file for the text file.\n"));
set_option_value((char_u *)"key", 0L, buf->b_p_key, OPT_LOCAL);
}
#endif
redraw_curbuf_later(NOT_VALID);
theend:
vim_free(fname_used);
recoverymode = FALSE;
if (mfp != NULL)
{
if (hp != NULL)
mf_put(mfp, hp, FALSE, FALSE);
mf_close(mfp, (vim_strchr(p_cpo, CPO_PRESERVE) != NULL));
}
if (buf != NULL)
{
#ifdef FEAT_CRYPT
if (buf->b_p_key != curbuf->b_p_key)
free_string_option(buf->b_p_key);
free_string_option(buf->b_p_cm);
#endif
vim_free(buf->b_ml.ml_stack);
vim_free(buf);
}
if (serious_error && called_from_main)
ml_close(curbuf, TRUE);
#ifdef FEAT_AUTOCMD
else
{
apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
}
#endif
return;
}
int
recover_names(
char_u *fname,
int list,
int nr,
char_u **fname_out)
{
int num_names;
char_u *(names[6]);
char_u *tail;
char_u *p;
int num_files;
int file_count = 0;
char_u **files;
int i;
char_u *dirp;
char_u *dir_name;
char_u *fname_res = NULL;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
#endif
if (fname != NULL)
{
#ifdef HAVE_READLINK
if (resolve_symlink(fname, fname_buf) == OK)
fname_res = fname_buf;
else
#endif
fname_res = fname;
}
if (list)
{
msg((char_u *)_("Swap files found:"));
msg_putchar('\n');
}
dir_name = alloc((unsigned)STRLEN(p_dir) + 1);
dirp = p_dir;
while (dir_name != NULL && *dirp)
{
(void)copy_option_part(&dirp, dir_name, 31000, ",");
if (dir_name[0] == '.' && dir_name[1] == NUL)
{
if (fname == NULL)
{
#ifdef VMS
names[0] = vim_strsave((char_u *)"*_sw%");
#else
names[0] = vim_strsave((char_u *)"*.sw?");
#endif
#if defined(UNIX) || defined(WIN3264)
names[1] = vim_strsave((char_u *)".*.sw?");
names[2] = vim_strsave((char_u *)".sw?");
num_names = 3;
#else
# ifdef VMS
names[1] = vim_strsave((char_u *)".*_sw%");
num_names = 2;
# else
num_names = 1;
# endif
#endif
}
else
num_names = recov_file_names(names, fname_res, TRUE);
}
else
{
if (fname == NULL)
{
#ifdef VMS
names[0] = concat_fnames(dir_name, (char_u *)"*_sw%", TRUE);
#else
names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
#endif
#if defined(UNIX) || defined(WIN3264)
names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
num_names = 3;
#else
# ifdef VMS
names[1] = concat_fnames(dir_name, (char_u *)".*_sw%", TRUE);
num_names = 2;
# else
num_names = 1;
# endif
#endif
}
else
{
#if defined(UNIX) || defined(WIN3264)
int len = (int)STRLEN(dir_name);
p = dir_name + len;
if (after_pathsep(dir_name, p) && len > 1 && p[-1] == p[-2])
{
tail = make_percent_swname(dir_name, fname_res);
}
else
#endif
{
tail = gettail(fname_res);
tail = concat_fnames(dir_name, tail, TRUE);
}
if (tail == NULL)
num_names = 0;
else
{
num_names = recov_file_names(names, tail, FALSE);
vim_free(tail);
}
}
}
for (i = 0; i < num_names; ++i)
{
if (names[i] == NULL)
{
for (i = 0; i < num_names; ++i)
vim_free(names[i]);
num_names = 0;
}
}
if (num_names == 0)
num_files = 0;
else if (expand_wildcards(num_names, names, &num_files, &files,
EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
num_files = 0;
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL)
{
stat_T st;
char_u *swapname;
swapname = modname(fname_res,
#if defined(VMS)
(char_u *)"_swp", FALSE
#else
(char_u *)".swp", TRUE
#endif
);
if (swapname != NULL)
{
if (mch_stat((char *)swapname, &st) != -1)
{
files = (char_u **)alloc((unsigned)sizeof(char_u *));
if (files != NULL)
{
files[0] = swapname;
swapname = NULL;
num_files = 1;
}
}
vim_free(swapname);
}
}
if (curbuf->b_ml.ml_mfp != NULL
&& (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
{
for (i = 0; i < num_files; ++i)
if (fullpathcmp(p, files[i], TRUE) & FPC_SAME)
{
vim_free(files[i]);
if (--num_files == 0)
vim_free(files);
else
for ( ; i < num_files; ++i)
files[i] = files[i + 1];
}
}
if (nr > 0)
{
file_count += num_files;
if (nr <= file_count)
{
*fname_out = vim_strsave(
files[nr - 1 + num_files - file_count]);
dirp = (char_u *)"";
}
}
else if (list)
{
if (dir_name[0] == '.' && dir_name[1] == NUL)
{
if (fname == NULL)
MSG_PUTS(_(" In current directory:\n"));
else
MSG_PUTS(_(" Using specified name:\n"));
}
else
{
MSG_PUTS(_(" In directory "));
msg_home_replace(dir_name);
MSG_PUTS(":\n");
}
if (num_files)
{
for (i = 0; i < num_files; ++i)
{
msg_outnum((long)++file_count);
MSG_PUTS(". ");
msg_puts(gettail(files[i]));
msg_putchar('\n');
(void)swapfile_info(files[i]);
}
}
else
MSG_PUTS(_(" -- none --\n"));
out_flush();
}
else
file_count += num_files;
for (i = 0; i < num_names; ++i)
vim_free(names[i]);
if (num_files > 0)
FreeWild(num_files, files);
}
vim_free(dir_name);
return file_count;
}
#if defined(UNIX) || defined(WIN3264)
static char_u *
make_percent_swname(char_u *dir, char_u *name)
{
char_u *d, *s, *f;
f = fix_fname(name != NULL ? name : (char_u *) "");
d = NULL;
if (f != NULL)
{
s = alloc((unsigned)(STRLEN(f) + 1));
if (s != NULL)
{
STRCPY(s, f);
for (d = s; *d != NUL; MB_PTR_ADV(d))
if (vim_ispathsep(*d))
*d = '%';
d = concat_fnames(dir, s, TRUE);
vim_free(s);
}
vim_free(f);
}
return d;
}
#endif
#if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
static int process_still_running;
#endif
static time_t
swapfile_info(char_u *fname)
{
stat_T st;
int fd;
struct block0 b0;
time_t x = (time_t)0;
char *p;
#ifdef UNIX
char_u uname[B0_UNAME_SIZE];
#endif
if (mch_stat((char *)fname, &st) != -1)
{
#ifdef UNIX
if (mch_get_uname(st.st_uid, uname, B0_UNAME_SIZE) == OK)
{
MSG_PUTS(_(" owned by: "));
msg_outtrans(uname);
MSG_PUTS(_(" dated: "));
}
else
#endif
MSG_PUTS(_(" dated: "));
x = st.st_mtime;
p = ctime(&x);
if (p == NULL)
MSG_PUTS("(invalid)\n");
else
MSG_PUTS(p);
}
fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
if (fd >= 0)
{
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
{
if (STRNCMP(b0.b0_version, "VIM 3.0", 7) == 0)
{
MSG_PUTS(_(" [from Vim version 3.0]"));
}
else if (ml_check_b0_id(&b0) == FAIL)
{
MSG_PUTS(_(" [does not look like a Vim swap file]"));
}
else
{
MSG_PUTS(_(" file name: "));
if (b0.b0_fname[0] == NUL)
MSG_PUTS(_("[No Name]"));
else
msg_outtrans(b0.b0_fname);
MSG_PUTS(_("\n modified: "));
MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
if (*(b0.b0_uname) != NUL)
{
MSG_PUTS(_("\n user name: "));
msg_outtrans(b0.b0_uname);
}
if (*(b0.b0_hname) != NUL)
{
if (*(b0.b0_uname) != NUL)
MSG_PUTS(_(" host name: "));
else
MSG_PUTS(_("\n host name: "));
msg_outtrans(b0.b0_hname);
}
if (char_to_long(b0.b0_pid) != 0L)
{
MSG_PUTS(_("\n process ID: "));
msg_outnum(char_to_long(b0.b0_pid));
#if defined(UNIX)
if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
{
MSG_PUTS(_(" (still running)"));
# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
process_still_running = TRUE;
# endif
}
#endif
}
if (b0_magic_wrong(&b0))
{
#if defined(MSWIN)
if (STRNCMP(b0.b0_hname, "PC ", 3) == 0)
MSG_PUTS(_("\n [not usable with this version of Vim]"));
else
#endif
MSG_PUTS(_("\n [not usable on this computer]"));
}
}
}
else
MSG_PUTS(_(" [cannot be read]"));
close(fd);
}
else
MSG_PUTS(_(" [cannot be opened]"));
msg_putchar('\n');
return x;
}
static int
recov_file_names(char_u **names, char_u *path, int prepend_dot)
{
int num_names;
char_u *p;
int i;
# ifndef WIN3264
int shortname = curbuf->b_shortname;
curbuf->b_shortname = FALSE;
# endif
num_names = 0;
if (prepend_dot)
{
names[num_names] = modname(path, (char_u *)".sw?", TRUE);
if (names[num_names] == NULL)
goto end;
++num_names;
}
#ifdef VMS
names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE);
#else
names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
#endif
if (names[num_names] == NULL)
goto end;
if (num_names >= 1)
{
p = names[num_names - 1];
i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
if (i > 0)
p += i;
if (STRCMP(p, names[num_names]) != 0)
++num_names;
else
vim_free(names[num_names]);
}
else
++num_names;
# ifndef WIN3264
curbuf->b_shortname = TRUE;
#ifdef VMS
names[num_names] = modname(path, (char_u *)"_sw%", FALSE);
#else
names[num_names] = modname(path, (char_u *)".sw?", FALSE);
#endif
if (names[num_names] == NULL)
goto end;
p = names[num_names];
i = STRLEN(names[num_names]) - STRLEN(names[num_names - 1]);
if (i > 0)
p += i;
if (STRCMP(names[num_names - 1], p) == 0)
vim_free(names[num_names]);
else
++num_names;
# endif
end:
# ifndef WIN3264
curbuf->b_shortname = shortname;
# endif
return num_names;
}
void
ml_sync_all(int check_file, int check_char)
{
buf_T *buf;
stat_T st;
FOR_ALL_BUFFERS(buf)
{
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
continue;
ml_flush_line(buf);
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
&& buf->b_ffname != NULL)
{
if (mch_stat((char *)buf->b_ffname, &st) == -1
|| st.st_mtime != buf->b_mtime_read
|| st.st_size != buf->b_orig_size)
{
ml_preserve(buf, FALSE);
did_check_timestamps = FALSE;
need_check_timestamps = TRUE;
}
}
if (buf->b_ml.ml_mfp->mf_dirty)
{
(void)mf_sync(buf->b_ml.ml_mfp, (check_char ? MFS_STOP : 0)
| (bufIsChanged(buf) ? MFS_FLUSH : 0));
if (check_char && ui_char_avail())
break;
}
}
}
void
ml_preserve(buf_T *buf, int message)
{
bhdr_T *hp;
linenr_T lnum;
memfile_T *mfp = buf->b_ml.ml_mfp;
int status;
int got_int_save = got_int;
if (mfp == NULL || mfp->mf_fname == NULL)
{
if (message)
EMSG(_("E313: Cannot preserve, there is no swap file"));
return;
}
got_int = FALSE;
ml_flush_line(buf);
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
status = mf_sync(mfp, MFS_ALL | MFS_FLUSH);
buf->b_ml.ml_stack_top = 0;
if (mf_need_trans(mfp) && !got_int)
{
lnum = 1;
while (mf_need_trans(mfp) && lnum <= buf->b_ml.ml_line_count)
{
hp = ml_find_line(buf, lnum, ML_FIND);
if (hp == NULL)
{
status = FAIL;
goto theend;
}
CHECK(buf->b_ml.ml_locked_low != lnum, "low != lnum");
lnum = buf->b_ml.ml_locked_high + 1;
}
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
if (mf_sync(mfp, MFS_ALL | MFS_FLUSH) == FAIL)
status = FAIL;
buf->b_ml.ml_stack_top = 0;
}
theend:
got_int |= got_int_save;
if (message)
{
if (status == OK)
MSG(_("File preserved"));
else
EMSG(_("E314: Preserve failed"));
}
}
char_u *
ml_get(linenr_T lnum)
{
return ml_get_buf(curbuf, lnum, FALSE);
}
char_u *
ml_get_pos(pos_T *pos)
{
return (ml_get_buf(curbuf, pos->lnum, FALSE) + pos->col);
}
char_u *
ml_get_curline(void)
{
return ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE);
}
char_u *
ml_get_cursor(void)
{
return (ml_get_buf(curbuf, curwin->w_cursor.lnum, FALSE) +
curwin->w_cursor.col);
}
char_u *
ml_get_buf(
buf_T *buf,
linenr_T lnum,
int will_change)
{
bhdr_T *hp;
DATA_BL *dp;
char_u *ptr;
static int recursive = 0;
if (lnum > buf->b_ml.ml_line_count)
{
if (recursive == 0)
{
++recursive;
IEMSGN(_("E315: ml_get: invalid lnum: %ld"), lnum);
--recursive;
}
errorret:
STRCPY(IObuff, "???");
return IObuff;
}
if (lnum <= 0)
lnum = 1;
if (buf->b_ml.ml_mfp == NULL)
return (char_u *)"";
if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release)
{
ml_flush_line(buf);
if ((hp = ml_find_line(buf, lnum, ML_FIND)) == NULL)
{
if (recursive == 0)
{
++recursive;
IEMSGN(_("E316: ml_get: cannot find line %ld"), lnum);
--recursive;
}
goto errorret;
}
dp = (DATA_BL *)(hp->bh_data);
ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK);
buf->b_ml.ml_line_ptr = ptr;
buf->b_ml.ml_line_lnum = lnum;
buf->b_ml.ml_flags &= ~ML_LINE_DIRTY;
}
if (will_change)
buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
return buf->b_ml.ml_line_ptr;
}
int
ml_line_alloced(void)
{
return (curbuf->b_ml.ml_flags & ML_LINE_DIRTY);
}
int
ml_append(
linenr_T lnum,
char_u *line,
colnr_T len,
int newfile)
{
if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
return FAIL;
if (curbuf->b_ml.ml_line_lnum != 0)
ml_flush_line(curbuf);
return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
}
#if defined(FEAT_SPELL) || defined(FEAT_QUICKFIX) || defined(PROTO)
int
ml_append_buf(
buf_T *buf,
linenr_T lnum,
char_u *line,
colnr_T len,
int newfile)
{
if (buf->b_ml.ml_mfp == NULL)
return FAIL;
if (buf->b_ml.ml_line_lnum != 0)
ml_flush_line(buf);
return ml_append_int(buf, lnum, line, len, newfile, FALSE);
}
#endif
static int
ml_append_int(
buf_T *buf,
linenr_T lnum,
char_u *line,
colnr_T len,
int newfile,
int mark)
{
int i;
int line_count;
int offset;
int from, to;
int space_needed;
int page_size;
int page_count;
int db_idx;
bhdr_T *hp;
memfile_T *mfp;
DATA_BL *dp;
PTR_BL *pp;
infoptr_T *ip;
if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
return FAIL;
if (lowest_marked && lowest_marked > lnum)
lowest_marked = lnum + 1;
if (len == 0)
len = (colnr_T)STRLEN(line) + 1;
space_needed = len + INDEX_SIZE;
mfp = buf->b_ml.ml_mfp;
page_size = mfp->mf_page_size;
if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
ML_INSERT)) == NULL)
return FAIL;
buf->b_ml.ml_flags &= ~ML_EMPTY;
if (lnum == 0)
db_idx = -1;
else
db_idx = lnum - buf->b_ml.ml_locked_low;
line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
dp = (DATA_BL *)(hp->bh_data);
if ((int)dp->db_free < space_needed && db_idx == line_count - 1
&& lnum < buf->b_ml.ml_line_count)
{
--(buf->b_ml.ml_locked_lineadd);
--(buf->b_ml.ml_locked_high);
if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
return FAIL;
db_idx = -1;
line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
dp = (DATA_BL *)(hp->bh_data);
}
++buf->b_ml.ml_line_count;
if ((int)dp->db_free >= space_needed)
{
dp->db_txt_start -= len;
dp->db_free -= space_needed;
++(dp->db_line_count);
if (line_count > db_idx + 1)
{
if (db_idx < 0)
offset = dp->db_txt_end;
else
offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
mch_memmove((char *)dp + dp->db_txt_start,
(char *)dp + dp->db_txt_start + len,
(size_t)(offset - (dp->db_txt_start + len)));
for (i = line_count - 1; i > db_idx; --i)
dp->db_index[i + 1] = dp->db_index[i] - len;
dp->db_index[db_idx + 1] = offset - len;
}
else
dp->db_index[db_idx + 1] = dp->db_txt_start;
mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
if (mark)
dp->db_index[db_idx + 1] |= DB_MARKED;
buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
if (!newfile)
buf->b_ml.ml_flags |= ML_LOCKED_POS;
}
else
{
long line_count_left, line_count_right;
int page_count_left, page_count_right;
bhdr_T *hp_left;
bhdr_T *hp_right;
bhdr_T *hp_new;
int lines_moved;
int data_moved = 0;
int total_moved = 0;
DATA_BL *dp_right, *dp_left;
int stack_idx;
int in_left;
int lineadd;
blocknr_T bnum_left, bnum_right;
linenr_T lnum_left, lnum_right;
int pb_idx;
PTR_BL *pp_new;
if (db_idx < 0)
{
lines_moved = 0;
in_left = TRUE;
}
else
{
lines_moved = line_count - db_idx - 1;
if (lines_moved == 0)
in_left = FALSE;
else
{
data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
dp->db_txt_start;
total_moved = data_moved + lines_moved * INDEX_SIZE;
if ((int)dp->db_free + total_moved >= space_needed)
{
in_left = TRUE;
space_needed = total_moved;
}
else
{
in_left = FALSE;
space_needed += total_moved;
}
}
}
page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
if ((hp_new = ml_new_data(mfp, newfile, page_count)) == NULL)
{
--(buf->b_ml.ml_locked_lineadd);
--(buf->b_ml.ml_locked_high);
return FAIL;
}
if (db_idx < 0)
{
hp_left = hp_new;
hp_right = hp;
line_count_left = 0;
line_count_right = line_count;
}
else
{
hp_left = hp;
hp_right = hp_new;
line_count_left = line_count;
line_count_right = 0;
}
dp_right = (DATA_BL *)(hp_right->bh_data);
dp_left = (DATA_BL *)(hp_left->bh_data);
bnum_left = hp_left->bh_bnum;
bnum_right = hp_right->bh_bnum;
page_count_left = hp_left->bh_page_count;
page_count_right = hp_right->bh_page_count;
if (!in_left)
{
dp_right->db_txt_start -= len;
dp_right->db_free -= len + INDEX_SIZE;
dp_right->db_index[0] = dp_right->db_txt_start;
if (mark)
dp_right->db_index[0] |= DB_MARKED;
mch_memmove((char *)dp_right + dp_right->db_txt_start,
line, (size_t)len);
++line_count_right;
}
if (lines_moved)
{
dp_right->db_txt_start -= data_moved;
dp_right->db_free -= total_moved;
mch_memmove((char *)dp_right + dp_right->db_txt_start,
(char *)dp_left + dp_left->db_txt_start,
(size_t)data_moved);
offset = dp_right->db_txt_start - dp_left->db_txt_start;
dp_left->db_txt_start += data_moved;
dp_left->db_free += total_moved;
for (to = line_count_right, from = db_idx + 1;
from < line_count_left; ++from, ++to)
dp_right->db_index[to] = dp->db_index[from] + offset;
line_count_right += lines_moved;
line_count_left -= lines_moved;
}
if (in_left)
{
dp_left->db_txt_start -= len;
dp_left->db_free -= len + INDEX_SIZE;
dp_left->db_index[line_count_left] = dp_left->db_txt_start;
if (mark)
dp_left->db_index[line_count_left] |= DB_MARKED;
mch_memmove((char *)dp_left + dp_left->db_txt_start,
line, (size_t)len);
++line_count_left;
}
if (db_idx < 0)
{
lnum_left = lnum + 1;
lnum_right = 0;
}
else
{
lnum_left = 0;
if (in_left)
lnum_right = lnum + 2;
else
lnum_right = lnum + 1;
}
dp_left->db_line_count = line_count_left;
dp_right->db_line_count = line_count_right;
if (lines_moved || in_left)
buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
if (!newfile && db_idx >= 0 && in_left)
buf->b_ml.ml_flags |= ML_LOCKED_POS;
mf_put(mfp, hp_new, TRUE, FALSE);
lineadd = buf->b_ml.ml_locked_lineadd;
buf->b_ml.ml_locked_lineadd = 0;
ml_find_line(buf, (linenr_T)0, ML_FLUSH);
for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
--stack_idx)
{
ip = &(buf->b_ml.ml_stack[stack_idx]);
pb_idx = ip->ip_index;
if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
return FAIL;
pp = (PTR_BL *)(hp->bh_data);
if (pp->pb_id != PTR_ID)
{
IEMSG(_("E317: pointer block id wrong 3"));
mf_put(mfp, hp, FALSE, FALSE);
return FAIL;
}
if (pp->pb_count < pp->pb_count_max)
{
if (pb_idx + 1 < (int)pp->pb_count)
mch_memmove(&pp->pb_pointer[pb_idx + 2],
&pp->pb_pointer[pb_idx + 1],
(size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
++pp->pb_count;
pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
if (lnum_left != 0)
pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
if (lnum_right != 0)
pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
mf_put(mfp, hp, TRUE, FALSE);
buf->b_ml.ml_stack_top = stack_idx + 1;
if (lineadd)
{
--(buf->b_ml.ml_stack_top);
ml_lineadd(buf, lineadd);
buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
lineadd;
++(buf->b_ml.ml_stack_top);
}
break;
}
else
{
for (;;)
{
hp_new = ml_new_ptr(mfp);
if (hp_new == NULL)
return FAIL;
pp_new = (PTR_BL *)(hp_new->bh_data);
if (hp->bh_bnum != 1)
break;
mch_memmove(pp_new, pp, (size_t)page_size);
pp->pb_count = 1;
pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum;
pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
pp->pb_pointer[0].pe_old_lnum = 1;
pp->pb_pointer[0].pe_page_count = 1;
mf_put(mfp, hp, TRUE, FALSE);
hp = hp_new;
pp = pp_new;
CHECK(stack_idx != 0, _("stack_idx should be 0"));
ip->ip_index = 0;
++stack_idx;
}
total_moved = pp->pb_count - pb_idx - 1;
if (total_moved)
{
mch_memmove(&pp_new->pb_pointer[0],
&pp->pb_pointer[pb_idx + 1],
(size_t)(total_moved) * sizeof(PTR_EN));
pp_new->pb_count = total_moved;
pp->pb_count -= total_moved - 1;
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
if (lnum_right)
pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
}
else
{
pp_new->pb_count = 1;
pp_new->pb_pointer[0].pe_bnum = bnum_right;
pp_new->pb_pointer[0].pe_line_count = line_count_right;
pp_new->pb_pointer[0].pe_page_count = page_count_right;
pp_new->pb_pointer[0].pe_old_lnum = lnum_right;
}
pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
if (lnum_left)
pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
lnum_left = 0;
lnum_right = 0;
line_count_right = 0;
for (i = 0; i < (int)pp_new->pb_count; ++i)
line_count_right += pp_new->pb_pointer[i].pe_line_count;
line_count_left = 0;
for (i = 0; i < (int)pp->pb_count; ++i)
line_count_left += pp->pb_pointer[i].pe_line_count;
bnum_left = hp->bh_bnum;
bnum_right = hp_new->bh_bnum;
page_count_left = 1;
page_count_right = 1;
mf_put(mfp, hp, TRUE, FALSE);
mf_put(mfp, hp_new, TRUE, FALSE);
}
}
if (stack_idx < 0)
{
IEMSG(_("E318: Updated too many blocks?"));
buf->b_ml.ml_stack_top = 0;
}
}
#ifdef FEAT_BYTEOFF
ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
#endif
#ifdef FEAT_NETBEANS_INTG
if (netbeans_active())
{
if (STRLEN(line) > 0)
netbeans_inserted(buf, lnum+1, (colnr_T)0, line, (int)STRLEN(line));
netbeans_inserted(buf, lnum+1, (colnr_T)STRLEN(line),
(char_u *)"\n", 1);
}
#endif
#ifdef FEAT_JOB_CHANNEL
if (buf->b_write_to_channel)
channel_write_new_lines(buf);
#endif
return OK;
}
int
ml_replace(linenr_T lnum, char_u *line, int copy)
{
if (line == NULL)
return FAIL;
if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
return FAIL;
if (copy && (line = vim_strsave(line)) == NULL)
return FAIL;
#ifdef FEAT_NETBEANS_INTG
if (netbeans_active())
{
netbeans_removed(curbuf, lnum, 0, (long)STRLEN(ml_get(lnum)));
netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line));
}
#endif
if (curbuf->b_ml.ml_line_lnum != lnum)
ml_flush_line(curbuf);
else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY)
vim_free(curbuf->b_ml.ml_line_ptr);
curbuf->b_ml.ml_line_ptr = line;
curbuf->b_ml.ml_line_lnum = lnum;
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
return OK;
}
int
ml_delete(linenr_T lnum, int message)
{
ml_flush_line(curbuf);
return ml_delete_int(curbuf, lnum, message);
}
static int
ml_delete_int(buf_T *buf, linenr_T lnum, int message)
{
bhdr_T *hp;
memfile_T *mfp;
DATA_BL *dp;
PTR_BL *pp;
infoptr_T *ip;
int count;
int idx;
int stack_idx;
int text_start;
int line_start;
long line_size;
int i;
if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
return FAIL;
if (lowest_marked && lowest_marked > lnum)
lowest_marked--;
if (buf->b_ml.ml_line_count == 1)
{
if (message
#ifdef FEAT_NETBEANS_INTG
&& !netbeansSuppressNoLines
#endif
)
set_keep_msg((char_u *)_(no_lines_msg), 0);
i = ml_replace((linenr_T)1, (char_u *)"", TRUE);
buf->b_ml.ml_flags |= ML_EMPTY;
return i;
}
mfp = buf->b_ml.ml_mfp;
if (mfp == NULL)
return FAIL;
if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
return FAIL;
dp = (DATA_BL *)(hp->bh_data);
count = (long)(buf->b_ml.ml_locked_high)
- (long)(buf->b_ml.ml_locked_low) + 2;
idx = lnum - buf->b_ml.ml_locked_low;
--buf->b_ml.ml_line_count;
line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
if (idx == 0)
line_size = dp->db_txt_end - line_start;
else
line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
#ifdef FEAT_NETBEANS_INTG
if (netbeans_active())
netbeans_removed(buf, lnum, 0, (long)line_size);
#endif
if (count == 1)
{
mf_free(mfp, hp);
buf->b_ml.ml_locked = NULL;
for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
--stack_idx)
{
buf->b_ml.ml_stack_top = 0;
ip = &(buf->b_ml.ml_stack[stack_idx]);
idx = ip->ip_index;
if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
return FAIL;
pp = (PTR_BL *)(hp->bh_data);
if (pp->pb_id != PTR_ID)
{
IEMSG(_("E317: pointer block id wrong 4"));
mf_put(mfp, hp, FALSE, FALSE);
return FAIL;
}
count = --(pp->pb_count);
if (count == 0)
mf_free(mfp, hp);
else
{
if (count != idx)
mch_memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
(size_t)(count - idx) * sizeof(PTR_EN));
mf_put(mfp, hp, TRUE, FALSE);
buf->b_ml.ml_stack_top = stack_idx;
if (buf->b_ml.ml_locked_lineadd != 0)
{
ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
buf->b_ml.ml_locked_lineadd;
}
++(buf->b_ml.ml_stack_top);
break;
}
}
CHECK(stack_idx < 0, _("deleted block 1?"));
}
else
{
text_start = dp->db_txt_start;
mch_memmove((char *)dp + text_start + line_size,
(char *)dp + text_start, (size_t)(line_start - text_start));
for (i = idx; i < count - 1; ++i)
dp->db_index[i] = dp->db_index[i + 1] + line_size;
dp->db_free += line_size + INDEX_SIZE;
dp->db_txt_start += line_size;
--(dp->db_line_count);
buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
}
#ifdef FEAT_BYTEOFF
ml_updatechunk(buf, lnum, line_size, ML_CHNK_DELLINE);
#endif
return OK;
}
void
ml_setmarked(linenr_T lnum)
{
bhdr_T *hp;
DATA_BL *dp;
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
|| curbuf->b_ml.ml_mfp == NULL)
return;
if (lowest_marked == 0 || lowest_marked > lnum)
lowest_marked = lnum;
if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
return;
dp = (DATA_BL *)(hp->bh_data);
dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
}
linenr_T
ml_firstmarked(void)
{
bhdr_T *hp;
DATA_BL *dp;
linenr_T lnum;
int i;
if (curbuf->b_ml.ml_mfp == NULL)
return (linenr_T) 0;
for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
{
if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
return (linenr_T)0;
dp = (DATA_BL *)(hp->bh_data);
for (i = lnum - curbuf->b_ml.ml_locked_low;
lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
if ((dp->db_index[i]) & DB_MARKED)
{
(dp->db_index[i]) &= DB_INDEX_MASK;
curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
lowest_marked = lnum + 1;
return lnum;
}
}
return (linenr_T) 0;
}
void
ml_clearmarked(void)
{
bhdr_T *hp;
DATA_BL *dp;
linenr_T lnum;
int i;
if (curbuf->b_ml.ml_mfp == NULL)
return;
for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; )
{
if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
return;
dp = (DATA_BL *)(hp->bh_data);
for (i = lnum - curbuf->b_ml.ml_locked_low;
lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
if ((dp->db_index[i]) & DB_MARKED)
{
(dp->db_index[i]) &= DB_INDEX_MASK;
curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
}
}
lowest_marked = 0;
return;
}
static void
ml_flush_line(buf_T *buf)
{
bhdr_T *hp;
DATA_BL *dp;
linenr_T lnum;
char_u *new_line;
char_u *old_line;
colnr_T new_len;
int old_len;
int extra;
int idx;
int start;
int count;
int i;
static int entered = FALSE;
if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
return;
if (buf->b_ml.ml_flags & ML_LINE_DIRTY)
{
if (entered)
return;
entered = TRUE;
lnum = buf->b_ml.ml_line_lnum;
new_line = buf->b_ml.ml_line_ptr;
hp = ml_find_line(buf, lnum, ML_FIND);
if (hp == NULL)
IEMSGN(_("E320: Cannot find line %ld"), lnum);
else
{
dp = (DATA_BL *)(hp->bh_data);
idx = lnum - buf->b_ml.ml_locked_low;
start = ((dp->db_index[idx]) & DB_INDEX_MASK);
old_line = (char_u *)dp + start;
if (idx == 0)
old_len = dp->db_txt_end - start;
else
old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
new_len = (colnr_T)STRLEN(new_line) + 1;
extra = new_len - old_len;
if ((int)dp->db_free >= extra)
{
count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
if (extra != 0 && idx < count - 1)
{
mch_memmove((char *)dp + dp->db_txt_start - extra,
(char *)dp + dp->db_txt_start,
(size_t)(start - dp->db_txt_start));
for (i = idx + 1; i < count; ++i)
dp->db_index[i] -= extra;
}
dp->db_index[idx] -= extra;
dp->db_free -= extra;
dp->db_txt_start -= extra;
mch_memmove(old_line - extra, new_line, (size_t)new_len);
buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
#ifdef FEAT_BYTEOFF
ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
#endif
}
else
{
(void)ml_append_int(buf, lnum, new_line, new_len, FALSE,
(dp->db_index[idx] & DB_MARKED));
(void)ml_delete_int(buf, lnum, FALSE);
}
}
vim_free(new_line);
entered = FALSE;
}
buf->b_ml.ml_line_lnum = 0;
}
static bhdr_T *
ml_new_data(memfile_T *mfp, int negative, int page_count)
{
bhdr_T *hp;
DATA_BL *dp;
if ((hp = mf_new(mfp, negative, page_count)) == NULL)
return NULL;
dp = (DATA_BL *)(hp->bh_data);
dp->db_id = DATA_ID;
dp->db_txt_start = dp->db_txt_end = page_count * mfp->mf_page_size;
dp->db_free = dp->db_txt_start - HEADER_SIZE;
dp->db_line_count = 0;
return hp;
}
static bhdr_T *
ml_new_ptr(memfile_T *mfp)
{
bhdr_T *hp;
PTR_BL *pp;
if ((hp = mf_new(mfp, FALSE, 1)) == NULL)
return NULL;
pp = (PTR_BL *)(hp->bh_data);
pp->pb_id = PTR_ID;
pp->pb_count = 0;
pp->pb_count_max = (short_u)((mfp->mf_page_size - sizeof(PTR_BL))
/ sizeof(PTR_EN) + 1);
return hp;
}
static bhdr_T *
ml_find_line(buf_T *buf, linenr_T lnum, int action)
{
DATA_BL *dp;
PTR_BL *pp;
infoptr_T *ip;
bhdr_T *hp;
memfile_T *mfp;
linenr_T t;
blocknr_T bnum, bnum2;
int dirty;
linenr_T low, high;
int top;
int page_count;
int idx;
mfp = buf->b_ml.ml_mfp;
if (buf->b_ml.ml_locked)
{
if (ML_SIMPLE(action)
&& buf->b_ml.ml_locked_low <= lnum
&& buf->b_ml.ml_locked_high >= lnum
&& !mf_dont_release)
{
if (action == ML_INSERT)
{
++(buf->b_ml.ml_locked_lineadd);
++(buf->b_ml.ml_locked_high);
}
else if (action == ML_DELETE)
{
--(buf->b_ml.ml_locked_lineadd);
--(buf->b_ml.ml_locked_high);
}
return (buf->b_ml.ml_locked);
}
mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
buf->b_ml.ml_flags & ML_LOCKED_POS);
buf->b_ml.ml_locked = NULL;
if (buf->b_ml.ml_locked_lineadd != 0)
ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
}
if (action == ML_FLUSH)
return NULL;
bnum = 1;
page_count = 1;
low = 1;
high = buf->b_ml.ml_line_count;
if (action == ML_FIND)
{
for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top)
{
ip = &(buf->b_ml.ml_stack[top]);
if (ip->ip_low <= lnum && ip->ip_high >= lnum)
{
bnum = ip->ip_bnum;
low = ip->ip_low;
high = ip->ip_high;
buf->b_ml.ml_stack_top = top;
break;
}
}
if (top < 0)
buf->b_ml.ml_stack_top = 0;
}
else
buf->b_ml.ml_stack_top = 0;
for (;;)
{
if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
goto error_noblock;
if (action == ML_INSERT)
++high;
else if (action == ML_DELETE)
--high;
dp = (DATA_BL *)(hp->bh_data);
if (dp->db_id == DATA_ID)
{
buf->b_ml.ml_locked = hp;
buf->b_ml.ml_locked_low = low;
buf->b_ml.ml_locked_high = high;
buf->b_ml.ml_locked_lineadd = 0;
buf->b_ml.ml_flags &= ~(ML_LOCKED_DIRTY | ML_LOCKED_POS);
return hp;
}
pp = (PTR_BL *)(dp);
if (pp->pb_id != PTR_ID)
{
IEMSG(_("E317: pointer block id wrong"));
goto error_block;
}
if ((top = ml_add_stack(buf)) < 0)
goto error_block;
ip = &(buf->b_ml.ml_stack[top]);
ip->ip_bnum = bnum;
ip->ip_low = low;
ip->ip_high = high;
ip->ip_index = -1;
dirty = FALSE;
for (idx = 0; idx < (int)pp->pb_count; ++idx)
{
t = pp->pb_pointer[idx].pe_line_count;
CHECK(t == 0, _("pe_line_count is zero"));
if ((low += t) > lnum)
{
ip->ip_index = idx;
bnum = pp->pb_pointer[idx].pe_bnum;
page_count = pp->pb_pointer[idx].pe_page_count;
high = low - 1;
low -= t;
if (bnum < 0)
{
bnum2 = mf_trans_del(mfp, bnum);
if (bnum != bnum2)
{
bnum = bnum2;
pp->pb_pointer[idx].pe_bnum = bnum;
dirty = TRUE;
}
}
break;
}
}
if (idx >= (int)pp->pb_count)
{
if (lnum > buf->b_ml.ml_line_count)
IEMSGN(_("E322: line number out of range: %ld past the end"),
lnum - buf->b_ml.ml_line_count);
else
IEMSGN(_("E323: line count wrong in block %ld"), bnum);
goto error_block;
}
if (action == ML_DELETE)
{
pp->pb_pointer[idx].pe_line_count--;
dirty = TRUE;
}
else if (action == ML_INSERT)
{
pp->pb_pointer[idx].pe_line_count++;
dirty = TRUE;
}
mf_put(mfp, hp, dirty, FALSE);
}
error_block:
mf_put(mfp, hp, FALSE, FALSE);
error_noblock:
if (action == ML_DELETE)
ml_lineadd(buf, 1);
else if (action == ML_INSERT)
ml_lineadd(buf, -1);
buf->b_ml.ml_stack_top = 0;
return NULL;
}
static int
ml_add_stack(buf_T *buf)
{
int top;
infoptr_T *newstack;
top = buf->b_ml.ml_stack_top;
if (top == buf->b_ml.ml_stack_size)
{
CHECK(top > 0, _("Stack size increases"));
newstack = (infoptr_T *)alloc((unsigned)sizeof(infoptr_T) *
(buf->b_ml.ml_stack_size + STACK_INCR));
if (newstack == NULL)
return -1;
if (top > 0)
mch_memmove(newstack, buf->b_ml.ml_stack,
(size_t)top * sizeof(infoptr_T));
vim_free(buf->b_ml.ml_stack);
buf->b_ml.ml_stack = newstack;
buf->b_ml.ml_stack_size += STACK_INCR;
}
buf->b_ml.ml_stack_top++;
return top;
}
static void
ml_lineadd(buf_T *buf, int count)
{
int idx;
infoptr_T *ip;
PTR_BL *pp;
memfile_T *mfp = buf->b_ml.ml_mfp;
bhdr_T *hp;
for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx)
{
ip = &(buf->b_ml.ml_stack[idx]);
if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
break;
pp = (PTR_BL *)(hp->bh_data);
if (pp->pb_id != PTR_ID)
{
mf_put(mfp, hp, FALSE, FALSE);
IEMSG(_("E317: pointer block id wrong 2"));
break;
}
pp->pb_pointer[ip->ip_index].pe_line_count += count;
ip->ip_high += count;
mf_put(mfp, hp, TRUE, FALSE);
}
}
#if defined(HAVE_READLINK) || defined(PROTO)
int
resolve_symlink(char_u *fname, char_u *buf)
{
char_u tmp[MAXPATHL];
int ret;
int depth = 0;
if (fname == NULL)
return FAIL;
vim_strncpy(tmp, fname, MAXPATHL - 1);
for (;;)
{
if (++depth == 100)
{
EMSG2(_("E773: Symlink loop for \"%s\""), fname);
return FAIL;
}
ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
if (ret <= 0)
{
if (errno == EINVAL || errno == ENOENT)
{
if (depth == 1)
return FAIL;
break;
}
return FAIL;
}
buf[ret] = NUL;
if (mch_isFullName(buf))
STRCPY(tmp, buf);
else
{
char_u *tail;
tail = gettail(tmp);
if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
return FAIL;
STRCPY(tail, buf);
}
}
return vim_FullName(tmp, buf, MAXPATHL, TRUE);
}
#endif
char_u *
makeswapname(
char_u *fname,
char_u *ffname UNUSED,
buf_T *buf,
char_u *dir_name)
{
char_u *r, *s;
char_u *fname_res = fname;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
#endif
#if defined(UNIX) || defined(WIN3264)
int len = (int)STRLEN(dir_name);
s = dir_name + len;
if (after_pathsep(dir_name, s) && len > 1 && s[-1] == s[-2])
{
r = NULL;
if ((s = make_percent_swname(dir_name, fname)) != NULL)
{
r = modname(s, (char_u *)".swp", FALSE);
vim_free(s);
}
return r;
}
#endif
#ifdef HAVE_READLINK
if (resolve_symlink(fname, fname_buf) == OK)
fname_res = fname_buf;
#endif
r = buf_modname(
(buf->b_p_sn || buf->b_shortname),
fname_res,
(char_u *)
#if defined(VMS)
"_swp",
#else
".swp",
#endif
dir_name[0] == '.' && dir_name[1] == NUL);
if (r == NULL)
return NULL;
s = get_file_in_dir(r, dir_name);
vim_free(r);
return s;
}
char_u *
get_file_in_dir(
char_u *fname,
char_u *dname)
{
char_u *t;
char_u *tail;
char_u *retval;
int save_char;
tail = gettail(fname);
if (dname[0] == '.' && dname[1] == NUL)
retval = vim_strsave(fname);
else if (dname[0] == '.' && vim_ispathsep(dname[1]))
{
if (tail == fname)
retval = concat_fnames(dname + 2, tail, TRUE);
else
{
save_char = *tail;
*tail = NUL;
t = concat_fnames(fname, dname + 2, TRUE);
*tail = save_char;
if (t == NULL)
retval = NULL;
else
{
retval = concat_fnames(t, tail, TRUE);
vim_free(t);
}
}
}
else
retval = concat_fnames(dname, tail, TRUE);
#ifdef WIN3264
if (retval != NULL)
for (t = gettail(retval); *t != NUL; MB_PTR_ADV(t))
if (*t == ':')
*t = '%';
#endif
return retval;
}
static void attention_message(buf_T *buf, char_u *fname);
static void
attention_message(
buf_T *buf,
char_u *fname)
{
stat_T st;
time_t x, sx;
char *p;
++no_wait_return;
(void)EMSG(_("E325: ATTENTION"));
MSG_PUTS(_("\nFound a swap file by the name \""));
msg_home_replace(fname);
MSG_PUTS("\"\n");
sx = swapfile_info(fname);
MSG_PUTS(_("While opening file \""));
msg_outtrans(buf->b_fname);
MSG_PUTS("\"\n");
if (mch_stat((char *)buf->b_fname, &st) != -1)
{
MSG_PUTS(_(" dated: "));
x = st.st_mtime;
p = ctime(&x);
if (p == NULL)
MSG_PUTS("(invalid)\n");
else
MSG_PUTS(p);
if (sx != 0 && x > sx)
MSG_PUTS(_(" NEWER than swap file!\n"));
}
MSG_PUTS(_("\n(1) Another program may be editing the same file. If this is the case,\n be careful not to end up with two different instances of the same\n file when making changes. Quit, or continue with caution.\n"));
MSG_PUTS(_("(2) An edit session for this file crashed.\n"));
MSG_PUTS(_(" If this is the case, use \":recover\" or \"vim -r "));
msg_outtrans(buf->b_fname);
MSG_PUTS(_("\"\n to recover the changes (see \":help recovery\").\n"));
MSG_PUTS(_(" If you did this already, delete the swap file \""));
msg_outtrans(fname);
MSG_PUTS(_("\"\n to avoid this message.\n"));
cmdline_row = msg_row;
--no_wait_return;
}
#ifdef FEAT_AUTOCMD
static int do_swapexists(buf_T *buf, char_u *fname);
static int
do_swapexists(buf_T *buf, char_u *fname)
{
set_vim_var_string(VV_SWAPNAME, fname, -1);
set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
++allbuf_lock;
apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
--allbuf_lock;
set_vim_var_string(VV_SWAPNAME, NULL, -1);
switch (*get_vim_var_str(VV_SWAPCHOICE))
{
case 'o': return 1;
case 'e': return 2;
case 'r': return 3;
case 'd': return 4;
case 'q': return 5;
case 'a': return 6;
}
return 0;
}
#endif
static char_u *
findswapname(
buf_T *buf,
char_u **dirp,
char_u *old_fname)
{
char_u *fname;
int n;
char_u *dir_name;
#ifdef AMIGA
BPTR fh;
#endif
int r;
char_u *buf_fname = buf->b_fname;
#if !defined(UNIX)
# define CREATE_DUMMY_FILE
FILE *dummyfd = NULL;
# ifdef WIN3264
if (buf_fname != NULL && !mch_isFullName(buf_fname)
&& vim_strchr(gettail(buf_fname), ':'))
{
char_u *t;
buf_fname = vim_strsave(buf_fname);
if (buf_fname == NULL)
buf_fname = buf->b_fname;
else
for (t = gettail(buf_fname); *t != NUL; MB_PTR_ADV(t))
if (*t == ':')
*t = '%';
}
# endif
if (!(buf->b_p_sn || buf->b_shortname) && buf_fname != NULL
&& mch_getperm(buf_fname) < 0)
dummyfd = mch_fopen((char *)buf_fname, "w");
#endif
dir_name = alloc((unsigned)STRLEN(*dirp) + 1);
if (dir_name == NULL)
*dirp = NULL;
else
(void)copy_option_part(dirp, dir_name, 31000, ",");
if (dir_name == NULL)
fname = NULL;
else
fname = makeswapname(buf_fname, buf->b_ffname, buf, dir_name);
for (;;)
{
if (fname == NULL)
break;
if ((n = (int)STRLEN(fname)) == 0)
{
vim_free(fname);
fname = NULL;
break;
}
#if defined(UNIX)
if (fname[n - 2] == 'w' && fname[n - 1] == 'p'
&& !(buf->b_p_sn || buf->b_shortname))
{
char_u *tail;
char_u *fname2;
stat_T s1, s2;
int f1, f2;
int created1 = FALSE, created2 = FALSE;
int same = FALSE;
tail = gettail(buf_fname);
if ( vim_strchr(tail, '.') != NULL
|| STRLEN(tail) > (size_t)8
|| *gettail(fname) == '.')
{
fname2 = alloc(n + 2);
if (fname2 != NULL)
{
STRCPY(fname2, fname);
if (vim_strchr(tail, '.') != NULL)
fname2[n - 1] = 'x';
else if (*gettail(fname) == '.')
{
fname2[n] = 'x';
fname2[n + 1] = NUL;
}
else
fname2[n - 5] += 1;
f1 = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
if (f1 < 0)
{
f1 = mch_open_rw((char *)fname,
O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
created1 = TRUE;
}
if (f1 >= 0)
{
f2 = mch_open((char *)fname2, O_RDONLY | O_EXTRA, 0);
if (f2 < 0)
{
f2 = mch_open_rw((char *)fname2,
O_RDWR|O_CREAT|O_EXCL|O_EXTRA);
created2 = TRUE;
}
if (f2 >= 0)
{
if (mch_fstat(f1, &s1) != -1
&& mch_fstat(f2, &s2) != -1
&& s1.st_dev == s2.st_dev
&& s1.st_ino == s2.st_ino)
same = TRUE;
close(f2);
if (created2)
mch_remove(fname2);
}
close(f1);
if (created1)
mch_remove(fname);
}
vim_free(fname2);
if (same)
{
buf->b_shortname = TRUE;
vim_free(fname);
fname = makeswapname(buf_fname, buf->b_ffname,
buf, dir_name);
continue;
}
}
}
}
#endif
if (mch_getperm(fname) < 0)
{
#ifdef HAVE_LSTAT
stat_T sb;
if (mch_lstat((char *)fname, &sb) < 0)
#else
# ifdef AMIGA
fh = Open((UBYTE *)fname, (long)MODE_NEWFILE);
if (fh != (BPTR)NULL)
{
Close(fh);
mch_remove(fname);
break;
}
if (IoErr() != ERROR_OBJECT_IN_USE
&& IoErr() != ERROR_OBJECT_EXISTS)
# endif
#endif
break;
}
if (old_fname != NULL && fnamecmp(fname, old_fname) == 0)
break;
if (fname[n - 2] == 'w' && fname[n - 1] == 'p')
{
if (!(buf->b_p_sn || buf->b_shortname))
{
fname[n - 1] = 'x';
r = mch_getperm(fname);
fname[n - 1] = 'p';
if (r >= 0)
{
buf->b_shortname = TRUE;
vim_free(fname);
fname = makeswapname(buf_fname, buf->b_ffname,
buf, dir_name);
continue;
}
}
if (!recoverymode && buf_fname != NULL
&& !buf->b_help && !(buf->b_flags & BF_DUMMY))
{
int fd;
struct block0 b0;
int differ = FALSE;
fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
if (fd >= 0)
{
if (read_eintr(fd, &b0, sizeof(b0)) == sizeof(b0))
{
if (b0.b0_flags & B0_SAME_DIR)
{
if (fnamecmp(gettail(buf->b_ffname),
gettail(b0.b0_fname)) != 0
|| !same_directory(fname, buf->b_ffname))
{
#ifdef CHECK_INODE
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
if (fnamecmp_ino(buf->b_ffname, NameBuff,
char_to_long(b0.b0_ino)))
#endif
differ = TRUE;
}
}
else
{
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
#ifdef CHECK_INODE
if (fnamecmp_ino(buf->b_ffname, NameBuff,
char_to_long(b0.b0_ino)))
differ = TRUE;
#else
if (fnamecmp(NameBuff, buf->b_ffname) != 0)
differ = TRUE;
#endif
}
}
close(fd);
}
if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
&& vim_strchr(p_shm, SHM_ATTENTION) == NULL)
{
#if defined(HAS_SWAP_EXISTS_ACTION)
int choice = 0;
#endif
#ifdef CREATE_DUMMY_FILE
int did_use_dummy = FALSE;
if (dummyfd != NULL)
{
fclose(dummyfd);
dummyfd = NULL;
mch_remove(buf_fname);
did_use_dummy = TRUE;
}
#endif
#if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
process_still_running = FALSE;
#endif
#ifdef FEAT_AUTOCMD
if (swap_exists_action != SEA_NONE
&& has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
choice = do_swapexists(buf, fname);
if (choice == 0)
#endif
{
#ifdef FEAT_GUI
if (gui.starting && !gui.in_use)
gui_start();
#endif
attention_message(buf, fname);
got_int = FALSE;
}
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if (swap_exists_action != SEA_NONE && choice == 0)
{
char_u *name;
name = alloc((unsigned)(STRLEN(fname)
+ STRLEN(_("Swap file \""))
+ STRLEN(_("\" already exists!")) + 5));
if (name != NULL)
{
STRCPY(name, _("Swap file \""));
home_replace(NULL, fname, name + STRLEN(name),
1000, TRUE);
STRCAT(name, _("\" already exists!"));
}
choice = do_dialog(VIM_WARNING,
(char_u *)_("VIM - ATTENTION"),
name == NULL
? (char_u *)_("Swap file already exists!")
: name,
# if defined(UNIX) || defined(VMS)
process_still_running
? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Quit\n&Abort") :
# endif
(char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover\n&Delete it\n&Quit\n&Abort"), 1, NULL, FALSE);
# if defined(UNIX) || defined(VMS)
if (process_still_running && choice >= 4)
choice++;
# endif
vim_free(name);
msg_scrolled = 0;
redraw_all_later(NOT_VALID);
}
#endif
#if defined(HAS_SWAP_EXISTS_ACTION)
if (choice > 0)
{
switch (choice)
{
case 1:
buf->b_p_ro = TRUE;
break;
case 2:
break;
case 3:
swap_exists_action = SEA_RECOVER;
break;
case 4:
mch_remove(fname);
break;
case 5:
swap_exists_action = SEA_QUIT;
break;
case 6:
swap_exists_action = SEA_QUIT;
got_int = TRUE;
break;
}
if (mch_getperm(fname) < 0)
break;
}
else
#endif
{
MSG_PUTS("\n");
if (msg_silent == 0)
need_wait_return = TRUE;
}
#ifdef CREATE_DUMMY_FILE
if (did_use_dummy)
dummyfd = mch_fopen((char *)buf_fname, "w");
#endif
}
}
}
if (fname[n - 1] == 'a')
{
if (fname[n - 2] == 'a')
{
EMSG(_("E326: Too many swap files found"));
vim_free(fname);
fname = NULL;
break;
}
--fname[n - 2];
fname[n - 1] = 'z' + 1;
}
--fname[n - 1];
}
vim_free(dir_name);
#ifdef CREATE_DUMMY_FILE
if (dummyfd != NULL)
{
fclose(dummyfd);
mch_remove(buf_fname);
}
#endif
#ifdef WIN3264
if (buf_fname != buf->b_fname)
vim_free(buf_fname);
#endif
return fname;
}
static int
b0_magic_wrong(ZERO_BL *b0p)
{
return (b0p->b0_magic_long != (long)B0_MAGIC_LONG
|| b0p->b0_magic_int != (int)B0_MAGIC_INT
|| b0p->b0_magic_short != (short)B0_MAGIC_SHORT
|| b0p->b0_magic_char != B0_MAGIC_CHAR);
}
#ifdef CHECK_INODE
static int
fnamecmp_ino(
char_u *fname_c,
char_u *fname_s,
long ino_block0)
{
stat_T st;
ino_t ino_c = 0;
ino_t ino_s;
char_u buf_c[MAXPATHL];
char_u buf_s[MAXPATHL];
int retval_c;
int retval_s;
if (mch_stat((char *)fname_c, &st) == 0)
ino_c = (ino_t)st.st_ino;
if (mch_stat((char *)fname_s, &st) == 0)
ino_s = (ino_t)st.st_ino;
else
ino_s = (ino_t)ino_block0;
if (ino_c && ino_s)
return (ino_c != ino_s);
retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
if (retval_c == OK && retval_s == OK)
return (STRCMP(buf_c, buf_s) != 0);
if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
return FALSE;
return TRUE;
}
#endif
static void
long_to_char(long n, char_u *s)
{
s[0] = (char_u)(n & 0xff);
n = (unsigned)n >> 8;
s[1] = (char_u)(n & 0xff);
n = (unsigned)n >> 8;
s[2] = (char_u)(n & 0xff);
n = (unsigned)n >> 8;
s[3] = (char_u)(n & 0xff);
}
static long
char_to_long(char_u *s)
{
long retval;
retval = s[3];
retval <<= 8;
retval |= s[2];
retval <<= 8;
retval |= s[1];
retval <<= 8;
retval |= s[0];
return retval;
}
void
ml_setflags(buf_T *buf)
{
bhdr_T *hp;
ZERO_BL *b0p;
if (!buf->b_ml.ml_mfp)
return;
for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
{
if (hp->bh_bnum == 0)
{
b0p = (ZERO_BL *)(hp->bh_data);
b0p->b0_dirty = buf->b_changed ? B0_DIRTY : 0;
b0p->b0_flags = (b0p->b0_flags & ~B0_FF_MASK)
| (get_fileformat(buf) + 1);
#ifdef FEAT_MBYTE
add_b0_fenc(b0p, buf);
#endif
hp->bh_flags |= BH_DIRTY;
mf_sync(buf->b_ml.ml_mfp, MFS_ZERO);
break;
}
}
}
#if defined(FEAT_CRYPT) || defined(PROTO)
char_u *
ml_encrypt_data(
memfile_T *mfp,
char_u *data,
off_T offset,
unsigned size)
{
DATA_BL *dp = (DATA_BL *)data;
char_u *head_end;
char_u *text_start;
char_u *new_data;
int text_len;
cryptstate_T *state;
if (dp->db_id != DATA_ID)
return data;
state = ml_crypt_prepare(mfp, offset, FALSE);
if (state == NULL)
return data;
new_data = (char_u *)alloc(size);
if (new_data == NULL)
return NULL;
head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
text_start = (char_u *)dp + dp->db_txt_start;
text_len = size - dp->db_txt_start;
mch_memmove(new_data, dp, head_end - (char_u *)dp);
crypt_encode(state, text_start, text_len, new_data + dp->db_txt_start);
crypt_free_state(state);
if (head_end < text_start)
vim_memset(new_data + (head_end - data), 0, text_start - head_end);
return new_data;
}
void
ml_decrypt_data(
memfile_T *mfp,
char_u *data,
off_T offset,
unsigned size)
{
DATA_BL *dp = (DATA_BL *)data;
char_u *head_end;
char_u *text_start;
int text_len;
cryptstate_T *state;
if (dp->db_id == DATA_ID)
{
head_end = (char_u *)(&dp->db_index[dp->db_line_count]);
text_start = (char_u *)dp + dp->db_txt_start;
text_len = dp->db_txt_end - dp->db_txt_start;
if (head_end > text_start || dp->db_txt_start > size
|| dp->db_txt_end > size)
return;
state = ml_crypt_prepare(mfp, offset, TRUE);
if (state != NULL)
{
crypt_decode_inplace(state, text_start, text_len);
crypt_free_state(state);
}
}
}
static cryptstate_T *
ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading)
{
buf_T *buf = mfp->mf_buffer;
char_u salt[50];
int method_nr;
char_u *key;
char_u *seed;
if (reading && mfp->mf_old_key != NULL)
{
method_nr = mfp->mf_old_cm;
key = mfp->mf_old_key;
seed = mfp->mf_old_seed;
}
else
{
method_nr = crypt_get_method_nr(buf);
key = buf->b_p_key;
seed = mfp->mf_seed;
}
if (*key == NUL)
return NULL;
if (method_nr == CRYPT_M_ZIP)
{
vim_snprintf((char *)salt, sizeof(salt), "%s%ld", key, (long)offset);
return crypt_create(method_nr, salt, NULL, 0, NULL, 0);
}
vim_snprintf((char *)salt, sizeof(salt), "%ld", (long)offset);
return crypt_create(method_nr, key, salt, (int)STRLEN(salt),
seed, MF_SEED_LEN);
}
#endif
#if defined(FEAT_BYTEOFF) || defined(PROTO)
#define MLCS_MAXL 800
#define MLCS_MINL 400
static void
ml_updatechunk(
buf_T *buf,
linenr_T line,
long len,
int updtype)
{
static buf_T *ml_upd_lastbuf = NULL;
static linenr_T ml_upd_lastline;
static linenr_T ml_upd_lastcurline;
static int ml_upd_lastcurix;
linenr_T curline = ml_upd_lastcurline;
int curix = ml_upd_lastcurix;
long size;
chunksize_T *curchnk;
int rest;
bhdr_T *hp;
DATA_BL *dp;
if (buf->b_ml.ml_usedchunks == -1 || len == 0)
return;
if (buf->b_ml.ml_chunksize == NULL)
{
buf->b_ml.ml_chunksize = (chunksize_T *)
alloc((unsigned)sizeof(chunksize_T) * 100);
if (buf->b_ml.ml_chunksize == NULL)
{
buf->b_ml.ml_usedchunks = -1;
return;
}
buf->b_ml.ml_numchunks = 100;
buf->b_ml.ml_usedchunks = 1;
buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
buf->b_ml.ml_chunksize[0].mlcs_totalsize = 1;
}
if (updtype == ML_CHNK_UPDLINE && buf->b_ml.ml_line_count == 1)
{
buf->b_ml.ml_usedchunks = 1;
buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
buf->b_ml.ml_chunksize[0].mlcs_totalsize =
(long)STRLEN(buf->b_ml.ml_line_ptr) + 1;
return;
}
if (buf != ml_upd_lastbuf || line != ml_upd_lastline + 1
|| updtype != ML_CHNK_ADDLINE)
{
for (curline = 1, curix = 0;
curix < buf->b_ml.ml_usedchunks - 1
&& line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines;
curix++)
{
curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
}
}
else if (line >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines
&& curix < buf->b_ml.ml_usedchunks - 1)
{
curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
curix++;
}
curchnk = buf->b_ml.ml_chunksize + curix;
if (updtype == ML_CHNK_DELLINE)
len = -len;
curchnk->mlcs_totalsize += len;
if (updtype == ML_CHNK_ADDLINE)
{
curchnk->mlcs_numlines++;
if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks)
{
chunksize_T *t_chunksize = buf->b_ml.ml_chunksize;
buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
buf->b_ml.ml_chunksize = (chunksize_T *)
vim_realloc(buf->b_ml.ml_chunksize,
sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
if (buf->b_ml.ml_chunksize == NULL)
{
vim_free(t_chunksize);
buf->b_ml.ml_usedchunks = -1;
return;
}
}
if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL)
{
int count;
int idx;
int text_end;
int linecnt;
mch_memmove(buf->b_ml.ml_chunksize + curix + 1,
buf->b_ml.ml_chunksize + curix,
(buf->b_ml.ml_usedchunks - curix) *
sizeof(chunksize_T));
size = 0;
linecnt = 0;
while (curline < buf->b_ml.ml_line_count
&& linecnt < MLCS_MINL)
{
if ((hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
{
buf->b_ml.ml_usedchunks = -1;
return;
}
dp = (DATA_BL *)(hp->bh_data);
count = (long)(buf->b_ml.ml_locked_high) -
(long)(buf->b_ml.ml_locked_low) + 1;
idx = curline - buf->b_ml.ml_locked_low;
curline = buf->b_ml.ml_locked_high + 1;
if (idx == 0)
text_end = dp->db_txt_end;
else
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
rest = count - idx;
if (linecnt + rest > MLCS_MINL)
{
idx += MLCS_MINL - linecnt - 1;
linecnt = MLCS_MINL;
}
else
{
idx = count - 1;
linecnt += rest;
}
size += text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
}
buf->b_ml.ml_chunksize[curix].mlcs_numlines = linecnt;
buf->b_ml.ml_chunksize[curix + 1].mlcs_numlines -= linecnt;
buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
buf->b_ml.ml_usedchunks++;
ml_upd_lastbuf = NULL;
return;
}
else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
&& curix == buf->b_ml.ml_usedchunks - 1
&& buf->b_ml.ml_line_count - line <= 1)
{
curchnk = buf->b_ml.ml_chunksize + curix + 1;
buf->b_ml.ml_usedchunks++;
if (line == buf->b_ml.ml_line_count)
{
curchnk->mlcs_numlines = 0;
curchnk->mlcs_totalsize = 0;
}
else
{
hp = ml_find_line(buf, buf->b_ml.ml_line_count, ML_FIND);
if (hp == NULL)
{
buf->b_ml.ml_usedchunks = -1;
return;
}
dp = (DATA_BL *)(hp->bh_data);
if (dp->db_line_count == 1)
rest = dp->db_txt_end - dp->db_txt_start;
else
rest =
((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
- dp->db_txt_start;
curchnk->mlcs_totalsize = rest;
curchnk->mlcs_numlines = 1;
curchnk[-1].mlcs_totalsize -= rest;
curchnk[-1].mlcs_numlines -= 1;
}
}
}
else if (updtype == ML_CHNK_DELLINE)
{
curchnk->mlcs_numlines--;
ml_upd_lastbuf = NULL;
if (curix < (buf->b_ml.ml_usedchunks - 1)
&& (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
<= MLCS_MINL)
{
curix++;
curchnk = buf->b_ml.ml_chunksize + curix;
}
else if (curix == 0 && curchnk->mlcs_numlines <= 0)
{
buf->b_ml.ml_usedchunks--;
mch_memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
return;
}
else if (curix == 0 || (curchnk->mlcs_numlines > 10
&& (curchnk->mlcs_numlines + curchnk[-1].mlcs_numlines)
> MLCS_MINL))
{
return;
}
curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
buf->b_ml.ml_usedchunks--;
if (curix < buf->b_ml.ml_usedchunks)
{
mch_memmove(buf->b_ml.ml_chunksize + curix,
buf->b_ml.ml_chunksize + curix + 1,
(buf->b_ml.ml_usedchunks - curix) *
sizeof(chunksize_T));
}
return;
}
ml_upd_lastbuf = buf;
ml_upd_lastline = line;
ml_upd_lastcurline = curline;
ml_upd_lastcurix = curix;
}
long
ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp)
{
linenr_T curline;
int curix;
long size;
bhdr_T *hp;
DATA_BL *dp;
int count;
int idx;
int start_idx;
int text_end;
long offset;
int len;
int ffdos = (get_fileformat(buf) == EOL_DOS);
int extra = 0;
ml_flush_line(curbuf);
if (buf->b_ml.ml_usedchunks == -1
|| buf->b_ml.ml_chunksize == NULL
|| lnum < 0)
return -1;
if (offp == NULL)
offset = 0;
else
offset = *offp;
if (lnum == 0 && offset <= 0)
return 1;
curline = 1;
curix = size = 0;
while (curix < buf->b_ml.ml_usedchunks - 1
&& ((lnum != 0
&& lnum >= curline + buf->b_ml.ml_chunksize[curix].mlcs_numlines)
|| (offset != 0
&& offset > size + buf->b_ml.ml_chunksize[curix].mlcs_totalsize
+ ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines)))
{
curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
if (offset && ffdos)
size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
curix++;
}
while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset))
{
if (curline > buf->b_ml.ml_line_count
|| (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
return -1;
dp = (DATA_BL *)(hp->bh_data);
count = (long)(buf->b_ml.ml_locked_high) -
(long)(buf->b_ml.ml_locked_low) + 1;
start_idx = idx = curline - buf->b_ml.ml_locked_low;
if (idx == 0)
text_end = dp->db_txt_end;
else
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
if (lnum != 0)
{
if (curline + (count - idx) >= lnum)
idx += lnum - curline - 1;
else
idx = count - 1;
}
else
{
extra = 0;
while (offset >= size
+ text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
+ ffdos)
{
if (ffdos)
size++;
if (idx == count - 1)
{
extra = 1;
break;
}
idx++;
}
}
len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
size += len;
if (offset != 0 && size >= offset)
{
if (size + ffdos == offset)
*offp = 0;
else if (idx == start_idx)
*offp = offset - size + len;
else
*offp = offset - size + len
- (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
curline += idx - start_idx + extra;
if (curline > buf->b_ml.ml_line_count)
return -1;
return curline;
}
curline = buf->b_ml.ml_locked_high + 1;
}
if (lnum != 0)
{
if (ffdos)
size += lnum - 1;
if ((!buf->b_p_fixeol || buf->b_p_bin) && !buf->b_p_eol
&& buf->b_ml.ml_line_count == lnum)
size -= ffdos + 1;
}
return size;
}
void
goto_byte(long cnt)
{
long boff = cnt;
linenr_T lnum;
ml_flush_line(curbuf);
setpcmark();
if (boff)
--boff;
lnum = ml_find_line_or_offset(curbuf, (linenr_T)0, &boff);
if (lnum < 1)
{
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
curwin->w_curswant = MAXCOL;
coladvance((colnr_T)MAXCOL);
}
else
{
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = (colnr_T)boff;
# ifdef FEAT_VIRTUALEDIT
curwin->w_cursor.coladd = 0;
# endif
curwin->w_set_curswant = TRUE;
}
check_cursor();
# ifdef FEAT_MBYTE
if (has_mbyte)
mb_adjust_cursor();
# endif
}
#endif