forked from aniani/vim
patch 8.2.3301: memory allocation functions don't have their own place
Problem: Memory allocation functions don't have their own place. Solution: Move memory allocation functions to alloc.c. (Yegappan Lakshmanan, closes #8717)
This commit is contained in:
parent
11328bc7df
commit
cbae580283
2
Filelist
2
Filelist
@ -23,6 +23,7 @@ SRC_ALL = \
|
|||||||
ci/setup-xvfb.sh \
|
ci/setup-xvfb.sh \
|
||||||
src/Make_all.mak \
|
src/Make_all.mak \
|
||||||
src/README.md \
|
src/README.md \
|
||||||
|
src/alloc.c \
|
||||||
src/alloc.h \
|
src/alloc.h \
|
||||||
src/arabic.c \
|
src/arabic.c \
|
||||||
src/arglist.c \
|
src/arglist.c \
|
||||||
@ -210,6 +211,7 @@ SRC_ALL = \
|
|||||||
src/testdir/popupbounce.vim \
|
src/testdir/popupbounce.vim \
|
||||||
src/proto.h \
|
src/proto.h \
|
||||||
src/protodef.h \
|
src/protodef.h \
|
||||||
|
src/proto/alloc.pro \
|
||||||
src/proto/arabic.pro \
|
src/proto/arabic.pro \
|
||||||
src/proto/arglist.pro \
|
src/proto/arglist.pro \
|
||||||
src/proto/autocmd.pro \
|
src/proto/autocmd.pro \
|
||||||
|
@ -80,6 +80,7 @@ endif
|
|||||||
|
|
||||||
# Common sources
|
# Common sources
|
||||||
SRC += \
|
SRC += \
|
||||||
|
alloc.c \
|
||||||
arabic.c \
|
arabic.c \
|
||||||
arglist.c \
|
arglist.c \
|
||||||
autocmd.c \
|
autocmd.c \
|
||||||
|
@ -723,6 +723,7 @@ LIB = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomdlg32 -lcomctl32 -lnetapi32 -l
|
|||||||
GUIOBJ = $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o
|
GUIOBJ = $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o
|
||||||
CUIOBJ = $(OUTDIR)/iscygpty.o
|
CUIOBJ = $(OUTDIR)/iscygpty.o
|
||||||
OBJ = \
|
OBJ = \
|
||||||
|
$(OUTDIR)/alloc.o \
|
||||||
$(OUTDIR)/arabic.o \
|
$(OUTDIR)/arabic.o \
|
||||||
$(OUTDIR)/arglist.o \
|
$(OUTDIR)/arglist.o \
|
||||||
$(OUTDIR)/autocmd.o \
|
$(OUTDIR)/autocmd.o \
|
||||||
|
@ -733,6 +733,7 @@ INCL = vim.h alloc.h ascii.h ex_cmds.h feature.h errors.h globals.h \
|
|||||||
spell.h structs.h term.h beval.h $(NBDEBUG_INCL)
|
spell.h structs.h term.h beval.h $(NBDEBUG_INCL)
|
||||||
|
|
||||||
OBJ = \
|
OBJ = \
|
||||||
|
$(OUTDIR)\alloc.obj \
|
||||||
$(OUTDIR)\arabic.obj \
|
$(OUTDIR)\arabic.obj \
|
||||||
$(OUTDIR)\arglist.obj \
|
$(OUTDIR)\arglist.obj \
|
||||||
$(OUTDIR)\autocmd.obj \
|
$(OUTDIR)\autocmd.obj \
|
||||||
@ -1542,6 +1543,8 @@ test_vim9:
|
|||||||
.cpp{$(OUTDIR)/}.obj::
|
.cpp{$(OUTDIR)/}.obj::
|
||||||
$(CC) $(CFLAGS_OUTDIR) $<
|
$(CC) $(CFLAGS_OUTDIR) $<
|
||||||
|
|
||||||
|
$(OUTDIR)/alloc.obj: $(OUTDIR) alloc.c $(INCL)
|
||||||
|
|
||||||
$(OUTDIR)/arabic.obj: $(OUTDIR) arabic.c $(INCL)
|
$(OUTDIR)/arabic.obj: $(OUTDIR) arabic.c $(INCL)
|
||||||
|
|
||||||
$(OUTDIR)/arglist.obj: $(OUTDIR) arglist.c $(INCL)
|
$(OUTDIR)/arglist.obj: $(OUTDIR) arglist.c $(INCL)
|
||||||
@ -1932,6 +1935,7 @@ $(PATHDEF_SRC): Make_mvc.mak
|
|||||||
|
|
||||||
# End Custom Build
|
# End Custom Build
|
||||||
proto.h: \
|
proto.h: \
|
||||||
|
proto/alloc.pro \
|
||||||
proto/arabic.pro \
|
proto/arabic.pro \
|
||||||
proto/arglist.pro \
|
proto/arglist.pro \
|
||||||
proto/autocmd.pro \
|
proto/autocmd.pro \
|
||||||
|
@ -306,6 +306,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) $(XPM_LIB)\
|
|||||||
$(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) $(LUA_LIB)
|
$(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) $(LUA_LIB)
|
||||||
|
|
||||||
SRC = \
|
SRC = \
|
||||||
|
alloc.c \
|
||||||
arabic.c \
|
arabic.c \
|
||||||
arglist.c \
|
arglist.c \
|
||||||
autocmd.c \
|
autocmd.c \
|
||||||
@ -425,6 +426,7 @@ SRC = \
|
|||||||
$(XDIFF_SRC)
|
$(XDIFF_SRC)
|
||||||
|
|
||||||
OBJ = \
|
OBJ = \
|
||||||
|
alloc.obj \
|
||||||
arabic.obj \
|
arabic.obj \
|
||||||
arglist.obj \
|
arglist.obj \
|
||||||
autocmd.obj \
|
autocmd.obj \
|
||||||
@ -738,6 +740,9 @@ lua_env :
|
|||||||
-@ !
|
-@ !
|
||||||
.ENDIF
|
.ENDIF
|
||||||
|
|
||||||
|
alloc.obj : alloc.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||||
|
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
|
||||||
|
[.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h
|
||||||
arabic.obj : arabic.c vim.h
|
arabic.obj : arabic.c vim.h
|
||||||
arglist.obj : arglist.c vim.h [.auto]config.h feature.h os_unix.h
|
arglist.obj : arglist.c vim.h [.auto]config.h feature.h os_unix.h
|
||||||
autocmd.obj : autocmd.c vim.h [.auto]config.h feature.h os_unix.h
|
autocmd.obj : autocmd.c vim.h [.auto]config.h feature.h os_unix.h
|
||||||
|
10
src/Makefile
10
src/Makefile
@ -1590,6 +1590,7 @@ include testdir/Make_all.mak
|
|||||||
# ALL_SRC: source files used for make depend and make lint
|
# ALL_SRC: source files used for make depend and make lint
|
||||||
|
|
||||||
BASIC_SRC = \
|
BASIC_SRC = \
|
||||||
|
alloc.c \
|
||||||
arabic.c \
|
arabic.c \
|
||||||
arglist.c \
|
arglist.c \
|
||||||
autocmd.c \
|
autocmd.c \
|
||||||
@ -1747,6 +1748,7 @@ LINT_SRC = $(BASIC_SRC) $(GUI_SRC) \
|
|||||||
#LINT_SRC = $(BASIC_SRC)
|
#LINT_SRC = $(BASIC_SRC)
|
||||||
|
|
||||||
OBJ_COMMON = \
|
OBJ_COMMON = \
|
||||||
|
objects/alloc.o \
|
||||||
objects/arabic.o \
|
objects/arabic.o \
|
||||||
objects/arglist.o \
|
objects/arglist.o \
|
||||||
objects/autocmd.o \
|
objects/autocmd.o \
|
||||||
@ -1917,6 +1919,7 @@ ALL_OBJ = $(OBJ_COMMON) \
|
|||||||
|
|
||||||
|
|
||||||
PRO_AUTO = \
|
PRO_AUTO = \
|
||||||
|
alloc.pro \
|
||||||
arabic.pro \
|
arabic.pro \
|
||||||
arglist.pro \
|
arglist.pro \
|
||||||
autocmd.pro \
|
autocmd.pro \
|
||||||
@ -3150,6 +3153,9 @@ objects/.dirstamp:
|
|||||||
# time.
|
# time.
|
||||||
$(ALL_OBJ): objects/.dirstamp
|
$(ALL_OBJ): objects/.dirstamp
|
||||||
|
|
||||||
|
objects/alloc.o: alloc.c
|
||||||
|
$(CCC) -o $@ alloc.c
|
||||||
|
|
||||||
objects/arabic.o: arabic.c
|
objects/arabic.o: arabic.c
|
||||||
$(CCC) -o $@ arabic.c
|
$(CCC) -o $@ arabic.c
|
||||||
|
|
||||||
@ -3711,6 +3717,10 @@ installglinks_haiku: $(HAIKU_GLINKS) install_haiku_extra
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
### (automatically generated by 'make depend')
|
### (automatically generated by 'make depend')
|
||||||
### Dependencies:
|
### Dependencies:
|
||||||
|
objects/alloc.o: alloc.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
||||||
|
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
||||||
|
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
||||||
|
proto.h errors.h globals.h
|
||||||
objects/arabic.o: arabic.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
objects/arabic.o: arabic.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
||||||
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
||||||
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
||||||
|
@ -23,6 +23,7 @@ Most code can be found in a file with an obvious name (incomplete list):
|
|||||||
|
|
||||||
File name | Description
|
File name | Description
|
||||||
--------------- | -----------
|
--------------- | -----------
|
||||||
|
alloc.c | memory management
|
||||||
arglist.c | handling argument list
|
arglist.c | handling argument list
|
||||||
autocmd.c | autocommands
|
autocmd.c | autocommands
|
||||||
blob.c | blob data type
|
blob.c | blob data type
|
||||||
|
872
src/alloc.c
Normal file
872
src/alloc.c
Normal file
@ -0,0 +1,872 @@
|
|||||||
|
/* vi:set ts=8 sts=4 sw=4 noet:
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See README.txt for an overview of the Vim source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* alloc.c: functions for memory management
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vim.h"
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* 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(size_t *sizep)
|
||||||
|
{
|
||||||
|
*sizep += sizeof(size_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mem_pre_alloc_l(size_t *sizep)
|
||||||
|
{
|
||||||
|
*sizep += sizeof(size_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mem_post_alloc(
|
||||||
|
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(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(void)
|
||||||
|
{
|
||||||
|
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\n%s", _("ERROR: "));
|
||||||
|
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])
|
||||||
|
puts(_("ERROR: "));
|
||||||
|
printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"),
|
||||||
|
mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak);
|
||||||
|
printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"),
|
||||||
|
num_alloc, num_freed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MEM_PROFILE
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
int
|
||||||
|
alloc_does_fail(size_t size)
|
||||||
|
{
|
||||||
|
if (alloc_fail_countdown == 0)
|
||||||
|
{
|
||||||
|
if (--alloc_fail_repeat <= 0)
|
||||||
|
alloc_fail_id = 0;
|
||||||
|
do_outofmem_msg(size);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
--alloc_fail_countdown;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 (2 * 8192L)
|
||||||
|
#define KEEP_ROOM_KB (KEEP_ROOM / 1024L)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The normal way to allocate memory. This handles an out-of-memory situation
|
||||||
|
* as well as possible, still returns NULL when we're completely out.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
alloc(size_t size)
|
||||||
|
{
|
||||||
|
return lalloc(size, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* alloc() with an ID for alloc_fail().
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
alloc_id(size_t size, alloc_id_T id UNUSED)
|
||||||
|
{
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
if (alloc_fail_id == id && alloc_does_fail(size))
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
return lalloc(size, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate memory and set all bytes to zero.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
alloc_clear(size_t size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = lalloc(size, TRUE);
|
||||||
|
if (p != NULL)
|
||||||
|
(void)vim_memset(p, 0, size);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same as alloc_clear() but with allocation id for testing
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
alloc_clear_id(size_t size, alloc_id_T id UNUSED)
|
||||||
|
{
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
if (alloc_fail_id == id && alloc_does_fail(size))
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
return alloc_clear(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate memory like lalloc() and set all bytes to zero.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
lalloc_clear(size_t size, int message)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = lalloc(size, message);
|
||||||
|
if (p != NULL)
|
||||||
|
(void)vim_memset(p, 0, size);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Low level memory allocation function.
|
||||||
|
* This is used often, KEEP IT FAST!
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
lalloc(size_t size, int message)
|
||||||
|
{
|
||||||
|
void *p; // pointer to new storage space
|
||||||
|
static int releasing = FALSE; // don't do mf_release_all() recursive
|
||||||
|
int try_again;
|
||||||
|
#if defined(HAVE_AVAIL_MEM)
|
||||||
|
static size_t allocated = 0; // allocated since last avail check
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Safety check for allocating zero bytes
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
// Don't hide this message
|
||||||
|
emsg_silent = 0;
|
||||||
|
iemsg(_("E341: Internal error: lalloc(0, )"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MEM_PROFILE
|
||||||
|
mem_pre_alloc_l(&size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop when out of memory: Try to release some memfile blocks and
|
||||||
|
* if some blocks are released call malloc again.
|
||||||
|
*/
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Handle three kind of systems:
|
||||||
|
* 1. No check for available memory: Just return.
|
||||||
|
* 2. Slow check for available memory: call mch_avail_mem() after
|
||||||
|
* allocating KEEP_ROOM amount of memory.
|
||||||
|
* 3. Strict check for available memory: call mch_avail_mem()
|
||||||
|
*/
|
||||||
|
if ((p = malloc(size)) != NULL)
|
||||||
|
{
|
||||||
|
#ifndef HAVE_AVAIL_MEM
|
||||||
|
// 1. No check for available memory: Just return.
|
||||||
|
goto theend;
|
||||||
|
#else
|
||||||
|
// 2. Slow check for available memory: call mch_avail_mem() after
|
||||||
|
// allocating (KEEP_ROOM / 2) amount of memory.
|
||||||
|
allocated += size;
|
||||||
|
if (allocated < KEEP_ROOM / 2)
|
||||||
|
goto theend;
|
||||||
|
allocated = 0;
|
||||||
|
|
||||||
|
// 3. check for available memory: call mch_avail_mem()
|
||||||
|
if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing)
|
||||||
|
{
|
||||||
|
free(p); // System is low... no go!
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto theend;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Remember that mf_release_all() is being called to avoid an endless
|
||||||
|
* loop, because mf_release_all() may call alloc() recursively.
|
||||||
|
*/
|
||||||
|
if (releasing)
|
||||||
|
break;
|
||||||
|
releasing = TRUE;
|
||||||
|
|
||||||
|
clear_sb_text(TRUE); // free any scrollback text
|
||||||
|
try_again = mf_release_all(); // release as many blocks as possible
|
||||||
|
|
||||||
|
releasing = FALSE;
|
||||||
|
if (!try_again)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message && p == NULL)
|
||||||
|
do_outofmem_msg(size);
|
||||||
|
|
||||||
|
theend:
|
||||||
|
#ifdef MEM_PROFILE
|
||||||
|
mem_post_alloc(&p, size);
|
||||||
|
#endif
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lalloc() with an ID for alloc_fail().
|
||||||
|
*/
|
||||||
|
#if defined(FEAT_SIGNS) || defined(PROTO)
|
||||||
|
void *
|
||||||
|
lalloc_id(size_t size, int message, alloc_id_T id UNUSED)
|
||||||
|
{
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
if (alloc_fail_id == id && alloc_does_fail(size))
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
return (lalloc(size, message));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MEM_PROFILE) || defined(PROTO)
|
||||||
|
/*
|
||||||
|
* realloc() with memory profiling.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
mem_realloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
mem_pre_free(&ptr);
|
||||||
|
mem_pre_alloc_s(&size);
|
||||||
|
|
||||||
|
p = realloc(ptr, size);
|
||||||
|
|
||||||
|
mem_post_alloc(&p, size);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid repeating the error message many times (they take 1 second each).
|
||||||
|
* Did_outofmem_msg is reset when a character is read.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
do_outofmem_msg(size_t size)
|
||||||
|
{
|
||||||
|
if (!did_outofmem_msg)
|
||||||
|
{
|
||||||
|
// Don't hide this message
|
||||||
|
emsg_silent = 0;
|
||||||
|
|
||||||
|
// Must come first to avoid coming back here when printing the error
|
||||||
|
// message fails, e.g. when setting v:errmsg.
|
||||||
|
did_outofmem_msg = TRUE;
|
||||||
|
|
||||||
|
semsg(_("E342: Out of memory! (allocating %lu bytes)"), (long_u)size);
|
||||||
|
|
||||||
|
if (starting == NO_SCREEN)
|
||||||
|
// Not even finished with initializations and already out of
|
||||||
|
// memory? Then nothing is going to work, exit.
|
||||||
|
mch_exit(123);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(EXITFREE) || defined(PROTO)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free everything that we allocated.
|
||||||
|
* Can be used to detect memory leaks, e.g., with ccmalloc.
|
||||||
|
* NOTE: This is tricky! Things are freed that functions depend on. Don't be
|
||||||
|
* surprised if Vim crashes...
|
||||||
|
* Some things can't be freed, esp. things local to a library function.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
free_all_mem(void)
|
||||||
|
{
|
||||||
|
buf_T *buf, *nextbuf;
|
||||||
|
|
||||||
|
// When we cause a crash here it is caught and Vim tries to exit cleanly.
|
||||||
|
// Don't try freeing everything again.
|
||||||
|
if (entered_free_all_mem)
|
||||||
|
return;
|
||||||
|
entered_free_all_mem = TRUE;
|
||||||
|
// Don't want to trigger autocommands from here on.
|
||||||
|
block_autocmds();
|
||||||
|
|
||||||
|
// Close all tabs and windows. Reset 'equalalways' to avoid redraws.
|
||||||
|
p_ea = FALSE;
|
||||||
|
if (first_tabpage != NULL && first_tabpage->tp_next != NULL)
|
||||||
|
do_cmdline_cmd((char_u *)"tabonly!");
|
||||||
|
if (!ONE_WINDOW)
|
||||||
|
do_cmdline_cmd((char_u *)"only!");
|
||||||
|
|
||||||
|
# if defined(FEAT_SPELL)
|
||||||
|
// Free all spell info.
|
||||||
|
spell_free_all();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(FEAT_BEVAL_TERM)
|
||||||
|
ui_remove_balloon();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_PROP_POPUP
|
||||||
|
if (curwin != NULL)
|
||||||
|
close_all_popups(TRUE);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Clear user commands (before deleting buffers).
|
||||||
|
ex_comclear(NULL);
|
||||||
|
|
||||||
|
// When exiting from mainerr_arg_missing curbuf has not been initialized,
|
||||||
|
// and not much else.
|
||||||
|
if (curbuf != NULL)
|
||||||
|
{
|
||||||
|
# ifdef FEAT_MENU
|
||||||
|
// Clear menus.
|
||||||
|
do_cmdline_cmd((char_u *)"aunmenu *");
|
||||||
|
# ifdef FEAT_MULTI_LANG
|
||||||
|
do_cmdline_cmd((char_u *)"menutranslate clear");
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
// Clear mappings, abbreviations, breakpoints.
|
||||||
|
do_cmdline_cmd((char_u *)"lmapclear");
|
||||||
|
do_cmdline_cmd((char_u *)"xmapclear");
|
||||||
|
do_cmdline_cmd((char_u *)"mapclear");
|
||||||
|
do_cmdline_cmd((char_u *)"mapclear!");
|
||||||
|
do_cmdline_cmd((char_u *)"abclear");
|
||||||
|
# if defined(FEAT_EVAL)
|
||||||
|
do_cmdline_cmd((char_u *)"breakdel *");
|
||||||
|
# endif
|
||||||
|
# if defined(FEAT_PROFILE)
|
||||||
|
do_cmdline_cmd((char_u *)"profdel *");
|
||||||
|
# endif
|
||||||
|
# if defined(FEAT_KEYMAP)
|
||||||
|
do_cmdline_cmd((char_u *)"set keymap=");
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef FEAT_TITLE
|
||||||
|
free_titles();
|
||||||
|
# endif
|
||||||
|
# if defined(FEAT_SEARCHPATH)
|
||||||
|
free_findfile();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Obviously named calls.
|
||||||
|
free_all_autocmds();
|
||||||
|
clear_termcodes();
|
||||||
|
free_all_marks();
|
||||||
|
alist_clear(&global_alist);
|
||||||
|
free_homedir();
|
||||||
|
free_users();
|
||||||
|
free_search_patterns();
|
||||||
|
free_old_sub();
|
||||||
|
free_last_insert();
|
||||||
|
free_insexpand_stuff();
|
||||||
|
free_prev_shellcmd();
|
||||||
|
free_regexp_stuff();
|
||||||
|
free_tag_stuff();
|
||||||
|
free_cd_dir();
|
||||||
|
# ifdef FEAT_SIGNS
|
||||||
|
free_signs();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
set_expr_line(NULL, NULL);
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_DIFF
|
||||||
|
if (curtab != NULL)
|
||||||
|
diff_clear(curtab);
|
||||||
|
# endif
|
||||||
|
clear_sb_text(TRUE); // free any scrollback text
|
||||||
|
|
||||||
|
// Free some global vars.
|
||||||
|
free_username();
|
||||||
|
# ifdef FEAT_CLIPBOARD
|
||||||
|
vim_regfree(clip_exclude_prog);
|
||||||
|
# endif
|
||||||
|
vim_free(last_cmdline);
|
||||||
|
vim_free(new_last_cmdline);
|
||||||
|
set_keep_msg(NULL, 0);
|
||||||
|
|
||||||
|
// Clear cmdline history.
|
||||||
|
p_hi = 0;
|
||||||
|
init_history();
|
||||||
|
# ifdef FEAT_PROP_POPUP
|
||||||
|
clear_global_prop_types();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef FEAT_QUICKFIX
|
||||||
|
{
|
||||||
|
win_T *win;
|
||||||
|
tabpage_T *tab;
|
||||||
|
|
||||||
|
qf_free_all(NULL);
|
||||||
|
// Free all location lists
|
||||||
|
FOR_ALL_TAB_WINDOWS(tab, win)
|
||||||
|
qf_free_all(win);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Close all script inputs.
|
||||||
|
close_all_scripts();
|
||||||
|
|
||||||
|
if (curwin != NULL)
|
||||||
|
// Destroy all windows. Must come before freeing buffers.
|
||||||
|
win_free_all();
|
||||||
|
|
||||||
|
// Free all option values. Must come after closing windows.
|
||||||
|
free_all_options();
|
||||||
|
|
||||||
|
// Free all buffers. Reset 'autochdir' to avoid accessing things that
|
||||||
|
// were freed already.
|
||||||
|
# ifdef FEAT_AUTOCHDIR
|
||||||
|
p_acd = FALSE;
|
||||||
|
# endif
|
||||||
|
for (buf = firstbuf; buf != NULL; )
|
||||||
|
{
|
||||||
|
bufref_T bufref;
|
||||||
|
|
||||||
|
set_bufref(&bufref, buf);
|
||||||
|
nextbuf = buf->b_next;
|
||||||
|
close_buffer(NULL, buf, DOBUF_WIPE, FALSE, FALSE);
|
||||||
|
if (bufref_valid(&bufref))
|
||||||
|
buf = nextbuf; // didn't work, try next one
|
||||||
|
else
|
||||||
|
buf = firstbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef FEAT_ARABIC
|
||||||
|
free_arshape_buf();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Clear registers.
|
||||||
|
clear_registers();
|
||||||
|
ResetRedobuff();
|
||||||
|
ResetRedobuff();
|
||||||
|
|
||||||
|
# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
|
||||||
|
vim_free(serverDelayedStartName);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// highlight info
|
||||||
|
free_highlight();
|
||||||
|
|
||||||
|
reset_last_sourcing();
|
||||||
|
|
||||||
|
if (first_tabpage != NULL)
|
||||||
|
{
|
||||||
|
free_tabpage(first_tabpage);
|
||||||
|
first_tabpage = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef UNIX
|
||||||
|
// Machine-specific free.
|
||||||
|
mch_free_mem();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// message history
|
||||||
|
for (;;)
|
||||||
|
if (delete_first_msg() == FAIL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
# ifdef FEAT_JOB_CHANNEL
|
||||||
|
channel_free_all();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_TIMERS
|
||||||
|
timer_free_all();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
// must be after channel_free_all() with unrefs partials
|
||||||
|
eval_clear();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_JOB_CHANNEL
|
||||||
|
// must be after eval_clear() with unrefs jobs
|
||||||
|
job_free_all();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
free_termoptions();
|
||||||
|
|
||||||
|
// screenlines (can't display anything now!)
|
||||||
|
free_screenlines();
|
||||||
|
|
||||||
|
# if defined(FEAT_SOUND)
|
||||||
|
sound_free();
|
||||||
|
# endif
|
||||||
|
# if defined(USE_XSMP)
|
||||||
|
xsmp_close();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_GUI_GTK
|
||||||
|
gui_mch_free_all();
|
||||||
|
# endif
|
||||||
|
clear_hl_tables();
|
||||||
|
|
||||||
|
vim_free(IObuff);
|
||||||
|
vim_free(NameBuff);
|
||||||
|
# ifdef FEAT_QUICKFIX
|
||||||
|
check_quickfix_busy();
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy "p[len]" into allocated memory, ignoring NUL characters.
|
||||||
|
* Returns NULL when out of memory.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
vim_memsave(char_u *p, size_t len)
|
||||||
|
{
|
||||||
|
char_u *ret = alloc(len);
|
||||||
|
|
||||||
|
if (ret != NULL)
|
||||||
|
mch_memmove(ret, p, len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Replacement for free() that ignores NULL pointers.
|
||||||
|
* Also skip free() when exiting for sure, this helps when we caught a deadly
|
||||||
|
* signal that was caused by a crash in free().
|
||||||
|
* If you want to set NULL after calling this function, you should use
|
||||||
|
* VIM_CLEAR() instead.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vim_free(void *x)
|
||||||
|
{
|
||||||
|
if (x != NULL && !really_exiting)
|
||||||
|
{
|
||||||
|
#ifdef MEM_PROFILE
|
||||||
|
mem_pre_free(&x);
|
||||||
|
#endif
|
||||||
|
free(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* Functions for handling growing arrays.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear an allocated growing array.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ga_clear(garray_T *gap)
|
||||||
|
{
|
||||||
|
vim_free(gap->ga_data);
|
||||||
|
ga_init(gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear a growing array that contains a list of strings.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ga_clear_strings(garray_T *gap)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (gap->ga_data != NULL)
|
||||||
|
for (i = 0; i < gap->ga_len; ++i)
|
||||||
|
vim_free(((char_u **)(gap->ga_data))[i]);
|
||||||
|
ga_clear(gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy a growing array that contains a list of strings.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ga_copy_strings(garray_T *from, garray_T *to)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ga_init2(to, sizeof(char_u *), 1);
|
||||||
|
if (ga_grow(to, from->ga_len) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
for (i = 0; i < from->ga_len; ++i)
|
||||||
|
{
|
||||||
|
char_u *orig = ((char_u **)from->ga_data)[i];
|
||||||
|
char_u *copy;
|
||||||
|
|
||||||
|
if (orig == NULL)
|
||||||
|
copy = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
copy = vim_strsave(orig);
|
||||||
|
if (copy == NULL)
|
||||||
|
{
|
||||||
|
to->ga_len = i;
|
||||||
|
ga_clear_strings(to);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
((char_u **)to->ga_data)[i] = copy;
|
||||||
|
}
|
||||||
|
to->ga_len = from->ga_len;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a growing array. Don't forget to set ga_itemsize and
|
||||||
|
* ga_growsize! Or use ga_init2().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ga_init(garray_T *gap)
|
||||||
|
{
|
||||||
|
gap->ga_data = NULL;
|
||||||
|
gap->ga_maxlen = 0;
|
||||||
|
gap->ga_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ga_init2(garray_T *gap, int itemsize, int growsize)
|
||||||
|
{
|
||||||
|
ga_init(gap);
|
||||||
|
gap->ga_itemsize = itemsize;
|
||||||
|
gap->ga_growsize = growsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make room in growing array "gap" for at least "n" items.
|
||||||
|
* Return FAIL for failure, OK otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ga_grow(garray_T *gap, int n)
|
||||||
|
{
|
||||||
|
if (gap->ga_maxlen - gap->ga_len < n)
|
||||||
|
return ga_grow_inner(gap, n);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ga_grow_inner(garray_T *gap, int n)
|
||||||
|
{
|
||||||
|
size_t old_len;
|
||||||
|
size_t new_len;
|
||||||
|
char_u *pp;
|
||||||
|
|
||||||
|
if (n < gap->ga_growsize)
|
||||||
|
n = gap->ga_growsize;
|
||||||
|
|
||||||
|
// A linear growth is very inefficient when the array grows big. This
|
||||||
|
// is a compromise between allocating memory that won't be used and too
|
||||||
|
// many copy operations. A factor of 1.5 seems reasonable.
|
||||||
|
if (n < gap->ga_len / 2)
|
||||||
|
n = gap->ga_len / 2;
|
||||||
|
|
||||||
|
new_len = gap->ga_itemsize * (gap->ga_len + n);
|
||||||
|
pp = vim_realloc(gap->ga_data, new_len);
|
||||||
|
if (pp == NULL)
|
||||||
|
return FAIL;
|
||||||
|
old_len = gap->ga_itemsize * gap->ga_maxlen;
|
||||||
|
vim_memset(pp + old_len, 0, new_len - old_len);
|
||||||
|
gap->ga_maxlen = gap->ga_len + n;
|
||||||
|
gap->ga_data = pp;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For a growing array that contains a list of strings: concatenate all the
|
||||||
|
* strings with a separating "sep".
|
||||||
|
* Returns NULL when out of memory.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
ga_concat_strings(garray_T *gap, char *sep)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int len = 0;
|
||||||
|
int sep_len = (int)STRLEN(sep);
|
||||||
|
char_u *s;
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
for (i = 0; i < gap->ga_len; ++i)
|
||||||
|
len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len;
|
||||||
|
|
||||||
|
s = alloc(len + 1);
|
||||||
|
if (s != NULL)
|
||||||
|
{
|
||||||
|
*s = NUL;
|
||||||
|
p = s;
|
||||||
|
for (i = 0; i < gap->ga_len; ++i)
|
||||||
|
{
|
||||||
|
if (p != s)
|
||||||
|
{
|
||||||
|
STRCPY(p, sep);
|
||||||
|
p += sep_len;
|
||||||
|
}
|
||||||
|
STRCPY(p, ((char_u **)(gap->ga_data))[i]);
|
||||||
|
p += STRLEN(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a copy of string "p" and add it to "gap".
|
||||||
|
* When out of memory nothing changes and FAIL is returned.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ga_add_string(garray_T *gap, char_u *p)
|
||||||
|
{
|
||||||
|
char_u *cp = vim_strsave(p);
|
||||||
|
|
||||||
|
if (cp == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
if (ga_grow(gap, 1) == FAIL)
|
||||||
|
{
|
||||||
|
vim_free(cp);
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
((char_u **)(gap->ga_data))[gap->ga_len++] = cp;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Concatenate a string to a growarray which contains bytes.
|
||||||
|
* When "s" is NULL does not do anything.
|
||||||
|
* Note: Does NOT copy the NUL at the end!
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ga_concat(garray_T *gap, char_u *s)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (s == NULL || *s == NUL)
|
||||||
|
return;
|
||||||
|
len = (int)STRLEN(s);
|
||||||
|
if (ga_grow(gap, len) == OK)
|
||||||
|
{
|
||||||
|
mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
|
||||||
|
gap->ga_len += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Concatenate 'len' bytes from string 's' to a growarray.
|
||||||
|
* When "s" is NULL does not do anything.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ga_concat_len(garray_T *gap, char_u *s, size_t len)
|
||||||
|
{
|
||||||
|
if (s == NULL || *s == NUL)
|
||||||
|
return;
|
||||||
|
if (ga_grow(gap, (int)len) == OK)
|
||||||
|
{
|
||||||
|
mch_memmove((char *)gap->ga_data + gap->ga_len, s, len);
|
||||||
|
gap->ga_len += (int)len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append one byte to a growarray which contains bytes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ga_append(garray_T *gap, int c)
|
||||||
|
{
|
||||||
|
if (ga_grow(gap, 1) == OK)
|
||||||
|
{
|
||||||
|
*((char *)gap->ga_data + gap->ga_len) = c;
|
||||||
|
++gap->ga_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(MSWIN) \
|
||||||
|
|| defined(PROTO)
|
||||||
|
/*
|
||||||
|
* Append the text in "gap" below the cursor line and clear "gap".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
append_ga_line(garray_T *gap)
|
||||||
|
{
|
||||||
|
// Remove trailing CR.
|
||||||
|
if (gap->ga_len > 0
|
||||||
|
&& !curbuf->b_p_bin
|
||||||
|
&& ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
|
||||||
|
--gap->ga_len;
|
||||||
|
ga_append(gap, NUL);
|
||||||
|
ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
|
||||||
|
gap->ga_len = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
866
src/misc2.c
866
src/misc2.c
@ -693,597 +693,6 @@ leftcol_changed(void)
|
|||||||
return retval;
|
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(size_t *sizep)
|
|
||||||
{
|
|
||||||
*sizep += sizeof(size_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
mem_pre_alloc_l(size_t *sizep)
|
|
||||||
{
|
|
||||||
*sizep += sizeof(size_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
mem_post_alloc(
|
|
||||||
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(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(void)
|
|
||||||
{
|
|
||||||
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\n%s", _("ERROR: "));
|
|
||||||
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])
|
|
||||||
puts(_("ERROR: "));
|
|
||||||
printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"),
|
|
||||||
mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak);
|
|
||||||
printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"),
|
|
||||||
num_alloc, num_freed);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // MEM_PROFILE
|
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
|
||||||
int
|
|
||||||
alloc_does_fail(size_t size)
|
|
||||||
{
|
|
||||||
if (alloc_fail_countdown == 0)
|
|
||||||
{
|
|
||||||
if (--alloc_fail_repeat <= 0)
|
|
||||||
alloc_fail_id = 0;
|
|
||||||
do_outofmem_msg(size);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
--alloc_fail_countdown;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 (2 * 8192L)
|
|
||||||
#define KEEP_ROOM_KB (KEEP_ROOM / 1024L)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The normal way to allocate memory. This handles an out-of-memory situation
|
|
||||||
* as well as possible, still returns NULL when we're completely out.
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
alloc(size_t size)
|
|
||||||
{
|
|
||||||
return lalloc(size, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* alloc() with an ID for alloc_fail().
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
alloc_id(size_t size, alloc_id_T id UNUSED)
|
|
||||||
{
|
|
||||||
#ifdef FEAT_EVAL
|
|
||||||
if (alloc_fail_id == id && alloc_does_fail(size))
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
return lalloc(size, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate memory and set all bytes to zero.
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
alloc_clear(size_t size)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
p = lalloc(size, TRUE);
|
|
||||||
if (p != NULL)
|
|
||||||
(void)vim_memset(p, 0, size);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Same as alloc_clear() but with allocation id for testing
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
alloc_clear_id(size_t size, alloc_id_T id UNUSED)
|
|
||||||
{
|
|
||||||
#ifdef FEAT_EVAL
|
|
||||||
if (alloc_fail_id == id && alloc_does_fail(size))
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
return alloc_clear(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate memory like lalloc() and set all bytes to zero.
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
lalloc_clear(size_t size, int message)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
p = lalloc(size, message);
|
|
||||||
if (p != NULL)
|
|
||||||
(void)vim_memset(p, 0, size);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Low level memory allocation function.
|
|
||||||
* This is used often, KEEP IT FAST!
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
lalloc(size_t size, int message)
|
|
||||||
{
|
|
||||||
void *p; // pointer to new storage space
|
|
||||||
static int releasing = FALSE; // don't do mf_release_all() recursive
|
|
||||||
int try_again;
|
|
||||||
#if defined(HAVE_AVAIL_MEM)
|
|
||||||
static size_t allocated = 0; // allocated since last avail check
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Safety check for allocating zero bytes
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
// Don't hide this message
|
|
||||||
emsg_silent = 0;
|
|
||||||
iemsg(_("E341: Internal error: lalloc(0, )"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MEM_PROFILE
|
|
||||||
mem_pre_alloc_l(&size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Loop when out of memory: Try to release some memfile blocks and
|
|
||||||
* if some blocks are released call malloc again.
|
|
||||||
*/
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Handle three kind of systems:
|
|
||||||
* 1. No check for available memory: Just return.
|
|
||||||
* 2. Slow check for available memory: call mch_avail_mem() after
|
|
||||||
* allocating KEEP_ROOM amount of memory.
|
|
||||||
* 3. Strict check for available memory: call mch_avail_mem()
|
|
||||||
*/
|
|
||||||
if ((p = malloc(size)) != NULL)
|
|
||||||
{
|
|
||||||
#ifndef HAVE_AVAIL_MEM
|
|
||||||
// 1. No check for available memory: Just return.
|
|
||||||
goto theend;
|
|
||||||
#else
|
|
||||||
// 2. Slow check for available memory: call mch_avail_mem() after
|
|
||||||
// allocating (KEEP_ROOM / 2) amount of memory.
|
|
||||||
allocated += size;
|
|
||||||
if (allocated < KEEP_ROOM / 2)
|
|
||||||
goto theend;
|
|
||||||
allocated = 0;
|
|
||||||
|
|
||||||
// 3. check for available memory: call mch_avail_mem()
|
|
||||||
if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing)
|
|
||||||
{
|
|
||||||
free(p); // System is low... no go!
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto theend;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Remember that mf_release_all() is being called to avoid an endless
|
|
||||||
* loop, because mf_release_all() may call alloc() recursively.
|
|
||||||
*/
|
|
||||||
if (releasing)
|
|
||||||
break;
|
|
||||||
releasing = TRUE;
|
|
||||||
|
|
||||||
clear_sb_text(TRUE); // free any scrollback text
|
|
||||||
try_again = mf_release_all(); // release as many blocks as possible
|
|
||||||
|
|
||||||
releasing = FALSE;
|
|
||||||
if (!try_again)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message && p == NULL)
|
|
||||||
do_outofmem_msg(size);
|
|
||||||
|
|
||||||
theend:
|
|
||||||
#ifdef MEM_PROFILE
|
|
||||||
mem_post_alloc(&p, size);
|
|
||||||
#endif
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* lalloc() with an ID for alloc_fail().
|
|
||||||
*/
|
|
||||||
#if defined(FEAT_SIGNS) || defined(PROTO)
|
|
||||||
void *
|
|
||||||
lalloc_id(size_t size, int message, alloc_id_T id UNUSED)
|
|
||||||
{
|
|
||||||
#ifdef FEAT_EVAL
|
|
||||||
if (alloc_fail_id == id && alloc_does_fail(size))
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
return (lalloc(size, message));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MEM_PROFILE) || defined(PROTO)
|
|
||||||
/*
|
|
||||||
* realloc() with memory profiling.
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
mem_realloc(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
mem_pre_free(&ptr);
|
|
||||||
mem_pre_alloc_s(&size);
|
|
||||||
|
|
||||||
p = realloc(ptr, size);
|
|
||||||
|
|
||||||
mem_post_alloc(&p, size);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Avoid repeating the error message many times (they take 1 second each).
|
|
||||||
* Did_outofmem_msg is reset when a character is read.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
do_outofmem_msg(size_t size)
|
|
||||||
{
|
|
||||||
if (!did_outofmem_msg)
|
|
||||||
{
|
|
||||||
// Don't hide this message
|
|
||||||
emsg_silent = 0;
|
|
||||||
|
|
||||||
// Must come first to avoid coming back here when printing the error
|
|
||||||
// message fails, e.g. when setting v:errmsg.
|
|
||||||
did_outofmem_msg = TRUE;
|
|
||||||
|
|
||||||
semsg(_("E342: Out of memory! (allocating %lu bytes)"), (long_u)size);
|
|
||||||
|
|
||||||
if (starting == NO_SCREEN)
|
|
||||||
// Not even finished with initializations and already out of
|
|
||||||
// memory? Then nothing is going to work, exit.
|
|
||||||
mch_exit(123);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(EXITFREE) || defined(PROTO)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free everything that we allocated.
|
|
||||||
* Can be used to detect memory leaks, e.g., with ccmalloc.
|
|
||||||
* NOTE: This is tricky! Things are freed that functions depend on. Don't be
|
|
||||||
* surprised if Vim crashes...
|
|
||||||
* Some things can't be freed, esp. things local to a library function.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
free_all_mem(void)
|
|
||||||
{
|
|
||||||
buf_T *buf, *nextbuf;
|
|
||||||
|
|
||||||
// When we cause a crash here it is caught and Vim tries to exit cleanly.
|
|
||||||
// Don't try freeing everything again.
|
|
||||||
if (entered_free_all_mem)
|
|
||||||
return;
|
|
||||||
entered_free_all_mem = TRUE;
|
|
||||||
// Don't want to trigger autocommands from here on.
|
|
||||||
block_autocmds();
|
|
||||||
|
|
||||||
// Close all tabs and windows. Reset 'equalalways' to avoid redraws.
|
|
||||||
p_ea = FALSE;
|
|
||||||
if (first_tabpage != NULL && first_tabpage->tp_next != NULL)
|
|
||||||
do_cmdline_cmd((char_u *)"tabonly!");
|
|
||||||
if (!ONE_WINDOW)
|
|
||||||
do_cmdline_cmd((char_u *)"only!");
|
|
||||||
|
|
||||||
# if defined(FEAT_SPELL)
|
|
||||||
// Free all spell info.
|
|
||||||
spell_free_all();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(FEAT_BEVAL_TERM)
|
|
||||||
ui_remove_balloon();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_PROP_POPUP
|
|
||||||
if (curwin != NULL)
|
|
||||||
close_all_popups(TRUE);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Clear user commands (before deleting buffers).
|
|
||||||
ex_comclear(NULL);
|
|
||||||
|
|
||||||
// When exiting from mainerr_arg_missing curbuf has not been initialized,
|
|
||||||
// and not much else.
|
|
||||||
if (curbuf != NULL)
|
|
||||||
{
|
|
||||||
# ifdef FEAT_MENU
|
|
||||||
// Clear menus.
|
|
||||||
do_cmdline_cmd((char_u *)"aunmenu *");
|
|
||||||
# ifdef FEAT_MULTI_LANG
|
|
||||||
do_cmdline_cmd((char_u *)"menutranslate clear");
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
// Clear mappings, abbreviations, breakpoints.
|
|
||||||
do_cmdline_cmd((char_u *)"lmapclear");
|
|
||||||
do_cmdline_cmd((char_u *)"xmapclear");
|
|
||||||
do_cmdline_cmd((char_u *)"mapclear");
|
|
||||||
do_cmdline_cmd((char_u *)"mapclear!");
|
|
||||||
do_cmdline_cmd((char_u *)"abclear");
|
|
||||||
# if defined(FEAT_EVAL)
|
|
||||||
do_cmdline_cmd((char_u *)"breakdel *");
|
|
||||||
# endif
|
|
||||||
# if defined(FEAT_PROFILE)
|
|
||||||
do_cmdline_cmd((char_u *)"profdel *");
|
|
||||||
# endif
|
|
||||||
# if defined(FEAT_KEYMAP)
|
|
||||||
do_cmdline_cmd((char_u *)"set keymap=");
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef FEAT_TITLE
|
|
||||||
free_titles();
|
|
||||||
# endif
|
|
||||||
# if defined(FEAT_SEARCHPATH)
|
|
||||||
free_findfile();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Obviously named calls.
|
|
||||||
free_all_autocmds();
|
|
||||||
clear_termcodes();
|
|
||||||
free_all_marks();
|
|
||||||
alist_clear(&global_alist);
|
|
||||||
free_homedir();
|
|
||||||
free_users();
|
|
||||||
free_search_patterns();
|
|
||||||
free_old_sub();
|
|
||||||
free_last_insert();
|
|
||||||
free_insexpand_stuff();
|
|
||||||
free_prev_shellcmd();
|
|
||||||
free_regexp_stuff();
|
|
||||||
free_tag_stuff();
|
|
||||||
free_cd_dir();
|
|
||||||
# ifdef FEAT_SIGNS
|
|
||||||
free_signs();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_EVAL
|
|
||||||
set_expr_line(NULL, NULL);
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_DIFF
|
|
||||||
if (curtab != NULL)
|
|
||||||
diff_clear(curtab);
|
|
||||||
# endif
|
|
||||||
clear_sb_text(TRUE); // free any scrollback text
|
|
||||||
|
|
||||||
// Free some global vars.
|
|
||||||
vim_free(username);
|
|
||||||
# ifdef FEAT_CLIPBOARD
|
|
||||||
vim_regfree(clip_exclude_prog);
|
|
||||||
# endif
|
|
||||||
vim_free(last_cmdline);
|
|
||||||
vim_free(new_last_cmdline);
|
|
||||||
set_keep_msg(NULL, 0);
|
|
||||||
|
|
||||||
// Clear cmdline history.
|
|
||||||
p_hi = 0;
|
|
||||||
init_history();
|
|
||||||
# ifdef FEAT_PROP_POPUP
|
|
||||||
clear_global_prop_types();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef FEAT_QUICKFIX
|
|
||||||
{
|
|
||||||
win_T *win;
|
|
||||||
tabpage_T *tab;
|
|
||||||
|
|
||||||
qf_free_all(NULL);
|
|
||||||
// Free all location lists
|
|
||||||
FOR_ALL_TAB_WINDOWS(tab, win)
|
|
||||||
qf_free_all(win);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Close all script inputs.
|
|
||||||
close_all_scripts();
|
|
||||||
|
|
||||||
if (curwin != NULL)
|
|
||||||
// Destroy all windows. Must come before freeing buffers.
|
|
||||||
win_free_all();
|
|
||||||
|
|
||||||
// Free all option values. Must come after closing windows.
|
|
||||||
free_all_options();
|
|
||||||
|
|
||||||
// Free all buffers. Reset 'autochdir' to avoid accessing things that
|
|
||||||
// were freed already.
|
|
||||||
# ifdef FEAT_AUTOCHDIR
|
|
||||||
p_acd = FALSE;
|
|
||||||
# endif
|
|
||||||
for (buf = firstbuf; buf != NULL; )
|
|
||||||
{
|
|
||||||
bufref_T bufref;
|
|
||||||
|
|
||||||
set_bufref(&bufref, buf);
|
|
||||||
nextbuf = buf->b_next;
|
|
||||||
close_buffer(NULL, buf, DOBUF_WIPE, FALSE, FALSE);
|
|
||||||
if (bufref_valid(&bufref))
|
|
||||||
buf = nextbuf; // didn't work, try next one
|
|
||||||
else
|
|
||||||
buf = firstbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef FEAT_ARABIC
|
|
||||||
free_arshape_buf();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Clear registers.
|
|
||||||
clear_registers();
|
|
||||||
ResetRedobuff();
|
|
||||||
ResetRedobuff();
|
|
||||||
|
|
||||||
# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
|
|
||||||
vim_free(serverDelayedStartName);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// highlight info
|
|
||||||
free_highlight();
|
|
||||||
|
|
||||||
reset_last_sourcing();
|
|
||||||
|
|
||||||
if (first_tabpage != NULL)
|
|
||||||
{
|
|
||||||
free_tabpage(first_tabpage);
|
|
||||||
first_tabpage = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef UNIX
|
|
||||||
// Machine-specific free.
|
|
||||||
mch_free_mem();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// message history
|
|
||||||
for (;;)
|
|
||||||
if (delete_first_msg() == FAIL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
# ifdef FEAT_JOB_CHANNEL
|
|
||||||
channel_free_all();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_TIMERS
|
|
||||||
timer_free_all();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_EVAL
|
|
||||||
// must be after channel_free_all() with unrefs partials
|
|
||||||
eval_clear();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_JOB_CHANNEL
|
|
||||||
// must be after eval_clear() with unrefs jobs
|
|
||||||
job_free_all();
|
|
||||||
# endif
|
|
||||||
|
|
||||||
free_termoptions();
|
|
||||||
|
|
||||||
// screenlines (can't display anything now!)
|
|
||||||
free_screenlines();
|
|
||||||
|
|
||||||
# if defined(FEAT_SOUND)
|
|
||||||
sound_free();
|
|
||||||
# endif
|
|
||||||
# if defined(USE_XSMP)
|
|
||||||
xsmp_close();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_GUI_GTK
|
|
||||||
gui_mch_free_all();
|
|
||||||
# endif
|
|
||||||
clear_hl_tables();
|
|
||||||
|
|
||||||
vim_free(IObuff);
|
|
||||||
vim_free(NameBuff);
|
|
||||||
# ifdef FEAT_QUICKFIX
|
|
||||||
check_quickfix_busy();
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy "p[len]" into allocated memory, ignoring NUL characters.
|
|
||||||
* Returns NULL when out of memory.
|
|
||||||
*/
|
|
||||||
char_u *
|
|
||||||
vim_memsave(char_u *p, size_t len)
|
|
||||||
{
|
|
||||||
char_u *ret = alloc(len);
|
|
||||||
|
|
||||||
if (ret != NULL)
|
|
||||||
mch_memmove(ret, p, len);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Isolate one part of a string option where parts are separated with
|
* Isolate one part of a string option where parts are separated with
|
||||||
* "sep_chars".
|
* "sep_chars".
|
||||||
@ -1325,25 +734,6 @@ copy_option_part(
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Replacement for free() that ignores NULL pointers.
|
|
||||||
* Also skip free() when exiting for sure, this helps when we caught a deadly
|
|
||||||
* signal that was caused by a crash in free().
|
|
||||||
* If you want to set NULL after calling this function, you should use
|
|
||||||
* VIM_CLEAR() instead.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
vim_free(void *x)
|
|
||||||
{
|
|
||||||
if (x != NULL && !really_exiting)
|
|
||||||
{
|
|
||||||
#ifdef MEM_PROFILE
|
|
||||||
mem_pre_free(&x);
|
|
||||||
#endif
|
|
||||||
free(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef HAVE_MEMSET
|
#ifndef HAVE_MEMSET
|
||||||
void *
|
void *
|
||||||
vim_memset(void *ptr, int c, size_t size)
|
vim_memset(void *ptr, int c, size_t size)
|
||||||
@ -1366,253 +756,6 @@ vim_isspace(int x)
|
|||||||
return ((x >= 9 && x <= 13) || x == ' ');
|
return ((x >= 9 && x <= 13) || x == ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************
|
|
||||||
* Functions for handling growing arrays.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear an allocated growing array.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ga_clear(garray_T *gap)
|
|
||||||
{
|
|
||||||
vim_free(gap->ga_data);
|
|
||||||
ga_init(gap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear a growing array that contains a list of strings.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ga_clear_strings(garray_T *gap)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (gap->ga_data != NULL)
|
|
||||||
for (i = 0; i < gap->ga_len; ++i)
|
|
||||||
vim_free(((char_u **)(gap->ga_data))[i]);
|
|
||||||
ga_clear(gap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copy a growing array that contains a list of strings.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ga_copy_strings(garray_T *from, garray_T *to)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ga_init2(to, sizeof(char_u *), 1);
|
|
||||||
if (ga_grow(to, from->ga_len) == FAIL)
|
|
||||||
return FAIL;
|
|
||||||
|
|
||||||
for (i = 0; i < from->ga_len; ++i)
|
|
||||||
{
|
|
||||||
char_u *orig = ((char_u **)from->ga_data)[i];
|
|
||||||
char_u *copy;
|
|
||||||
|
|
||||||
if (orig == NULL)
|
|
||||||
copy = NULL;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
copy = vim_strsave(orig);
|
|
||||||
if (copy == NULL)
|
|
||||||
{
|
|
||||||
to->ga_len = i;
|
|
||||||
ga_clear_strings(to);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
((char_u **)to->ga_data)[i] = copy;
|
|
||||||
}
|
|
||||||
to->ga_len = from->ga_len;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize a growing array. Don't forget to set ga_itemsize and
|
|
||||||
* ga_growsize! Or use ga_init2().
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ga_init(garray_T *gap)
|
|
||||||
{
|
|
||||||
gap->ga_data = NULL;
|
|
||||||
gap->ga_maxlen = 0;
|
|
||||||
gap->ga_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ga_init2(garray_T *gap, int itemsize, int growsize)
|
|
||||||
{
|
|
||||||
ga_init(gap);
|
|
||||||
gap->ga_itemsize = itemsize;
|
|
||||||
gap->ga_growsize = growsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make room in growing array "gap" for at least "n" items.
|
|
||||||
* Return FAIL for failure, OK otherwise.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ga_grow(garray_T *gap, int n)
|
|
||||||
{
|
|
||||||
if (gap->ga_maxlen - gap->ga_len < n)
|
|
||||||
return ga_grow_inner(gap, n);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
ga_grow_inner(garray_T *gap, int n)
|
|
||||||
{
|
|
||||||
size_t old_len;
|
|
||||||
size_t new_len;
|
|
||||||
char_u *pp;
|
|
||||||
|
|
||||||
if (n < gap->ga_growsize)
|
|
||||||
n = gap->ga_growsize;
|
|
||||||
|
|
||||||
// A linear growth is very inefficient when the array grows big. This
|
|
||||||
// is a compromise between allocating memory that won't be used and too
|
|
||||||
// many copy operations. A factor of 1.5 seems reasonable.
|
|
||||||
if (n < gap->ga_len / 2)
|
|
||||||
n = gap->ga_len / 2;
|
|
||||||
|
|
||||||
new_len = gap->ga_itemsize * (gap->ga_len + n);
|
|
||||||
pp = vim_realloc(gap->ga_data, new_len);
|
|
||||||
if (pp == NULL)
|
|
||||||
return FAIL;
|
|
||||||
old_len = gap->ga_itemsize * gap->ga_maxlen;
|
|
||||||
vim_memset(pp + old_len, 0, new_len - old_len);
|
|
||||||
gap->ga_maxlen = gap->ga_len + n;
|
|
||||||
gap->ga_data = pp;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For a growing array that contains a list of strings: concatenate all the
|
|
||||||
* strings with a separating "sep".
|
|
||||||
* Returns NULL when out of memory.
|
|
||||||
*/
|
|
||||||
char_u *
|
|
||||||
ga_concat_strings(garray_T *gap, char *sep)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int len = 0;
|
|
||||||
int sep_len = (int)STRLEN(sep);
|
|
||||||
char_u *s;
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
for (i = 0; i < gap->ga_len; ++i)
|
|
||||||
len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len;
|
|
||||||
|
|
||||||
s = alloc(len + 1);
|
|
||||||
if (s != NULL)
|
|
||||||
{
|
|
||||||
*s = NUL;
|
|
||||||
p = s;
|
|
||||||
for (i = 0; i < gap->ga_len; ++i)
|
|
||||||
{
|
|
||||||
if (p != s)
|
|
||||||
{
|
|
||||||
STRCPY(p, sep);
|
|
||||||
p += sep_len;
|
|
||||||
}
|
|
||||||
STRCPY(p, ((char_u **)(gap->ga_data))[i]);
|
|
||||||
p += STRLEN(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make a copy of string "p" and add it to "gap".
|
|
||||||
* When out of memory nothing changes and FAIL is returned.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ga_add_string(garray_T *gap, char_u *p)
|
|
||||||
{
|
|
||||||
char_u *cp = vim_strsave(p);
|
|
||||||
|
|
||||||
if (cp == NULL)
|
|
||||||
return FAIL;
|
|
||||||
|
|
||||||
if (ga_grow(gap, 1) == FAIL)
|
|
||||||
{
|
|
||||||
vim_free(cp);
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
((char_u **)(gap->ga_data))[gap->ga_len++] = cp;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Concatenate a string to a growarray which contains bytes.
|
|
||||||
* When "s" is NULL does not do anything.
|
|
||||||
* Note: Does NOT copy the NUL at the end!
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ga_concat(garray_T *gap, char_u *s)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
|
|
||||||
if (s == NULL || *s == NUL)
|
|
||||||
return;
|
|
||||||
len = (int)STRLEN(s);
|
|
||||||
if (ga_grow(gap, len) == OK)
|
|
||||||
{
|
|
||||||
mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
|
|
||||||
gap->ga_len += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Concatenate 'len' bytes from string 's' to a growarray.
|
|
||||||
* When "s" is NULL does not do anything.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ga_concat_len(garray_T *gap, char_u *s, size_t len)
|
|
||||||
{
|
|
||||||
if (s == NULL || *s == NUL)
|
|
||||||
return;
|
|
||||||
if (ga_grow(gap, (int)len) == OK)
|
|
||||||
{
|
|
||||||
mch_memmove((char *)gap->ga_data + gap->ga_len, s, len);
|
|
||||||
gap->ga_len += (int)len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Append one byte to a growarray which contains bytes.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ga_append(garray_T *gap, int c)
|
|
||||||
{
|
|
||||||
if (ga_grow(gap, 1) == OK)
|
|
||||||
{
|
|
||||||
*((char *)gap->ga_data + gap->ga_len) = c;
|
|
||||||
++gap->ga_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(MSWIN) \
|
|
||||||
|| defined(PROTO)
|
|
||||||
/*
|
|
||||||
* Append the text in "gap" below the cursor line and clear "gap".
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
append_ga_line(garray_T *gap)
|
|
||||||
{
|
|
||||||
// Remove trailing CR.
|
|
||||||
if (gap->ga_len > 0
|
|
||||||
&& !curbuf->b_p_bin
|
|
||||||
&& ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
|
|
||||||
--gap->ga_len;
|
|
||||||
ga_append(gap, NUL);
|
|
||||||
ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
|
|
||||||
gap->ga_len = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* functions that use lookup tables for various things, generally to do with
|
* functions that use lookup tables for various things, generally to do with
|
||||||
* special key codes.
|
* special key codes.
|
||||||
@ -3282,6 +2425,15 @@ get_user_name(char_u *buf, int len)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the memory allocated by get_user_name()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
free_username(void)
|
||||||
|
{
|
||||||
|
vim_free(username);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_QSORT
|
#ifndef HAVE_QSORT
|
||||||
/*
|
/*
|
||||||
* Our own qsort(), for systems that don't have it.
|
* Our own qsort(), for systems that don't have it.
|
||||||
|
@ -58,6 +58,7 @@ extern int _stricoll(char *a, char *b);
|
|||||||
# include "crypt.pro"
|
# include "crypt.pro"
|
||||||
# include "crypt_zip.pro"
|
# include "crypt_zip.pro"
|
||||||
# endif
|
# endif
|
||||||
|
# include "alloc.pro"
|
||||||
# include "arglist.pro"
|
# include "arglist.pro"
|
||||||
# include "autocmd.pro"
|
# include "autocmd.pro"
|
||||||
# include "buffer.pro"
|
# include "buffer.pro"
|
||||||
|
29
src/proto/alloc.pro
Normal file
29
src/proto/alloc.pro
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/* alloc.c */
|
||||||
|
void vim_mem_profile_dump(void);
|
||||||
|
int alloc_does_fail(size_t size);
|
||||||
|
void *alloc(size_t size);
|
||||||
|
void *alloc_id(size_t size, alloc_id_T id);
|
||||||
|
void *alloc_clear(size_t size);
|
||||||
|
void *alloc_clear_id(size_t size, alloc_id_T id);
|
||||||
|
void *lalloc_clear(size_t size, int message);
|
||||||
|
void *lalloc(size_t size, int message);
|
||||||
|
void *lalloc_id(size_t size, int message, alloc_id_T id);
|
||||||
|
void *mem_realloc(void *ptr, size_t size);
|
||||||
|
void do_outofmem_msg(size_t size);
|
||||||
|
void free_all_mem(void);
|
||||||
|
char_u *vim_memsave(char_u *p, size_t len);
|
||||||
|
void vim_free(void *x);
|
||||||
|
void ga_clear(garray_T *gap);
|
||||||
|
void ga_clear_strings(garray_T *gap);
|
||||||
|
int ga_copy_strings(garray_T *from, garray_T *to);
|
||||||
|
void ga_init(garray_T *gap);
|
||||||
|
void ga_init2(garray_T *gap, int itemsize, int growsize);
|
||||||
|
int ga_grow(garray_T *gap, int n);
|
||||||
|
int ga_grow_inner(garray_T *gap, int n);
|
||||||
|
char_u *ga_concat_strings(garray_T *gap, char *sep);
|
||||||
|
int ga_add_string(garray_T *gap, char_u *p);
|
||||||
|
void ga_concat(garray_T *gap, char_u *s);
|
||||||
|
void ga_concat_len(garray_T *gap, char_u *s, size_t len);
|
||||||
|
void ga_append(garray_T *gap, int c);
|
||||||
|
void append_ga_line(garray_T *gap);
|
||||||
|
/* vim: set ft=c : */
|
@ -19,35 +19,8 @@ void check_cursor_col_win(win_T *win);
|
|||||||
void check_cursor(void);
|
void check_cursor(void);
|
||||||
void adjust_cursor_col(void);
|
void adjust_cursor_col(void);
|
||||||
int leftcol_changed(void);
|
int leftcol_changed(void);
|
||||||
void vim_mem_profile_dump(void);
|
|
||||||
int alloc_does_fail(size_t size);
|
|
||||||
void *alloc(size_t size);
|
|
||||||
void *alloc_id(size_t size, alloc_id_T id);
|
|
||||||
void *alloc_clear(size_t size);
|
|
||||||
void *alloc_clear_id(size_t size, alloc_id_T id);
|
|
||||||
void *lalloc_clear(size_t size, int message);
|
|
||||||
void *lalloc(size_t size, int message);
|
|
||||||
void *lalloc_id(size_t size, int message, alloc_id_T id);
|
|
||||||
void *mem_realloc(void *ptr, size_t size);
|
|
||||||
void do_outofmem_msg(size_t size);
|
|
||||||
void free_all_mem(void);
|
|
||||||
char_u *vim_memsave(char_u *p, size_t len);
|
|
||||||
int copy_option_part(char_u **option, char_u *buf, int maxlen, char *sep_chars);
|
int copy_option_part(char_u **option, char_u *buf, int maxlen, char *sep_chars);
|
||||||
void vim_free(void *x);
|
|
||||||
int vim_isspace(int x);
|
int vim_isspace(int x);
|
||||||
void ga_clear(garray_T *gap);
|
|
||||||
void ga_clear_strings(garray_T *gap);
|
|
||||||
int ga_copy_strings(garray_T *from, garray_T *to);
|
|
||||||
void ga_init(garray_T *gap);
|
|
||||||
void ga_init2(garray_T *gap, int itemsize, int growsize);
|
|
||||||
int ga_grow(garray_T *gap, int n);
|
|
||||||
int ga_grow_inner(garray_T *gap, int n);
|
|
||||||
char_u *ga_concat_strings(garray_T *gap, char *sep);
|
|
||||||
int ga_add_string(garray_T *gap, char_u *p);
|
|
||||||
void ga_concat(garray_T *gap, char_u *s);
|
|
||||||
void ga_concat_len(garray_T *gap, char_u *s, size_t len);
|
|
||||||
void ga_append(garray_T *gap, int c);
|
|
||||||
void append_ga_line(garray_T *gap);
|
|
||||||
int simplify_key(int key, int *modifiers);
|
int simplify_key(int key, int *modifiers);
|
||||||
int handle_x_keys(int key);
|
int handle_x_keys(int key);
|
||||||
char_u *get_special_key_name(int c, int modifiers);
|
char_u *get_special_key_name(int c, int modifiers);
|
||||||
@ -75,6 +48,7 @@ int get_shape_idx(int mouse);
|
|||||||
void update_mouseshape(int shape_idx);
|
void update_mouseshape(int shape_idx);
|
||||||
int vim_chdir(char_u *new_dir);
|
int vim_chdir(char_u *new_dir);
|
||||||
int get_user_name(char_u *buf, int len);
|
int get_user_name(char_u *buf, int len);
|
||||||
|
void free_username(void);
|
||||||
int filewritable(char_u *fname);
|
int filewritable(char_u *fname);
|
||||||
int get2c(FILE *fd);
|
int get2c(FILE *fd);
|
||||||
int get3c(FILE *fd);
|
int get3c(FILE *fd);
|
||||||
|
@ -755,6 +755,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
3301,
|
||||||
/**/
|
/**/
|
||||||
3300,
|
3300,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user