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

📄 memline.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
 * - there is not enough room in the current block
 * - appending to the last line in the block
 * - not appending to the last line in the file
 * insert in front of the next block.
 */
    if ((int)dp->db_free < space_needed && db_idx == line_count - 1
					    && lnum < buf->b_ml.ml_line_count)
    {
	/*
	 * Now that the line is not going to be inserted in the block that we
	 * expected, the line count has to be adjusted in the pointer blocks
	 * by using ml_locked_lineadd.
	 */
	--(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;		    /* careful, it is negative! */
		    /* get line count before the insertion */
	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)	/* enough room in data block */
    {
/*
 * Insert new line in existing data block, or in data block allocated above.
 */
	dp->db_txt_start -= len;
	dp->db_free -= space_needed;
	++(dp->db_line_count);

	/*
	 * move the text of the lines that follow to the front
	 * adjust the indexes of the lines that follow
	 */
	if (line_count > db_idx + 1)	    /* if there are following lines */
	{
	    /*
	     * Offset is the start of the previous line.
	     * This will become the character just after the new line.
	     */
	    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				    /* add line at the end */
	    dp->db_index[db_idx + 1] = dp->db_txt_start;

	/*
	 * copy the text into the block
	 */
	mch_memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
	if (mark)
	    dp->db_index[db_idx + 1] |= DB_MARKED;

	/*
	 * Mark the block dirty.
	 */
	buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
	if (!newfile)
	    buf->b_ml.ml_flags |= ML_LOCKED_POS;
    }
    else	    /* not enough space in data block */
    {
/*
 * If there is not enough room we have to create a new data block and copy some
 * lines into it.
 * Then we have to insert an entry in the pointer block.
 * If this pointer block also is full, we go up another block, and so on, up
 * to the root if necessary.
 * The line counts in the pointer blocks have already been adjusted by
 * ml_find_line().
 */
	long	    line_count_left, line_count_right;
	int	    page_count_left, page_count_right;
	BHDR	    *hp_left;
	BHDR	    *hp_right;
	BHDR	    *hp_new;
	int	    lines_moved;
	int	    data_moved = 0;	    /* init to shut up gcc */
	int	    total_moved = 0;	    /* init to shut up gcc */
	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;

	/*
	 * We are going to allocate a new data block. Depending on the
	 * situation it will be put to the left or right of the existing
	 * block.  If possible we put the new line in the left block and move
	 * the lines after it to the right block. Otherwise the new line is
	 * also put in the right block. This method is more efficient when
	 * inserting a lot of lines at one place.
	 */
	if (db_idx < 0)		/* left block is new, right block is existing */
	{
	    lines_moved = 0;
	    in_left = TRUE;
	    /* space_needed does not change */
	}
	else			/* left block is existing, right block is new */
	{
	    lines_moved = line_count - db_idx - 1;
	    if (lines_moved == 0)
		in_left = FALSE;	/* put new line in right block */
					/* space_needed does not change */
	    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;	/* put new line in left block */
		    space_needed = total_moved;
		}
		else
		{
		    in_left = FALSE;	    /* put new line in right block */
		    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)
	{
			/* correct line counts in pointer blocks */
	    --(buf->b_ml.ml_locked_lineadd);
	    --(buf->b_ml.ml_locked_high);
	    return FAIL;
	}
	if (db_idx < 0)		/* left block is new */
	{
	    hp_left = hp_new;
	    hp_right = hp;
	    line_count_left = 0;
	    line_count_right = line_count;
	}
	else			/* right block is new */
	{
	    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;

	/*
	 * May move the new line into the right/new block.
	 */
	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;
	}
	/*
	 * may move lines from the left/old block to the right/new one.
	 */
	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;

	    /*
	     * update indexes in the new block
	     */
	    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;
	}

	/*
	 * May move the new line into the left (old or new) block.
	 */
	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)		/* left block is new */
	{
	    lnum_left = lnum + 1;
	    lnum_right = 0;
	}
	else			/* right block is new */
	{
	    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;

	/*
	 * release the two data blocks
	 * The new one (hp_new) already has a correct blocknumber.
	 * The old one (hp, in ml_locked) gets a positive blocknumber if
	 * we changed it and we are not editing a new file.
	 */
	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);

	/*
	 * flush the old data block
	 * set ml_locked_lineadd to 0, because the updating of the
	 * pointer blocks is done below
	 */
	lineadd = buf->b_ml.ml_locked_lineadd;
	buf->b_ml.ml_locked_lineadd = 0;
	ml_find_line(buf, (linenr_t)0, ML_FLUSH);   /* flush data block */

	/*
	 * update pointer blocks for the new data block
	 */
	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);   /* must be pointer block */
	    if (pp->pb_id != PTR_ID)
	    {
		EMSG("pointer block id wrong 3");
		mf_put(mfp, hp, FALSE, FALSE);
		return FAIL;
	    }
	    /*
	     * TODO: If the pointer block is full and we are adding at the end
	     * try to insert in front of the next block
	     */
	    if (pp->pb_count < pp->pb_count_max)    /* block not full, add one entry */
	    {
		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;	    /* truncate stack */

		if (lineadd)
		{
		    --(buf->b_ml.ml_stack_top);
			/* fix line count for rest of blocks in the stack */
		    ml_lineadd(buf, lineadd);
							/* fix stack itself */
		    buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
								      lineadd;
		    ++(buf->b_ml.ml_stack_top);
		}

		return OK;
	    }
	    else			/* pointer block full */
	    {
		/*
		 * split the pointer block
		 * allocate a new pointer block
		 * move some of the pointer into the new block
		 * prepare for updating the parent block
		 */
		for (;;)	/* do this twice when splitting block 1 */
		{
		    hp_new = ml_new_ptr(mfp);
		    if (hp_new == NULL)	    /* TODO: try to fix tree */
			return FAIL;
		    pp_new = (PTR_BL *)(hp_new->bh_data);

		    if (hp->bh_bnum != 1)
			break;

		    /*
		     * if block 1 becomes full the tree is given an extra level
		     * The pointers from block 1 are moved into the new block.
		     * block 1 is updated to point to the new block
		     * then continue to split the new block
		     */
		    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);   /* release block 1 */
		    hp = hp_new;		    /* new block is to be split */
		    pp = pp_new;
		    CHECK(stack_idx != 0, "stack_idx should be 0");
		    ip->ip_index = 0;
		    ++stack_idx;	/* do block 1 again later */
		}
		/*
		 * move the pointers after the current one to the new block
		 * If there are none, the new entry will be in the new block.
		 */
		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;

		/*
		 * recompute line counts
		 */
		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);
	    }
	}
	EMSG("Updated too many blocks?");
	buf->b_ml.ml_stack_top = 0;	/* invalidate stack */
    }
    return OK;
}

/*
 * replace line lnum, with buffering, in current buffer
 *
 * If copy is TRUE, make a copy of the line, otherwise the line has been
 * copied to allocated memory already.
 * NOTE: For syntax highlighting, need to call syn_changed() when
 * update_screenline() is not used.
 *
 * return FAIL for failure, OK otherwise
 */
    int
ml_replace(lnum, line, copy)
    linenr_t	lnum;
    char_u	*line;
    int		copy;
{
    if (line == NULL)		/* just checking... */
	return FAIL;

    if (curbuf->b_ml.ml_line_lnum != lnum)	    /* other line buffered */
	ml_flush_line(curbuf);			    /* flush it */
    else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
	vim_free(curbuf->b_ml.ml_line_ptr);	    /* free it */
    if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */
	return FAIL;
    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;
}

/*
 * delete line 'lnum'
 *
 * return FAIL for failure, OK otherwise
 */
    int
ml_delete(lnum, message)
    linenr_t	lnum;
    int		message;
{
#ifdef SYNTAX_HL
    if (curbuf->b_syn_change_lnum > lnum)
	curbuf->b_syn_change_lnum = lnum;
#endif

    ml_flush_line(curbuf);
    return ml_delete_int(curbuf, lnum, message);
}

    static int
ml_delete_int(buf, lnum, message)
    BUF		*buf;
    linenr_t	l

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -