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:
parent
2e485d60ff
commit
2853ca830a
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
41
Src/exec.c
41
Src/exec.c
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
21
Src/init.c
21
Src/init.c
|
@ -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;
|
||||
|
|
12
Src/parse.c
12
Src/parse.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -33,6 +33,7 @@ V02zregexparse.ztst
|
|||
V03mathfunc.ztst
|
||||
V04features.ztst
|
||||
V05styles.ztst
|
||||
V06parameter.ztst
|
||||
Y01completion.ztst
|
||||
Y02compmatch.ztst
|
||||
Y03arguments.ztst
|
||||
|
|
|
@ -183,6 +183,7 @@
|
|||
>p:dis_galiases
|
||||
>p:dis_reswords
|
||||
>p:dis_saliases
|
||||
>p:funcsourcetrace
|
||||
>p:funcstack
|
||||
>p:functions
|
||||
>p:functrace
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue