blob: 5f39085bce258d1011c7a7ddf61826830fcae8b5 [file] [log] [blame]
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * alloc.c: functions for memory management
12 */
13
14#include "vim.h"
15
16/**********************************************************************
17 * Various routines dealing with allocation and deallocation of memory.
18 */
19
20#if defined(MEM_PROFILE) || defined(PROTO)
21
22# define MEM_SIZES 8200
23static long_u mem_allocs[MEM_SIZES];
24static long_u mem_frees[MEM_SIZES];
25static long_u mem_allocated;
26static long_u mem_freed;
27static long_u mem_peak;
28static long_u num_alloc;
29static long_u num_freed;
30
31 static void
32mem_pre_alloc_s(size_t *sizep)
33{
34 *sizep += sizeof(size_t);
35}
36
37 static void
38mem_pre_alloc_l(size_t *sizep)
39{
40 *sizep += sizeof(size_t);
41}
42
43 static void
44mem_post_alloc(
45 void **pp,
46 size_t size)
47{
48 if (*pp == NULL)
49 return;
50 size -= sizeof(size_t);
51 *(long_u *)*pp = size;
52 if (size <= MEM_SIZES-1)
53 mem_allocs[size-1]++;
54 else
55 mem_allocs[MEM_SIZES-1]++;
56 mem_allocated += size;
57 if (mem_allocated - mem_freed > mem_peak)
58 mem_peak = mem_allocated - mem_freed;
59 num_alloc++;
60 *pp = (void *)((char *)*pp + sizeof(size_t));
61}
62
63 static void
64mem_pre_free(void **pp)
65{
66 long_u size;
67
68 *pp = (void *)((char *)*pp - sizeof(size_t));
69 size = *(size_t *)*pp;
70 if (size <= MEM_SIZES-1)
71 mem_frees[size-1]++;
72 else
73 mem_frees[MEM_SIZES-1]++;
74 mem_freed += size;
75 num_freed++;
76}
77
78/*
79 * called on exit via atexit()
80 */
81 void
82vim_mem_profile_dump(void)
83{
84 int i, j;
85
86 printf("\r\n");
87 j = 0;
88 for (i = 0; i < MEM_SIZES - 1; i++)
89 {
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +010090 if (mem_allocs[i] == 0 && mem_frees[i] == 0)
91 continue;
92
93 if (mem_frees[i] > mem_allocs[i])
94 printf("\r\n%s", _("ERROR: "));
95 printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]);
96 j++;
97 if (j > 3)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +020098 {
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +010099 j = 0;
100 printf("\r\n");
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200101 }
102 }
103
104 i = MEM_SIZES - 1;
105 if (mem_allocs[i])
106 {
107 printf("\r\n");
108 if (mem_frees[i] > mem_allocs[i])
109 puts(_("ERROR: "));
110 printf("[>%d / %4lu-%-4lu]", i, mem_allocs[i], mem_frees[i]);
111 }
112
113 printf(_("\n[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n"),
114 mem_allocated, mem_freed, mem_allocated - mem_freed, mem_peak);
115 printf(_("[calls] total re/malloc()'s %lu, total free()'s %lu\n\n"),
116 num_alloc, num_freed);
117}
118
119#endif // MEM_PROFILE
120
121#ifdef FEAT_EVAL
122 int
123alloc_does_fail(size_t size)
124{
125 if (alloc_fail_countdown == 0)
126 {
127 if (--alloc_fail_repeat <= 0)
128 alloc_fail_id = 0;
129 do_outofmem_msg(size);
130 return TRUE;
131 }
132 --alloc_fail_countdown;
133 return FALSE;
134}
135#endif
136
137/*
138 * Some memory is reserved for error messages and for being able to
139 * call mf_release_all(), which needs some memory for mf_trans_add().
140 */
141#define KEEP_ROOM (2 * 8192L)
142#define KEEP_ROOM_KB (KEEP_ROOM / 1024L)
143
144/*
145 * The normal way to allocate memory. This handles an out-of-memory situation
146 * as well as possible, still returns NULL when we're completely out.
147 */
148 void *
149alloc(size_t size)
150{
151 return lalloc(size, TRUE);
152}
153
Dominique Pelle748b3082022-01-08 12:41:16 +0000154#if defined(FEAT_QUICKFIX) || defined(PROTO)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200155/*
156 * alloc() with an ID for alloc_fail().
157 */
158 void *
159alloc_id(size_t size, alloc_id_T id UNUSED)
160{
Bram Moolenaarf80f40a2022-08-25 16:02:23 +0100161# ifdef FEAT_EVAL
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200162 if (alloc_fail_id == id && alloc_does_fail(size))
163 return NULL;
Bram Moolenaarf80f40a2022-08-25 16:02:23 +0100164# endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200165 return lalloc(size, TRUE);
166}
Dominique Pelle748b3082022-01-08 12:41:16 +0000167#endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200168
169/*
170 * Allocate memory and set all bytes to zero.
171 */
172 void *
173alloc_clear(size_t size)
174{
175 void *p;
176
177 p = lalloc(size, TRUE);
178 if (p != NULL)
179 (void)vim_memset(p, 0, size);
180 return p;
181}
182
183/*
184 * Same as alloc_clear() but with allocation id for testing
185 */
186 void *
187alloc_clear_id(size_t size, alloc_id_T id UNUSED)
188{
189#ifdef FEAT_EVAL
190 if (alloc_fail_id == id && alloc_does_fail(size))
191 return NULL;
192#endif
193 return alloc_clear(size);
194}
195
196/*
197 * Allocate memory like lalloc() and set all bytes to zero.
198 */
199 void *
200lalloc_clear(size_t size, int message)
201{
202 void *p;
203
204 p = lalloc(size, message);
205 if (p != NULL)
206 (void)vim_memset(p, 0, size);
207 return p;
208}
209
210/*
211 * Low level memory allocation function.
212 * This is used often, KEEP IT FAST!
213 */
214 void *
215lalloc(size_t size, int message)
216{
217 void *p; // pointer to new storage space
218 static int releasing = FALSE; // don't do mf_release_all() recursive
219 int try_again;
220#if defined(HAVE_AVAIL_MEM)
221 static size_t allocated = 0; // allocated since last avail check
222#endif
223
224 // Safety check for allocating zero bytes
225 if (size == 0)
226 {
227 // Don't hide this message
228 emsg_silent = 0;
RestorerZ68ebcee2023-05-31 17:12:14 +0100229 iemsg(e_internal_error_lalloc_zero);
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200230 return NULL;
231 }
232
233#ifdef MEM_PROFILE
234 mem_pre_alloc_l(&size);
235#endif
236
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200237 // Loop when out of memory: Try to release some memfile blocks and
238 // if some blocks are released call malloc again.
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200239 for (;;)
240 {
Dominique Pelleaf4a61a2021-12-27 17:21:41 +0000241 // Handle three kinds of systems:
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200242 // 1. No check for available memory: Just return.
243 // 2. Slow check for available memory: call mch_avail_mem() after
244 // allocating KEEP_ROOM amount of memory.
245 // 3. Strict check for available memory: call mch_avail_mem()
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200246 if ((p = malloc(size)) != NULL)
247 {
248#ifndef HAVE_AVAIL_MEM
249 // 1. No check for available memory: Just return.
250 goto theend;
251#else
252 // 2. Slow check for available memory: call mch_avail_mem() after
253 // allocating (KEEP_ROOM / 2) amount of memory.
254 allocated += size;
255 if (allocated < KEEP_ROOM / 2)
256 goto theend;
257 allocated = 0;
258
259 // 3. check for available memory: call mch_avail_mem()
260 if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing)
261 {
262 free(p); // System is low... no go!
263 p = NULL;
264 }
265 else
266 goto theend;
267#endif
268 }
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200269 // Remember that mf_release_all() is being called to avoid an endless
270 // loop, because mf_release_all() may call alloc() recursively.
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200271 if (releasing)
272 break;
273 releasing = TRUE;
274
275 clear_sb_text(TRUE); // free any scrollback text
276 try_again = mf_release_all(); // release as many blocks as possible
277
278 releasing = FALSE;
279 if (!try_again)
280 break;
281 }
282
283 if (message && p == NULL)
284 do_outofmem_msg(size);
285
286theend:
287#ifdef MEM_PROFILE
288 mem_post_alloc(&p, size);
289#endif
290 return p;
291}
292
293/*
294 * lalloc() with an ID for alloc_fail().
295 */
296#if defined(FEAT_SIGNS) || defined(PROTO)
297 void *
298lalloc_id(size_t size, int message, alloc_id_T id UNUSED)
299{
300#ifdef FEAT_EVAL
301 if (alloc_fail_id == id && alloc_does_fail(size))
302 return NULL;
303#endif
304 return (lalloc(size, message));
305}
306#endif
307
308#if defined(MEM_PROFILE) || defined(PROTO)
309/*
310 * realloc() with memory profiling.
311 */
312 void *
313mem_realloc(void *ptr, size_t size)
314{
315 void *p;
316
317 mem_pre_free(&ptr);
318 mem_pre_alloc_s(&size);
319
320 p = realloc(ptr, size);
321
322 mem_post_alloc(&p, size);
323
324 return p;
325}
326#endif
327
328/*
329* Avoid repeating the error message many times (they take 1 second each).
330* Did_outofmem_msg is reset when a character is read.
331*/
332 void
333do_outofmem_msg(size_t size)
334{
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100335 if (did_outofmem_msg)
336 return;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200337
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100338 // Don't hide this message
339 emsg_silent = 0;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200340
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100341 // Must come first to avoid coming back here when printing the error
342 // message fails, e.g. when setting v:errmsg.
343 did_outofmem_msg = TRUE;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200344
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100345 semsg(_(e_out_of_memory_allocating_nr_bytes), (long_u)size);
346
347 if (starting == NO_SCREEN)
348 // Not even finished with initializations and already out of
349 // memory? Then nothing is going to work, exit.
350 mch_exit(123);
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200351}
352
353#if defined(EXITFREE) || defined(PROTO)
354
355/*
356 * Free everything that we allocated.
357 * Can be used to detect memory leaks, e.g., with ccmalloc.
358 * NOTE: This is tricky! Things are freed that functions depend on. Don't be
359 * surprised if Vim crashes...
360 * Some things can't be freed, esp. things local to a library function.
361 */
362 void
363free_all_mem(void)
364{
365 buf_T *buf, *nextbuf;
366
367 // When we cause a crash here it is caught and Vim tries to exit cleanly.
368 // Don't try freeing everything again.
369 if (entered_free_all_mem)
370 return;
371 entered_free_all_mem = TRUE;
372 // Don't want to trigger autocommands from here on.
373 block_autocmds();
374
375 // Close all tabs and windows. Reset 'equalalways' to avoid redraws.
376 p_ea = FALSE;
377 if (first_tabpage != NULL && first_tabpage->tp_next != NULL)
378 do_cmdline_cmd((char_u *)"tabonly!");
379 if (!ONE_WINDOW)
380 do_cmdline_cmd((char_u *)"only!");
381
382# if defined(FEAT_SPELL)
383 // Free all spell info.
384 spell_free_all();
385# endif
386
387# if defined(FEAT_BEVAL_TERM)
388 ui_remove_balloon();
389# endif
390# ifdef FEAT_PROP_POPUP
391 if (curwin != NULL)
392 close_all_popups(TRUE);
393# endif
394
395 // Clear user commands (before deleting buffers).
396 ex_comclear(NULL);
397
398 // When exiting from mainerr_arg_missing curbuf has not been initialized,
399 // and not much else.
400 if (curbuf != NULL)
401 {
402# ifdef FEAT_MENU
403 // Clear menus.
404 do_cmdline_cmd((char_u *)"aunmenu *");
zeertzjq79ae1522022-07-01 12:13:15 +0100405 do_cmdline_cmd((char_u *)"tlunmenu *");
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200406# ifdef FEAT_MULTI_LANG
407 do_cmdline_cmd((char_u *)"menutranslate clear");
408# endif
409# endif
410 // Clear mappings, abbreviations, breakpoints.
411 do_cmdline_cmd((char_u *)"lmapclear");
412 do_cmdline_cmd((char_u *)"xmapclear");
413 do_cmdline_cmd((char_u *)"mapclear");
414 do_cmdline_cmd((char_u *)"mapclear!");
415 do_cmdline_cmd((char_u *)"abclear");
416# if defined(FEAT_EVAL)
417 do_cmdline_cmd((char_u *)"breakdel *");
418# endif
419# if defined(FEAT_PROFILE)
420 do_cmdline_cmd((char_u *)"profdel *");
421# endif
422# if defined(FEAT_KEYMAP)
423 do_cmdline_cmd((char_u *)"set keymap=");
424# endif
425 }
426
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200427 free_titles();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200428 free_findfile();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200429
430 // Obviously named calls.
431 free_all_autocmds();
432 clear_termcodes();
433 free_all_marks();
434 alist_clear(&global_alist);
435 free_homedir();
436 free_users();
437 free_search_patterns();
438 free_old_sub();
439 free_last_insert();
440 free_insexpand_stuff();
441 free_prev_shellcmd();
442 free_regexp_stuff();
443 free_tag_stuff();
Yegappan Lakshmanan7645da52021-12-04 14:02:30 +0000444 free_xim_stuff();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200445 free_cd_dir();
446# ifdef FEAT_SIGNS
447 free_signs();
448# endif
449# ifdef FEAT_EVAL
450 set_expr_line(NULL, NULL);
451# endif
452# ifdef FEAT_DIFF
453 if (curtab != NULL)
454 diff_clear(curtab);
455# endif
456 clear_sb_text(TRUE); // free any scrollback text
457
458 // Free some global vars.
459 free_username();
460# ifdef FEAT_CLIPBOARD
461 vim_regfree(clip_exclude_prog);
462# endif
463 vim_free(last_cmdline);
464 vim_free(new_last_cmdline);
465 set_keep_msg(NULL, 0);
466
467 // Clear cmdline history.
468 p_hi = 0;
469 init_history();
470# ifdef FEAT_PROP_POPUP
471 clear_global_prop_types();
472# endif
473
474# ifdef FEAT_QUICKFIX
Yegappan Lakshmanan975a6652022-10-14 13:11:13 +0100475 free_quickfix();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200476# endif
477
478 // Close all script inputs.
479 close_all_scripts();
480
481 if (curwin != NULL)
482 // Destroy all windows. Must come before freeing buffers.
483 win_free_all();
484
485 // Free all option values. Must come after closing windows.
486 free_all_options();
487
488 // Free all buffers. Reset 'autochdir' to avoid accessing things that
489 // were freed already.
490# ifdef FEAT_AUTOCHDIR
491 p_acd = FALSE;
492# endif
493 for (buf = firstbuf; buf != NULL; )
494 {
495 bufref_T bufref;
496
497 set_bufref(&bufref, buf);
498 nextbuf = buf->b_next;
499 close_buffer(NULL, buf, DOBUF_WIPE, FALSE, FALSE);
500 if (bufref_valid(&bufref))
501 buf = nextbuf; // didn't work, try next one
502 else
503 buf = firstbuf;
504 }
505
506# ifdef FEAT_ARABIC
507 free_arshape_buf();
508# endif
509
510 // Clear registers.
511 clear_registers();
512 ResetRedobuff();
513 ResetRedobuff();
514
515# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
516 vim_free(serverDelayedStartName);
517# endif
518
519 // highlight info
520 free_highlight();
521
522 reset_last_sourcing();
523
524 if (first_tabpage != NULL)
525 {
526 free_tabpage(first_tabpage);
527 first_tabpage = NULL;
528 }
529
530# ifdef UNIX
531 // Machine-specific free.
532 mch_free_mem();
533# endif
534
535 // message history
536 for (;;)
537 if (delete_first_msg() == FAIL)
538 break;
539
540# ifdef FEAT_JOB_CHANNEL
541 channel_free_all();
542# endif
543# ifdef FEAT_TIMERS
544 timer_free_all();
545# endif
546# ifdef FEAT_EVAL
547 // must be after channel_free_all() with unrefs partials
548 eval_clear();
549# endif
550# ifdef FEAT_JOB_CHANNEL
551 // must be after eval_clear() with unrefs jobs
552 job_free_all();
553# endif
554
555 free_termoptions();
Bram Moolenaarb3a29552021-11-19 11:28:04 +0000556 free_cur_term();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200557
558 // screenlines (can't display anything now!)
559 free_screenlines();
560
561# if defined(FEAT_SOUND)
562 sound_free();
563# endif
564# if defined(USE_XSMP)
565 xsmp_close();
566# endif
567# ifdef FEAT_GUI_GTK
568 gui_mch_free_all();
569# endif
Bram Moolenaarc7269f82021-12-05 11:36:23 +0000570# ifdef FEAT_TCL
571 vim_tcl_finalize();
572# endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200573 clear_hl_tables();
574
575 vim_free(IObuff);
576 vim_free(NameBuff);
577# ifdef FEAT_QUICKFIX
578 check_quickfix_busy();
579# endif
Bram Moolenaar44ddf192022-06-21 22:15:25 +0100580# ifdef FEAT_EVAL
581 free_resub_eval_result();
582# endif
K.Takata3c240f62023-05-31 12:47:45 +0100583 free_vbuf();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200584}
585#endif
586
587/*
588 * Copy "p[len]" into allocated memory, ignoring NUL characters.
589 * Returns NULL when out of memory.
590 */
591 char_u *
592vim_memsave(char_u *p, size_t len)
593{
594 char_u *ret = alloc(len);
595
596 if (ret != NULL)
597 mch_memmove(ret, p, len);
598 return ret;
599}
600
601/*
602 * Replacement for free() that ignores NULL pointers.
603 * Also skip free() when exiting for sure, this helps when we caught a deadly
604 * signal that was caused by a crash in free().
605 * If you want to set NULL after calling this function, you should use
606 * VIM_CLEAR() instead.
607 */
608 void
609vim_free(void *x)
610{
611 if (x != NULL && !really_exiting)
612 {
613#ifdef MEM_PROFILE
614 mem_pre_free(&x);
615#endif
616 free(x);
617 }
618}
619
620/************************************************************************
621 * Functions for handling growing arrays.
622 */
623
624/*
625 * Clear an allocated growing array.
626 */
627 void
628ga_clear(garray_T *gap)
629{
630 vim_free(gap->ga_data);
631 ga_init(gap);
632}
633
634/*
635 * Clear a growing array that contains a list of strings.
636 */
637 void
638ga_clear_strings(garray_T *gap)
639{
640 int i;
641
642 if (gap->ga_data != NULL)
643 for (i = 0; i < gap->ga_len; ++i)
644 vim_free(((char_u **)(gap->ga_data))[i]);
645 ga_clear(gap);
646}
647
Dominique Pelle748b3082022-01-08 12:41:16 +0000648#if defined(FEAT_EVAL) || defined(PROTO)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200649/*
650 * Copy a growing array that contains a list of strings.
651 */
652 int
653ga_copy_strings(garray_T *from, garray_T *to)
654{
655 int i;
656
657 ga_init2(to, sizeof(char_u *), 1);
658 if (ga_grow(to, from->ga_len) == FAIL)
659 return FAIL;
660
661 for (i = 0; i < from->ga_len; ++i)
662 {
663 char_u *orig = ((char_u **)from->ga_data)[i];
664 char_u *copy;
665
666 if (orig == NULL)
667 copy = NULL;
668 else
669 {
670 copy = vim_strsave(orig);
671 if (copy == NULL)
672 {
673 to->ga_len = i;
674 ga_clear_strings(to);
675 return FAIL;
676 }
677 }
678 ((char_u **)to->ga_data)[i] = copy;
679 }
680 to->ga_len = from->ga_len;
681 return OK;
682}
Dominique Pelle748b3082022-01-08 12:41:16 +0000683#endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200684
685/*
686 * Initialize a growing array. Don't forget to set ga_itemsize and
687 * ga_growsize! Or use ga_init2().
688 */
689 void
690ga_init(garray_T *gap)
691{
692 gap->ga_data = NULL;
693 gap->ga_maxlen = 0;
694 gap->ga_len = 0;
695}
696
697 void
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000698ga_init2(garray_T *gap, size_t itemsize, int growsize)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200699{
700 ga_init(gap);
K.Takata1a804522022-01-26 16:45:20 +0000701 gap->ga_itemsize = (int)itemsize;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200702 gap->ga_growsize = growsize;
703}
704
705/*
706 * Make room in growing array "gap" for at least "n" items.
707 * Return FAIL for failure, OK otherwise.
708 */
709 int
710ga_grow(garray_T *gap, int n)
711{
712 if (gap->ga_maxlen - gap->ga_len < n)
713 return ga_grow_inner(gap, n);
714 return OK;
715}
716
Yegappan Lakshmanan7c7e19c2022-04-09 11:09:07 +0100717/*
718 * Same as ga_grow() but uses an allocation id for testing.
719 */
720 int
721ga_grow_id(garray_T *gap, int n, alloc_id_T id UNUSED)
722{
723#ifdef FEAT_EVAL
724 if (alloc_fail_id == id && alloc_does_fail(sizeof(list_T)))
725 return FAIL;
726#endif
727
728 return ga_grow(gap, n);
729}
730
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200731 int
732ga_grow_inner(garray_T *gap, int n)
733{
734 size_t old_len;
735 size_t new_len;
736 char_u *pp;
737
738 if (n < gap->ga_growsize)
739 n = gap->ga_growsize;
740
741 // A linear growth is very inefficient when the array grows big. This
742 // is a compromise between allocating memory that won't be used and too
743 // many copy operations. A factor of 1.5 seems reasonable.
744 if (n < gap->ga_len / 2)
745 n = gap->ga_len / 2;
746
=?UTF-8?q?Dundar=20G=C3=B6c?=d5cec1f2022-01-29 15:19:23 +0000747 new_len = (size_t)gap->ga_itemsize * (gap->ga_len + n);
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200748 pp = vim_realloc(gap->ga_data, new_len);
749 if (pp == NULL)
750 return FAIL;
=?UTF-8?q?Dundar=20G=C3=B6c?=d5cec1f2022-01-29 15:19:23 +0000751 old_len = (size_t)gap->ga_itemsize * gap->ga_maxlen;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200752 vim_memset(pp + old_len, 0, new_len - old_len);
753 gap->ga_maxlen = gap->ga_len + n;
754 gap->ga_data = pp;
755 return OK;
756}
757
758/*
759 * For a growing array that contains a list of strings: concatenate all the
760 * strings with a separating "sep".
761 * Returns NULL when out of memory.
762 */
763 char_u *
764ga_concat_strings(garray_T *gap, char *sep)
765{
766 int i;
767 int len = 0;
768 int sep_len = (int)STRLEN(sep);
769 char_u *s;
770 char_u *p;
771
772 for (i = 0; i < gap->ga_len; ++i)
773 len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len;
774
775 s = alloc(len + 1);
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100776 if (s == NULL)
777 return NULL;
778
779 *s = NUL;
780 p = s;
781 for (i = 0; i < gap->ga_len; ++i)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200782 {
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100783 if (p != s)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200784 {
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100785 STRCPY(p, sep);
786 p += sep_len;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200787 }
Yegappan Lakshmananb1f471e2022-09-05 14:33:47 +0100788 STRCPY(p, ((char_u **)(gap->ga_data))[i]);
789 p += STRLEN(p);
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200790 }
791 return s;
792}
793
794/*
795 * Make a copy of string "p" and add it to "gap".
796 * When out of memory nothing changes and FAIL is returned.
797 */
798 int
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000799ga_copy_string(garray_T *gap, char_u *p)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200800{
801 char_u *cp = vim_strsave(p);
802
803 if (cp == NULL)
804 return FAIL;
805
806 if (ga_grow(gap, 1) == FAIL)
807 {
808 vim_free(cp);
809 return FAIL;
810 }
811 ((char_u **)(gap->ga_data))[gap->ga_len++] = cp;
812 return OK;
813}
814
815/*
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000816 * Add string "p" to "gap".
Bram Moolenaar94674f22023-01-06 18:42:20 +0000817 * When out of memory FAIL is returned (caller may want to free "p").
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000818 */
819 int
820ga_add_string(garray_T *gap, char_u *p)
821{
822 if (ga_grow(gap, 1) == FAIL)
823 return FAIL;
824 ((char_u **)(gap->ga_data))[gap->ga_len++] = p;
825 return OK;
826}
827
828/*
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200829 * Concatenate a string to a growarray which contains bytes.
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100830 * When "s" is NULL memory allocation fails does not do anything.
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200831 * Note: Does NOT copy the NUL at the end!
832 */
833 void
834ga_concat(garray_T *gap, char_u *s)
835{
836 int len;
837
838 if (s == NULL || *s == NUL)
839 return;
840 len = (int)STRLEN(s);
841 if (ga_grow(gap, len) == OK)
842 {
843 mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
844 gap->ga_len += len;
845 }
846}
847
848/*
849 * Concatenate 'len' bytes from string 's' to a growarray.
850 * When "s" is NULL does not do anything.
851 */
852 void
853ga_concat_len(garray_T *gap, char_u *s, size_t len)
854{
Yegappan Lakshmanan36a5b682022-03-19 12:56:51 +0000855 if (s == NULL || *s == NUL || len == 0)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200856 return;
857 if (ga_grow(gap, (int)len) == OK)
858 {
859 mch_memmove((char *)gap->ga_data + gap->ga_len, s, len);
860 gap->ga_len += (int)len;
861 }
862}
863
864/*
865 * Append one byte to a growarray which contains bytes.
866 */
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100867 int
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200868ga_append(garray_T *gap, int c)
869{
Bram Moolenaar0abc2872022-05-10 13:24:30 +0100870 if (ga_grow(gap, 1) == FAIL)
871 return FAIL;
872 *((char *)gap->ga_data + gap->ga_len) = c;
873 ++gap->ga_len;
874 return OK;
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200875}
876
877#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(MSWIN) \
878 || defined(PROTO)
879/*
880 * Append the text in "gap" below the cursor line and clear "gap".
881 */
882 void
883append_ga_line(garray_T *gap)
884{
885 // Remove trailing CR.
886 if (gap->ga_len > 0
887 && !curbuf->b_p_bin
888 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
889 --gap->ga_len;
890 ga_append(gap, NUL);
891 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
892 gap->ga_len = 0;
893}
894#endif
895