From 2853ca830ac8d504b7374de2be0ec82122d33c2d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 11 Aug 2008 19:22:54 +0000 Subject: 25247 with further modifications: add $funcsourcetrace --- ChangeLog | 9 +++++++++ Doc/Zsh/mod_parameter.yo | 12 +++++++++++- Src/Modules/parameter.c | 36 ++++++++++++++++++++++++++++++++++-- Src/Modules/parameter.mdd | 2 +- Src/exec.c | 41 +++++++++++++++++++++++++++++++++++------ Src/hashtable.c | 1 + Src/init.c | 21 +++++++++++++++++++-- Src/parse.c | 12 ++++++++---- Src/signals.c | 1 + Src/utils.c | 5 ++++- Src/zsh.h | 6 +++++- Test/.distfiles | 1 + Test/V01zmodload.ztst | 1 + Test/V06parameter.ztst | 37 +++++++++++++++++++++++++++++++++++++ 14 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 Test/V06parameter.ztst diff --git a/ChangeLog b/ChangeLog index 973fcb941..0fc0e5c99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2008-08-11 Peter Stephenson + + * 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 * unposted: Doc/Zsh/builtins.yo, Doc/Zsh/func.yo: prevent various diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo index 434397fbf..d3ace6df0 100644 --- a/Doc/Zsh/mod_parameter.yo +++ b/Doc/Zsh/mod_parameter.yo @@ -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() diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index efb22fafd..74593afc0 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -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, diff --git a/Src/Modules/parameter.mdd b/Src/Modules/parameter.mdd index d506dacb3..04cb6d077 100644 --- a/Src/Modules/parameter.mdd +++ b/Src/Modules/parameter.mdd @@ -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" diff --git a/Src/exec.c b/Src/exec.c index 6ca5b2f2b..f483f7aaf 100644 --- a/Src/exec.c +++ b/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; diff --git a/Src/hashtable.c b/Src/hashtable.c index 160cda506..212882b3f 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -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)); } diff --git a/Src/init.c b/Src/init.c index d8a0dbc57..2f84fc445 100644 --- a/Src/init.c +++ b/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; diff --git a/Src/parse.c b/Src/parse.c index beb88b451..a455b591e 100644 --- a/Src/parse.c +++ b/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; diff --git a/Src/signals.c b/Src/signals.c index d978c3dec..b794f1527 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -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; } diff --git a/Src/utils.c b/Src/utils.c index ec2df7cd0..dfece68a8 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -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 { diff --git a/Src/zsh.h b/Src/zsh.h index 49c08c7ac..173b89183 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -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 */ diff --git a/Test/.distfiles b/Test/.distfiles index 6fd78491b..53d2b2dd6 100644 --- a/Test/.distfiles +++ b/Test/.distfiles @@ -33,6 +33,7 @@ V02zregexparse.ztst V03mathfunc.ztst V04features.ztst V05styles.ztst +V06parameter.ztst Y01completion.ztst Y02compmatch.ztst Y03arguments.ztst diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst index a51535791..55ac9004d 100644 --- a/Test/V01zmodload.ztst +++ b/Test/V01zmodload.ztst @@ -183,6 +183,7 @@ >p:dis_galiases >p:dis_reswords >p:dis_saliases +>p:funcsourcetrace >p:funcstack >p:functions >p:functrace diff --git a/Test/V06parameter.ztst b/Test/V06parameter.ztst new file mode 100644 index 000000000..8b4fc30d5 --- /dev/null +++ b/Test/V06parameter.ztst @@ -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 -- cgit 1.4.1