0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

updated for version 7.0052

This commit is contained in:
Bram Moolenaar
2005-02-26 23:04:13 +00:00
parent 5313dcb75a
commit 05159a0c6a
57 changed files with 9098 additions and 348 deletions

View File

@@ -106,6 +106,7 @@ static char *e_funcdict = N_("E717: Dictionary entry already exists");
static char *e_funcref = N_("E718: Funcref required");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
static char *e_nofunc = N_("E130: Unknown function: %s");
/*
* All user-defined global variables are stored in dictionary "globvardict".
@@ -153,6 +154,24 @@ struct ufunc
int uf_calls; /* nr of active calls */
garray_T uf_args; /* arguments */
garray_T uf_lines; /* function lines */
#ifdef FEAT_PROFILE
int uf_profiling; /* TRUE when func is being profiled */
/* profiling the function as a whole */
int uf_tm_count; /* nr of calls */
proftime_T uf_tm_total; /* time spend in function + children */
proftime_T uf_tm_self; /* time spend in function itself */
proftime_T uf_tm_start; /* time at function call */
proftime_T uf_tm_children; /* time spent in children this call */
/* profiling the function per line */
int *uf_tml_count; /* nr of times line was executed */
proftime_T *uf_tml_total; /* time spend in a line + children */
proftime_T *uf_tml_self; /* time spend in a line itself */
proftime_T uf_tml_start; /* start time for current line */
proftime_T uf_tml_children; /* time spent in children for this line */
proftime_T uf_tml_wait; /* start wait time for current line */
int uf_tml_idx; /* index of line being timed; -1 if none */
int uf_tml_execed; /* line being timed was executed */
#endif
scid_T uf_script_ID; /* ID of script where function was defined,
used for s: variables */
int uf_refcount; /* for numbered function: reference count */
@@ -205,6 +224,9 @@ typedef struct funccall_S
linenr_T breakpoint; /* next line with breakpoint or zero */
int dbg_tick; /* debug_tick when breakpoint was set */
int level; /* top nesting level of executed function */
#ifdef FEAT_PROFILE
proftime_T prof_child; /* time spent in a child */
#endif
} funccall_T;
/*
@@ -293,6 +315,7 @@ static struct vimvar
{VV_NAME("insertmode", VAR_STRING), VV_RO},
{VV_NAME("val", VAR_UNKNOWN), VV_RO},
{VV_NAME("key", VAR_UNKNOWN), VV_RO},
{VV_NAME("profiling", VAR_NUMBER), VV_RO},
};
/* shorthand */
@@ -345,7 +368,6 @@ static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2))
static char_u *list2string __ARGS((typval_T *tv));
static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo));
static dict_T *dict_alloc __ARGS((void));
static void dict_unref __ARGS((dict_T *d));
static void dict_free __ARGS((dict_T *d));
static dictitem_T *dictitem_alloc __ARGS((char_u *key));
@@ -399,6 +421,7 @@ static void f_did_filetype __ARGS((typval_T *argvars, typval_T *rettv));
static void f_diff_filler __ARGS((typval_T *argvars, typval_T *rettv));
static void f_diff_hlID __ARGS((typval_T *argvars, typval_T *rettv));
static void f_empty __ARGS((typval_T *argvars, typval_T *rettv));
static void f_errorlist __ARGS((typval_T *argvars, typval_T *rettv));
static void f_escape __ARGS((typval_T *argvars, typval_T *rettv));
static void f_eval __ARGS((typval_T *argvars, typval_T *rettv));
static void f_eventhandler __ARGS((typval_T *argvars, typval_T *rettv));
@@ -582,6 +605,9 @@ static void cat_func_name __ARGS((char_u *buf, ufunc_T *fp));
static ufunc_T *find_func __ARGS((char_u *name));
static int function_exists __ARGS((char_u *name));
static int builtin_function __ARGS((char_u *name));
#ifdef FEAT_PROFILE
static void func_do_profile __ARGS((ufunc_T *fp));
#endif
static int script_autoload __ARGS((char_u *name));
static char_u *autoload_name __ARGS((char_u *name));
static void func_free __ARGS((ufunc_T *fp));
@@ -1170,20 +1196,60 @@ call_vim_function(func, argc, argv, safe)
void *
save_funccal()
{
funccall_T *fc;
funccall_T *fc = current_funccal;
fc = current_funccal;
current_funccal = NULL;
return (void *)fc;
}
void
restore_funccal(fc)
void *fc;
restore_funccal(vfc)
void *vfc;
{
current_funccal = (funccall_T *)fc;
funccall_T *fc = (funccall_T *)vfc;
current_funccal = fc;
}
#if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Prepare profiling for entering a child or something else that is not
* counted for the script/function itself.
* Should always be called in pair with prof_child_exit().
*/
void
prof_child_enter(tm)
proftime_T *tm; /* place to store waittime */
{
funccall_T *fc = current_funccal;
if (fc != NULL && fc->func->uf_profiling)
profile_start(&fc->prof_child);
script_prof_save(tm);
}
/*
* Take care of time spent in a child.
* Should always be called after prof_child_enter().
*/
void
prof_child_exit(tm)
proftime_T *tm; /* where waittime was stored */
{
funccall_T *fc = current_funccal;
if (fc != NULL && fc->func->uf_profiling)
{
profile_end(&fc->prof_child);
profile_sub_wait(tm, &fc->prof_child); /* don't count waiting time */
profile_add(&fc->func->uf_tm_children, &fc->prof_child);
profile_add(&fc->func->uf_tml_children, &fc->prof_child);
}
script_prof_restore(tm);
}
#endif
#ifdef FEAT_FOLDING
/*
* Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding
@@ -5020,12 +5086,33 @@ list_append_tv(l, tv)
list_T *l;
typval_T *tv;
{
listitem_T *ni = listitem_alloc();
listitem_T *li = listitem_alloc();
if (ni == NULL)
if (li == NULL)
return FAIL;
copy_tv(tv, &ni->li_tv);
list_append(l, ni);
copy_tv(tv, &li->li_tv);
list_append(l, li);
return OK;
}
/*
* Add a dictionary to a list. Used by errorlist().
* Return FAIL when out of memory.
*/
int
list_append_dict(list, dict)
list_T *list;
dict_T *dict;
{
listitem_T *li = listitem_alloc();
if (li == NULL)
return FAIL;
li->li_tv.v_type = VAR_DICT;
li->li_tv.v_lock = 0;
li->li_tv.vval.v_dict = dict;
list_append(list, li);
++dict->dv_refcount;
return OK;
}
@@ -5266,7 +5353,7 @@ list_join(gap, l, sep, echo)
/*
* Allocate an empty header for a dictionary.
*/
static dict_T *
dict_T *
dict_alloc()
{
dict_T *d;
@@ -5469,6 +5556,42 @@ dict_add(d, item)
return hash_add(&d->dv_hashtab, item->di_key);
}
/*
* Add a number or string entry to dictionary "d".
* When "str" is NULL use number "nr", otherwise use "str".
* Returns FAIL when out of memory and when key already exists.
*/
int
dict_add_nr_str(d, key, nr, str)
dict_T *d;
char *key;
long nr;
char_u *str;
{
dictitem_T *item;
item = dictitem_alloc((char_u *)key);
if (item == NULL)
return FAIL;
item->di_tv.v_lock = 0;
if (str == NULL)
{
item->di_tv.v_type = VAR_NUMBER;
item->di_tv.vval.v_number = nr;
}
else
{
item->di_tv.v_type = VAR_STRING;
item->di_tv.vval.v_string = vim_strsave(str);
}
if (dict_add(d, item) == FAIL)
{
dictitem_free(item);
return FAIL;
}
return OK;
}
/*
* Get the number of items in a Dictionary.
*/
@@ -5844,6 +5967,7 @@ get_env_tv(arg, rettv, evaluate)
int len;
int cc;
char_u *name;
int mustfree = FALSE;
++*arg;
name = *arg;
@@ -5854,12 +5978,18 @@ get_env_tv(arg, rettv, evaluate)
{
cc = name[len];
name[len] = NUL;
/* first try mch_getenv(), fast for normal environment vars */
string = mch_getenv(name);
/* first try vim_getenv(), fast for normal environment vars */
string = vim_getenv(name, &mustfree);
if (string != NULL && *string != NUL)
string = vim_strsave(string);
{
if (!mustfree)
string = vim_strsave(string);
}
else
{
if (mustfree)
vim_free(string);
/* next try expanding things like $VIM and ${HOME} */
string = expand_env_save(name - 1);
if (string != NULL && *string == '$')
@@ -5923,6 +6053,7 @@ static struct fst
{"diff_filler", 1, 1, f_diff_filler},
{"diff_hlID", 2, 2, f_diff_hlID},
{"empty", 1, 1, f_empty},
{"errorlist", 0, 0, f_errorlist},
{"escape", 2, 2, f_escape},
{"eval", 1, 1, f_eval},
{"eventhandler", 0, 0, f_eventhandler},
@@ -7420,6 +7551,36 @@ f_empty(argvars, rettv)
rettv->vval.v_number = n;
}
/*
* "errorlist()" function
*/
/*ARGSUSED*/
static void
f_errorlist(argvars, rettv)
typval_T *argvars;
typval_T *rettv;
{
#ifdef FEAT_QUICKFIX
list_T *l;
#endif
rettv->vval.v_number = FALSE;
#ifdef FEAT_QUICKFIX
l = list_alloc();
if (l != NULL)
{
if (get_errorlist(l) != FAIL)
{
rettv->vval.v_list = l;
rettv->v_type = VAR_LIST;
++l->lv_refcount;
}
else
list_free(l);
}
#endif
}
/*
* "escape({string}, {chars})" function
*/
@@ -9212,6 +9373,9 @@ f_has(argvars, rettv)
#ifdef FEAT_PRINTER
"printer",
#endif
#ifdef FEAT_PROFILE
"profile",
#endif
#ifdef FEAT_QUICKFIX
"quickfix",
#endif
@@ -12651,25 +12815,27 @@ f_strridx(argvars, rettv)
needle = get_tv_string(&argvars[1]);
haystack = get_tv_string_buf(&argvars[0], buf);
haystack_len = STRLEN(haystack);
if (argvars[2].v_type != VAR_UNKNOWN)
{
/* Third argument: upper limit for index */
end_idx = get_tv_number(&argvars[2]);
if (end_idx < 0)
{
/* can never find a match */
rettv->vval.v_number = -1;
return;
}
}
else
end_idx = haystack_len;
if (*needle == NUL)
{
/* Empty string matches past the end. */
lastmatch = haystack + haystack_len;
lastmatch = haystack + end_idx;
}
else
{
if (argvars[2].v_type != VAR_UNKNOWN)
{
/* Third argument: upper limit for index */
end_idx = get_tv_number(&argvars[2]);
if (end_idx < 0)
{
/* can never find a match */
rettv->vval.v_number = -1;
return;
}
}
else
end_idx = haystack_len;
for (rest = haystack; *rest != '\0'; ++rest)
{
rest = (char_u *)strstr((char *)rest, (char *)needle);
@@ -15625,6 +15791,14 @@ ex_function(eap)
}
fp->uf_args = newargs;
fp->uf_lines = newlines;
#ifdef FEAT_PROFILE
fp->uf_tml_count = NULL;
fp->uf_tml_total = NULL;
fp->uf_tml_self = NULL;
fp->uf_profiling = FALSE;
if (prof_def_func())
func_do_profile(fp);
#endif
fp->uf_varargs = varargs;
fp->uf_flags = flags;
fp->uf_calls = 0;
@@ -15912,6 +16086,92 @@ builtin_function(name)
return ASCII_ISLOWER(name[0]) && vim_strchr(name, ':') == NULL;
}
#if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Start profiling function "fp".
*/
static void
func_do_profile(fp)
ufunc_T *fp;
{
fp->uf_tm_count = 0;
profile_zero(&fp->uf_tm_self);
profile_zero(&fp->uf_tm_total);
if (fp->uf_tml_count == NULL)
fp->uf_tml_count = (int *)alloc_clear((unsigned)
(sizeof(int) * fp->uf_lines.ga_len));
if (fp->uf_tml_total == NULL)
fp->uf_tml_total = (proftime_T *)alloc_clear((unsigned)
(sizeof(proftime_T) * fp->uf_lines.ga_len));
if (fp->uf_tml_self == NULL)
fp->uf_tml_self = (proftime_T *)alloc_clear((unsigned)
(sizeof(proftime_T) * fp->uf_lines.ga_len));
fp->uf_tml_idx = -1;
if (fp->uf_tml_count == NULL || fp->uf_tml_total == NULL
|| fp->uf_tml_self == NULL)
return; /* out of memory */
fp->uf_profiling = TRUE;
}
/*
* Dump the profiling results for all functions in file "fd".
*/
void
func_dump_profile(fd)
FILE *fd;
{
hashitem_T *hi;
int todo;
ufunc_T *fp;
int i;
todo = func_hashtab.ht_used;
for (hi = func_hashtab.ht_array; todo > 0; ++hi)
{
if (!HASHITEM_EMPTY(hi))
{
--todo;
fp = HI2UF(hi);
if (fp->uf_profiling)
{
if (fp->uf_name[0] == K_SPECIAL)
fprintf(fd, "FUNCTION <SNR>%s()\n", fp->uf_name + 3);
else
fprintf(fd, "FUNCTION %s()\n", fp->uf_name);
if (fp->uf_tm_count == 1)
fprintf(fd, "Called 1 time\n");
else
fprintf(fd, "Called %d times\n", fp->uf_tm_count);
fprintf(fd, "Total time: %s\n", profile_msg(&fp->uf_tm_total));
fprintf(fd, " Self time: %s\n", profile_msg(&fp->uf_tm_self));
fprintf(fd, "\n");
fprintf(fd, "count total (s) self (s)\n");
for (i = 0; i < fp->uf_lines.ga_len; ++i)
{
if (fp->uf_tml_count[i] > 0)
{
fprintf(fd, "%5d ", fp->uf_tml_count[i]);
if (profile_equal(&fp->uf_tml_total[i],
&fp->uf_tml_self[i]))
fprintf(fd, " ");
else
fprintf(fd, "%s ",
profile_msg(&fp->uf_tml_total[i]));
fprintf(fd, "%s ", profile_msg(&fp->uf_tml_self[i]));
}
else
fprintf(fd, " ");
fprintf(fd, "%s\n", FUNCLINE(fp, i));
}
fprintf(fd, "\n");
}
}
}
}
#endif
/*
* If "name" has a package name try autoloading the script for it.
* Return TRUE if a package was loaded.
@@ -16065,7 +16325,7 @@ ex_delfunction(eap)
{
if (fp == NULL)
{
EMSG2(_("E130: Undefined function: %s"), eap->arg);
EMSG2(_(e_nofunc), eap->arg);
return;
}
if (fp->uf_calls > 0)
@@ -16097,6 +16357,11 @@ func_free(fp)
/* clear this function */
ga_clear_strings(&(fp->uf_args));
ga_clear_strings(&(fp->uf_lines));
#ifdef FEAT_PROFILE
vim_free(fp->uf_tml_count);
vim_free(fp->uf_tml_total);
vim_free(fp->uf_tml_self);
#endif
/* remove the function from the function hashtable */
hi = hash_find(&func_hashtab, UF2HIKEY(fp));
@@ -16178,6 +16443,9 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
int ai;
char_u numbuf[NUMBUFLEN];
char_u *name;
#ifdef FEAT_PROFILE
proftime_T wait_start;
#endif
/* If depth of calling is getting too high, don't execute the function */
if (depth >= p_mfd)
@@ -16341,6 +16609,22 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
--no_wait_return;
}
}
#ifdef FEAT_PROFILE
if (do_profiling)
{
if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
func_do_profile(fp);
if (fp->uf_profiling
|| (save_fcp != NULL && &save_fcp->func->uf_profiling))
{
++fp->uf_tm_count;
profile_start(&fp->uf_tm_start);
profile_zero(&fp->uf_tm_children);
}
script_prof_save(&wait_start);
}
#endif
save_current_SID = current_SID;
current_SID = fp->uf_script_ID;
save_did_emsg = did_emsg;
@@ -16360,6 +16644,22 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
rettv->vval.v_number = -1;
}
#ifdef FEAT_PROFILE
if (fp->uf_profiling || (save_fcp != NULL && &save_fcp->func->uf_profiling))
{
profile_end(&fp->uf_tm_start);
profile_sub_wait(&wait_start, &fp->uf_tm_start);
profile_add(&fp->uf_tm_total, &fp->uf_tm_start);
profile_add(&fp->uf_tm_self, &fp->uf_tm_start);
profile_sub(&fp->uf_tm_self, &fp->uf_tm_children);
if (save_fcp != NULL && &save_fcp->func->uf_profiling)
{
profile_add(&save_fcp->func->uf_tm_children, &fp->uf_tm_start);
profile_add(&save_fcp->func->uf_tml_children, &fp->uf_tm_start);
}
}
#endif
/* when being verbose, mention the return value */
if (p_verbose >= 12)
{
@@ -16398,6 +16698,10 @@ call_user_func(fp, argcount, argvars, rettv, firstline, lastline, selfdict)
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
current_SID = save_current_SID;
#ifdef FEAT_PROFILE
if (do_profiling)
script_prof_restore(&wait_start);
#endif
if (p_verbose >= 12 && sourcing_name != NULL)
{
@@ -16624,19 +16928,24 @@ get_func_line(c, cookie, indent)
int indent; /* not used */
{
funccall_T *fcp = (funccall_T *)cookie;
char_u *retval;
garray_T *gap; /* growarray with function lines */
ufunc_T *fp = fcp->func;
char_u *retval;
garray_T *gap; /* growarray with function lines */
/* If breakpoints have been added/deleted need to check for it. */
if (fcp->dbg_tick != debug_tick)
{
fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->uf_name,
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
sourcing_lnum);
fcp->dbg_tick = debug_tick;
}
#ifdef FEAT_PROFILE
if (do_profiling)
func_line_end(cookie);
#endif
gap = &fcp->func->uf_lines;
if ((fcp->func->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
gap = &fp->uf_lines;
if ((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
retval = NULL;
else if (fcp->returned || fcp->linenr >= gap->ga_len)
retval = NULL;
@@ -16644,14 +16953,18 @@ get_func_line(c, cookie, indent)
{
retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
sourcing_lnum = fcp->linenr;
#ifdef FEAT_PROFILE
if (do_profiling)
func_line_start(cookie);
#endif
}
/* Did we encounter a breakpoint? */
if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum)
{
dbg_breakpoint(fcp->func->uf_name, sourcing_lnum);
dbg_breakpoint(fp->uf_name, sourcing_lnum);
/* Find next breakpoint. */
fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->uf_name,
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
sourcing_lnum);
fcp->dbg_tick = debug_tick;
}
@@ -16659,6 +16972,71 @@ get_func_line(c, cookie, indent)
return retval;
}
#if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Called when starting to read a function line.
* "sourcing_lnum" must be correct!
* When skipping lines it may not actually be executed, but we won't find out
* until later and we need to store the time now.
*/
void
func_line_start(cookie)
void *cookie;
{
funccall_T *fcp = (funccall_T *)cookie;
ufunc_T *fp = fcp->func;
if (fp->uf_profiling && sourcing_lnum >= 1
&& sourcing_lnum <= fp->uf_lines.ga_len)
{
fp->uf_tml_idx = sourcing_lnum - 1;
fp->uf_tml_execed = FALSE;
profile_start(&fp->uf_tml_start);
profile_zero(&fp->uf_tml_children);
profile_get_wait(&fp->uf_tml_wait);
}
}
/*
* Called when actually executing a function line.
*/
void
func_line_exec(cookie)
void *cookie;
{
funccall_T *fcp = (funccall_T *)cookie;
ufunc_T *fp = fcp->func;
if (fp->uf_profiling && fp->uf_tml_idx >= 0)
fp->uf_tml_execed = TRUE;
}
/*
* Called when done with a function line.
*/
void
func_line_end(cookie)
void *cookie;
{
funccall_T *fcp = (funccall_T *)cookie;
ufunc_T *fp = fcp->func;
if (fp->uf_profiling && fp->uf_tml_idx >= 0)
{
if (fp->uf_tml_execed)
{
++fp->uf_tml_count[fp->uf_tml_idx];
profile_end(&fp->uf_tml_start);
profile_sub_wait(&fp->uf_tml_wait, &fp->uf_tml_start);
profile_add(&fp->uf_tml_self[fp->uf_tml_idx], &fp->uf_tml_start);
profile_add(&fp->uf_tml_total[fp->uf_tml_idx], &fp->uf_tml_start);
profile_sub(&fp->uf_tml_self[fp->uf_tml_idx], &fp->uf_tml_children);
}
fp->uf_tml_idx = -1;
}
}
#endif
/*
* Return TRUE if the currently active function should be ended, because a
* return was encountered or an error occured. Used inside a ":while".