# HG changeset patch # User Bram Moolenaar # Date 1628280004 -7200 # Node ID bb10978996935cfbf1b316b9d7153e899fe1a2b9 # Parent 7407b745d43cc30c31cbfefed75abc281ab90039 patch 8.2.3301: memory allocation functions don't have their own place Commit: https://github.com/vim/vim/commit/cbae5802832b29f3a1af4cb6b0fc8cf69f17cbf4 Author: Yegappan Lakshmanan Date: Fri Aug 6 21:51:55 2021 +0200 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) diff --git a/Filelist b/Filelist --- a/Filelist +++ b/Filelist @@ -23,6 +23,7 @@ SRC_ALL = \ ci/setup-xvfb.sh \ src/Make_all.mak \ src/README.md \ + src/alloc.c \ src/alloc.h \ src/arabic.c \ src/arglist.c \ @@ -210,6 +211,7 @@ SRC_ALL = \ src/testdir/popupbounce.vim \ src/proto.h \ src/protodef.h \ + src/proto/alloc.pro \ src/proto/arabic.pro \ src/proto/arglist.pro \ src/proto/autocmd.pro \ diff --git a/src/Make_ami.mak b/src/Make_ami.mak --- a/src/Make_ami.mak +++ b/src/Make_ami.mak @@ -80,6 +80,7 @@ endif # Common sources SRC += \ + alloc.c \ arabic.c \ arglist.c \ autocmd.c \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -723,6 +723,7 @@ LIB = -lkernel32 -luser32 -lgdi32 -ladva GUIOBJ = $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o CUIOBJ = $(OUTDIR)/iscygpty.o OBJ = \ + $(OUTDIR)/alloc.o \ $(OUTDIR)/arabic.o \ $(OUTDIR)/arglist.o \ $(OUTDIR)/autocmd.o \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -733,6 +733,7 @@ INCL = vim.h alloc.h ascii.h ex_cmds.h f spell.h structs.h term.h beval.h $(NBDEBUG_INCL) OBJ = \ + $(OUTDIR)\alloc.obj \ $(OUTDIR)\arabic.obj \ $(OUTDIR)\arglist.obj \ $(OUTDIR)\autocmd.obj \ @@ -1542,6 +1543,8 @@ test_vim9: .cpp{$(OUTDIR)/}.obj:: $(CC) $(CFLAGS_OUTDIR) $< +$(OUTDIR)/alloc.obj: $(OUTDIR) alloc.c $(INCL) + $(OUTDIR)/arabic.obj: $(OUTDIR) arabic.c $(INCL) $(OUTDIR)/arglist.obj: $(OUTDIR) arglist.c $(INCL) @@ -1932,6 +1935,7 @@ E_LINKARGS2 = $(E000_LINKARGS2:>=^^>) # End Custom Build proto.h: \ + proto/alloc.pro \ proto/arabic.pro \ proto/arglist.pro \ proto/autocmd.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -306,6 +306,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_ $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) $(LUA_LIB) SRC = \ + alloc.c \ arabic.c \ arglist.c \ autocmd.c \ @@ -425,6 +426,7 @@ SRC = \ $(XDIFF_SRC) OBJ = \ + alloc.obj \ arabic.obj \ arglist.obj \ autocmd.obj \ @@ -738,6 +740,9 @@ lua_env : -@ ! .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 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 diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -1590,6 +1590,7 @@ include testdir/Make_all.mak # ALL_SRC: source files used for make depend and make lint BASIC_SRC = \ + alloc.c \ arabic.c \ arglist.c \ autocmd.c \ @@ -1747,6 +1748,7 @@ LINT_SRC = $(BASIC_SRC) $(GUI_SRC) \ #LINT_SRC = $(BASIC_SRC) OBJ_COMMON = \ + objects/alloc.o \ objects/arabic.o \ objects/arglist.o \ objects/autocmd.o \ @@ -1917,6 +1919,7 @@ ALL_OBJ = $(OBJ_COMMON) \ PRO_AUTO = \ + alloc.pro \ arabic.pro \ arglist.pro \ autocmd.pro \ @@ -3150,6 +3153,9 @@ objects/.dirstamp: # time. $(ALL_OBJ): objects/.dirstamp +objects/alloc.o: alloc.c + $(CCC) -o $@ alloc.c + objects/arabic.o: arabic.c $(CCC) -o $@ arabic.c @@ -3711,6 +3717,10 @@ installglinks_haiku: $(HAIKU_GLINKS) ins ############################################################################### ### (automatically generated by 'make depend') ### 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 \ 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 \ diff --git a/src/README.md b/src/README.md --- a/src/README.md +++ b/src/README.md @@ -23,6 +23,7 @@ Most code can be found in a file with an File name | Description --------------- | ----------- +alloc.c | memory management arglist.c | handling argument list autocmd.c | autocommands blob.c | blob data type diff --git a/src/alloc.c b/src/alloc.c new file mode 100644 --- /dev/null +++ b/src/alloc.c @@ -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 + diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -693,597 +693,6 @@ leftcol_changed(void) 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 * "sep_chars". @@ -1325,25 +734,6 @@ copy_option_part( 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 void * vim_memset(void *ptr, int c, size_t size) @@ -1367,253 +757,6 @@ vim_isspace(int 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 * special key codes. */ @@ -3282,6 +2425,15 @@ get_user_name(char_u *buf, int len) return OK; } +/* + * Free the memory allocated by get_user_name() + */ + void +free_username(void) +{ + vim_free(username); +} + #ifndef HAVE_QSORT /* * Our own qsort(), for systems that don't have it. diff --git a/src/proto.h b/src/proto.h --- a/src/proto.h +++ b/src/proto.h @@ -58,6 +58,7 @@ extern int _stricoll(char *a, char *b); # include "crypt.pro" # include "crypt_zip.pro" # endif +# include "alloc.pro" # include "arglist.pro" # include "autocmd.pro" # include "buffer.pro" diff --git a/src/proto/alloc.pro b/src/proto/alloc.pro new file mode 100644 --- /dev/null +++ b/src/proto/alloc.pro @@ -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 : */ diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro --- a/src/proto/misc2.pro +++ b/src/proto/misc2.pro @@ -19,35 +19,8 @@ void check_cursor_col_win(win_T *win); void check_cursor(void); void adjust_cursor_col(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); -void vim_free(void *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 handle_x_keys(int key); 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); int vim_chdir(char_u *new_dir); int get_user_name(char_u *buf, int len); +void free_username(void); int filewritable(char_u *fname); int get2c(FILE *fd); int get3c(FILE *fd); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3301, +/**/ 3300, /**/ 3299,