]> granicus.if.org Git - vim/commitdiff
patch 8.2.3301: memory allocation functions don't have their own place v8.2.3301
authorYegappan Lakshmanan <yegappan@yahoo.com>
Fri, 6 Aug 2021 19:51:55 +0000 (21:51 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 6 Aug 2021 19:51:55 +0000 (21:51 +0200)
Problem:    Memory allocation functions don't have their own place.
Solution:   Move memory allocation functions to alloc.c.  (Yegappan
            Lakshmanan, closes #8717)

13 files changed:
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 [new file with mode: 0644]
src/misc2.c
src/proto.h
src/proto/alloc.pro [new file with mode: 0644]
src/proto/misc2.pro
src/version.c

index 8324ada6be1e6a12a35a7bf77406e8c21fd50318..8ff2feb43607d757fa2d49760d4ee6126d3ee76e 100644 (file)
--- 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 \
index 678f99994b946d0358032b7715aada1e434bdac2..12f7fe5571cc58a0879995f189e156074e83f06c 100644 (file)
@@ -80,6 +80,7 @@ endif
 
 # Common sources
 SRC += \
+       alloc.c \
        arabic.c \
        arglist.c \
        autocmd.c \
index f12ffac8e08ac84f9e1d72848181fc8060ca286d..1b881b5f48b1474cf4ddf2fe24231442545510e0 100644 (file)
@@ -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
 CUIOBJ = $(OUTDIR)/iscygpty.o
 OBJ = \
+       $(OUTDIR)/alloc.o \
        $(OUTDIR)/arabic.o \
        $(OUTDIR)/arglist.o \
        $(OUTDIR)/autocmd.o \
index 18b5a88c5f4529a07d6c6fc0e694a678aed685dc..5d725cc056d29ed57ac758f0c8b04b6442fa373e 100644 (file)
@@ -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)
 
 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 @@ $(PATHDEF_SRC): Make_mvc.mak
 
 # End Custom Build
 proto.h: \
+       proto/alloc.pro \
        proto/arabic.pro \
        proto/arglist.pro \
        proto/autocmd.pro \
index 3f65201c5035f0376024d58df48675a048b8d70b..9dde7616ee84272d88e4d8cee1a10365be542561 100644 (file)
@@ -306,6 +306,7 @@ ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) $(XPM_LIB)\
           $(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
index 6fa9d25c614e5952f155486c71e963135962ab06..4ac2634a5e9f5ec05abaa17f20b4653863c286a3 100644 (file)
@@ -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) install_haiku_extra
 ###############################################################################
 ### (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 \
index a3a23be2d6f64db8c7c3730d3ad51f3b0ac3bbb0..cefbecaef092acca1a95ddf07e7f6c6a32dbef0c 100644 (file)
@@ -23,6 +23,7 @@ Most code can be found in a file with an obvious name (incomplete list):
 
 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 (file)
index 0000000..817e322
--- /dev/null
@@ -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
+
index 2e83d2dd171aac243e37996695233ba8bf38f351..271014f7a3fec1521c4d7f1f1a281ae3bce8181f 100644 (file)
@@ -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)
@@ -1366,253 +756,6 @@ vim_isspace(int 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
  * 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.
index f639ad553b2ab13200a137237225b6c6324c6728..6c26aee38cc30779062f5e4511840f73fb7b923f 100644 (file)
@@ -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 (file)
index 0000000..2069ca8
--- /dev/null
@@ -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 : */
index a9e2b844c2fe9beea8232dfe1cec0462b3cf4914..e34202127ac91259841e8e3c197cbd4c8313162d 100644 (file)
@@ -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);
index 096fcf283d7a3711d590a794226df188840dc003..3f5a6f787f7f3459f946bb8a16f72d40800db4c9 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3301,
 /**/
     3300,
 /**/