1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-06-01 04:46:08 +02:00

25247 with further modifications: add $funcsourcetrace

This commit is contained in:
Peter Stephenson 2008-08-11 19:22:54 +00:00
parent 2e485d60ff
commit 2853ca830a
14 changed files with 167 additions and 18 deletions

View File

@ -1,3 +1,12 @@
2008-08-11 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 25247 with further modifications: Doc/Zsh/mod_parameter.yo,
Src/exec.c, Src/hashtable.c, Src/init.c, Src/parse.c,
Src/signals.c, Src/utils.c, Src/zsh.h, Src/Modules/parameter.c,
Src/Modules/parameter.mdd, Test/.distfiles,
Test/V01zmodload.ztst, Test/V06parameter.ztst: add
$funcsourcetrace parameter to zsh/parameter.
2008-08-11 Peter Stephenson <pws@csr.com>
* unposted: Doc/Zsh/builtins.yo, Doc/Zsh/func.yo: prevent various

View File

@ -164,6 +164,16 @@ item(tt(userdirs))(
This associative array maps user names to the pathnames of their home
directories.
)
vindex(funcsourcetrace)
item(tt(funcsourcetrace))(
This array contains the file names and line numbers of the
points where the functions currently being executed were
defined. The line number is the line where the `tt(function) var(name)'
or `var(name) tt(LPAR()RPAR())' started. In the case of an autoloaded
function in native zsh format where only the body of the function occurs
in the file the line number is reported as zero.
The format of each element is var(filename)tt(:)var(lineno).
)
vindex(funcstack)
item(tt(funcstack))(
This array contains the names of the functions currently being
@ -174,6 +184,6 @@ vindex(functrace)
item(tt(functrace))(
This array contains the names and line numbers of the callers
corresponding to the functions currently being executed.
The format of each element is name:lineno.
The format of each element is var(name)tt(:)var(lineno).
)
enditem()

View File

@ -286,7 +286,7 @@ setfunction(char *name, char *val, int dis)
zsfree(val);
return;
}
shf = (Shfunc) zalloc(sizeof(*shf));
shf = (Shfunc) zshcalloc(sizeof(*shf));
shf->funcdef = dupeprog(prog, 0);
shf->node.flags = dis;
@ -529,7 +529,35 @@ functracegetfn(UNUSED(Param pm))
char *colonpair;
colonpair = zhalloc(strlen(f->caller) + (f->lineno > 9999 ? 24 : 6));
sprintf(colonpair, "%s:%d", f->caller, f->lineno);
sprintf(colonpair, "%s:%ld", f->caller, (long)f->lineno);
*p = colonpair;
}
*p = NULL;
return ret;
}
/* Functions for the funcsourcetrace special parameter. */
/**/
static char **
funcsourcetracegetfn(UNUSED(Param pm))
{
Funcstack f;
int num;
char **ret, **p;
for (f = funcstack, num = 0; f; f = f->prev, num++);
ret = (char **) zhalloc((num + 1) * sizeof(char *));
for (f = funcstack, p = ret; f; f = f->prev, p++) {
char *colonpair;
char *fname = f->filename ? f->filename : "";
colonpair = zhalloc(strlen(fname) + (f->flineno > 9999 ? 24 : 6));
sprintf(colonpair, "%s:%ld", fname, (long)f->flineno);
*p = colonpair;
}
@ -1773,6 +1801,8 @@ static const struct gsu_array funcstack_gsu =
{ funcstackgetfn, arrsetfn, stdunsetfn };
static const struct gsu_array functrace_gsu =
{ functracegetfn, arrsetfn, stdunsetfn };
static const struct gsu_array funcsourcetrace_gsu =
{ funcsourcetracegetfn, arrsetfn, stdunsetfn };
static const struct gsu_array reswords_gsu =
{ reswordsgetfn, arrsetfn, stdunsetfn };
static const struct gsu_array disreswords_gsu =
@ -1801,6 +1831,8 @@ static struct paramdef partab[] = {
&disreswords_gsu, NULL, NULL),
SPECIALPMDEF("dis_saliases", 0,
&pmdissaliases_gsu, getpmdissalias, scanpmdissaliases),
SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY,
&funcsourcetrace_gsu, NULL, NULL),
SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY,
&funcstack_gsu, NULL, NULL),
SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,

View File

@ -2,6 +2,6 @@ name=zsh/parameter
link=either
load=yes
autofeatures="p:parameters p:commands p:functions p:dis_functions p:funcstack p:functrace p:builtins p:dis_builtins p:reswords p:dis_reswords p:options p:modules p:dirstack p:history p:historywords p:jobtexts p:jobdirs p:jobstates p:nameddirs p:userdirs p:aliases p:dis_aliases p:galiases p:dis_galiases p:saliases p:dis_saliases"
autofeatures="p:parameters p:commands p:functions p:dis_functions p:funcsourcetrace p:funcstack p:functrace p:builtins p:dis_builtins p:reswords p:dis_reswords p:options p:modules p:dirstack p:history p:historywords p:jobtexts p:jobdirs p:jobstates p:nameddirs p:userdirs p:aliases p:dis_aliases p:galiases p:dis_galiases p:saliases p:dis_saliases"
objects="parameter.o"

View File

@ -191,7 +191,7 @@ mod_export Eprog
parse_string(char *s)
{
Eprog p;
int oldlineno = lineno;
zlong oldlineno = lineno;
lexsave();
inpush(s, INP_LINENO, NULL);
@ -1016,7 +1016,8 @@ execlist(Estate state, int dont_change_job, int exiting)
Wordcode next;
wordcode code;
int ret, cj, csp, ltype;
int old_pline_level, old_list_pipe, oldlineno;
int old_pline_level, old_list_pipe;
zlong oldlineno;
/*
* ERREXIT only forces the shell to exit if the last command in a &&
* or || fails. This is the case even if an earlier command is a
@ -3961,6 +3962,8 @@ execfuncdef(Estate state, UNUSED(int do_exec))
shf = (Shfunc) zalloc(sizeof(*shf));
shf->funcdef = prog;
shf->node.flags = 0;
shf->filename = ztrdup(scriptfilename);
shf->lineno = lineno;
if (!names) {
/*
@ -4059,15 +4062,24 @@ static int
execautofn(Estate state, UNUSED(int do_exec))
{
Shfunc shf;
char *oldscriptname;
char *oldscriptname, *oldscriptfilename;
if (!(shf = loadautofn(state->prog->shf, 1, 0)))
return 1;
/*
* Probably we didn't know the filename where this function was
* defined yet.
*/
if (funcstack && !funcstack->filename)
funcstack->filename = dupstring(shf->filename);
oldscriptname = scriptname;
scriptname = dupstring(shf->node.nam);
oldscriptfilename = scriptfilename;
scriptname = scriptfilename = dupstring(shf->node.nam);
execode(shf->funcdef, 1, 0);
scriptname = oldscriptname;
scriptfilename = oldscriptfilename;
return lastval;
}
@ -4078,11 +4090,12 @@ loadautofn(Shfunc shf, int fksh, int autol)
{
int noalias = noaliases, ksh = 1;
Eprog prog;
char *fname;
pushheap();
noaliases = (shf->node.flags & PM_UNALIASED);
prog = getfpfunc(shf->node.nam, &ksh);
prog = getfpfunc(shf->node.nam, &ksh, &fname);
noaliases = noalias;
if (ksh == 1) {
@ -4112,6 +4125,7 @@ loadautofn(Shfunc shf, int fksh, int autol)
else
shf->funcdef = dupeprog(prog, 0);
shf->node.flags &= ~PM_UNDEFINED;
shf->filename = fname;
} else {
VARARR(char, n, strlen(shf->node.nam) + 1);
strcpy(n, shf->node.nam);
@ -4123,6 +4137,7 @@ loadautofn(Shfunc shf, int fksh, int autol)
zwarn("%s: function not defined by file", n);
locallevel++;
popheap();
zsfree(fname);
return NULL;
}
}
@ -4133,6 +4148,7 @@ loadautofn(Shfunc shf, int fksh, int autol)
else
shf->funcdef = dupeprog(stripkshdef(prog, shf->node.nam), 0);
shf->node.flags &= ~PM_UNDEFINED;
shf->filename = fname;
}
popheap();
@ -4172,6 +4188,7 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
#ifdef MAX_FUNCTION_DEPTH
static int funcdepth;
#endif
Shfunc shf;
pushheap();
@ -4243,6 +4260,15 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
fstack.prev = funcstack;
funcstack = &fstack;
if ((shf = (Shfunc) shfunctab->getnode(shfunctab, name))) {
fstack.flineno = shf->lineno;
fstack.filename = dupstring(shf->filename);
} else {
fstack.flineno = 0;
fstack.filename = dupstring(fstack.caller);
}
if (prog->flags & EF_RUN) {
Shfunc shf;
@ -4362,7 +4388,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
/**/
Eprog
getfpfunc(char *s, int *ksh)
getfpfunc(char *s, int *ksh, char **fname)
{
char **pp, buf[PATH_MAX];
off_t len;
@ -4397,6 +4423,9 @@ getfpfunc(char *s, int *ksh)
r = parse_string(d);
scriptname = oldscriptname;
if (fname)
*fname = ztrdup(buf);
zfree(d, len + 1);
return r;

View File

@ -852,6 +852,7 @@ freeshfuncnode(HashNode hn)
zsfree(shf->node.nam);
if (shf->funcdef)
freeeprog(shf->funcdef);
zsfree(shf->filename);
zfree(shf, sizeof(struct shfunc));
}

View File

@ -268,7 +268,7 @@ parseargs(char **argv)
/* -c command */
cmd = *argv;
opts[INTERACTIVE] &= 1;
scriptname = ztrdup("zsh");
scriptname = scriptfilename = ztrdup("zsh");
} else if (**argv == 'o') {
if (!*++*argv)
argv++;
@ -325,6 +325,7 @@ parseargs(char **argv)
}
opts[INTERACTIVE] &= 1;
argzero = *argv;
scriptfilename = argzero;
argv++;
}
while (*argv)
@ -1051,10 +1052,12 @@ mod_export int
source(char *s)
{
Eprog prog;
int tempfd = -1, fd, cj, oldlineno;
int tempfd = -1, fd, cj;
zlong oldlineno;
int oldshst, osubsh, oloops;
FILE *obshin;
char *old_scriptname = scriptname, *us;
char *old_scriptfilename = scriptfilename;
unsigned char *ocs;
int ocsp;
int otrap_return = trap_return, otrap_state = trap_state;
@ -1087,6 +1090,7 @@ source(char *s)
loops = 0;
dosetopt(SHINSTDIN, 0, 1);
scriptname = s;
scriptfilename = s;
/*
* The special return behaviour of traps shouldn't
@ -1096,6 +1100,17 @@ source(char *s)
trap_state = TRAP_STATE_INACTIVE;
sourcelevel++;
/* { */
/* struct funcstack fstack; */
/* fstack.name = dupstring("source"); */
/* fstack.caller = dupstring(scriptfilename); */
/* fstack.flineno = oldlineno; */
/* fstack.lineno = oldlineno; */
/* fstack.filename = NULL; */
/* fstack.prev = funcstack; */
/* funcstack = &fstack; */
/* } */
if (prog) {
pushheap();
errflag = 0;
@ -1103,6 +1118,7 @@ source(char *s)
popheap();
} else
loop(0, 0); /* loop through the file to be sourced */
/* funcstack = funcstack->prev; */
sourcelevel--;
trap_state = otrap_state;
@ -1126,6 +1142,7 @@ source(char *s)
if (!exit_pending)
retflag = 0;
scriptname = old_scriptname;
scriptfilename = old_scriptfilename;
free(cmdstack);
cmdstack = ocs;
cmdsp = ocsp;

View File

@ -720,7 +720,8 @@ par_sublist2(int *complex)
static int
par_pline(int *complex)
{
int p, line = lineno;
int p;
zlong line = lineno;
p = ecadd(0);
@ -1414,8 +1415,9 @@ par_subsh(int *complex)
static void
par_funcdef(void)
{
int oecused = ecused, oldlineno = lineno, num = 0, onp, p, c = 0;
int oecused = ecused, num = 0, onp, p, c = 0;
int so, oecssub = ecssub;
zlong oldlineno = lineno;
lineno = 0;
nocorrect = 1;
@ -1646,7 +1648,8 @@ par_simple(int *complex, int nr)
p += nrediradd;
sr += nrediradd;
} else if (tok == INOUTPAR) {
int oldlineno = lineno, onp, so, oecssub = ecssub;
zlong oldlineno = lineno;
int onp, so, oecssub = ecssub;
*complex = c;
lineno = 0;
@ -2860,7 +2863,8 @@ cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs,
return 1;
}
noaliases = (shf->node.flags & PM_UNALIASED);
if (!(prog = getfpfunc(shf->node.nam, NULL)) || prog == &dummy_eprog) {
if (!(prog = getfpfunc(shf->node.nam, NULL, NULL)) ||
prog == &dummy_eprog) {
noaliases = ona;
zwarnnam(nam, "can't load function: %s", shf->node.nam);
return 1;

View File

@ -705,6 +705,7 @@ dosavetrap(int sig, int level)
newshf->node.nam = ztrdup(shf->node.nam);
newshf->node.flags = shf->node.flags;
newshf->funcdef = dupeprog(shf->funcdef, 0);
newshf->filename = ztrdup(shf->filename);
if (shf->node.flags & PM_UNDEFINED)
newshf->funcdef->shf = newshf;
}

View File

@ -33,7 +33,10 @@
/* name of script being sourced */
/**/
mod_export char *scriptname;
mod_export char *scriptname; /* is sometimes a function name */
/**/
mod_export char *scriptfilename;
#ifdef MULTIBYTE_SUPPORT
struct widechar_array {

View File

@ -1061,6 +1061,8 @@ struct cmdnam {
struct shfunc {
struct hashnode node;
char *filename; /* Name of file located in */
int lineno; /* line number in above file */
Eprog funcdef; /* function definition */
};
@ -1079,8 +1081,10 @@ struct shfunc {
struct funcstack {
Funcstack prev; /* previous in stack */
char *name; /* name of function called */
char *filename; /* file function resides in */
char *caller; /* name of caller */
int lineno; /* line number in file */
zlong flineno; /* line number in file */
zlong lineno; /* line offset from beginning of function */
};
/* node in list of function call wrappers */

View File

@ -33,6 +33,7 @@ V02zregexparse.ztst
V03mathfunc.ztst
V04features.ztst
V05styles.ztst
V06parameter.ztst
Y01completion.ztst
Y02compmatch.ztst
Y03arguments.ztst

View File

@ -183,6 +183,7 @@
>p:dis_galiases
>p:dis_reswords
>p:dis_saliases
>p:funcsourcetrace
>p:funcstack
>p:functions
>p:functrace

37
Test/V06parameter.ztst Normal file
View File

@ -0,0 +1,37 @@
%prep
zmodload zsh/parameter
%test
print -r -- 'print Started functrace.zsh
:
print $LINENO + $functrace + $funcsourcetrace
:
fn() {
print Inside function $0
print $LINENO + $functrace + $funcsourcetrace
}
:
fn
:
fpath=(. $fpath)
:
echo '\''print Inside $0
print $LINENO + $functrace + $funcsourcetrace
'\'' >autofn
:
autoload autofn
:
autofn
autofn' >functrace.zsh
$ZTST_testdir/../Src/zsh +Z -f ./functrace.zsh
0:Function tracing
>Started functrace.zsh
>3 + +
>Inside function fn
>2 + ./functrace.zsh:10 + ./functrace.zsh:5
>Inside autofn
>2 + ./functrace.zsh:20 + ./autofn:0
>Inside autofn
>2 + ./functrace.zsh:21 + ./autofn:0