📄 memline.c
字号:
char_u *dirp;
mfp = buf->b_ml.ml_mfp;
if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf) /* nothing to do */
return;
/*
* Try all directories in 'directory' option.
*/
dirp = p_dir;
for (;;)
{
if (*dirp == NUL)
break;
fname = findswapname(buf, &dirp, NULL); /* allocates fname */
if (fname == NULL)
continue;
if (mf_open_file(mfp, fname) == OK) /* consumes fname! */
break;
}
if (mfp->mf_fname == NULL) /* Failed! */
{
need_wait_return = TRUE; /* call wait_return later */
++no_wait_return;
(void)EMSG2("Unable to open swap file for \"%s\", recovery impossible",
buf->b_fname == NULL ? (char_u *)"No File" : buf->b_fname);
--no_wait_return;
}
else
{
#if defined(MSDOS) || defined(WIN32) || defined(RISCOS)
/*
* set full pathname for swap file now, because a ":!cd dir" may
* change directory without us knowing it.
*/
mf_fullname(mfp);
#endif
/* Flush block zero, so others can read it */
(void)mf_sync(mfp, MFS_ZERO);
}
/* don't try to open a swap file again */
buf->b_may_swap = FALSE;
}
/*
* If still need to create a swap file, and starting to edit a not-readonly
* file, or reading into an existing buffer, create a swap file now.
*/
void
check_need_swap(newfile)
int newfile; /* reading file into new buffer */
{
if (curbuf->b_may_swap && (!curbuf->b_p_ro || !newfile))
ml_open_file(curbuf);
}
/*
* Close memline for buffer 'buf'.
* If 'del_file' is TRUE, delete the swap file
*/
void
ml_close(buf, del_file)
BUF *buf;
int del_file;
{
if (buf->b_ml.ml_mfp == NULL) /* not open */
return;
mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp 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);
buf->b_ml.ml_mfp = NULL;
}
/*
* Close all existing memlines and memfiles.
* Used when exiting.
* When 'del_file' is TRUE, delete the memfiles.
*/
void
ml_close_all(del_file)
int del_file;
{
BUF *buf;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
ml_close(buf, del_file);
}
/*
* Close all memfiles for not modified buffers.
* Only use just before exiting!
*/
void
ml_close_notmod()
{
BUF *buf;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
if (!buf_changed(buf))
ml_close(buf, TRUE); /* close all not-modified buffers */
}
/*
* Update the timestamp in the .swp file.
* Used when the file has been written.
*/
void
ml_timestamp(buf)
BUF *buf;
{
MEMFILE *mfp;
BHDR *hp;
ZERO_BL *b0p;
mfp = buf->b_ml.ml_mfp;
if (mfp == NULL || (hp = mf_get(mfp, (blocknr_t)0, 1)) == NULL)
return;
b0p = (ZERO_BL *)(hp->bh_data);
if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
EMSG("ml_timestamp: Didn't get block 0??");
else
set_b0_fname(b0p, buf);
mf_put(mfp, hp, TRUE, FALSE);
}
/*
* Write file name and timestamp into block 0 of a swap file.
* Also set buf->b_mtime.
* Don't use NameBuff[]!!!
*/
static void
set_b0_fname(b0p, buf)
ZERO_BL *b0p;
BUF *buf;
{
struct stat st;
size_t flen, ulen;
char_u uname[B0_UNAME_SIZE];
if (buf->b_ffname == NULL)
b0p->b0_fname[0] = NUL;
else
{
/*
* For a file under the home directory of the current user, we try to
* replace the home directory path with "~user". This helps when
* editing the same file on different machines over a network.
* First replace home dir path with "~/" with home_replace().
* Then insert the user name to get "~user/".
*/
home_replace(NULL, buf->b_ffname, b0p->b0_fname, B0_FNAME_SIZE, TRUE);
if (b0p->b0_fname[0] == '~')
{
flen = STRLEN(b0p->b0_fname);
/* If there is no user name or it is too long, don't use "~/" */
if (mch_get_user_name(uname, B0_UNAME_SIZE) == FAIL ||
(ulen = STRLEN(uname)) + flen > B0_FNAME_SIZE - 1)
STRNCPY(b0p->b0_fname, buf->b_ffname, B0_FNAME_SIZE);
else
{
mch_memmove(b0p->b0_fname + ulen + 1, b0p->b0_fname + 1, flen);
mch_memmove(b0p->b0_fname + 1, uname, ulen);
}
}
if (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->b_mtime = st.st_mtime;
buf->b_mtime_read = st.st_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;
}
}
}
/*
* try to recover curbuf from the .swp file
*/
void
ml_recover()
{
BUF *buf = NULL;
MEMFILE *mfp = NULL;
char_u *fname;
BHDR *hp = NULL;
ZERO_BL *b0p;
PTR_BL *pp;
DATA_BL *dp;
IPTR *ip;
blocknr_t bnum;
int page_count;
struct stat 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;
called_from_main = (curbuf->b_ml.ml_mfp == NULL);
attr = hl_attr(HLF_E);
/*
* If the file name ends in ".sw?" we use it directly.
* Otherwise a search is done to find the swap file(s).
*/
fname = curbuf->b_fname;
if (fname == NULL) /* When there is no file name */
fname = (char_u *)"";
len = STRLEN(fname);
if (len >= 4 &&
#if defined(VMS) || defined(RISCOS)
STRNICMP(fname + len - 4, "_sw" , 3)
#else
STRNICMP(fname + len - 4, ".sw" , 3)
#endif
== 0)
{
directly = TRUE;
fname = vim_strsave(fname); /* make a copy for mf_open */
}
else
{
directly = FALSE;
/* count the number of matching swap files */
len = recover_names(&fname, FALSE, 0);
if (len == 0) /* no swap files found */
{
EMSG2("No swap file found for %s", fname);
goto theend;
}
if (len == 1) /* one swap file found, use it */
i = 1;
else /* several swap files found, choose */
{
/* list the names of the swap files */
(void)recover_names(&fname, TRUE, 0);
msg_putchar('\n');
MSG_PUTS("Enter number of swap file to use (0 to quit): ");
i = get_number(FALSE);
if (i < 1 || i > len)
goto theend;
}
/* get the swap file name that will be used */
(void)recover_names(&fname, FALSE, i);
}
if (fname == NULL)
goto theend; /* out of memory */
/* When called from main() still need to initialize storage structure */
if (called_from_main && ml_open() == FAIL)
getout(1);
/*
* allocate a buffer structure (only the memline in it is really used)
*/
buf = (BUF *)alloc((unsigned)sizeof(BUF));
if (buf == NULL)
{
vim_free(fname);
goto theend;
}
/*
* init fields in memline struct
*/
buf->b_ml.ml_stack_size = 0; /* no stack yet */
buf->b_ml.ml_stack = NULL; /* no stack yet */
buf->b_ml.ml_stack_top = 0; /* nothing in the stack */
buf->b_ml.ml_line_lnum = 0; /* no cached line */
buf->b_ml.ml_locked = NULL; /* no locked block */
buf->b_ml.ml_flags = 0;
/*
* open the memfile from the old swap file
*/
p = vim_strsave(fname); /* save fname for the message */
mfp = mf_open(fname, FALSE); /* consumes fname! */
if (mfp == NULL || mfp->mf_fd < 0)
{
if (p != NULL)
{
EMSG2("Cannot open %s", p);
vim_free(p);
}
goto theend;
}
vim_free(p);
buf->b_ml.ml_mfp = mfp;
/*
* try to read block 0
*/
if ((hp = mf_get(mfp, (blocknr_t)0, 1)) == NULL)
{
msg_start();
MSG_PUTS_ATTR("Unable to read block 0 from ", attr);
msg_outtrans_attr(mfp->mf_fname, attr);
MSG_PUTS_ATTR(
"\nMaybe no changes were made or Vim did not update the swap file",
attr);
msg_end();
goto theend;
}
b0p = (ZERO_BL *)(hp->bh_data);
if (STRNCMP(b0p->b0_version, "VIM 3.0", 7) == 0)
{
msg_start();
MSG_PUTS("The file ");
msg_outtrans(mfp->mf_fname);
MSG_PUTS(" cannot be used with this version of Vim.\n");
MSG_PUTS("Use Vim version 3.0.\n");
msg_end();
goto theend;
}
if (b0p->b0_id[0] != BLOCK0_ID0 || b0p->b0_id[1] != BLOCK0_ID1)
{
EMSG2("%s is not a swap file", mfp->mf_fname);
goto theend;
}
if (b0_magic_wrong(b0p))
{
msg_start();
MSG_PUTS_ATTR("The file ", attr);
msg_outtrans_attr(mfp->mf_fname, attr);
#if defined(MSDOS) || defined(WIN32)
if (STRNCMP(b0p->b0_hname, "PC ", 3) == 0)
MSG_PUTS_ATTR(" cannot be used with this version of Vim.\n", attr);
else
#endif
MSG_PUTS_ATTR(" cannot be used on this computer.\n", attr);
MSG_PUTS_ATTR("The file was created on ", attr);
/* avoid going past the end of currupted hostname */
b0p->b0_fname[0] = NUL;
MSG_PUTS_ATTR(b0p->b0_hname, attr);
MSG_PUTS_ATTR(",\nor the file has been damaged.", attr);
msg_end();
goto theend;
}
/*
* If we guessed the wrong page size, we have to recalculate the
* highest block number in the file.
*/
if (mfp->mf_page_size != (unsigned)char_to_long(b0p->b0_page_size))
{
mfp->mf_page_size = (unsigned)char_to_long(b0p->b0_page_size);
if ((size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
mfp->mf_blocknr_max = 0; /* no file or empty file */
else
mfp->mf_blocknr_max = size / mfp->mf_page_size;
mfp->mf_infile_count = mfp->mf_blocknr_max;
}
/*
* If .swp file name given directly, use name from swap file for buffer.
*/
if (directly)
{
expand_env(b0p->b0_fname, NameBuff, MAXPATHL);
if (setfname(NameBuff, NULL, TRUE) == FAIL)
goto theend;
}
home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
smsg((char_u *)"Using swap file \"%s\"", NameBuff);
if (curbuf->b_ffname == NULL)
STRCPY(NameBuff, "No File");
else
home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
smsg((char_u *)"Original file \"%s\"", NameBuff);
msg_putchar('\n');
/*
* check date of swap file and original file
*/
mtime = char_to_long(b0p->b0_mtime);
if (curbuf->b_ffname != NULL &&
stat((char *)curbuf->b_ffname, &org_stat) != -1 &&
((stat((char *)mfp->mf_fname, &swp_stat) != -1 &&
org_stat.st_mtime > swp_stat.st_mtime) ||
org_stat.st_mtime != mtime))
{
EMSG("Warning: Original file may have been changed");
}
out_flush();
mf_put(mfp, hp, FALSE, FALSE); /* release block 0 */
hp = NULL;
/*
* Now that we are sure that the file is going to be recovered, clear the
* contents of the current buffer.
*/
while (!(curbuf->b_ml.ml_flags & ML_EMPTY))
ml_delete((linenr_t)1, FALSE);
bnum = 1; /* start with block 1 */
page_count = 1; /* which is 1 page */
lnum = 0; /* append after line 0 in curbuf */
line_count = 0;
idx = 0; /* start with first index in block 1 */
error = 0;
buf->b_ml.ml_stack_top = 0;
buf->b_ml.ml_stack = NULL;
buf->b_ml.ml_stack_size = 0; /* no stack yet */
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); /* release previous block */
/*
* get block
*/
if ((hp = mf_get(mfp, (blocknr_t)bnum, page_count)) == NULL)
{
if (bnum == 1)
{
EMSG2("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 /* there is a block */
{
pp = (PTR_BL *)(hp->bh_data);
if (pp->pb_id == PTR_ID) /* it is a pointer block */
{
/* check line count when using pointer block first time */
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -