zsh-workers
 help / color / mirror / code / Atom feed
* Getting source file and line number of a function.
@ 2008-07-27  1:06 Rocky Bernstein
  2008-07-28  8:34 ` Peter Stephenson
  0 siblings, 1 reply; 13+ messages in thread
From: Rocky Bernstein @ 2008-07-27  1:06 UTC (permalink / raw)
  To: zsh-workers

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?


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-07-27  1:06 Getting source file and line number of a function Rocky Bernstein
@ 2008-07-28  8:34 ` Peter Stephenson
  2008-07-28 12:46   ` Rocky Bernstein
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stephenson @ 2008-07-28  8:34 UTC (permalink / raw)
  To: zsh-workers

"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.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-07-28  8:34 ` Peter Stephenson
@ 2008-07-28 12:46   ` Rocky Bernstein
  2008-07-30  2:31     ` Rocky Bernstein
  2008-08-09 18:21     ` Peter Stephenson
  0 siblings, 2 replies; 13+ messages in thread
From: Rocky Bernstein @ 2008-07-28 12:46 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 3419 bytes --]

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@csr.com> 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@csr.com>                  Software Engineer
> CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
> Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: functrace-patch.diff --]
[-- Type: text/x-diff; name=functrace-patch.diff, Size: 4418 bytes --]

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;
     }

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-07-28 12:46   ` Rocky Bernstein
@ 2008-07-30  2:31     ` Rocky Bernstein
  2008-07-30  8:22       ` Peter Stephenson
  2008-08-09 18:21     ` Peter Stephenson
  1 sibling, 1 reply; 13+ messages in thread
From: Rocky Bernstein @ 2008-07-30  2:31 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 3850 bytes --]

Attached is slight improvement on the patch posted before - it adds
source files to be put in functrace.

I'm not sure how functrace strings get freed; an explicit free() doesn't work

However see my next post regarding trap DEBUG.

On Mon, Jul 28, 2008 at 8:46 AM, Rocky Bernstein
<rocky.bernstein@gmail.com> wrote:
> 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@csr.com> 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@csr.com>                  Software Engineer
>> CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
>> Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070
>>
>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: functrace.diff --]
[-- Type: text/x-diff; name=functrace.diff, Size: 4621 bytes --]

cvs diff -u
cvs diff: Diffing .
Index: exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.134
diff -u -r1.134 exec.c
--- exec.c	17 Jul 2008 11:27:57 -0000	1.134
+++ exec.c	30 Jul 2008 02:21:43 -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: init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.86
diff -u -r1.86 init.c
--- init.c	17 Jul 2008 11:27:57 -0000	1.86
+++ init.c	30 Jul 2008 02:21:43 -0000
@@ -334,6 +334,7 @@
 	    }
 	    opts[INTERACTIVE] &= 1;
 	    argzero = *argv;
+	    scriptfilename = argzero;
 	    argv++;
 	}
 	while (*argv)
@@ -1065,8 +1066,10 @@
     int oldshst, osubsh, oloops;
     FILE *obshin;
     char *old_scriptname = scriptname, *us;
+    const char *old_scriptfilename = scriptfilename;
     unsigned char *ocs;
     int ocsp;
+    struct funcstack fstack;
 
     if (!s || 
 	(!(prog = try_source_file((us = unmeta(s)))) &&
@@ -1096,8 +1099,17 @@
     loops  = 0;
     dosetopt(SHINSTDIN, 0, 1);
     scriptname = s;
+    scriptfilename = s;
 
     sourcelevel++;
+    fstack.name = "source";
+    fstack.caller = dupstring(scriptname);
+    fstack.flineno = oldlineno;
+    fstack.lineno = oldlineno;
+    fstack.filename = dupstring(old_scriptfilename);
+    fstack.prev = funcstack;
+    funcstack = &fstack;
+    
     if (prog) {
 	pushheap();
 	errflag = 0;
@@ -1105,6 +1117,8 @@
 	popheap();
     } else
 	loop(0, 0);		     /* loop through the file to be sourced  */
+    funcstack = funcstack->prev;
+    scriptfilename = old_scriptfilename;
     sourcelevel--;
 
     /* restore the current shell state */
Index: utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.197
diff -u -r1.197 utils.c
--- utils.c	17 Jul 2008 11:27:57 -0000	1.197
+++ utils.c	30 Jul 2008 02:21:45 -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: zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.138
diff -u -r1.138 zsh.h
--- zsh.h	12 Jun 2008 13:45:06 -0000	1.138
+++ zsh.h	30 Jul 2008 02:21:46 -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 Builtins
cvs diff: Diffing Modules
Index: Modules/parameter.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/parameter.c,v
retrieving revision 1.45
diff -u -r1.45 parameter.c
--- Modules/parameter.c	5 Sep 2007 16:16:17 -0000	1.45
+++ Modules/parameter.c	30 Jul 2008 02:21: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;
     }

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-07-30  2:31     ` Rocky Bernstein
@ 2008-07-30  8:22       ` Peter Stephenson
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Stephenson @ 2008-07-30  8:22 UTC (permalink / raw)
  To: zsh-workers

"Rocky Bernstein" wrote:
> Attached is slight improvement on the patch posted before - it adds
> source files to be put in functrace.

I'm still working on the original---there's a lot that needs doing
because getting all the different parts right is complicated.  I'm still
wondering how to get the line numbers for autoloaded functions correct
(this seems to be an existing problem no one had noticed).  So you'd
better wait until I have a revised version of that before modifying it.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-07-28 12:46   ` Rocky Bernstein
  2008-07-30  2:31     ` Rocky Bernstein
@ 2008-08-09 18:21     ` Peter Stephenson
  2008-08-10  1:11       ` Rocky Bernstein
  2008-08-11 14:00       ` Richard Hartmann
  1 sibling, 2 replies; 13+ messages in thread
From: Peter Stephenson @ 2008-08-09 18:21 UTC (permalink / raw)
  To: zsh-workers

On Mon, 28 Jul 2008 08:46:43 -0400
"Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
> 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.

I've finally got something that's at least consistent.  Whether it does
what is needed is another matter, but I suspect it's at least going in
the right direction.  It's a little different from Rocky's original.

Instead of hijacking $functrace, I've added another array,
$funcfiletrace.  I've made their behaviours' parallel one another,
i.e. they're always the same length.

What was really doing my brain in was working out what was supposed to
be relative to what, given that I wanted to keep $functrace doing what
it always did unless that really proved to be senseless (and I don't
think it did).  Eventually, I realised $functrace doesn't give you the
current context, it gives you the calling context (i.e. if you want the
current $LINENO or function name you get it some other way---the may be
more work to do here about the name part).  So I've made $funcfiletrace
do the same, except that it's the context where the function was
originally defined, not the point of the current call.  Example below.

In more detail, this modified version checks for a NULL scriptfilename,
sets and also restores it in some more places (in particular autoload
files), frees the filename from the Shfunc structure, tries to ensure
that that is NULL if there isn't a name (that meant tracking down some
more places where Shfunc's are created), handles NULL filenames in
parameter.c, and fixes up an additional oddity with autoload (we don't
know on the first execution of the function where the file is, so we
need to fix up funcstack when it's already in use).

I haven't done anything about the sourced script tracing yet.  It's
probably a good idea; we should obviously make sure it's consistent.

There could be more stuff I've missed.  For example, I haven't looked at
whether ksh-style autoloads need something different.  It's perfectly
possible we'll need additional variables in zsh/parameter.  It would be
nice to have some way of telling what sort of context we were in
(function defined in line or autloaded, sourced file, script).  For now
I'm happy if this looks like it's going the right way.

Anyway, here's an example script showing this in action:


## start
print Started functrace.zsh
zmodload zsh/parameter

print $LINENO; print $functrace; print $funcfiletrace

fn() {
    print Inside function $0
    print $LINENO; print $functrace; print $funcfiletrace
}

fn

fpath=(. $fpath)

echo 'print Inside $0
  print $LINENO; print $functrace; print $funcfiletrace
' >autofn

autoload autofn

autofn
autofn
## end


Output:


## start
Started functrace.zsh
4


Inside function fn
2
../functrace.zsh:11
../functrace.zsh:6
Inside autofn
2
../functrace.zsh:21
./autofn:0
Inside autofn
2
../functrace.zsh:22
./autofn:0
## end


Notes:
- (As I said above) only when we're inside a function do $functrace and
  $funcfiletrace come alive, and then they give the calling context.

- $functrace says where the function got called.  $funcfiletrace says where
  the function got defined.

- The line number 0 for the autoloaded function is not an error.  The
  file is autofn; this is a zsh autoload, so the line that started
  the definition was not in the file at all.  In other words, this
  is telling you the function was autoloaded from the entire contents of
  that file.  It's a relative path here because it got picked up from
  "." in fpath; that's an unusual case in practice, so although it's
  true that the file name could be ambiguous I haven't felt like
  sanitizing the path.

- The two autofn's are there to check the problem I noted above with
  the use of funcstack the first time.


Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.138
diff -u -r1.138 exec.c
--- Src/exec.c	7 Aug 2008 16:25:16 -0000	1.138
+++ Src/exec.c	9 Aug 2008 18:10:14 -0000
@@ -191,7 +191,7 @@
 parse_string(char *s)
 {
     Eprog p;
-    int oldlineno = lineno;
+    zlong oldlineno = lineno;
 
     lexsave();
     inpush(s, INP_LINENO, NULL);
@@ -1016,7 +1016,8 @@
     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 @@
 	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 @@
 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 @@
 {
     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 @@
 	    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 @@
 		zwarn("%s: function not defined by file", n);
 		locallevel++;
 		popheap();
+		zsfree(fname);
 		return NULL;
 	    }
 	}
@@ -4133,6 +4148,7 @@
 	else
 	    shf->funcdef = dupeprog(stripkshdef(prog, shf->node.nam), 0);
 	shf->node.flags &= ~PM_UNDEFINED;
+	shf->filename = fname;
     }
     popheap();
 
@@ -4172,6 +4188,7 @@
 #ifdef MAX_FUNCTION_DEPTH
     static int funcdepth;
 #endif
+    Shfunc shf;
 
     pushheap();
 
@@ -4243,6 +4260,15 @@
     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 @@
 
 /**/
 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 @@
 		    r = parse_string(d);
 		    scriptname = oldscriptname;
 
+		    if (fname)
+			*fname = ztrdup(buf);
+
 		    zfree(d, len + 1);
 
 		    return r;
Index: Src/hashtable.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/hashtable.c,v
retrieving revision 1.27
diff -u -r1.27 hashtable.c
--- Src/hashtable.c	1 Nov 2007 10:59:40 -0000	1.27
+++ Src/hashtable.c	9 Aug 2008 18:10:14 -0000
@@ -852,6 +852,7 @@
     zsfree(shf->node.nam);
     if (shf->funcdef)
 	freeeprog(shf->funcdef);
+    zsfree(shf->filename);
     zfree(shf, sizeof(struct shfunc));
 }
 
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.91
diff -u -r1.91 init.c
--- Src/init.c	7 Aug 2008 16:25:16 -0000	1.91
+++ Src/init.c	9 Aug 2008 18:10:14 -0000
@@ -268,7 +268,7 @@
 		/* -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 @@
 	    }
 	    opts[INTERACTIVE] &= 1;
 	    argzero = *argv;
+	    scriptfilename = argzero;
 	    argv++;
 	}
 	while (*argv)
@@ -1051,10 +1052,12 @@
 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 @@
     loops  = 0;
     dosetopt(SHINSTDIN, 0, 1);
     scriptname = s;
+    scriptfilename = s;
 
     /*
      * The special return behaviour of traps shouldn't
@@ -1096,6 +1100,17 @@
     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 @@
 	popheap();
     } else
 	loop(0, 0);		     /* loop through the file to be sourced  */
+    /* funcstack = funcstack->prev; */
     sourcelevel--;
 
     trap_state = otrap_state;
@@ -1126,6 +1142,7 @@
     if (!exit_pending)
 	retflag = 0;
     scriptname = old_scriptname;
+    scriptfilename = old_scriptfilename;
     free(cmdstack);
     cmdstack = ocs;
     cmdsp = ocsp;
Index: Src/parse.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/parse.c,v
retrieving revision 1.70
diff -u -r1.70 parse.c
--- Src/parse.c	1 Jul 2008 18:38:40 -0000	1.70
+++ Src/parse.c	9 Aug 2008 18:10:15 -0000
@@ -720,7 +720,8 @@
 static int
 par_pline(int *complex)
 {
-    int p, line = lineno;
+    int p;
+    zlong line = lineno;
 
     p = ecadd(0);
 
@@ -1414,8 +1415,9 @@
 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 @@
 	    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 @@
 	    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;
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.198
diff -u -r1.198 utils.c
--- Src/utils.c	31 Jul 2008 08:44:21 -0000	1.198
+++ Src/utils.c	9 Aug 2008 18:10:17 -0000
@@ -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 {
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.140
diff -u -r1.140 zsh.h
--- Src/zsh.h	7 Aug 2008 16:25:16 -0000	1.140
+++ Src/zsh.h	9 Aug 2008 18:10:18 -0000
@@ -1061,6 +1061,8 @@
 
 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 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 */
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	9 Aug 2008 18:10:18 -0000
@@ -286,7 +286,7 @@
 	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 @@
 	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 funcfiletrace special parameter. */
+
+/**/
+static char **
+funcfiletracegetfn(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 @@
 { funcstackgetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array functrace_gsu =
 { functracegetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array funcfiletrace_gsu =
+{ funcfiletracegetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array reswords_gsu =
 { reswordsgetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array disreswords_gsu =
@@ -1807,6 +1837,8 @@
 		 scanpmfunctions),
     SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
 	    &functrace_gsu, NULL, NULL),
+    SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY,
+	    &funcfiletrace_gsu, NULL, NULL),
     SPECIALPMDEF("galiases", 0,
 	    &pmgaliases_gsu, getpmgalias, scanpmgaliases),
     SPECIALPMDEF("history", PM_READONLY,
-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-09 18:21     ` Peter Stephenson
@ 2008-08-10  1:11       ` Rocky Bernstein
  2008-08-11 19:32         ` Peter Stephenson
  2008-08-11 14:00       ` Richard Hartmann
  1 sibling, 1 reply; 13+ messages in thread
From: Rocky Bernstein @ 2008-08-10  1:11 UTC (permalink / raw)
  To: zsh-workers

Great! Let me know when code is committed into CVS which includes
tracking source calls, and I'll revise the zshdb code then.

Ditto for instruction skipping and/or showing the command to be run.

Thanks.

On Sat, Aug 9, 2008 at 2:21 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> On Mon, 28 Jul 2008 08:46:43 -0400
> "Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
>> 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.
>
> I've finally got something that's at least consistent.  Whether it does
> what is needed is another matter, but I suspect it's at least going in
> the right direction.  It's a little different from Rocky's original.
>
> Instead of hijacking $functrace, I've added another array,
> $funcfiletrace.  I've made their behaviours' parallel one another,
> i.e. they're always the same length.
>
> What was really doing my brain in was working out what was supposed to
> be relative to what, given that I wanted to keep $functrace doing what
> it always did unless that really proved to be senseless (and I don't
> think it did).  Eventually, I realised $functrace doesn't give you the
> current context, it gives you the calling context (i.e. if you want the
> current $LINENO or function name you get it some other way---the may be
> more work to do here about the name part).  So I've made $funcfiletrace
> do the same, except that it's the context where the function was
> originally defined, not the point of the current call.  Example below.
>
> In more detail, this modified version checks for a NULL scriptfilename,
> sets and also restores it in some more places (in particular autoload
> files), frees the filename from the Shfunc structure, tries to ensure
> that that is NULL if there isn't a name (that meant tracking down some
> more places where Shfunc's are created), handles NULL filenames in
> parameter.c, and fixes up an additional oddity with autoload (we don't
> know on the first execution of the function where the file is, so we
> need to fix up funcstack when it's already in use).
>
> I haven't done anything about the sourced script tracing yet.  It's
> probably a good idea; we should obviously make sure it's consistent.
>
> There could be more stuff I've missed.  For example, I haven't looked at
> whether ksh-style autoloads need something different.  It's perfectly
> possible we'll need additional variables in zsh/parameter.  It would be
> nice to have some way of telling what sort of context we were in
> (function defined in line or autloaded, sourced file, script).  For now
> I'm happy if this looks like it's going the right way.
>
> Anyway, here's an example script showing this in action:
>
>
> ## start
> print Started functrace.zsh
> zmodload zsh/parameter
>
> print $LINENO; print $functrace; print $funcfiletrace
>
> fn() {
>    print Inside function $0
>    print $LINENO; print $functrace; print $funcfiletrace
> }
>
> fn
>
> fpath=(. $fpath)
>
> echo 'print Inside $0
>  print $LINENO; print $functrace; print $funcfiletrace
> ' >autofn
>
> autoload autofn
>
> autofn
> autofn
> ## end
>
>
> Output:
>
>
> ## start
> Started functrace.zsh
> 4
>
>
> Inside function fn
> 2
> ../functrace.zsh:11
> ../functrace.zsh:6
> Inside autofn
> 2
> ../functrace.zsh:21
> ./autofn:0
> Inside autofn
> 2
> ../functrace.zsh:22
> ./autofn:0
> ## end
>
>
> Notes:
> - (As I said above) only when we're inside a function do $functrace and
>  $funcfiletrace come alive, and then they give the calling context.
>
> - $functrace says where the function got called.  $funcfiletrace says where
>  the function got defined.
>
> - The line number 0 for the autoloaded function is not an error.  The
>  file is autofn; this is a zsh autoload, so the line that started
>  the definition was not in the file at all.  In other words, this
>  is telling you the function was autoloaded from the entire contents of
>  that file.  It's a relative path here because it got picked up from
>  "." in fpath; that's an unusual case in practice, so although it's
>  true that the file name could be ambiguous I haven't felt like
>  sanitizing the path.
>
> - The two autofn's are there to check the problem I noted above with
>  the use of funcstack the first time.
>
>
> Index: Src/exec.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
> retrieving revision 1.138
> diff -u -r1.138 exec.c
> --- Src/exec.c  7 Aug 2008 16:25:16 -0000       1.138
> +++ Src/exec.c  9 Aug 2008 18:10:14 -0000
> @@ -191,7 +191,7 @@
>  parse_string(char *s)
>  {
>     Eprog p;
> -    int oldlineno = lineno;
> +    zlong oldlineno = lineno;
>
>     lexsave();
>     inpush(s, INP_LINENO, NULL);
> @@ -1016,7 +1016,8 @@
>     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 @@
>        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 @@
>  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 @@
>  {
>     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 @@
>            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 @@
>                zwarn("%s: function not defined by file", n);
>                locallevel++;
>                popheap();
> +               zsfree(fname);
>                return NULL;
>            }
>        }
> @@ -4133,6 +4148,7 @@
>        else
>            shf->funcdef = dupeprog(stripkshdef(prog, shf->node.nam), 0);
>        shf->node.flags &= ~PM_UNDEFINED;
> +       shf->filename = fname;
>     }
>     popheap();
>
> @@ -4172,6 +4188,7 @@
>  #ifdef MAX_FUNCTION_DEPTH
>     static int funcdepth;
>  #endif
> +    Shfunc shf;
>
>     pushheap();
>
> @@ -4243,6 +4260,15 @@
>     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 @@
>
>  /**/
>  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 @@
>                    r = parse_string(d);
>                    scriptname = oldscriptname;
>
> +                   if (fname)
> +                       *fname = ztrdup(buf);
> +
>                    zfree(d, len + 1);
>
>                    return r;
> Index: Src/hashtable.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/hashtable.c,v
> retrieving revision 1.27
> diff -u -r1.27 hashtable.c
> --- Src/hashtable.c     1 Nov 2007 10:59:40 -0000       1.27
> +++ Src/hashtable.c     9 Aug 2008 18:10:14 -0000
> @@ -852,6 +852,7 @@
>     zsfree(shf->node.nam);
>     if (shf->funcdef)
>        freeeprog(shf->funcdef);
> +    zsfree(shf->filename);
>     zfree(shf, sizeof(struct shfunc));
>  }
>
> Index: Src/init.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/init.c,v
> retrieving revision 1.91
> diff -u -r1.91 init.c
> --- Src/init.c  7 Aug 2008 16:25:16 -0000       1.91
> +++ Src/init.c  9 Aug 2008 18:10:14 -0000
> @@ -268,7 +268,7 @@
>                /* -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 @@
>            }
>            opts[INTERACTIVE] &= 1;
>            argzero = *argv;
> +           scriptfilename = argzero;
>            argv++;
>        }
>        while (*argv)
> @@ -1051,10 +1052,12 @@
>  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 @@
>     loops  = 0;
>     dosetopt(SHINSTDIN, 0, 1);
>     scriptname = s;
> +    scriptfilename = s;
>
>     /*
>      * The special return behaviour of traps shouldn't
> @@ -1096,6 +1100,17 @@
>     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 @@
>        popheap();
>     } else
>        loop(0, 0);                  /* loop through the file to be sourced  */
> +    /* funcstack = funcstack->prev; */
>     sourcelevel--;
>
>     trap_state = otrap_state;
> @@ -1126,6 +1142,7 @@
>     if (!exit_pending)
>        retflag = 0;
>     scriptname = old_scriptname;
> +    scriptfilename = old_scriptfilename;
>     free(cmdstack);
>     cmdstack = ocs;
>     cmdsp = ocsp;
> Index: Src/parse.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/parse.c,v
> retrieving revision 1.70
> diff -u -r1.70 parse.c
> --- Src/parse.c 1 Jul 2008 18:38:40 -0000       1.70
> +++ Src/parse.c 9 Aug 2008 18:10:15 -0000
> @@ -720,7 +720,8 @@
>  static int
>  par_pline(int *complex)
>  {
> -    int p, line = lineno;
> +    int p;
> +    zlong line = lineno;
>
>     p = ecadd(0);
>
> @@ -1414,8 +1415,9 @@
>  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 @@
>            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 @@
>            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;
> Index: Src/utils.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
> retrieving revision 1.198
> diff -u -r1.198 utils.c
> --- Src/utils.c 31 Jul 2008 08:44:21 -0000      1.198
> +++ Src/utils.c 9 Aug 2008 18:10:17 -0000
> @@ -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 {
> Index: Src/zsh.h
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
> retrieving revision 1.140
> diff -u -r1.140 zsh.h
> --- Src/zsh.h   7 Aug 2008 16:25:16 -0000       1.140
> +++ Src/zsh.h   9 Aug 2008 18:10:18 -0000
> @@ -1061,6 +1061,8 @@
>
>  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 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 */
> 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     9 Aug 2008 18:10:18 -0000
> @@ -286,7 +286,7 @@
>        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 @@
>        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 funcfiletrace special parameter. */
> +
> +/**/
> +static char **
> +funcfiletracegetfn(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 @@
>  { funcstackgetfn, arrsetfn, stdunsetfn };
>  static const struct gsu_array functrace_gsu =
>  { functracegetfn, arrsetfn, stdunsetfn };
> +static const struct gsu_array funcfiletrace_gsu =
> +{ funcfiletracegetfn, arrsetfn, stdunsetfn };
>  static const struct gsu_array reswords_gsu =
>  { reswordsgetfn, arrsetfn, stdunsetfn };
>  static const struct gsu_array disreswords_gsu =
> @@ -1807,6 +1837,8 @@
>                 scanpmfunctions),
>     SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
>            &functrace_gsu, NULL, NULL),
> +    SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY,
> +           &funcfiletrace_gsu, NULL, NULL),
>     SPECIALPMDEF("galiases", 0,
>            &pmgaliases_gsu, getpmgalias, scanpmgaliases),
>     SPECIALPMDEF("history", PM_READONLY,
> --
> Peter Stephenson <p.w.stephenson@ntlworld.com>
> Web page now at http://homepage.ntlworld.com/p.w.stephenson/
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-09 18:21     ` Peter Stephenson
  2008-08-10  1:11       ` Rocky Bernstein
@ 2008-08-11 14:00       ` Richard Hartmann
  2008-08-13 20:51         ` Peter Stephenson
  1 sibling, 1 reply; 13+ messages in thread
From: Richard Hartmann @ 2008-08-11 14:00 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Sat, Aug 9, 2008 at 20:21, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:

[stuff about $funcfiletrace]

This just gave me an idea: Why not enhance `whence` so it is able to
tell in what file and starting on what line a function has been defined?


Richard


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-10  1:11       ` Rocky Bernstein
@ 2008-08-11 19:32         ` Peter Stephenson
  2008-08-11 19:39           ` Rocky Bernstein
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stephenson @ 2008-08-11 19:32 UTC (permalink / raw)
  To: zsh-workers

"Rocky Bernstein" wrote:
> Great! Let me know when code is committed into CVS which includes
> tracking source calls, and I'll revise the zshdb code then.
> 
> Ditto for instruction skipping and/or showing the command to be run.

I've committed the source code tracing, but I decided "funcsourcetrace"
was a better name than "funcfiletrace", since "file" doesn't really
distinguish the purpose of the new variable.  I've added a test and
fixed a couple of additional bugs.  The test is fairly simple and it's
quite possible that extending it would reveal further problems.

The instruction skipping using "setopt ERR_EXIT" is also there.

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-11 19:32         ` Peter Stephenson
@ 2008-08-11 19:39           ` Rocky Bernstein
  2008-08-11 19:51             ` Peter Stephenson
  0 siblings, 1 reply; 13+ messages in thread
From: Rocky Bernstein @ 2008-08-11 19:39 UTC (permalink / raw)
  To: zsh-workers

funcsourcetrace contains entries for source'd files, right?

On Mon, Aug 11, 2008 at 3:32 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> "Rocky Bernstein" wrote:
>> Great! Let me know when code is committed into CVS which includes
>> tracking source calls, and I'll revise the zshdb code then.
>>
>> Ditto for instruction skipping and/or showing the command to be run.
>
> I've committed the source code tracing, but I decided "funcsourcetrace"
> was a better name than "funcfiletrace", since "file" doesn't really
> distinguish the purpose of the new variable.  I've added a test and
> fixed a couple of additional bugs.  The test is fairly simple and it's
> quite possible that extending it would reveal further problems.
>
> The instruction skipping using "setopt ERR_EXIT" is also there.
>
> --
> Peter Stephenson <p.w.stephenson@ntlworld.com>
> Web page now at http://homepage.ntlworld.com/p.w.stephenson/
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-11 19:39           ` Rocky Bernstein
@ 2008-08-11 19:51             ` Peter Stephenson
  2008-08-11 20:01               ` Rocky Bernstein
  0 siblings, 1 reply; 13+ messages in thread
From: Peter Stephenson @ 2008-08-11 19:51 UTC (permalink / raw)
  To: Rocky Bernstein; +Cc: zsh-workers, pws

"Rocky Bernstein" wrote:
> funcsourcetrace contains entries for source'd files, right?

It's still just the information for the source of functions.  I haven't
modified it to know about sourced files yet.

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-11 19:51             ` Peter Stephenson
@ 2008-08-11 20:01               ` Rocky Bernstein
  0 siblings, 0 replies; 13+ messages in thread
From: Rocky Bernstein @ 2008-08-11 20:01 UTC (permalink / raw)
  To: zsh-workers

Ok. I think I'll hold off updating until that happens.

On Mon, Aug 11, 2008 at 3:51 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> "Rocky Bernstein" wrote:
>> funcsourcetrace contains entries for source'd files, right?
>
> It's still just the information for the source of functions.  I haven't
> modified it to know about sourced files yet.


>
> --
> Peter Stephenson <p.w.stephenson@ntlworld.com>
> Web page now at http://homepage.ntlworld.com/p.w.stephenson/
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Getting source file and line number of a function.
  2008-08-11 14:00       ` Richard Hartmann
@ 2008-08-13 20:51         ` Peter Stephenson
  0 siblings, 0 replies; 13+ messages in thread
From: Peter Stephenson @ 2008-08-13 20:51 UTC (permalink / raw)
  To: zsh-workers

On Mon, 11 Aug 2008 16:00:21 +0200
"Richard Hartmann" <richih.mailinglist@gmail.com> wrote:
> On Sat, Aug 9, 2008 at 20:21, Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
> 
> [stuff about $funcfiletrace]

(which now really is called that...)

> This just gave me an idea: Why not enhance `whence` so it is able to
> tell in what file and starting on what line a function has been defined?

Just to note I haven't forgot this yet (haven't looked at if or where it
fits without messing up the format).  I think it would be useful to
provide an associative array in zsh/parameter with this information to
get at it easily, something like $functionsources (since the assoc
array with the functions is called $functions).

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2008-08-13 20:52 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-07-27  1:06 Getting source file and line number of a function Rocky Bernstein
2008-07-28  8:34 ` Peter Stephenson
2008-07-28 12:46   ` Rocky Bernstein
2008-07-30  2:31     ` Rocky Bernstein
2008-07-30  8:22       ` Peter Stephenson
2008-08-09 18:21     ` Peter Stephenson
2008-08-10  1:11       ` Rocky Bernstein
2008-08-11 19:32         ` Peter Stephenson
2008-08-11 19:39           ` Rocky Bernstein
2008-08-11 19:51             ` Peter Stephenson
2008-08-11 20:01               ` Rocky Bernstein
2008-08-11 14:00       ` Richard Hartmann
2008-08-13 20:51         ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).