0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -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

@@ -25,6 +25,54 @@
static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
#ifdef FEAT_EVAL
/* Growarray to store the names of sourced scripts.
* For Unix also store the dev/ino, so that we don't have to stat() each
* script when going through the list. */
typedef struct scriptitem_S
{
char_u *sn_name;
# ifdef UNIX
int sn_dev;
ino_t sn_ino;
# endif
# ifdef FEAT_PROFILE
int sn_prof_on; /* TRUE when script is/was profiled */
int sn_pr_force; /* forceit: profile defined functions */
proftime_T sn_pr_child; /* time set when going into first child */
int sn_pr_nest; /* nesting for sn_pr_child */
/* profiling the script as a whole */
int sn_pr_count; /* nr of times sourced */
proftime_T sn_pr_total; /* time spend in script + children */
proftime_T sn_pr_self; /* time spend in script itself */
proftime_T sn_pr_start; /* time at script start */
proftime_T sn_pr_children; /* time in children after script start */
/* profiling the script per line */
garray_T sn_prl_ga; /* things stored for every line */
proftime_T sn_prl_start; /* start time for current line */
proftime_T sn_prl_children; /* time spent in children for this line */
proftime_T sn_prl_wait; /* wait start time for current line */
int sn_prl_idx; /* index of line being timed; -1 if none */
int sn_prl_execed; /* line being timed was executed */
# endif
} scriptitem_T;
static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
# ifdef FEAT_PROFILE
/* Struct used in sn_prl_ga for every line of a script. */
typedef struct sn_prl_S
{
int snp_count; /* nr of times line was executed */
proftime_T sn_prl_total; /* time spend in a line + children */
proftime_T sn_prl_self; /* time spend in a line itself */
} sn_prl_T;
# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
# endif
#endif
#if defined(FEAT_EVAL) || defined(PROTO)
static int debug_greedy = FALSE; /* batch mode debugging: don't save
and restore typeahead. */
@@ -352,41 +400,54 @@ struct debuggy
char_u *dbg_name; /* function or file name */
regprog_T *dbg_prog; /* regexp program */
linenr_T dbg_lnum; /* line number in function or file */
int dbg_forceit; /* ! used */
};
static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
static int last_breakp = 0; /* nr of last defined breakpoint */
#ifdef FEAT_PROFILE
/* Profiling uses file and func names similar to breakpoints. */
static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
#endif
#define DBG_FUNC 1
#define DBG_FILE 2
static int dbg_parsearg __ARGS((char_u *arg));
static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
/*
* Parse the arguments of ":breakadd" or ":breakdel" and put them in the entry
* just after the last one in dbg_breakp. Note that "dbg_name" is allocated.
* Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
* in the entry just after the last one in dbg_breakp. Note that "dbg_name"
* is allocated.
* Returns FAIL for failure.
*/
static int
dbg_parsearg(arg)
dbg_parsearg(arg, gap)
char_u *arg;
garray_T *gap; /* either &dbg_breakp or &prof_ga */
{
char_u *p = arg;
char_u *q;
struct debuggy *bp;
int here = FALSE;
if (ga_grow(&dbg_breakp, 1) == FAIL)
if (ga_grow(gap, 1) == FAIL)
return FAIL;
bp = &BREAKP(dbg_breakp.ga_len);
bp = &DEBUGGY(gap, gap->ga_len);
/* Find "func" or "file". */
if (STRNCMP(p, "func", 4) == 0)
bp->dbg_type = DBG_FUNC;
else if (STRNCMP(p, "file", 4) == 0)
bp->dbg_type = DBG_FILE;
else if (STRNCMP(p, "here", 4) == 0)
else if (
#ifdef FEAT_PROFILE
gap != &prof_ga &&
#endif
STRNCMP(p, "here", 4) == 0)
{
if (curbuf->b_ffname == NULL)
{
@@ -406,7 +467,11 @@ dbg_parsearg(arg)
/* Find optional line number. */
if (here)
bp->dbg_lnum = curwin->w_cursor.lnum;
else if (VIM_ISDIGIT(*p))
else if (
#ifdef FEAT_PROFILE
gap != &prof_ga &&
#endif
VIM_ISDIGIT(*p))
{
bp->dbg_lnum = getdigits(&p);
p = skipwhite(p);
@@ -474,10 +539,19 @@ ex_breakadd(eap)
{
struct debuggy *bp;
char_u *pat;
garray_T *gap;
if (dbg_parsearg(eap->arg) == OK)
gap = &dbg_breakp;
#ifdef FEAT_PROFILE
if (eap->cmdidx == CMD_profile)
gap = &prof_ga;
#endif
if (dbg_parsearg(eap->arg, gap) == OK)
{
bp = &BREAKP(dbg_breakp.ga_len);
bp = &DEBUGGY(gap, gap->ga_len);
bp->dbg_forceit = eap->forceit;
pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
if (pat != NULL)
{
@@ -490,8 +564,14 @@ ex_breakadd(eap)
{
if (bp->dbg_lnum == 0) /* default line number is 1 */
bp->dbg_lnum = 1;
BREAKP(dbg_breakp.ga_len++).dbg_nr = ++last_breakp;
++debug_tick;
#ifdef FEAT_PROFILE
if (eap->cmdidx != CMD_profile)
#endif
{
DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
++debug_tick;
}
++gap->ga_len;
}
}
}
@@ -536,7 +616,7 @@ ex_breakdel(eap)
else
{
/* ":breakdel {func|file} [lnum] {name}" */
if (dbg_parsearg(eap->arg) == FAIL)
if (dbg_parsearg(eap->arg, &dbg_breakp) == FAIL)
return;
bp = &BREAKP(dbg_breakp.ga_len);
for (i = 0; i < dbg_breakp.ga_len; ++i)
@@ -604,6 +684,35 @@ dbg_find_breakpoint(file, fname, after)
int file; /* TRUE for a file, FALSE for a function */
char_u *fname; /* file or function name */
linenr_T after; /* after this line number */
{
return debuggy_find(file, fname, after, &dbg_breakp, NULL);
}
#if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Return TRUE if profiling is on for a function or sourced file.
*/
int
has_profiling(file, fname, fp)
int file; /* TRUE for a file, FALSE for a function */
char_u *fname; /* file or function name */
int *fp; /* return: forceit */
{
return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
!= (linenr_T)0);
}
#endif
/*
* Common code for dbg_find_breakpoint() and has_profiling().
*/
static linenr_T
debuggy_find(file, fname, after, gap, fp)
int file; /* TRUE for a file, FALSE for a function */
char_u *fname; /* file or function name */
linenr_T after; /* after this line number */
garray_T *gap; /* either &dbg_breakp or &prof_ga */
int *fp; /* if not NULL: return forceit */
{
struct debuggy *bp;
int i;
@@ -612,6 +721,10 @@ dbg_find_breakpoint(file, fname, after)
char_u *name = fname;
int prev_got_int;
/* Return quickly when there are no breakpoints. */
if (gap->ga_len == 0)
return (linenr_T)0;
/* Replace K_SNR in function name with "<SNR>". */
if (!file && fname[0] == K_SPECIAL)
{
@@ -625,26 +738,32 @@ dbg_find_breakpoint(file, fname, after)
}
}
for (i = 0; i < dbg_breakp.ga_len; ++i)
for (i = 0; i < gap->ga_len; ++i)
{
/* skip entries that are not useful or are for a line that is beyond
* an already found breakpoint */
bp = &BREAKP(i);
if ((bp->dbg_type == DBG_FILE) == file
&& bp->dbg_lnum > after
&& (lnum == 0 || bp->dbg_lnum < lnum))
/* Skip entries that are not useful or are for a line that is beyond
* an already found breakpoint. */
bp = &DEBUGGY(gap, i);
if (((bp->dbg_type == DBG_FILE) == file && (
#ifdef FEAT_PROFILE
gap == &prof_ga ||
#endif
(bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
{
regmatch.regprog = bp->dbg_prog;
regmatch.rm_ic = FALSE;
/*
* Save the value of got_int and reset it. We don't want a previous
* interruption cancel matching, only hitting CTRL-C while matching
* should abort it.
* Save the value of got_int and reset it. We don't want a
* previous interruption cancel matching, only hitting CTRL-C
* while matching should abort it.
*/
prev_got_int = got_int;
got_int = FALSE;
if (vim_regexec(&regmatch, name, (colnr_T)0))
{
lnum = bp->dbg_lnum;
if (fp != NULL)
*fp = bp->dbg_forceit;
}
got_int |= prev_got_int;
}
}
@@ -666,6 +785,339 @@ dbg_breakpoint(name, lnum)
debug_breakpoint_name = name;
debug_breakpoint_lnum = lnum;
}
# if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Functions for profiling.
*/
static void script_do_profile __ARGS((scriptitem_T *si));
static void script_dump_profile __ARGS((FILE *fd));
static proftime_T prof_wait_time;
/*
* Set the time in "tm" to zero.
*/
void
profile_zero(tm)
proftime_T *tm;
{
tm->tv_usec = 0;
tm->tv_sec = 0;
}
/*
* Store the current time in "tm".
*/
void
profile_start(tm)
proftime_T *tm;
{
gettimeofday(tm, NULL);
}
/*
* Compute the elapsed time from "tm" till now and store in "tm".
*/
void
profile_end(tm)
proftime_T *tm;
{
proftime_T now;
gettimeofday(&now, NULL);
tm->tv_usec = now.tv_usec - tm->tv_usec;
tm->tv_sec = now.tv_sec - tm->tv_sec;
if (tm->tv_usec < 0)
{
tm->tv_usec += 1000000;
--tm->tv_sec;
}
}
/*
* Subtract the time "tm2" from "tm".
*/
void
profile_sub(tm, tm2)
proftime_T *tm, *tm2;
{
tm->tv_usec -= tm2->tv_usec;
tm->tv_sec -= tm2->tv_sec;
if (tm->tv_usec < 0)
{
tm->tv_usec += 1000000;
--tm->tv_sec;
}
}
/*
* Add the time "tm2" to "tm".
*/
void
profile_add(tm, tm2)
proftime_T *tm, *tm2;
{
tm->tv_usec += tm2->tv_usec;
tm->tv_sec += tm2->tv_sec;
if (tm->tv_usec >= 1000000)
{
tm->tv_usec -= 1000000;
++tm->tv_sec;
}
}
/*
* Get the current waittime.
*/
void
profile_get_wait(tm)
proftime_T *tm;
{
*tm = prof_wait_time;
}
/*
* Subtract the passed waittime since "tm" from "tma".
*/
void
profile_sub_wait(tm, tma)
proftime_T *tm, *tma;
{
proftime_T tm3 = prof_wait_time;
profile_sub(&tm3, tm);
profile_sub(tma, &tm3);
}
/*
* Return TRUE if "tm1" and "tm2" are equal.
*/
int
profile_equal(tm1, tm2)
proftime_T *tm1, *tm2;
{
return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
}
/*
* Return a string that represents a time.
* Uses a static buffer!
*/
char *
profile_msg(tm)
proftime_T *tm;
{
static char buf[50];
sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
return buf;
}
static char_u *profile_fname = NULL;
/*
* ":profile cmd args"
*/
void
ex_profile(eap)
exarg_T *eap;
{
char_u *e;
int len;
e = skiptowhite(eap->arg);
len = e - eap->arg;
e = skipwhite(e);
if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
{
vim_free(profile_fname);
profile_fname = vim_strsave(e);
do_profiling = TRUE;
profile_zero(&prof_wait_time);
set_vim_var_nr(VV_PROFILING, 1L);
}
else if (!do_profiling)
EMSG(_("E750: First use :profile start <fname>"));
else
{
/* The rest is similar to ":breakadd". */
ex_breakadd(eap);
}
}
/*
* Dump the profiling info.
*/
void
profile_dump()
{
FILE *fd;
if (profile_fname != NULL)
{
fd = fopen((char *)profile_fname, "w");
if (fd == NULL)
EMSG2(_(e_notopen), profile_fname);
else
{
func_dump_profile(fd);
script_dump_profile(fd);
fclose(fd);
}
}
}
/*
* Start profiling script "fp".
*/
static void
script_do_profile(si)
scriptitem_T *si;
{
si->sn_pr_count = 0;
profile_zero(&si->sn_pr_total);
profile_zero(&si->sn_pr_self);
ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
si->sn_prl_idx = -1;
si->sn_prof_on = TRUE;
si->sn_pr_nest = 0;
}
/*
* save time when starting to invoke another script or function.
*/
void
script_prof_save(tm)
proftime_T *tm; /* place to store wait time */
{
scriptitem_T *si;
if (current_SID > 0 && current_SID <= script_items.ga_len)
{
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && si->sn_pr_nest++ == 0)
profile_start(&si->sn_pr_child);
}
profile_get_wait(tm);
}
/*
* Count time spent in children after invoking another script or function.
*/
void
script_prof_restore(tm)
proftime_T *tm;
{
scriptitem_T *si;
if (current_SID > 0 && current_SID <= script_items.ga_len)
{
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && --si->sn_pr_nest == 0)
{
profile_end(&si->sn_pr_child);
profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
profile_add(&si->sn_pr_children, &si->sn_pr_child);
profile_add(&si->sn_prl_children, &si->sn_pr_child);
}
}
}
static proftime_T inchar_time;
/*
* Called when starting to wait for the user to type a character.
*/
void
prof_inchar_enter()
{
profile_start(&inchar_time);
}
/*
* Called when finished waiting for the user to type a character.
*/
void
prof_inchar_exit()
{
profile_end(&inchar_time);
profile_add(&prof_wait_time, &inchar_time);
}
/*
* Dump the profiling results for all scripts in file "fd".
*/
static void
script_dump_profile(fd)
FILE *fd;
{
int id;
scriptitem_T *si;
int i;
FILE *sfd;
sn_prl_T *pp;
for (id = 1; id <= script_items.ga_len; ++id)
{
si = &SCRIPT_ITEM(id);
if (si->sn_prof_on)
{
fprintf(fd, "SCRIPT %s\n", si->sn_name);
if (si->sn_pr_count == 1)
fprintf(fd, "Sourced 1 time\n");
else
fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
fprintf(fd, "\n");
fprintf(fd, "count total (s) self (s)\n");
sfd = fopen((char *)si->sn_name, "r");
if (sfd == NULL)
fprintf(fd, "Cannot open file!\n");
else
{
for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
{
if (vim_fgets(IObuff, IOSIZE, sfd))
break;
pp = &PRL_ITEM(si, i);
if (pp->snp_count > 0)
{
fprintf(fd, "%5d ", pp->snp_count);
if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
fprintf(fd, " ");
else
fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
}
else
fprintf(fd, " ");
fprintf(fd, "%s", IObuff);
}
fclose(sfd);
}
fprintf(fd, "\n");
}
}
}
/*
* Return TRUE when a function defined in the current script should be
* profiled.
*/
int
prof_def_func()
{
scriptitem_T *si = &SCRIPT_ITEM(current_SID);
return si->sn_pr_force;
}
# endif
#endif
/*
@@ -2116,24 +2568,6 @@ source_level(cookie)
static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
#ifdef FEAT_EVAL
/* Growarray to store the names of sourced scripts.
* For Unix also store the dev/ino, so that we don't have to stat() each
* script when going through the list. */
struct scriptstuff
{
char_u *name;
# ifdef UNIX
int dev;
ino_t ino;
# endif
};
static garray_T script_names = {0, 0, sizeof(struct scriptstuff), 4, NULL};
#define SCRIPT_NAME(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].name)
#define SCRIPT_DEV(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].dev)
#define SCRIPT_INO(id) (((struct scriptstuff *)script_names.ga_data)[(id) - 1].ino)
#endif
#if defined(WIN32) && defined(FEAT_CSCOPE)
static FILE *fopen_noinh_readbin __ARGS((char *filename));
@@ -2177,6 +2611,7 @@ do_source(fname, check_other, is_vimrc)
static scid_T last_current_SID = 0;
void *save_funccalp;
int save_debug_break_level = debug_break_level;
scriptitem_T *si = NULL;
# ifdef UNIX
struct stat st;
int stat_ok;
@@ -2186,6 +2621,9 @@ do_source(fname, check_other, is_vimrc)
struct timeval tv_rel;
struct timeval tv_start;
#endif
#ifdef FEAT_PROFILE
proftime_T wait_start;
#endif
#ifdef RISCOS
p = mch_munge_fname(fname);
@@ -2327,6 +2765,15 @@ do_source(fname, check_other, is_vimrc)
#endif
#ifdef FEAT_EVAL
# ifdef FEAT_PROFILE
if (do_profiling)
prof_child_enter(&wait_start); /* entering a child now */
# endif
/* Don't use local function variables, if called from a function.
* Also starts profiling timer for nested script. */
save_funccalp = save_funccal();
/*
* Check if this script was sourced before to finds its SID.
* If it's new, generate a new SID.
@@ -2335,48 +2782,72 @@ do_source(fname, check_other, is_vimrc)
# ifdef UNIX
stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
# endif
for (current_SID = script_names.ga_len; current_SID > 0; --current_SID)
if (SCRIPT_NAME(current_SID) != NULL
for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
{
si = &SCRIPT_ITEM(current_SID);
if (si->sn_name != NULL
&& (
# ifdef UNIX
/* Compare dev/ino when possible, it catches symbolic
* links. Also compare file names, the inode may change
* when the file was edited. */
((stat_ok && SCRIPT_DEV(current_SID) != -1)
&& (SCRIPT_DEV(current_SID) == st.st_dev
&& SCRIPT_INO(current_SID) == st.st_ino)) ||
((stat_ok && si->sn_dev != -1)
&& (si->sn_dev == st.st_dev
&& si->sn_ino == st.st_ino)) ||
# endif
fnamecmp(SCRIPT_NAME(current_SID), fname_exp) == 0))
fnamecmp(si->sn_name, fname_exp) == 0))
break;
}
if (current_SID == 0)
{
current_SID = ++last_current_SID;
if (ga_grow(&script_names, (int)(current_SID - script_names.ga_len))
== OK)
if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
== FAIL)
goto almosttheend;
while (script_items.ga_len < current_SID)
{
while (script_names.ga_len < current_SID)
{
SCRIPT_NAME(script_names.ga_len + 1) = NULL;
++script_names.ga_len;
}
SCRIPT_NAME(current_SID) = fname_exp;
# ifdef UNIX
if (stat_ok)
{
SCRIPT_DEV(current_SID) = st.st_dev;
SCRIPT_INO(current_SID) = st.st_ino;
}
else
SCRIPT_DEV(current_SID) = -1;
++script_items.ga_len;
SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
# ifdef FEAT_PROFILE
SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
# endif
fname_exp = NULL;
}
si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp;
fname_exp = NULL;
# ifdef UNIX
if (stat_ok)
{
si->sn_dev = st.st_dev;
si->sn_ino = st.st_ino;
}
else
si->sn_dev = -1;
# endif
/* Allocate the local script variables to use for this script. */
new_script_vars(current_SID);
}
/* Don't use local function variables, if called from a function */
save_funccalp = save_funccal();
# ifdef FEAT_PROFILE
if (do_profiling)
{
int forceit;
/* Check if we do profiling for this script. */
if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
{
script_do_profile(si);
si->sn_pr_force = forceit;
}
if (si->sn_prof_on)
{
++si->sn_pr_count;
profile_start(&si->sn_pr_start);
profile_zero(&si->sn_pr_children);
}
}
# endif
#endif
/*
@@ -2386,20 +2857,27 @@ do_source(fname, check_other, is_vimrc)
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
retval = OK;
fclose(cookie.fp);
vim_free(cookie.nextline);
#ifdef FEAT_MBYTE
convert_setup(&cookie.conv, NULL, NULL);
#ifdef FEAT_PROFILE
if (do_profiling)
{
/* Get "si" again, "script_items" may have been reallocated. */
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on)
{
profile_end(&si->sn_pr_start);
profile_sub_wait(&wait_start, &si->sn_pr_start);
profile_add(&si->sn_pr_total, &si->sn_pr_start);
profile_add(&si->sn_pr_self, &si->sn_pr_start);
profile_sub(&si->sn_pr_self, &si->sn_pr_children);
}
}
#endif
if (got_int)
EMSG(_(e_interr));
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
#ifdef FEAT_EVAL
current_SID = save_current_SID;
restore_funccal(save_funccalp);
#endif
if (p_verbose > 1)
{
msg_str((char_u *)_("finished sourcing %s"), fname);
@@ -2426,6 +2904,21 @@ do_source(fname, check_other, is_vimrc)
++debug_break_level;
#endif
#ifdef FEAT_EVAL
almosttheend:
current_SID = save_current_SID;
restore_funccal(save_funccalp);
# ifdef FEAT_PROFILE
if (do_profiling)
prof_child_exit(&wait_start); /* leaving a child now */
# endif
#endif
fclose(cookie.fp);
vim_free(cookie.nextline);
#ifdef FEAT_MBYTE
convert_setup(&cookie.conv, NULL, NULL);
#endif
theend:
vim_free(fname_exp);
return retval;
@@ -2442,9 +2935,9 @@ ex_scriptnames(eap)
{
int i;
for (i = 1; i <= script_names.ga_len && !got_int; ++i)
if (SCRIPT_NAME(i) != NULL)
smsg((char_u *)"%3d: %s", i, SCRIPT_NAME(i));
for (i = 1; i <= script_items.ga_len && !got_int; ++i)
if (SCRIPT_ITEM(i).sn_name != NULL)
smsg((char_u *)"%3d: %s", i, SCRIPT_ITEM(i).sn_name);
}
# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
@@ -2456,9 +2949,9 @@ scriptnames_slash_adjust()
{
int i;
for (i = 1; i <= script_names.ga_len; ++i)
if (SCRIPT_NAME(i) != NULL)
slash_adjust(SCRIPT_NAME(i));
for (i = 1; i <= script_items.ga_len; ++i)
if (SCRIPT_ITEM(i).sn_name != NULL)
slash_adjust(SCRIPT_ITEM(i).sn_name);
}
# endif
@@ -2477,8 +2970,9 @@ get_scriptname(id)
return (char_u *)"-c argument";
if (id == SID_ENV)
return (char_u *)"environment variable";
return SCRIPT_NAME(id);
return SCRIPT_ITEM(id).sn_name;
}
#endif
#if defined(USE_CR) || defined(PROTO)
@@ -2565,6 +3059,10 @@ getsourceline(c, cookie, indent)
sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
sp->dbg_tick = debug_tick;
}
# ifdef FEAT_PROFILE
if (do_profiling)
script_line_end();
# endif
#endif
/*
* Get current line. If there is a read-ahead line, use it, otherwise get
@@ -2579,6 +3077,10 @@ getsourceline(c, cookie, indent)
line = sp->nextline;
sp->nextline = NULL;
++sourcing_lnum;
#ifdef FEAT_PROFILE
if (do_profiling)
script_line_start();
#endif
}
/* Only concatenate lines starting with a \ when 'cpoptions' doesn't
@@ -2783,6 +3285,90 @@ get_one_sourceline(sp)
return NULL;
}
#if defined(FEAT_PROFILE) || defined(PROTO)
/*
* Called when starting to read a script 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
script_line_start()
{
scriptitem_T *si;
sn_prl_T *pp;
if (current_SID <= 0 || current_SID > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && sourcing_lnum >= 1)
{
/* Grow the array before starting the timer, so that the time spend
* here isn't counted. */
ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
si->sn_prl_idx = sourcing_lnum - 1;
while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
&& si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
{
/* Zero counters for a line that was not used before. */
pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
pp->snp_count = 0;
profile_zero(&pp->sn_prl_total);
profile_zero(&pp->sn_prl_self);
++si->sn_prl_ga.ga_len;
}
si->sn_prl_execed = FALSE;
profile_start(&si->sn_prl_start);
profile_zero(&si->sn_prl_children);
profile_get_wait(&si->sn_prl_wait);
}
}
/*
* Called when actually executing a function line.
*/
void
script_line_exec()
{
scriptitem_T *si;
if (current_SID <= 0 || current_SID > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && si->sn_prl_idx >= 0)
si->sn_prl_execed = TRUE;
}
/*
* Called when done with a function line.
*/
void
script_line_end()
{
scriptitem_T *si;
sn_prl_T *pp;
if (current_SID <= 0 || current_SID > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_SID);
if (si->sn_prof_on && si->sn_prl_idx >= 0
&& si->sn_prl_idx < si->sn_prl_ga.ga_len)
{
if (si->sn_prl_execed)
{
pp = &PRL_ITEM(si, si->sn_prl_idx);
++pp->snp_count;
profile_end(&si->sn_prl_start);
profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
profile_add(&pp->sn_prl_self, &si->sn_prl_start);
profile_add(&pp->sn_prl_total, &si->sn_prl_start);
profile_sub(&pp->sn_prl_self, &si->sn_prl_children);
}
si->sn_prl_idx = -1;
}
}
#endif
/*
* ":scriptencoding": Set encoding conversion for a sourced script.
* Without the multi-byte feature it's simply ignored.