Patch 8.2.3301
Problem: Memory allocation functions don't have their own place.
Solution: Move memory allocation functions to alloc.c. (Yegappan
Lakshmanan, closes #8717)
Files: Filelist, src/Make_ami.mak, src/Make_cyg_ming.mak,
src/Make_mvc.mak, src/Make_vms.mms, src/Makefile, src/README.md,
src/alloc.c, src/misc2.c, src/proto.h, src/proto/
alloc.pro,
src/proto/
misc2.pro
*** ../vim-8.2.3300/Filelist 2021-07-10 21:28:55.323050112 +0200
--- Filelist 2021-08-06 21:45:45.293392385 +0200
***************
*** 23,28 ****
--- 23,29 ----
ci/setup-xvfb.sh \
src/Make_all.mak \
src/README.md \
+ src/alloc.c \
src/alloc.h \
src/arabic.c \
src/arglist.c \
***************
*** 210,215 ****
--- 211,217 ----
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 \
*** ../vim-8.2.3300/src/Make_ami.mak 2021-07-10 21:28:55.323050112 +0200
--- src/Make_ami.mak 2021-08-06 21:45:45.293392385 +0200
***************
*** 80,85 ****
--- 80,86 ----
# Common sources
SRC += \
+ alloc.c \
arabic.c \
arglist.c \
autocmd.c \
*** ../vim-8.2.3300/src/Make_cyg_ming.mak 2021-07-10 21:28:55.323050112 +0200
--- src/Make_cyg_ming.mak 2021-08-06 21:45:45.293392385 +0200
***************
*** 723,728 ****
--- 723,729 ----
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 \
*** ../vim-8.2.3300/src/Make_mvc.mak 2021-07-30 20:51:51.761101629 +0200
--- src/Make_mvc.mak 2021-08-06 21:45:45.293392385 +0200
***************
*** 733,738 ****
--- 733,739 ----
spell.h structs.h term.h beval.h $(NBDEBUG_INCL)
OBJ = \
+ $(OUTDIR)\alloc.obj \
$(OUTDIR)\arabic.obj \
$(OUTDIR)\arglist.obj \
$(OUTDIR)\autocmd.obj \
***************
*** 1542,1547 ****
--- 1543,1550 ----
.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,1937 ****
--- 1935,1941 ----
# End Custom Build
proto.h: \
+ proto/
alloc.pro \
proto/
arabic.pro \
proto/
arglist.pro \
proto/
autocmd.pro \
*** ../vim-8.2.3300/src/Make_vms.mms 2021-07-10 21:28:55.323050112 +0200
--- src/Make_vms.mms 2021-08-06 21:45:45.293392385 +0200
***************
*** 306,311 ****
--- 306,312 ----
$(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(RUBY_LIB) $(LUA_LIB)
SRC = \
+ alloc.c \
arabic.c \
arglist.c \
autocmd.c \
***************
*** 425,430 ****
--- 426,432 ----
$(XDIFF_SRC)
OBJ = \
+ alloc.obj \
arabic.obj \
arglist.obj \
autocmd.obj \
***************
*** 738,743 ****
--- 740,748 ----
-@ !
.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
*** ../vim-8.2.3300/src/Makefile 2021-07-10 21:28:55.323050112 +0200
--- src/Makefile 2021-08-06 21:45:45.293392385 +0200
***************
*** 1590,1595 ****
--- 1590,1596 ----
# ALL_SRC: source files used for make depend and make lint
BASIC_SRC = \
+ alloc.c \
arabic.c \
arglist.c \
autocmd.c \
***************
*** 1747,1752 ****
--- 1748,1754 ----
#LINT_SRC = $(BASIC_SRC)
OBJ_COMMON = \
+ objects/alloc.o \
objects/arabic.o \
objects/arglist.o \
objects/autocmd.o \
***************
*** 1917,1922 ****
--- 1919,1925 ----
PRO_AUTO = \
+
alloc.pro \
arabic.pro \
arglist.pro \
autocmd.pro \
***************
*** 3150,3155 ****
--- 3153,3161 ----
# time.
$(ALL_OBJ): objects/.dirstamp
+ objects/alloc.o: alloc.c
+ $(CCC) -o $@ alloc.c
+
objects/arabic.o: arabic.c
$(CCC) -o $@ arabic.c
***************
*** 3711,3716 ****
--- 3717,3726 ----
###############################################################################
### (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 \
*** ../vim-8.2.3300/src/README.md 2021-07-10 21:28:55.323050112 +0200
--- src/README.md 2021-08-06 21:45:45.293392385 +0200
***************
*** 23,28 ****
--- 23,29 ----
File name | Description
--------------- | -----------
+ alloc.c | memory management
arglist.c | handling argument list
autocmd.c | autocommands
blob.c | blob data type
*** ../vim-8.2.3300/src/alloc.c 2021-08-06 21:50:45.728793017 +0200
--- src/alloc.c 2021-08-06 21:45:45.293392385 +0200
***************
*** 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
+
*** ../vim-8.2.3300/src/misc2.c 2021-07-31 12:43:19.464837526 +0200
--- src/misc2.c 2021-08-06 21:45:45.293392385 +0200
***************
*** 693,1289 ****
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".
--- 693,698 ----
***************
*** 1325,1349 ****
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)
--- 734,739 ----
***************
*** 1367,1619 ****
}
/************************************************************************
- * 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.
*/
--- 757,762 ----
***************
*** 3282,3287 ****
--- 2425,2439 ----
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.
*** ../vim-8.2.3300/src/proto.h 2021-08-02 18:07:15.186473836 +0200
--- src/proto.h 2021-08-06 21:45:45.293392385 +0200
***************
*** 58,63 ****
--- 58,64 ----
# include "
crypt.pro"
# include "
crypt_zip.pro"
# endif
+ # include "
alloc.pro"
# include "
arglist.pro"
# include "
autocmd.pro"
# include "
buffer.pro"
*** ../vim-8.2.3300/src/proto/
alloc.pro 2021-08-06 21:50:45.744792984 +0200
--- src/proto/
alloc.pro 2021-08-06 21:47:27.585199367 +0200
***************
*** 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 : */
*** ../vim-8.2.3300/src/proto/
misc2.pro 2021-07-29 20:22:10.738009542 +0200
--- src/proto/
misc2.pro 2021-08-06 21:47:31.377191966 +0200
***************
*** 19,53 ****
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);
--- 19,26 ----
***************
*** 75,80 ****
--- 48,54 ----
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);
*** ../vim-8.2.3300/src/version.c 2021-08-06 21:34:34.630972197 +0200
--- src/version.c 2021-08-06 21:47:07.149238948 +0200
***************
*** 757,758 ****
--- 757,760 ----
{ /* Add new patch number below this line */
+ /**/
+ 3301,
/**/
--
A computer programmer is a device for turning requirements into
undocumented features. It runs on cola, pizza and Dilbert cartoons.
Bram Moolenaar
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///