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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202108061952.176JqOfT1661978%40masaka.moolenaar.net.

Raspunde prin e-mail lui