]>
Commit | Line | Data |
---|---|---|
65bfde4c AG |
1 | To: vim-dev@vim.org |
2 | Subject: Patch 7.2.070 | |
3 | Fcc: outbox | |
4 | From: Bram Moolenaar <Bram@moolenaar.net> | |
5 | Mime-Version: 1.0 | |
6 | Content-Type: text/plain; charset=ISO-8859-1 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ------------ | |
9 | ||
10 | Patch 7.2.070 | |
11 | Problem: Crash when a function returns a:000. (Matt Wozkiski) | |
12 | Solution: Don't put the function struct on the stack, allocate it. Free it | |
13 | only when nothing in it is used. | |
14 | Files: src/eval.c | |
15 | ||
16 | ||
17 | *** ../vim-7.2.069/src/eval.c Tue Dec 9 10:56:50 2008 | |
18 | --- src/eval.c Wed Dec 17 21:32:26 2008 | |
19 | *************** | |
20 | *** 32,37 **** | |
21 | --- 32,40 ---- | |
22 | ||
23 | #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ | |
24 | ||
25 | + #define DO_NOT_FREE_CNT 99999 /* refcount for dict or list that should not | |
26 | + be freed. */ | |
27 | + | |
28 | /* | |
29 | * In a hashtab item "hi_key" points to "di_key" in a dictitem. | |
30 | * This avoids adding a pointer to the hashtab item. | |
31 | *************** | |
32 | *** 789,794 **** | |
33 | --- 792,799 ---- | |
34 | static void func_unref __ARGS((char_u *name)); | |
35 | static void func_ref __ARGS((char_u *name)); | |
36 | static void call_user_func __ARGS((ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict)); | |
37 | + static int can_free_funccal __ARGS((funccall_T *fc, int copyID)) ; | |
38 | + static void free_funccal __ARGS((funccall_T *fc, int free_val)); | |
39 | static void add_nr_var __ARGS((dict_T *dp, dictitem_T *v, char *name, varnumber_T nr)); | |
40 | static win_T *find_win_by_nr __ARGS((typval_T *vp, tabpage_T *tp)); | |
41 | static void getwinvar __ARGS((typval_T *argvars, typval_T *rettv, int off)); | |
42 | *************** | |
43 | *** 923,928 **** | |
44 | --- 928,937 ---- | |
45 | /* pointer to funccal for currently active function */ | |
46 | funccall_T *current_funccal = NULL; | |
47 | ||
48 | + /* pointer to list of previously used funccal, still around because some | |
49 | + * item in it is still being used. */ | |
50 | + funccall_T *previous_funccal = NULL; | |
51 | + | |
52 | /* | |
53 | * Return TRUE when a function was ended by a ":return" command. | |
54 | */ | |
55 | *************** | |
56 | *** 6490,6496 **** | |
57 | buf_T *buf; | |
58 | win_T *wp; | |
59 | int i; | |
60 | ! funccall_T *fc; | |
61 | int did_free = FALSE; | |
62 | #ifdef FEAT_WINDOWS | |
63 | tabpage_T *tp; | |
64 | --- 6499,6505 ---- | |
65 | buf_T *buf; | |
66 | win_T *wp; | |
67 | int i; | |
68 | ! funccall_T *fc, **pfc; | |
69 | int did_free = FALSE; | |
70 | #ifdef FEAT_WINDOWS | |
71 | tabpage_T *tp; | |
72 | *************** | |
73 | *** 6574,6579 **** | |
74 | --- 6583,6602 ---- | |
75 | else | |
76 | ll = ll->lv_used_next; | |
77 | ||
78 | + /* check if any funccal can be freed now */ | |
79 | + for (pfc = &previous_funccal; *pfc != NULL; ) | |
80 | + { | |
81 | + if (can_free_funccal(*pfc, copyID)) | |
82 | + { | |
83 | + fc = *pfc; | |
84 | + *pfc = fc->caller; | |
85 | + free_funccal(fc, TRUE); | |
86 | + did_free = TRUE; | |
87 | + } | |
88 | + else | |
89 | + pfc = &(*pfc)->caller; | |
90 | + } | |
91 | + | |
92 | return did_free; | |
93 | } | |
94 | ||
95 | *************** | |
96 | *** 18962,18968 **** | |
97 | dictitem_T *dict_var; | |
98 | { | |
99 | hash_init(&dict->dv_hashtab); | |
100 | ! dict->dv_refcount = 99999; | |
101 | dict_var->di_tv.vval.v_dict = dict; | |
102 | dict_var->di_tv.v_type = VAR_DICT; | |
103 | dict_var->di_tv.v_lock = VAR_FIXED; | |
104 | --- 18985,18991 ---- | |
105 | dictitem_T *dict_var; | |
106 | { | |
107 | hash_init(&dict->dv_hashtab); | |
108 | ! dict->dv_refcount = DO_NOT_FREE_CNT; | |
109 | dict_var->di_tv.vval.v_dict = dict; | |
110 | dict_var->di_tv.v_type = VAR_DICT; | |
111 | dict_var->di_tv.v_lock = VAR_FIXED; | |
112 | *************** | |
113 | *** 19299,19304 **** | |
114 | --- 19322,19329 ---- | |
115 | * Copy the values from typval_T "from" to typval_T "to". | |
116 | * When needed allocates string or increases reference count. | |
117 | * Does not make a copy of a list or dict but copies the reference! | |
118 | + * It is OK for "from" and "to" to point to the same item. This is used to | |
119 | + * make a copy later. | |
120 | */ | |
121 | static void | |
122 | copy_tv(from, to) | |
123 | *************** | |
124 | *** 21111,21117 **** | |
125 | char_u *save_sourcing_name; | |
126 | linenr_T save_sourcing_lnum; | |
127 | scid_T save_current_SID; | |
128 | ! funccall_T fc; | |
129 | int save_did_emsg; | |
130 | static int depth = 0; | |
131 | dictitem_T *v; | |
132 | --- 21136,21142 ---- | |
133 | char_u *save_sourcing_name; | |
134 | linenr_T save_sourcing_lnum; | |
135 | scid_T save_current_SID; | |
136 | ! funccall_T *fc; | |
137 | int save_did_emsg; | |
138 | static int depth = 0; | |
139 | dictitem_T *v; | |
140 | *************** | |
141 | *** 21137,21172 **** | |
142 | ||
143 | line_breakcheck(); /* check for CTRL-C hit */ | |
144 | ||
145 | ! fc.caller = current_funccal; | |
146 | ! current_funccal = &fc; | |
147 | ! fc.func = fp; | |
148 | ! fc.rettv = rettv; | |
149 | rettv->vval.v_number = 0; | |
150 | ! fc.linenr = 0; | |
151 | ! fc.returned = FALSE; | |
152 | ! fc.level = ex_nesting_level; | |
153 | /* Check if this function has a breakpoint. */ | |
154 | ! fc.breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); | |
155 | ! fc.dbg_tick = debug_tick; | |
156 | ||
157 | /* | |
158 | ! * Note about using fc.fixvar[]: This is an array of FIXVAR_CNT variables | |
159 | * with names up to VAR_SHORT_LEN long. This avoids having to alloc/free | |
160 | * each argument variable and saves a lot of time. | |
161 | */ | |
162 | /* | |
163 | * Init l: variables. | |
164 | */ | |
165 | ! init_var_dict(&fc.l_vars, &fc.l_vars_var); | |
166 | if (selfdict != NULL) | |
167 | { | |
168 | /* Set l:self to "selfdict". Use "name" to avoid a warning from | |
169 | * some compiler that checks the destination size. */ | |
170 | ! v = &fc.fixvar[fixvar_idx++].var; | |
171 | name = v->di_key; | |
172 | STRCPY(name, "self"); | |
173 | v->di_flags = DI_FLAGS_RO + DI_FLAGS_FIX; | |
174 | ! hash_add(&fc.l_vars.dv_hashtab, DI2HIKEY(v)); | |
175 | v->di_tv.v_type = VAR_DICT; | |
176 | v->di_tv.v_lock = 0; | |
177 | v->di_tv.vval.v_dict = selfdict; | |
178 | --- 21162,21198 ---- | |
179 | ||
180 | line_breakcheck(); /* check for CTRL-C hit */ | |
181 | ||
182 | ! fc = (funccall_T *)alloc(sizeof(funccall_T)); | |
183 | ! fc->caller = current_funccal; | |
184 | ! current_funccal = fc; | |
185 | ! fc->func = fp; | |
186 | ! fc->rettv = rettv; | |
187 | rettv->vval.v_number = 0; | |
188 | ! fc->linenr = 0; | |
189 | ! fc->returned = FALSE; | |
190 | ! fc->level = ex_nesting_level; | |
191 | /* Check if this function has a breakpoint. */ | |
192 | ! fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); | |
193 | ! fc->dbg_tick = debug_tick; | |
194 | ||
195 | /* | |
196 | ! * Note about using fc->fixvar[]: This is an array of FIXVAR_CNT variables | |
197 | * with names up to VAR_SHORT_LEN long. This avoids having to alloc/free | |
198 | * each argument variable and saves a lot of time. | |
199 | */ | |
200 | /* | |
201 | * Init l: variables. | |
202 | */ | |
203 | ! init_var_dict(&fc->l_vars, &fc->l_vars_var); | |
204 | if (selfdict != NULL) | |
205 | { | |
206 | /* Set l:self to "selfdict". Use "name" to avoid a warning from | |
207 | * some compiler that checks the destination size. */ | |
208 | ! v = &fc->fixvar[fixvar_idx++].var; | |
209 | name = v->di_key; | |
210 | STRCPY(name, "self"); | |
211 | v->di_flags = DI_FLAGS_RO + DI_FLAGS_FIX; | |
212 | ! hash_add(&fc->l_vars.dv_hashtab, DI2HIKEY(v)); | |
213 | v->di_tv.v_type = VAR_DICT; | |
214 | v->di_tv.v_lock = 0; | |
215 | v->di_tv.vval.v_dict = selfdict; | |
216 | *************** | |
217 | *** 21178,21208 **** | |
218 | * Set a:0 to "argcount". | |
219 | * Set a:000 to a list with room for the "..." arguments. | |
220 | */ | |
221 | ! init_var_dict(&fc.l_avars, &fc.l_avars_var); | |
222 | ! add_nr_var(&fc.l_avars, &fc.fixvar[fixvar_idx++].var, "0", | |
223 | (varnumber_T)(argcount - fp->uf_args.ga_len)); | |
224 | /* Use "name" to avoid a warning from some compiler that checks the | |
225 | * destination size. */ | |
226 | ! v = &fc.fixvar[fixvar_idx++].var; | |
227 | name = v->di_key; | |
228 | STRCPY(name, "000"); | |
229 | v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; | |
230 | ! hash_add(&fc.l_avars.dv_hashtab, DI2HIKEY(v)); | |
231 | v->di_tv.v_type = VAR_LIST; | |
232 | v->di_tv.v_lock = VAR_FIXED; | |
233 | ! v->di_tv.vval.v_list = &fc.l_varlist; | |
234 | ! vim_memset(&fc.l_varlist, 0, sizeof(list_T)); | |
235 | ! fc.l_varlist.lv_refcount = 99999; | |
236 | ! fc.l_varlist.lv_lock = VAR_FIXED; | |
237 | ||
238 | /* | |
239 | * Set a:firstline to "firstline" and a:lastline to "lastline". | |
240 | * Set a:name to named arguments. | |
241 | * Set a:N to the "..." arguments. | |
242 | */ | |
243 | ! add_nr_var(&fc.l_avars, &fc.fixvar[fixvar_idx++].var, "firstline", | |
244 | (varnumber_T)firstline); | |
245 | ! add_nr_var(&fc.l_avars, &fc.fixvar[fixvar_idx++].var, "lastline", | |
246 | (varnumber_T)lastline); | |
247 | for (i = 0; i < argcount; ++i) | |
248 | { | |
249 | --- 21204,21234 ---- | |
250 | * Set a:0 to "argcount". | |
251 | * Set a:000 to a list with room for the "..." arguments. | |
252 | */ | |
253 | ! init_var_dict(&fc->l_avars, &fc->l_avars_var); | |
254 | ! add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0", | |
255 | (varnumber_T)(argcount - fp->uf_args.ga_len)); | |
256 | /* Use "name" to avoid a warning from some compiler that checks the | |
257 | * destination size. */ | |
258 | ! v = &fc->fixvar[fixvar_idx++].var; | |
259 | name = v->di_key; | |
260 | STRCPY(name, "000"); | |
261 | v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; | |
262 | ! hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); | |
263 | v->di_tv.v_type = VAR_LIST; | |
264 | v->di_tv.v_lock = VAR_FIXED; | |
265 | ! v->di_tv.vval.v_list = &fc->l_varlist; | |
266 | ! vim_memset(&fc->l_varlist, 0, sizeof(list_T)); | |
267 | ! fc->l_varlist.lv_refcount = DO_NOT_FREE_CNT; | |
268 | ! fc->l_varlist.lv_lock = VAR_FIXED; | |
269 | ||
270 | /* | |
271 | * Set a:firstline to "firstline" and a:lastline to "lastline". | |
272 | * Set a:name to named arguments. | |
273 | * Set a:N to the "..." arguments. | |
274 | */ | |
275 | ! add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline", | |
276 | (varnumber_T)firstline); | |
277 | ! add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", | |
278 | (varnumber_T)lastline); | |
279 | for (i = 0; i < argcount; ++i) | |
280 | { | |
281 | *************** | |
282 | *** 21218,21224 **** | |
283 | } | |
284 | if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) | |
285 | { | |
286 | ! v = &fc.fixvar[fixvar_idx++].var; | |
287 | v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; | |
288 | } | |
289 | else | |
290 | --- 21244,21250 ---- | |
291 | } | |
292 | if (fixvar_idx < FIXVAR_CNT && STRLEN(name) <= VAR_SHORT_LEN) | |
293 | { | |
294 | ! v = &fc->fixvar[fixvar_idx++].var; | |
295 | v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX; | |
296 | } | |
297 | else | |
298 | *************** | |
299 | *** 21230,21236 **** | |
300 | v->di_flags = DI_FLAGS_RO; | |
301 | } | |
302 | STRCPY(v->di_key, name); | |
303 | ! hash_add(&fc.l_avars.dv_hashtab, DI2HIKEY(v)); | |
304 | ||
305 | /* Note: the values are copied directly to avoid alloc/free. | |
306 | * "argvars" must have VAR_FIXED for v_lock. */ | |
307 | --- 21256,21262 ---- | |
308 | v->di_flags = DI_FLAGS_RO; | |
309 | } | |
310 | STRCPY(v->di_key, name); | |
311 | ! hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v)); | |
312 | ||
313 | /* Note: the values are copied directly to avoid alloc/free. | |
314 | * "argvars" must have VAR_FIXED for v_lock. */ | |
315 | *************** | |
316 | *** 21239,21247 **** | |
317 | ||
318 | if (ai >= 0 && ai < MAX_FUNC_ARGS) | |
319 | { | |
320 | ! list_append(&fc.l_varlist, &fc.l_listitems[ai]); | |
321 | ! fc.l_listitems[ai].li_tv = argvars[i]; | |
322 | ! fc.l_listitems[ai].li_tv.v_lock = VAR_FIXED; | |
323 | } | |
324 | } | |
325 | ||
326 | --- 21265,21273 ---- | |
327 | ||
328 | if (ai >= 0 && ai < MAX_FUNC_ARGS) | |
329 | { | |
330 | ! list_append(&fc->l_varlist, &fc->l_listitems[ai]); | |
331 | ! fc->l_listitems[ai].li_tv = argvars[i]; | |
332 | ! fc->l_listitems[ai].li_tv.v_lock = VAR_FIXED; | |
333 | } | |
334 | } | |
335 | ||
336 | *************** | |
337 | *** 21306,21312 **** | |
338 | if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL)) | |
339 | func_do_profile(fp); | |
340 | if (fp->uf_profiling | |
341 | ! || (fc.caller != NULL && fc.caller->func->uf_profiling)) | |
342 | { | |
343 | ++fp->uf_tm_count; | |
344 | profile_start(&call_start); | |
345 | --- 21332,21338 ---- | |
346 | if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL)) | |
347 | func_do_profile(fp); | |
348 | if (fp->uf_profiling | |
349 | ! || (fc->caller != NULL && fc->caller->func->uf_profiling)) | |
350 | { | |
351 | ++fp->uf_tm_count; | |
352 | profile_start(&call_start); | |
353 | *************** | |
354 | *** 21322,21328 **** | |
355 | did_emsg = FALSE; | |
356 | ||
357 | /* call do_cmdline() to execute the lines */ | |
358 | ! do_cmdline(NULL, get_func_line, (void *)&fc, | |
359 | DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); | |
360 | ||
361 | --RedrawingDisabled; | |
362 | --- 21348,21354 ---- | |
363 | did_emsg = FALSE; | |
364 | ||
365 | /* call do_cmdline() to execute the lines */ | |
366 | ! do_cmdline(NULL, get_func_line, (void *)fc, | |
367 | DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); | |
368 | ||
369 | --RedrawingDisabled; | |
370 | *************** | |
371 | *** 21337,21352 **** | |
372 | ||
373 | #ifdef FEAT_PROFILE | |
374 | if (do_profiling == PROF_YES && (fp->uf_profiling | |
375 | ! || (fc.caller != NULL && fc.caller->func->uf_profiling))) | |
376 | { | |
377 | profile_end(&call_start); | |
378 | profile_sub_wait(&wait_start, &call_start); | |
379 | profile_add(&fp->uf_tm_total, &call_start); | |
380 | profile_self(&fp->uf_tm_self, &call_start, &fp->uf_tm_children); | |
381 | ! if (fc.caller != NULL && fc.caller->func->uf_profiling) | |
382 | { | |
383 | ! profile_add(&fc.caller->func->uf_tm_children, &call_start); | |
384 | ! profile_add(&fc.caller->func->uf_tml_children, &call_start); | |
385 | } | |
386 | } | |
387 | #endif | |
388 | --- 21363,21378 ---- | |
389 | ||
390 | #ifdef FEAT_PROFILE | |
391 | if (do_profiling == PROF_YES && (fp->uf_profiling | |
392 | ! || (fc->caller != NULL && fc->caller->func->uf_profiling))) | |
393 | { | |
394 | profile_end(&call_start); | |
395 | profile_sub_wait(&wait_start, &call_start); | |
396 | profile_add(&fp->uf_tm_total, &call_start); | |
397 | profile_self(&fp->uf_tm_self, &call_start, &fp->uf_tm_children); | |
398 | ! if (fc->caller != NULL && fc->caller->func->uf_profiling) | |
399 | { | |
400 | ! profile_add(&fc->caller->func->uf_tm_children, &call_start); | |
401 | ! profile_add(&fc->caller->func->uf_tml_children, &call_start); | |
402 | } | |
403 | } | |
404 | #endif | |
405 | *************** | |
406 | *** 21359,21367 **** | |
407 | ||
408 | if (aborting()) | |
409 | smsg((char_u *)_("%s aborted"), sourcing_name); | |
410 | ! else if (fc.rettv->v_type == VAR_NUMBER) | |
411 | smsg((char_u *)_("%s returning #%ld"), sourcing_name, | |
412 | ! (long)fc.rettv->vval.v_number); | |
413 | else | |
414 | { | |
415 | char_u buf[MSG_BUF_LEN]; | |
416 | --- 21385,21393 ---- | |
417 | ||
418 | if (aborting()) | |
419 | smsg((char_u *)_("%s aborted"), sourcing_name); | |
420 | ! else if (fc->rettv->v_type == VAR_NUMBER) | |
421 | smsg((char_u *)_("%s returning #%ld"), sourcing_name, | |
422 | ! (long)fc->rettv->vval.v_number); | |
423 | else | |
424 | { | |
425 | char_u buf[MSG_BUF_LEN]; | |
426 | *************** | |
427 | *** 21372,21378 **** | |
428 | /* The value may be very long. Skip the middle part, so that we | |
429 | * have some idea how it starts and ends. smsg() would always | |
430 | * truncate it at the end. */ | |
431 | ! s = tv2string(fc.rettv, &tofree, numbuf2, 0); | |
432 | if (s != NULL) | |
433 | { | |
434 | trunc_string(s, buf, MSG_BUF_CLEN); | |
435 | --- 21398,21404 ---- | |
436 | /* The value may be very long. Skip the middle part, so that we | |
437 | * have some idea how it starts and ends. smsg() would always | |
438 | * truncate it at the end. */ | |
439 | ! s = tv2string(fc->rettv, &tofree, numbuf2, 0); | |
440 | if (s != NULL) | |
441 | { | |
442 | trunc_string(s, buf, MSG_BUF_CLEN); | |
443 | *************** | |
444 | *** 21408,21421 **** | |
445 | } | |
446 | ||
447 | did_emsg |= save_did_emsg; | |
448 | ! current_funccal = fc.caller; | |
449 | ||
450 | ! /* The a: variables typevals were not allocated, only free the allocated | |
451 | ! * variables. */ | |
452 | ! vars_clear_ext(&fc.l_avars.dv_hashtab, FALSE); | |
453 | ||
454 | ! vars_clear(&fc.l_vars.dv_hashtab); /* free all l: variables */ | |
455 | ! --depth; | |
456 | } | |
457 | ||
458 | /* | |
459 | --- 21434,21517 ---- | |
460 | } | |
461 | ||
462 | did_emsg |= save_did_emsg; | |
463 | ! current_funccal = fc->caller; | |
464 | ! --depth; | |
465 | ||
466 | ! /* if the a:000 list and the a: dict are not referenced we can free the | |
467 | ! * funccall_T and what's in it. */ | |
468 | ! if (fc->l_varlist.lv_refcount == DO_NOT_FREE_CNT | |
469 | ! && fc->l_vars.dv_refcount == DO_NOT_FREE_CNT | |
470 | ! && fc->l_avars.dv_refcount == DO_NOT_FREE_CNT) | |
471 | ! { | |
472 | ! free_funccal(fc, FALSE); | |
473 | ! } | |
474 | ! else | |
475 | ! { | |
476 | ! hashitem_T *hi; | |
477 | ! listitem_T *li; | |
478 | ! int todo; | |
479 | ||
480 | ! /* "fc" is still in use. This can happen when returning "a:000" or | |
481 | ! * assigning "l:" to a global variable. | |
482 | ! * Link "fc" in the list for garbage collection later. */ | |
483 | ! fc->caller = previous_funccal; | |
484 | ! previous_funccal = fc; | |
485 | ! | |
486 | ! /* Make a copy of the a: variables, since we didn't do that above. */ | |
487 | ! todo = (int)fc->l_avars.dv_hashtab.ht_used; | |
488 | ! for (hi = fc->l_avars.dv_hashtab.ht_array; todo > 0; ++hi) | |
489 | ! { | |
490 | ! if (!HASHITEM_EMPTY(hi)) | |
491 | ! { | |
492 | ! --todo; | |
493 | ! v = HI2DI(hi); | |
494 | ! copy_tv(&v->di_tv, &v->di_tv); | |
495 | ! } | |
496 | ! } | |
497 | ! | |
498 | ! /* Make a copy of the a:000 items, since we didn't do that above. */ | |
499 | ! for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) | |
500 | ! copy_tv(&li->li_tv, &li->li_tv); | |
501 | ! } | |
502 | ! } | |
503 | ! | |
504 | ! /* | |
505 | ! * Return TRUE if items in "fc" do not have "copyID". That means they are not | |
506 | ! * referenced from anywyere. | |
507 | ! */ | |
508 | ! static int | |
509 | ! can_free_funccal(fc, copyID) | |
510 | ! funccall_T *fc; | |
511 | ! int copyID; | |
512 | ! { | |
513 | ! return (fc->l_varlist.lv_copyID != copyID | |
514 | ! && fc->l_vars.dv_copyID != copyID | |
515 | ! && fc->l_avars.dv_copyID != copyID); | |
516 | ! } | |
517 | ! | |
518 | ! /* | |
519 | ! * Free "fc" and what it contains. | |
520 | ! */ | |
521 | ! static void | |
522 | ! free_funccal(fc, free_val) | |
523 | ! funccall_T *fc; | |
524 | ! int free_val; /* a: vars were allocated */ | |
525 | ! { | |
526 | ! listitem_T *li; | |
527 | ! | |
528 | ! /* The a: variables typevals may not have been allocated, only free the | |
529 | ! * allocated variables. */ | |
530 | ! vars_clear_ext(&fc->l_avars.dv_hashtab, free_val); | |
531 | ! | |
532 | ! /* free all l: variables */ | |
533 | ! vars_clear(&fc->l_vars.dv_hashtab); | |
534 | ! | |
535 | ! /* Free the a:000 variables if they were allocated. */ | |
536 | ! if (free_val) | |
537 | ! for (li = fc->l_varlist.lv_first; li != NULL; li = li->li_next) | |
538 | ! clear_tv(&li->li_tv); | |
539 | ! | |
540 | ! vim_free(fc); | |
541 | } | |
542 | ||
543 | /* | |
544 | *** ../vim-7.2.069/src/version.c Tue Dec 9 22:34:02 2008 | |
545 | --- src/version.c Sun Dec 21 12:47:07 2008 | |
546 | *************** | |
547 | *** 678,679 **** | |
548 | --- 678,681 ---- | |
549 | { /* Add new patch number below this line */ | |
550 | + /**/ | |
551 | + 70, | |
552 | /**/ | |
553 | ||
554 | -- | |
555 | Close your shells, or I'll kill -9 you | |
556 | Tomorrow I'll quota you | |
557 | Remember the disks'll always be full | |
558 | And then while I'm away | |
559 | I'll write ~ everyday | |
560 | And I'll send-pr all my buggings to you. | |
561 | [ CVS log "Beatles style" for FreeBSD ports/INDEX, Satoshi Asami ] | |
562 | ||
563 | /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ | |
564 | /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ | |
565 | \\\ download, build and distribute -- http://www.A-A-P.org /// | |
566 | \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |