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

📄 misc2.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 4 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * misc2.c: Various functions.
 */

#include "vim.h"

#ifdef HAVE_FCNTL_H
# include <fcntl.h>	    /* for chdir() */
#endif

/*
 * coladvance(col)
 *
 * Try to advance the Cursor to the specified column.
 *
 * return OK if desired column is reached, FAIL if not
 */
    int
coladvance(wcol)
    colnr_t	    wcol;
{
    int		idx;
    char_u	*ptr;
    colnr_t	col;

    ptr = ml_get_curline();

    /* try to advance to the specified column */
    idx = -1;
    col = 0;
    while (col <= wcol && *ptr)
    {
	++idx;
	/* Count a tab for what it's worth (if list mode not on) */
	col += lbr_chartabsize(ptr, col);
	++ptr;
    }
    /*
     * In Insert mode it is allowed to be one char beyond the end of the line.
     * Also in Visual mode, when 'selection' is not "old".
     */
    if (((State & INSERT) || (VIsual_active && *p_sel != 'o')) && col <= wcol)
	++idx;
    if (idx < 0)
	curwin->w_cursor.col = 0;
    else
	curwin->w_cursor.col = idx;
#ifdef MULTI_BYTE
    /* prevent cursor from moving on the trail byte */
    if (is_dbcs)
	AdjustCursorForMultiByteCharacter();
#endif

    if (col <= wcol)
	return FAIL;	    /* Couldn't reach column */
    else
	return OK;	    /* Reached column */
}

/*
 * inc(p)
 *
 * Increment the line pointer 'p' crossing line boundaries as necessary.
 * Return 1 when crossing a line, -1 when at end of file, 0 otherwise.
 */
    int
inc_cursor()
{
    return inc(&curwin->w_cursor);
}

    int
inc(lp)
    FPOS  *lp;
{
    char_u  *p = ml_get_pos(lp);

    if (*p != NUL)	/* still within line, move to next char (may be NUL) */
    {
#ifdef MULTI_BYTE
	if (is_dbcs && IsLeadByte(p[0]) && p[1] != NUL)
	{
	    lp->col += 2;
	    return ((p[2] != NUL) ? 0 : 1);
	}
#endif
	lp->col++;
	return ((p[1] != NUL) ? 0 : 1);
    }
    if (lp->lnum != curbuf->b_ml.ml_line_count)     /* there is a next line */
    {
	lp->col = 0;
	lp->lnum++;
	return 1;
    }
    return -1;
}

/*
 * incl(lp): same as inc(), but skip the NUL at the end of non-empty lines
 */
    int
incl(lp)
    FPOS    *lp;
{
    int	    r;

    if ((r = inc(lp)) == 1 && lp->col)
	r = inc(lp);
    return r;
}

/*
 * dec(p)
 *
 * Decrement the line pointer 'p' crossing line boundaries as necessary.
 * Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
 */
    int
dec_cursor()
{
#ifdef MULTI_BYTE
    return (is_dbcs ? han_dec(&curwin->w_cursor) : dec(&curwin->w_cursor));
#else
    return dec(&curwin->w_cursor);
#endif
}

    int
dec(lp)
    FPOS  *lp;
{
    if (lp->col > 0)
    {		/* still within line */
	lp->col--;
	return 0;
    }
    if (lp->lnum > 1)
    {		/* there is a prior line */
	lp->lnum--;
	lp->col = STRLEN(ml_get(lp->lnum));
	return 1;
    }
    return -1;			/* at start of file */
}

/*
 * decl(lp): same as dec(), but skip the NUL at the end of non-empty lines
 */
    int
decl(lp)
    FPOS    *lp;
{
    int	    r;

    if ((r = dec(lp)) == 1 && lp->col)
	r = dec(lp);
    return r;
}

/*
 * Make sure curwin->w_cursor.lnum is valid.
 */
    void
check_cursor_lnum()
{
    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
	curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
    if (curwin->w_cursor.lnum <= 0)
	curwin->w_cursor.lnum = 1;
}

/*
 * Make sure curwin->w_cursor.col is valid.
 */
    void
check_cursor_col()
{
    colnr_t len;

    len = STRLEN(ml_get_curline());
    if (len == 0)
	curwin->w_cursor.col = 0;
    else if (curwin->w_cursor.col >= len)
    {
	if (State & INSERT || restart_edit)
	    curwin->w_cursor.col = len;
	else
	    curwin->w_cursor.col = len - 1;
    }
}

/*
 * make sure curwin->w_cursor in on a valid character
 */
    void
adjust_cursor()
{
    check_cursor_lnum();
    check_cursor_col();
}

/*
 * Make sure curwin->w_cursor is not on the NUL at the end of the line.
 * Allow it when in Visual mode and 'selection' is not "old".
 */
    void
adjust_cursor_col()
{
    if ((!VIsual_active || *p_sel == 'o')
	    && curwin->w_cursor.col && gchar_cursor() == NUL)
	--curwin->w_cursor.col;
}

/*
 * When curwin->w_leftcol has changed, adjust the cursor position.
 * Return TRUE if the cursor was moved.
 */
    int
leftcol_changed()
{
    long	lastcol;
    colnr_t	s, e;
    int		retval = FALSE;

    changed_cline_bef_curs();
    lastcol = curwin->w_leftcol + Columns - (curwin->w_p_nu ? 8 : 0) - 1;
    validate_virtcol();

    /*
     * If the cursor is right or left of the screen, move it to last or first
     * character.
     */
    if (curwin->w_virtcol > (colnr_t)lastcol)
    {
	retval = TRUE;
	coladvance((colnr_t)lastcol);
    }
    else if (curwin->w_virtcol < curwin->w_leftcol)
    {
	retval = TRUE;
	(void)coladvance(curwin->w_leftcol);
    }

    /*
     * If the start of the character under the cursor is not on the screen,
     * advance the cursor one more char.  If this fails (last char of the
     * line) adjust the scrolling.
     */
    getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
    if (e > (colnr_t)lastcol)
    {
	retval = TRUE;
	coladvance(s - 1);
    }
    else if (s < curwin->w_leftcol)
    {
	retval = TRUE;
	if (coladvance(e + 1) == FAIL)	/* there isn't another character */
	{
	    curwin->w_leftcol = s;	/* adjust w_leftcol instead */
	    changed_cline_bef_curs();
	}
    }

    redraw_later(NOT_VALID);
    return retval;
}

/**********************************************************************
 * Various routines dealing with allocation and deallocation of memory.
 */

#if defined(MEM_PROFILE) || defined(PROTO)

# define MEM_SIZES  8200
static long_u mem_allocs[MEM_SIZES];
static long_u mem_frees[MEM_SIZES];
static long_u mem_allocated;
static long_u mem_freed;
static long_u mem_peak;
static long_u num_alloc;
static long_u num_freed;

static void mem_pre_alloc_s __ARGS((size_t *sizep));
static void mem_pre_alloc_l __ARGS((long_u *sizep));
static void mem_post_alloc __ARGS((void **pp, size_t size));
static void mem_pre_free __ARGS((void **pp));

    static void
mem_pre_alloc_s(sizep)
    size_t *sizep;
{
    *sizep += sizeof(size_t);
}

    static void
mem_pre_alloc_l(sizep)
    long_u *sizep;
{
    *sizep += sizeof(size_t);
}

    static void
mem_post_alloc(pp, size)
    void **pp;
    size_t size;
{
    if (*pp == NULL)
	return;
    size -= sizeof(size_t);
    *(long_u *)*pp = size;
    if (size <= MEM_SIZES-1)
	mem_allocs[size-1]++;
    else
	mem_allocs[MEM_SIZES-1]++;
    mem_allocated += size;
    if (mem_allocated - mem_freed > mem_peak)
	mem_peak = mem_allocated - mem_freed;
    num_alloc++;
    *pp = (void *)((char *)*pp + sizeof(size_t));
}

    static void
mem_pre_free(pp)
    void **pp;
{
    long_u size;

    *pp = (void *)((char *)*pp - sizeof(size_t));
    size = *(size_t *)*pp;
    if (size <= MEM_SIZES-1)
	mem_frees[size-1]++;
    else
	mem_frees[MEM_SIZES-1]++;
    mem_freed += size;
    num_freed++;
}

/*
 * called on exit via atexit()
 */
    void
vim_mem_profile_dump()
{
    int i, j;

    printf("\r\n");
    j = 0;
    for (i = 0; i < MEM_SIZES - 1; i++)
    {
	if (mem_allocs[i] || mem_frees[i])
	{
	    if (mem_frees[i] > mem_allocs[i])
		printf("\r\nERROR: ");
	    printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]);
	    j++;
	    if (j > 3)
	    {
		j = 0;
		printf("\r\n");
	    }
	}
    }

    i = MEM_SIZES - 1;
    if (mem_allocs[i])
    {
	printf("\r\n");
	if (mem_frees[i] > mem_allocs[i])
	    printf("ERROR: ");
	printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]);
    }

    printf("\r\n\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\r\n",
	    mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak);
    printf("[calls] total re/malloc()'s %lu, total free()'s %lu\r\n\n",
	    num_alloc, num_freed);
}

#endif /* MEM_PROFILE */

/*
 * Some memory is reserved for error messages and for being able to
 * call mf_release_all(), which needs some memory for mf_trans_add().
 */
#define KEEP_ROOM 8192L

static void vim_strup __ARGS((char_u *p));

/*
 * Note: if unsinged is 16 bits we can only allocate up to 64K with alloc().
 * Use lalloc for larger blocks.
 */
    char_u *
alloc(size)
    unsigned	    size;
{
    return (lalloc((long_u)size, TRUE));
}

/*
 * Allocate memory and set all bytes to zero.
 */
    char_u *
alloc_clear(size)
    unsigned	    size;
{
    char_u *p;

    p = (lalloc((long_u)size, TRUE));
    if (p != NULL)
	(void)vim_memset(p, 0, (size_t)size);
    return p;
}

/*
 * alloc() with check for maximum line length
 */
    char_u *
alloc_check(size)
    unsigned	    size;
{
#if !defined(UNIX) && !defined(__EMX__)
    if (sizeof(int) == 2 && size > 0x7fff)
    {
	EMSG("Line is becoming too long");
	return NULL;
    }
#endif
    return (lalloc((long_u)size, TRUE));
}

/*
 * Allocate memory like lalloc() and set all bytes to zero.
 */
    char_u *
lalloc_clear(size, message)
    long_u	size;
    int		message;
{
    char_u *p;

    p = (lalloc(size, message));
    if (p != NULL)
	(void)vim_memset(p, 0, (size_t)size);
    return p;
}

    char_u *
lalloc(size, message)
    long_u	size;
    int		message;
{
    char_u	*p;		    /* pointer to new storage space */
    static int	releasing = FALSE;  /* don't do mf_release_all() recursive */
    int		try_again;

    if (size <= 0)
    {
	EMSGN("Internal error: lalloc(%ld, )", size);
	return NULL;
    }

#ifdef MEM_PROFILE
    mem_pre_alloc_l(&size);
#endif

#if defined(MSDOS) && !defined(DJGPP)
    if (size >= 0xfff0)		/* in MSDOS we can't deal with >64K blocks */
	p = NULL;
    else
#endif

    /*
     * If out of memory, try to release some memfile blocks.
     * If some blocks are released call malloc again.
     */
    for (;;)
    {
	if ((p = (char_u *)malloc((size_t)size)) != NULL)
	{
	    if (mch_avail_mem(TRUE) < KEEP_ROOM && !releasing)
	    {				    /* System is low... no go! */
		    vim_free((char *)p);
		    p = NULL;
	    }
	}
    /*
     * Remember that mf_release_all() is being called to avoid an endless loop,
     * because mf_release_all() may call alloc() recursively.
     */
	if (p != NULL || releasing)
	    break;
	releasing = TRUE;
	try_again = mf_release_all();
	releasing = FALSE;
	if (!try_again)
	    break;
    }

    if (message && p == NULL)
	do_outofmem_msg();

#ifdef MEM_PROFILE
    mem_post_alloc((void **)&p, (size_t)size);
#endif

    return (p);
}

#if defined(MEM_PROFILE) || defined(PROTO)
/*
 * realloc(), with memory profiling.
 */
    void *
vim_realloc(ptr, size)
    void *ptr;

⌨️ 快捷键说明

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