⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memline.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -