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