Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Getting source file and line number of a function.
- X-seq: zsh-workers 25428
- From: "Rocky Bernstein" <rocky.bernstein@xxxxxxxxx>
- To: zsh-workers@xxxxxxxxxx
- Subject: Re: Getting source file and line number of a function.
- Date: Sat, 9 Aug 2008 21:11:15 -0400
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from:to :subject:in-reply-to:mime-version:content-type :content-transfer-encoding:content-disposition:references; bh=tuCclZTYF9RcL1BfAvAMYETXPB4Ecmirlwy9dDmweds=; b=QHqajbLELd4eXkV6jbT2YLMhtkfakRiDV5qZYnte9UgdrQYrlqdeTh4kpJyip/fXzX rY7P9ActmqvNcGrv7XO5UwzFVQZ5O56b2OIQbLClTsdjutHjAFgtZCJlFjmXo9w3PdJs cd1W8oQo6/+DTlwtjmbrAiFir0tMnV/K7VkUY=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:to:subject:in-reply-to:mime-version :content-type:content-transfer-encoding:content-disposition :references; b=g5iYnuyV6BuGAioL+PLisJG0Ph4DznBkJkEJbQa3rD2+dg9BJAPB2wccun+XPerO4R lhbHqG+2Vf+jxX0F3tXmNpCegVTVn0JcBDZ9rKiwKPQDMifiWgrjctVZCSnqcvVDP79s BvkL9FF2Xt3UfsFG6DR5WpSfvOEFme6yCKWnw=
- In-reply-to: <20080809192111.7213e919@pws-pc>
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
- References: <6cd6de210807261806r7ff184fdtcc7859cca0a98aef@xxxxxxxxxxxxxx> <200807280834.m6S8YEVo026326@xxxxxxxxxxxxxx> <6cd6de210807280546k14a1a59fo40cb6ed968b1227b@xxxxxxxxxxxxxx> <20080809192111.7213e919@pws-pc>
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@xxxxxxxxxxxx> wrote:
> On Mon, 28 Jul 2008 08:46:43 -0400
> "Rocky Bernstein" <rocky.bernstein@xxxxxxxxx> 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@xxxxxxxxxxxx>
> Web page now at http://homepage.ntlworld.com/p.w.stephenson/
>
Messages sorted by:
Reverse Date,
Date,
Thread,
Author