Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: funcstack[-1] (formerly Suppress tracing of "set +x")



On Fri, 5 Feb 2016 10:44:44 +0000
Peter Stephenson <p.stephenson@xxxxxxxxxxx> wrote:
> Drifting a bit away from the original topic... I tried to improve this
> so you didn't get the "(anon)" in the PS4 output, instead something more
> useful.  I came up with this...
> 
>   () {
>     setopt localoptions promptsubst
>     PS4=${PS4//\%N/'${funcstack[2]:-$0}'}
>     setopt xtrace
>     # some command
>   }
> 
> This sort of works, but it struck me that it's harder than it might be
> to get the name of the top level script.  If you run the above from the
> command line, funcstack is one deep with just the "(anon)", and $0 is
> also "(anon").  I couldn't see a way of getting what the value of the
> scriptname name would be at the top level.  Am I missing something?
> Should funcstack show this (I vaguely expected it would) or is this
> going to cause other problems?

The extra funcstack element would look something like this.  This lines
it up better with the eval context (but it's still in the opposite
order, which was stupid but it's too late now).  In funcstack itself the
choice is easy: it's the scriptname or the shell executable.  In the
other debug arrays that give a source for the code, I've used the
special string <environment> as away of indicating there's smoething
there (to keep the arrays the same length) but there's no logical caller
at the scripting level.

My main worry is someone is using ${#funcstack} to decide if they're at
top-level, rather than zsh_eval_context, which would now fail.  If this
is common or considered standard we're out of luck.  I consider
$funcstack for debugging, in which case adding more information is
fair game, but I don't think you're forced to look at it that way.

diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo
index 3d260f8..7c35a7a 100644
--- a/Doc/Zsh/mod_parameter.yo
+++ b/Doc/Zsh/mod_parameter.yo
@@ -205,7 +205,10 @@ The format of each element is var(filename)tt(:)var(lineno).
 For functions autoloaded from a file in native zsh format, where only the
 body of the function occurs in the file, or for files that have been
 executed by the tt(source) or `tt(.)' builtins, the trace information is
-shown as var(filename)tt(:)var(0), since the entire file is the definition.
+shown as var(filename)tt(:)var(0), since the entire file is the
+definition.  The last entry corresponds to the top-level shell or
+script; the definition file as is always shown as tt(<environment>) with
+line number zero.
 
 Most users will be interested in the information in the
 tt(funcfiletrace) array instead.
@@ -215,15 +218,13 @@ item(tt(funcstack))(
 This array contains the names of the functions, sourced files,
 and (if tt(EVAL_LINENO) is set) tt(eval) commands. currently being
 executed. The first element is the name of the function using the
-parameter.
+parameter; the last element is the name of the top-level script
+or shell.
 
 The standard shell array tt(zsh_eval_context) can be used to
 determine the type of shell construct being executed at each depth:
 note, however, that is in the opposite order, with the most recent
-item last, and it is more detailed, for example including an
-entry for tt(toplevel), the main shell code being executed
-either interactively or from a script, which is not present
-in tt($funcstack).
+item last, and it is more detailed.
 )
 vindex(functrace)
 item(tt(functrace))(
@@ -232,5 +233,8 @@ corresponding to the functions currently being executed.
 The format of each element is var(name)tt(:)var(lineno).
 Callers are also shown for sourced files; the caller is the point
 where the tt(source) or `tt(.)' command was executed.
+The last entry corresponds to the top-level shell or
+script; its caller as is always shown as tt(<environment>) with
+line number zero.
 )
 enditem()
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 04d4485..7523450 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -588,7 +588,8 @@ funcsourcetracegetfn(UNUSED(Param pm))
 
     for (f = funcstack, p = ret; f; f = f->prev, p++) {
 	char *colonpair;
-	char *fname = f->filename ? f->filename : "";
+	char *fname = f->tp == FS_TOP ? "<environment>" :
+	    f->filename ? f->filename : "";
 
 	colonpair = zhalloc(strlen(fname) + (f->flineno > 9999 ? 24 : 6));
 #if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD)
@@ -621,7 +622,7 @@ funcfiletracegetfn(UNUSED(Param pm))
     for (f = funcstack, p = ret; f; f = f->prev, p++) {
 	char *colonpair, *fname;
 
-	if (!f->prev || f->prev->tp == FS_SOURCE) {
+	if (!f->prev || f->prev->tp == FS_SOURCE || f->prev->tp == FS_TOP) {
 	    /*
 	     * Calling context is a file---either the parent
 	     * script or interactive shell, or a sourced
diff --git a/Src/builtin.c b/Src/builtin.c
index 63f964d..f64a688 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5483,7 +5483,7 @@ eval(char **argv)
 	scriptname = "(eval)";
 	fstack.prev = funcstack;
 	fstack.name = scriptname;
-	fstack.caller = funcstack ? funcstack->name : dupstring(argzero);
+	fstack.caller = funcstack->name;
 	fstack.lineno = lineno;
 	fstack.tp = FS_EVAL;
 
@@ -5497,7 +5497,7 @@ eval(char **argv)
 	 * for $funcfiletrace---eval is similar to an inlined function
 	 * call from a tracing perspective.
 	 */
-	if (!funcstack || funcstack->tp == FS_SOURCE) {
+	if (funcstack->tp == FS_SOURCE || funcstack->tp == FS_TOP) {
 	    fstack.flineno = fstack.lineno;
 	    fstack.filename = fstack.caller;
 	} else {
diff --git a/Src/exec.c b/Src/exec.c
index 352615c..ed7f036 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4901,7 +4901,7 @@ execautofn_basic(Estate state, UNUSED(int do_exec))
      * Probably we didn't know the filename where this function was
      * defined yet.
      */
-    if (funcstack && !funcstack->filename)
+    if (funcstack->tp != FS_TOP && !funcstack->filename)
 	funcstack->filename = dupstring(shf->filename);
 
     oldscriptname = scriptname;
@@ -5202,8 +5202,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	 * 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.caller = funcstack->name;
 	fstack.lineno = lineno;
 	fstack.prev = funcstack;
 	fstack.tp = FS_FUNC;
diff --git a/Src/init.c b/Src/init.c
index 4097327..9f56417 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -246,6 +246,7 @@ static int restricted;
 static void
 parseargs(char **argv, char **runscript, char **cmdptr)
 {
+    static struct funcstack funcstack_top;
     char **x;
     LinkList paramlist;
 
@@ -312,6 +313,14 @@ parseargs(char **argv, char **runscript, char **cmdptr)
     free(paramlist);
     argzero = ztrdup(argzero);
     posixzero = ztrdup(posixzero);
+
+    /* We now know the global context... */
+    funcstack_top.name = dupstring(*runscript ? *runscript : argzero);
+    funcstack_top.caller = "<environment>";
+    funcstack_top.lineno = 0;
+    funcstack_top.prev = NULL;
+    funcstack_top.tp = FS_TOP;
+    funcstack = &funcstack_top;
 }
 
 /* Insert into list in order of pointer value */
@@ -1359,8 +1368,7 @@ source(char *s)
     sourcelevel++;
 
     fstack.name = scriptfilename;
-    fstack.caller = funcstack ? funcstack->name :
-	dupstring(old_scriptfilename ? old_scriptfilename : "zsh");
+    fstack.caller = funcstack->name;
     fstack.flineno = 0;
     fstack.lineno = oldlineno;
     fstack.filename = scriptfilename;
diff --git a/Src/prompt.c b/Src/prompt.c
index be067ee..fa4dd00 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -848,7 +848,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 		bv->bp += strlen(bv->bp);
 		break;
 	    case 'x':
-		if (funcstack && funcstack->tp != FS_SOURCE &&
+		if (funcstack->tp != FS_SOURCE && funcstack->tp != FS_TOP &&
 		    !IN_EVAL_TRAP())
 		    promptpath(funcstack->filename ? funcstack->filename : "",
 			       arg, 0);
diff --git a/Src/zsh.h b/Src/zsh.h
index b83b8bd..77a021e 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1242,6 +1242,7 @@ struct shfunc {
 /* tp in funcstack */
 
 enum {
+    FS_TOP,
     FS_SOURCE,
     FS_FUNC,
     FS_EVAL
diff --git a/Test/V06parameter.ztst b/Test/V06parameter.ztst
index c7df35d..1a6aa5b 100644
--- a/Test/V06parameter.ztst
+++ b/Test/V06parameter.ztst
@@ -1,15 +1,20 @@
 %test
 
-  print 'print In sourced file
-  print $LINENO + $functrace + $funcsourcetrace
+   fdata="line:            \$LINENO\\n"
+  fdata+="functrace:       \$functrace\\n"
+  fdata+="funcfiletrace:   \$funcfiletrace\\n"
+  fdata+="funcsourcetrace: \$funcsourcetrace\\n"
+  fdata+="funcstack:       \$funcstack"
+  print -r -- 'print In sourced file
+  print "'$fdata'"
   ' >sourcedfile
   print -r -- 'print Started functrace.zsh
   module_path=(./Modules)
-  print $LINENO + $functrace + $funcsourcetrace
+  print "'$fdata'"
   :
   fn() {
     print Inside function $0
-    print $LINENO + $functrace + $funcsourcetrace
+    print "'$fdata'"
   }
   :
   fn
@@ -17,7 +22,7 @@
   fpath=(. $fpath)
   :
   echo '\''print Inside $0
-    print $LINENO + $functrace + $funcsourcetrace
+    print "'$fdata'"
   '\'' >autofn
   :
   autoload autofn
@@ -28,15 +33,35 @@
   $ZTST_testdir/../Src/zsh +Z -f ./functrace.zsh
 0:Function tracing
 >Started functrace.zsh
->3 + +
+>line:            3
+>functrace:       <environment>:0
+>funcfiletrace:   <environment>:0
+>funcsourcetrace: <environment>:0
+>funcstack:       ./functrace.zsh
 >Inside function fn
->2 + ./functrace.zsh:10 + ./functrace.zsh:5
+>line:            2
+>functrace:       ./functrace.zsh:10 <environment>:0
+>funcfiletrace:   ./functrace.zsh:10 <environment>:0
+>funcsourcetrace: ./functrace.zsh:5 <environment>:0
+>funcstack:       fn ./functrace.zsh
 >Inside autofn
->2 + ./functrace.zsh:20 + ./autofn:0
+>line:            2
+>functrace:       ./functrace.zsh:20 <environment>:0
+>funcfiletrace:   ./functrace.zsh:20 <environment>:0
+>funcsourcetrace: ./autofn:0 <environment>:0
+>funcstack:       autofn ./functrace.zsh
 >Inside autofn
->2 + ./functrace.zsh:21 + ./autofn:0
+>line:            2
+>functrace:       ./functrace.zsh:21 <environment>:0
+>funcfiletrace:   ./functrace.zsh:21 <environment>:0
+>funcsourcetrace: ./autofn:0 <environment>:0
+>funcstack:       autofn ./functrace.zsh
 >In sourced file
->2 + ./functrace.zsh:22 + ./sourcedfile:0
+>line:            2
+>functrace:       ./functrace.zsh:22 <environment>:0
+>funcfiletrace:   ./functrace.zsh:22 <environment>:0
+>funcsourcetrace: ./sourcedfile:0 <environment>:0
+>funcstack:       ./sourcedfile ./functrace.zsh
 
   print -r -- 'module_path=(./Modules)
   debug_hook() { print $funcfiletrace[1] $functrace[1]; }



Messages sorted by: Reverse Date, Date, Thread, Author