From 0cba5ef62ad8e98924c2bd9367f9c7c7e72e2fd0 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 3 Sep 2008 09:08:18 +0000 Subject: 25595: fix line numbers with EVAL_LINENO, try to fix oddities with funcstack and sourced files, simplify use of caller element of funcstack --- Src/Modules/parameter.c | 15 +++++++++++---- Src/builtin.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- Src/exec.c | 13 +++++++++---- Src/init.c | 25 ++++++++++++------------- Src/zsh.h | 10 +++++++++- 5 files changed, 84 insertions(+), 24 deletions(-) (limited to 'Src') diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 4119c4982..b6c8c5608 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -583,7 +583,7 @@ funcfiletracegetfn(UNUSED(Param pm)) for (f = funcstack, p = ret; f; f = f->prev, p++) { char *colonpair, *fname; - if (!f->prev || f->prev->sourced) { + if (!f->prev || f->prev->tp == FS_SOURCE) { /* * Calling context is a file---either the parent * script or interactive shell, or a sourced @@ -595,13 +595,20 @@ funcfiletracegetfn(UNUSED(Param pm)) sprintf(colonpair, "%s:%ld", f->caller, (long)f->lineno); } else { /* - * Calling context is a function; we need to find the line number - * in the file where that function was defined. For this we need - * the $funcsourcetrace information for the context above, + * Calling context is a function or eval; we need to find + * the line number in the file where that function was + * defined or the eval was called. For this we need the + * $funcsourcetrace information for the context above, * together with the $functrace line number for the current * context. */ long flineno = (long)(f->prev->flineno + f->lineno); + /* + * Line numbers in eval start from 1, not zero, + * so offset by one to get line in file. + */ + if (f->prev->tp == FS_EVAL) + flineno--; fname = f->prev->filename ? f->prev->filename : ""; colonpair = zhalloc(strlen(fname) + (flineno > 9999 ? 24 : 6)); diff --git a/Src/builtin.c b/Src/builtin.c index 654665bfc..69f0aaa6e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -4712,15 +4712,53 @@ bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func)) { Eprog prog; char *oscriptname = scriptname; - int oineval = ineval; + int oineval = ineval, fpushed; + struct funcstack fstack; + /* * If EVALLINENO is not set, we use the line number of the * environment and must flag this up to exec.c. Otherwise, * we use a special script name to indicate the special line number. */ ineval = !isset(EVALLINENO); - if (!ineval) + if (!ineval) { scriptname = "(eval)"; + fstack.prev = funcstack; + fstack.name = scriptname; + fstack.caller = funcstack ? funcstack->name : dupstring(argzero); + fstack.lineno = lineno; + fstack.tp = FS_EVAL; + + /* + * To get file line numbers, we need to know if parent is + * the original script/shell or a sourced file, in which + * case we use the line number raw, or a function or eval, + * in which case we need to deduce where that came from. + * + * This replicates the logic for working out the information + * for $funcfiletrace---eval is similar to an inlined function + * call from a tracing perspective. + */ + if (!funcstack || funcstack->tp == FS_SOURCE) { + fstack.flineno = fstack.lineno; + fstack.filename = fstack.caller; + } else { + fstack.flineno = funcstack->flineno + lineno; + /* + * Line numbers in eval start from 1, not zero, + * so offset by one to get line in file. + */ + if (funcstack->tp == FS_EVAL) + fstack.flineno--; + fstack.filename = funcstack->filename; + if (!fstack.filename) + fstack.filename = ""; + } + funcstack = &fstack; + + fpushed = 1; + } else + fpushed = 0; prog = parse_string(zjoin(argv, ' ', 1)); if (prog) { @@ -4737,6 +4775,9 @@ bin_eval(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func)) lastval = 1; } + if (fpushed) + funcstack = funcstack->prev; + errflag = 0; scriptname = oscriptname; ineval = oineval; diff --git a/Src/exec.c b/Src/exec.c index cf0efed19..a46dfd683 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4264,10 +4264,16 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval) } #endif fstack.name = dupstring(name); - fstack.caller = dupstring(oargv0 ? oargv0 : argzero); + /* + * The caller is whatever is immediately before on the stack, + * unless we're at the top, in which case it's the script + * or interactive shell name. + */ + fstack.caller = funcstack ? funcstack->name : + dupstring(oargv0 ? oargv0 : argzero); fstack.lineno = lineno; fstack.prev = funcstack; - fstack.sourced = 0; + fstack.tp = FS_FUNC; funcstack = &fstack; if ((shf = (Shfunc) shfunctab->getnode(shfunctab, name))) { @@ -4277,8 +4283,7 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval) fstack.flineno = 0; fstack.filename = dupstring(fstack.caller); } - - + if (prog->flags & EF_RUN) { Shfunc shf; diff --git a/Src/init.c b/Src/init.c index 7e912a363..923b94876 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1061,6 +1061,7 @@ source(char *s) unsigned char *ocs; int ocsp; int otrap_return = trap_return, otrap_state = trap_state; + struct funcstack fstack; if (!s || (!(prog = try_source_file((us = unmeta(s)))) && @@ -1100,19 +1101,17 @@ source(char *s) trap_state = TRAP_STATE_INACTIVE; sourcelevel++; - { - struct funcstack fstack; - fstack.name = dupstring("source"); - fstack.caller = dupstring(old_scriptfilename ? old_scriptfilename : - "zsh"); - fstack.flineno = 0; - fstack.lineno = oldlineno; - fstack.filename = fstack.name; - fstack.prev = funcstack; - fstack.sourced = 1; - funcstack = &fstack; - } - + + fstack.name = scriptfilename; + fstack.caller = funcstack ? funcstack->name : + dupstring(old_scriptfilename ? old_scriptfilename : "zsh"); + fstack.flineno = 0; + fstack.lineno = oldlineno; + fstack.filename = scriptfilename; + fstack.prev = funcstack; + fstack.tp = FS_SOURCE; + funcstack = &fstack; + if (prog) { pushheap(); errflag = 0; diff --git a/Src/zsh.h b/Src/zsh.h index 011aa3634..9326e1a11 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1077,6 +1077,14 @@ struct shfunc { #define SFC_COMPLETE 5 /* called from completion code */ #define SFC_CWIDGET 6 /* new style completion widget */ +/* tp in funcstack */ + +enum { + FS_SOURCE, + FS_FUNC, + FS_EVAL +}; + /* node in function stack */ struct funcstack { @@ -1086,7 +1094,7 @@ struct funcstack { char *caller; /* name of caller */ zlong flineno; /* line number in file */ zlong lineno; /* line offset from beginning of function */ - int sourced; /* type of entry is a sourced file */ + int tp; /* type of entry: sourced file, func, eval */ }; /* node in list of function call wrappers */ -- cgit 1.4.1