comparison src/alloc.c @ 25529:bb1097899693 v8.2.3301

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