📄 misc2.c
字号:
/* 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 + -