blob: e3cd8578f6efcfbaca1b812ac3090a3a883a044e [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 {
90 if (mem_allocs[i] || mem_frees[i])
91 {
92 if (mem_frees[i] > mem_allocs[i])
93 printf("\r\n%s", _("ERROR: "));
94 printf("[%4d / %4lu-%-4lu] ", i + 1, mem_allocs[i], mem_frees[i]);
95 j++;
96 if (j > 3)
97 {
98 j = 0;
99 printf("\r\n");
100 }
101 }
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{
161#ifdef FEAT_EVAL
162 if (alloc_fail_id == id && alloc_does_fail(size))
163 return NULL;
164#endif
165 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
Dominique Pelle748b3082022-01-08 12:41:16 +0000183#if defined(FEAT_SIGNS) || defined(PROTO)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200184/*
185 * Same as alloc_clear() but with allocation id for testing
186 */
187 void *
188alloc_clear_id(size_t size, alloc_id_T id UNUSED)
189{
190#ifdef FEAT_EVAL
191 if (alloc_fail_id == id && alloc_does_fail(size))
192 return NULL;
193#endif
194 return alloc_clear(size);
195}
Dominique Pelle748b3082022-01-08 12:41:16 +0000196#endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200197
198/*
199 * Allocate memory like lalloc() and set all bytes to zero.
200 */
201 void *
202lalloc_clear(size_t size, int message)
203{
204 void *p;
205
206 p = lalloc(size, message);
207 if (p != NULL)
208 (void)vim_memset(p, 0, size);
209 return p;
210}
211
212/*
213 * Low level memory allocation function.
214 * This is used often, KEEP IT FAST!
215 */
216 void *
217lalloc(size_t size, int message)
218{
219 void *p; // pointer to new storage space
220 static int releasing = FALSE; // don't do mf_release_all() recursive
221 int try_again;
222#if defined(HAVE_AVAIL_MEM)
223 static size_t allocated = 0; // allocated since last avail check
224#endif
225
226 // Safety check for allocating zero bytes
227 if (size == 0)
228 {
229 // Don't hide this message
230 emsg_silent = 0;
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000231 iemsg(_(e_internal_error_lalloc_zero));
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200232 return NULL;
233 }
234
235#ifdef MEM_PROFILE
236 mem_pre_alloc_l(&size);
237#endif
238
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200239 // Loop when out of memory: Try to release some memfile blocks and
240 // if some blocks are released call malloc again.
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200241 for (;;)
242 {
Dominique Pelleaf4a61a2021-12-27 17:21:41 +0000243 // Handle three kinds of systems:
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200244 // 1. No check for available memory: Just return.
245 // 2. Slow check for available memory: call mch_avail_mem() after
246 // allocating KEEP_ROOM amount of memory.
247 // 3. Strict check for available memory: call mch_avail_mem()
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200248 if ((p = malloc(size)) != NULL)
249 {
250#ifndef HAVE_AVAIL_MEM
251 // 1. No check for available memory: Just return.
252 goto theend;
253#else
254 // 2. Slow check for available memory: call mch_avail_mem() after
255 // allocating (KEEP_ROOM / 2) amount of memory.
256 allocated += size;
257 if (allocated < KEEP_ROOM / 2)
258 goto theend;
259 allocated = 0;
260
261 // 3. check for available memory: call mch_avail_mem()
262 if (mch_avail_mem(TRUE) < KEEP_ROOM_KB && !releasing)
263 {
264 free(p); // System is low... no go!
265 p = NULL;
266 }
267 else
268 goto theend;
269#endif
270 }
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200271 // Remember that mf_release_all() is being called to avoid an endless
272 // loop, because mf_release_all() may call alloc() recursively.
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200273 if (releasing)
274 break;
275 releasing = TRUE;
276
277 clear_sb_text(TRUE); // free any scrollback text
278 try_again = mf_release_all(); // release as many blocks as possible
279
280 releasing = FALSE;
281 if (!try_again)
282 break;
283 }
284
285 if (message && p == NULL)
286 do_outofmem_msg(size);
287
288theend:
289#ifdef MEM_PROFILE
290 mem_post_alloc(&p, size);
291#endif
292 return p;
293}
294
295/*
296 * lalloc() with an ID for alloc_fail().
297 */
298#if defined(FEAT_SIGNS) || defined(PROTO)
299 void *
300lalloc_id(size_t size, int message, alloc_id_T id UNUSED)
301{
302#ifdef FEAT_EVAL
303 if (alloc_fail_id == id && alloc_does_fail(size))
304 return NULL;
305#endif
306 return (lalloc(size, message));
307}
308#endif
309
310#if defined(MEM_PROFILE) || defined(PROTO)
311/*
312 * realloc() with memory profiling.
313 */
314 void *
315mem_realloc(void *ptr, size_t size)
316{
317 void *p;
318
319 mem_pre_free(&ptr);
320 mem_pre_alloc_s(&size);
321
322 p = realloc(ptr, size);
323
324 mem_post_alloc(&p, size);
325
326 return p;
327}
328#endif
329
330/*
331* Avoid repeating the error message many times (they take 1 second each).
332* Did_outofmem_msg is reset when a character is read.
333*/
334 void
335do_outofmem_msg(size_t size)
336{
337 if (!did_outofmem_msg)
338 {
339 // Don't hide this message
340 emsg_silent = 0;
341
342 // Must come first to avoid coming back here when printing the error
343 // message fails, e.g. when setting v:errmsg.
344 did_outofmem_msg = TRUE;
345
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000346 semsg(_(e_out_of_memory_allocating_nr_bytes), (long_u)size);
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200347
348 if (starting == NO_SCREEN)
349 // Not even finished with initializations and already out of
350 // memory? Then nothing is going to work, exit.
351 mch_exit(123);
352 }
353}
354
355#if defined(EXITFREE) || defined(PROTO)
356
357/*
358 * Free everything that we allocated.
359 * Can be used to detect memory leaks, e.g., with ccmalloc.
360 * NOTE: This is tricky! Things are freed that functions depend on. Don't be
361 * surprised if Vim crashes...
362 * Some things can't be freed, esp. things local to a library function.
363 */
364 void
365free_all_mem(void)
366{
367 buf_T *buf, *nextbuf;
368
369 // When we cause a crash here it is caught and Vim tries to exit cleanly.
370 // Don't try freeing everything again.
371 if (entered_free_all_mem)
372 return;
373 entered_free_all_mem = TRUE;
374 // Don't want to trigger autocommands from here on.
375 block_autocmds();
376
377 // Close all tabs and windows. Reset 'equalalways' to avoid redraws.
378 p_ea = FALSE;
379 if (first_tabpage != NULL && first_tabpage->tp_next != NULL)
380 do_cmdline_cmd((char_u *)"tabonly!");
381 if (!ONE_WINDOW)
382 do_cmdline_cmd((char_u *)"only!");
383
384# if defined(FEAT_SPELL)
385 // Free all spell info.
386 spell_free_all();
387# endif
388
389# if defined(FEAT_BEVAL_TERM)
390 ui_remove_balloon();
391# endif
392# ifdef FEAT_PROP_POPUP
393 if (curwin != NULL)
394 close_all_popups(TRUE);
395# endif
396
397 // Clear user commands (before deleting buffers).
398 ex_comclear(NULL);
399
400 // When exiting from mainerr_arg_missing curbuf has not been initialized,
401 // and not much else.
402 if (curbuf != NULL)
403 {
404# ifdef FEAT_MENU
405 // Clear menus.
406 do_cmdline_cmd((char_u *)"aunmenu *");
407# ifdef FEAT_MULTI_LANG
408 do_cmdline_cmd((char_u *)"menutranslate clear");
409# endif
410# endif
411 // Clear mappings, abbreviations, breakpoints.
412 do_cmdline_cmd((char_u *)"lmapclear");
413 do_cmdline_cmd((char_u *)"xmapclear");
414 do_cmdline_cmd((char_u *)"mapclear");
415 do_cmdline_cmd((char_u *)"mapclear!");
416 do_cmdline_cmd((char_u *)"abclear");
417# if defined(FEAT_EVAL)
418 do_cmdline_cmd((char_u *)"breakdel *");
419# endif
420# if defined(FEAT_PROFILE)
421 do_cmdline_cmd((char_u *)"profdel *");
422# endif
423# if defined(FEAT_KEYMAP)
424 do_cmdline_cmd((char_u *)"set keymap=");
425# endif
426 }
427
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200428 free_titles();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200429# if defined(FEAT_SEARCHPATH)
430 free_findfile();
431# endif
432
433 // Obviously named calls.
434 free_all_autocmds();
435 clear_termcodes();
436 free_all_marks();
437 alist_clear(&global_alist);
438 free_homedir();
439 free_users();
440 free_search_patterns();
441 free_old_sub();
442 free_last_insert();
443 free_insexpand_stuff();
444 free_prev_shellcmd();
445 free_regexp_stuff();
446 free_tag_stuff();
Yegappan Lakshmanan7645da52021-12-04 14:02:30 +0000447 free_xim_stuff();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200448 free_cd_dir();
449# ifdef FEAT_SIGNS
450 free_signs();
451# endif
452# ifdef FEAT_EVAL
453 set_expr_line(NULL, NULL);
454# endif
455# ifdef FEAT_DIFF
456 if (curtab != NULL)
457 diff_clear(curtab);
458# endif
459 clear_sb_text(TRUE); // free any scrollback text
460
461 // Free some global vars.
462 free_username();
463# ifdef FEAT_CLIPBOARD
464 vim_regfree(clip_exclude_prog);
465# endif
466 vim_free(last_cmdline);
467 vim_free(new_last_cmdline);
468 set_keep_msg(NULL, 0);
469
470 // Clear cmdline history.
471 p_hi = 0;
472 init_history();
473# ifdef FEAT_PROP_POPUP
474 clear_global_prop_types();
475# endif
476
477# ifdef FEAT_QUICKFIX
478 {
479 win_T *win;
480 tabpage_T *tab;
481
482 qf_free_all(NULL);
483 // Free all location lists
484 FOR_ALL_TAB_WINDOWS(tab, win)
485 qf_free_all(win);
486 }
487# endif
488
489 // Close all script inputs.
490 close_all_scripts();
491
492 if (curwin != NULL)
493 // Destroy all windows. Must come before freeing buffers.
494 win_free_all();
495
496 // Free all option values. Must come after closing windows.
497 free_all_options();
498
499 // Free all buffers. Reset 'autochdir' to avoid accessing things that
500 // were freed already.
501# ifdef FEAT_AUTOCHDIR
502 p_acd = FALSE;
503# endif
504 for (buf = firstbuf; buf != NULL; )
505 {
506 bufref_T bufref;
507
508 set_bufref(&bufref, buf);
509 nextbuf = buf->b_next;
510 close_buffer(NULL, buf, DOBUF_WIPE, FALSE, FALSE);
511 if (bufref_valid(&bufref))
512 buf = nextbuf; // didn't work, try next one
513 else
514 buf = firstbuf;
515 }
516
517# ifdef FEAT_ARABIC
518 free_arshape_buf();
519# endif
520
521 // Clear registers.
522 clear_registers();
523 ResetRedobuff();
524 ResetRedobuff();
525
526# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
527 vim_free(serverDelayedStartName);
528# endif
529
530 // highlight info
531 free_highlight();
532
533 reset_last_sourcing();
534
535 if (first_tabpage != NULL)
536 {
537 free_tabpage(first_tabpage);
538 first_tabpage = NULL;
539 }
540
541# ifdef UNIX
542 // Machine-specific free.
543 mch_free_mem();
544# endif
545
546 // message history
547 for (;;)
548 if (delete_first_msg() == FAIL)
549 break;
550
551# ifdef FEAT_JOB_CHANNEL
552 channel_free_all();
553# endif
554# ifdef FEAT_TIMERS
555 timer_free_all();
556# endif
557# ifdef FEAT_EVAL
558 // must be after channel_free_all() with unrefs partials
559 eval_clear();
560# endif
561# ifdef FEAT_JOB_CHANNEL
562 // must be after eval_clear() with unrefs jobs
563 job_free_all();
564# endif
565
566 free_termoptions();
Bram Moolenaarb3a29552021-11-19 11:28:04 +0000567 free_cur_term();
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200568
569 // screenlines (can't display anything now!)
570 free_screenlines();
571
572# if defined(FEAT_SOUND)
573 sound_free();
574# endif
575# if defined(USE_XSMP)
576 xsmp_close();
577# endif
578# ifdef FEAT_GUI_GTK
579 gui_mch_free_all();
580# endif
Bram Moolenaarc7269f82021-12-05 11:36:23 +0000581# ifdef FEAT_TCL
582 vim_tcl_finalize();
583# endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200584 clear_hl_tables();
585
586 vim_free(IObuff);
587 vim_free(NameBuff);
588# ifdef FEAT_QUICKFIX
589 check_quickfix_busy();
590# endif
591}
592#endif
593
594/*
595 * Copy "p[len]" into allocated memory, ignoring NUL characters.
596 * Returns NULL when out of memory.
597 */
598 char_u *
599vim_memsave(char_u *p, size_t len)
600{
601 char_u *ret = alloc(len);
602
603 if (ret != NULL)
604 mch_memmove(ret, p, len);
605 return ret;
606}
607
608/*
609 * Replacement for free() that ignores NULL pointers.
610 * Also skip free() when exiting for sure, this helps when we caught a deadly
611 * signal that was caused by a crash in free().
612 * If you want to set NULL after calling this function, you should use
613 * VIM_CLEAR() instead.
614 */
615 void
616vim_free(void *x)
617{
618 if (x != NULL && !really_exiting)
619 {
620#ifdef MEM_PROFILE
621 mem_pre_free(&x);
622#endif
623 free(x);
624 }
625}
626
627/************************************************************************
628 * Functions for handling growing arrays.
629 */
630
631/*
632 * Clear an allocated growing array.
633 */
634 void
635ga_clear(garray_T *gap)
636{
637 vim_free(gap->ga_data);
638 ga_init(gap);
639}
640
641/*
642 * Clear a growing array that contains a list of strings.
643 */
644 void
645ga_clear_strings(garray_T *gap)
646{
647 int i;
648
649 if (gap->ga_data != NULL)
650 for (i = 0; i < gap->ga_len; ++i)
651 vim_free(((char_u **)(gap->ga_data))[i]);
652 ga_clear(gap);
653}
654
Dominique Pelle748b3082022-01-08 12:41:16 +0000655#if defined(FEAT_EVAL) || defined(PROTO)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200656/*
657 * Copy a growing array that contains a list of strings.
658 */
659 int
660ga_copy_strings(garray_T *from, garray_T *to)
661{
662 int i;
663
664 ga_init2(to, sizeof(char_u *), 1);
665 if (ga_grow(to, from->ga_len) == FAIL)
666 return FAIL;
667
668 for (i = 0; i < from->ga_len; ++i)
669 {
670 char_u *orig = ((char_u **)from->ga_data)[i];
671 char_u *copy;
672
673 if (orig == NULL)
674 copy = NULL;
675 else
676 {
677 copy = vim_strsave(orig);
678 if (copy == NULL)
679 {
680 to->ga_len = i;
681 ga_clear_strings(to);
682 return FAIL;
683 }
684 }
685 ((char_u **)to->ga_data)[i] = copy;
686 }
687 to->ga_len = from->ga_len;
688 return OK;
689}
Dominique Pelle748b3082022-01-08 12:41:16 +0000690#endif
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200691
692/*
693 * Initialize a growing array. Don't forget to set ga_itemsize and
694 * ga_growsize! Or use ga_init2().
695 */
696 void
697ga_init(garray_T *gap)
698{
699 gap->ga_data = NULL;
700 gap->ga_maxlen = 0;
701 gap->ga_len = 0;
702}
703
704 void
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000705ga_init2(garray_T *gap, size_t itemsize, int growsize)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200706{
707 ga_init(gap);
708 gap->ga_itemsize = itemsize;
709 gap->ga_growsize = growsize;
710}
711
712/*
713 * Make room in growing array "gap" for at least "n" items.
714 * Return FAIL for failure, OK otherwise.
715 */
716 int
717ga_grow(garray_T *gap, int n)
718{
719 if (gap->ga_maxlen - gap->ga_len < n)
720 return ga_grow_inner(gap, n);
721 return OK;
722}
723
724 int
725ga_grow_inner(garray_T *gap, int n)
726{
727 size_t old_len;
728 size_t new_len;
729 char_u *pp;
730
731 if (n < gap->ga_growsize)
732 n = gap->ga_growsize;
733
734 // A linear growth is very inefficient when the array grows big. This
735 // is a compromise between allocating memory that won't be used and too
736 // many copy operations. A factor of 1.5 seems reasonable.
737 if (n < gap->ga_len / 2)
738 n = gap->ga_len / 2;
739
740 new_len = gap->ga_itemsize * (gap->ga_len + n);
741 pp = vim_realloc(gap->ga_data, new_len);
742 if (pp == NULL)
743 return FAIL;
744 old_len = gap->ga_itemsize * gap->ga_maxlen;
745 vim_memset(pp + old_len, 0, new_len - old_len);
746 gap->ga_maxlen = gap->ga_len + n;
747 gap->ga_data = pp;
748 return OK;
749}
750
751/*
752 * For a growing array that contains a list of strings: concatenate all the
753 * strings with a separating "sep".
754 * Returns NULL when out of memory.
755 */
756 char_u *
757ga_concat_strings(garray_T *gap, char *sep)
758{
759 int i;
760 int len = 0;
761 int sep_len = (int)STRLEN(sep);
762 char_u *s;
763 char_u *p;
764
765 for (i = 0; i < gap->ga_len; ++i)
766 len += (int)STRLEN(((char_u **)(gap->ga_data))[i]) + sep_len;
767
768 s = alloc(len + 1);
769 if (s != NULL)
770 {
771 *s = NUL;
772 p = s;
773 for (i = 0; i < gap->ga_len; ++i)
774 {
775 if (p != s)
776 {
777 STRCPY(p, sep);
778 p += sep_len;
779 }
780 STRCPY(p, ((char_u **)(gap->ga_data))[i]);
781 p += STRLEN(p);
782 }
783 }
784 return s;
785}
786
787/*
788 * Make a copy of string "p" and add it to "gap".
789 * When out of memory nothing changes and FAIL is returned.
790 */
791 int
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000792ga_copy_string(garray_T *gap, char_u *p)
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200793{
794 char_u *cp = vim_strsave(p);
795
796 if (cp == NULL)
797 return FAIL;
798
799 if (ga_grow(gap, 1) == FAIL)
800 {
801 vim_free(cp);
802 return FAIL;
803 }
804 ((char_u **)(gap->ga_data))[gap->ga_len++] = cp;
805 return OK;
806}
807
808/*
Bram Moolenaar9f1a39a2022-01-08 15:39:39 +0000809 * Add string "p" to "gap".
810 * When out of memory "p" is freed and FAIL is returned.
811 */
812 int
813ga_add_string(garray_T *gap, char_u *p)
814{
815 if (ga_grow(gap, 1) == FAIL)
816 return FAIL;
817 ((char_u **)(gap->ga_data))[gap->ga_len++] = p;
818 return OK;
819}
820
821/*
Yegappan Lakshmanancbae5802021-08-06 21:51:55 +0200822 * Concatenate a string to a growarray which contains bytes.
823 * When "s" is NULL does not do anything.
824 * Note: Does NOT copy the NUL at the end!
825 */
826 void
827ga_concat(garray_T *gap, char_u *s)
828{
829 int len;
830
831 if (s == NULL || *s == NUL)
832 return;
833 len = (int)STRLEN(s);
834 if (ga_grow(gap, len) == OK)
835 {
836 mch_memmove((char *)gap->ga_data + gap->ga_len, s, (size_t)len);
837 gap->ga_len += len;
838 }
839}
840
841/*
842 * Concatenate 'len' bytes from string 's' to a growarray.
843 * When "s" is NULL does not do anything.
844 */
845 void
846ga_concat_len(garray_T *gap, char_u *s, size_t len)
847{
848 if (s == NULL || *s == NUL)
849 return;
850 if (ga_grow(gap, (int)len) == OK)
851 {
852 mch_memmove((char *)gap->ga_data + gap->ga_len, s, len);
853 gap->ga_len += (int)len;
854 }
855}
856
857/*
858 * Append one byte to a growarray which contains bytes.
859 */
860 void
861ga_append(garray_T *gap, int c)
862{
863 if (ga_grow(gap, 1) == OK)
864 {
865 *((char *)gap->ga_data + gap->ga_len) = c;
866 ++gap->ga_len;
867 }
868}
869
870#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(MSWIN) \
871 || defined(PROTO)
872/*
873 * Append the text in "gap" below the cursor line and clear "gap".
874 */
875 void
876append_ga_line(garray_T *gap)
877{
878 // Remove trailing CR.
879 if (gap->ga_len > 0
880 && !curbuf->b_p_bin
881 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
882 --gap->ga_len;
883 ga_append(gap, NUL);
884 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
885 gap->ga_len = 0;
886}
887#endif
888