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

Re: Getting source file and line number of a function.



Patch should be added. It's not the only way to do this and it changes
the functrace (which could easily be addressed, so there might be some
discussion.

Comments about how the patch works are below. For the little that I've
tried, it seems to work. Of course there are other line number
weirdnesses I haven't worked out yet.

One thing  more easily addressed is the fact that sourcing a file
doesn't show in functrace and I think it should. I think sourcing is
in fact like a function call. In fact one can write "source" as a
function which does a read/eval of the file name.

In looking at the code in surrounding the patch one question I have is
how the strings allocated for  funcstack->name and funcstack->caller
get freed? This is relevant if one extends source to do the same
thing.

Thanks.


On Mon, Jul 28, 2008 at 4:34 AM, Peter Stephenson <pws@xxxxxxx> wrote:
> "Rocky Bernstein" wrote:
>> I see that zsh has now has array variables functrace and
>> funcstack. Functrace stack gives a function name and a line offset
>> from the function. But for many things involving location reporting,
>> it would more be desirable to have a filename and absolute line
>> location.
>>
>> Alternatively, if there were a way to get the filename and line number
>> of the beginning of a given function, one can do some arithmetic to
>> get the absolute position.
>>
>> Is there currently a way to get this information. Should I try at
>> submitting a patch?
>
> It would be useful to have information referred to the autoload file,
> and I've wondered about how to do it, but I don't think it's trivial
> with the current way line numbers work.  We would probably need to add
> an extra internal variable for file line numbers, and present another
> variable (or array, if in the funcstack style) to users to distinguish
> the two.

This is more or less the approach I tried. There is a variable called
scriptname which I think is a little misleading. It is the name of the
file when not in a function but gets set to a function name when that
is run. So I added a variable called scriptfilename which mirrors
scriptname but doesn't get changed when a function is run.

When functions are defined, I save the current file, scriptfilename,
and line number, lineno, in the shfunc structure. As for the C
funcstack list, rather than remove any of the existing information, I
added two more fields for the filename and absolute line number. Right
now I changed the functrace routine in Src/Modules/parameter.c to use
these new fields rather than the old ones. If one wants the function
name rather than the file name, one can always use funcstack which has
that. So right now you can't easily get the line number relative to
the beginning of the function, although it's there.

bash can show the new information, file name and starting line number using

declare -F *fn*

(Actually, shopt extdebug also has to be set.) It might be helpful to
add that, and this would be one way to get the old function offset
information. Another way would be to turn functrace into a builtin
function and pass (an optional?) parameter indicating what flavor of
information you want. Or a 3rd routine/variable could be used.

>
> --
> Peter Stephenson <pws@xxxxxxx>                  Software Engineer
> CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
> Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070
>
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.134
diff -u -r1.134 exec.c
--- Src/exec.c	17 Jul 2008 11:27:57 -0000	1.134
+++ Src/exec.c	28 Jul 2008 01:48:40 -0000
@@ -3913,6 +3913,8 @@
 	shf = (Shfunc) zalloc(sizeof(*shf));
 	shf->funcdef = prog;
 	shf->node.flags = 0;
+	shf->filename = ztrdup(scriptfilename);
+	shf->lineno = lineno;
 
 	if (!names) {
 	    /*
@@ -4123,6 +4125,7 @@
 #ifdef MAX_FUNCTION_DEPTH
     static int funcdepth;
 #endif
+    Shfunc shf;
 
     pushheap();
 
@@ -4193,7 +4196,15 @@
     fstack.lineno = lineno;
     fstack.prev = funcstack;
     funcstack = &fstack;
-
+    if (oargv0 && (shf = (Shfunc) shfunctab->getnode(shfunctab, oargv0))) {
+        fstack.flineno = shf->lineno + lineno;
+	fstack.filename = dupstring(shf->filename);
+    } else {
+        fstack.flineno = lineno;
+	fstack.filename = dupstring(fstack.caller);
+    }
+    
+    
     if (prog->flags & EF_RUN) {
 	Shfunc shf;
 
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.86
diff -u -r1.86 init.c
--- Src/init.c	17 Jul 2008 11:27:57 -0000	1.86
+++ Src/init.c	28 Jul 2008 01:48:41 -0000
@@ -334,6 +334,7 @@
 	    }
 	    opts[INTERACTIVE] &= 1;
 	    argzero = *argv;
+	    scriptfilename = argzero;
 	    argv++;
 	}
 	while (*argv)
@@ -1096,8 +1097,20 @@
     loops  = 0;
     dosetopt(SHINSTDIN, 0, 1);
     scriptname = s;
+    scriptfilename = s;
 
     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;
@@ -1105,6 +1118,7 @@
 	popheap();
     } else
 	loop(0, 0);		     /* loop through the file to be sourced  */
+    /* funcstack = funcstack->prev; */
     sourcelevel--;
 
     /* restore the current shell state */
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.197
diff -u -r1.197 utils.c
--- Src/utils.c	17 Jul 2008 11:27:57 -0000	1.197
+++ Src/utils.c	28 Jul 2008 01:48:42 -0000
@@ -33,7 +33,8 @@
 /* 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 {
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.138
diff -u -r1.138 zsh.h
--- Src/zsh.h	12 Jun 2008 13:45:06 -0000	1.138
+++ Src/zsh.h	28 Jul 2008 01:48:43 -0000
@@ -1059,6 +1059,8 @@
 
 struct shfunc {
     struct hashnode node;
+    char *filename;             /* Name of file located in */
+    int lineno;			/* line number in above file */
     Eprog funcdef;		/* function definition    */
 };
 
@@ -1077,8 +1079,10 @@
 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 */
+    int flineno;		/* line number in file */
+    int lineno;			/* line offset from beginning of function */
 };
 
 /* node in list of function call wrappers */
cvs diff: Diffing Src/Builtins
cvs diff: Diffing Src/Modules
Index: Src/Modules/parameter.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/parameter.c,v
retrieving revision 1.45
diff -u -r1.45 parameter.c
--- Src/Modules/parameter.c	5 Sep 2007 16:16:17 -0000	1.45
+++ Src/Modules/parameter.c	28 Jul 2008 01:48:46 -0000
@@ -528,8 +528,8 @@
     for (f = funcstack, p = ret; f; f = f->prev, p++) {
 	char *colonpair;
 
-	colonpair = zhalloc(strlen(f->caller) + (f->lineno > 9999 ? 24 : 6));
-	sprintf(colonpair, "%s:%d", f->caller, f->lineno);
+	colonpair = zhalloc(strlen(f->filename) + (f->flineno > 9999 ? 24 : 6));
+	sprintf(colonpair, "%s:%d", f->filename, f->flineno);
 
 	*p = colonpair;
     }


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