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:
750
src/ex_cmds2.c
750
src/ex_cmds2.c
@@ -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(®match, 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.
|
||||
|
Reference in New Issue
Block a user