zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: source file info from PS4
@ 2008-09-16 14:50 Peter Stephenson
  2008-09-16 16:17 ` Rocky Bernstein
  2008-09-17 16:39 ` Rocky Bernstein
  0 siblings, 2 replies; 9+ messages in thread
From: Peter Stephenson @ 2008-09-16 14:50 UTC (permalink / raw)
  To: Zsh hackers list

Now we have logic for finding the source file and corresponding line
number of executed code, this adds the prompt escapes %x and %I which
are like %N and %i but for the file where the code was defined.  %x isn't
ideal but upper and lower case %s, %f and %n are all used.  It stands
for "execution file", or something.  The idea is that you set
PS4='+%x:%I>'

While doing this, I spotted that we could improve the information
available to funcstack and the interface to doshfunc() by passing in a
Shfunc instead of an Eprog.  This is a *much* cleaner interface.  Now
the funcstack entry is guaranteed to get the details of the shell
function correct.

Index: Doc/Zsh/prompt.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/prompt.yo,v
retrieving revision 1.15
diff -u -r1.15 prompt.yo
--- Doc/Zsh/prompt.yo	24 Jun 2008 08:44:16 -0000	1.15
+++ Doc/Zsh/prompt.yo	16 Sep 2008 14:41:10 -0000
@@ -113,6 +113,11 @@
 shell function given by tt(%N).  This is most useful for debugging as part
 of tt($PS4).
 )
+item(tt(%I))(
+The line number currently being executed in the file tt(%x).  This is
+similar to tt(%i), but the line number is always a line number in the
+file where the code was defined, even if the code is a shell function.
+)
 item(tt(%j))(
 The number of jobs.
 )
@@ -126,6 +131,11 @@
 the `tt(%)' to specify a number of trailing path components to show; zero
 means the full path.  A negative integer specifies leading components.
 )
+item(tt(%x))(
+The name of the file containing the source code currently being
+executed.  This behaves as tt(%N) except that function and eval command
+names are not shown, instead the file where they were defined.
+)
 xitem(tt(%c))
 xitem(tt(%.))
 item(tt(%C))(
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.151
diff -u -r1.151 exec.c
--- Src/exec.c	11 Sep 2008 17:14:39 -0000	1.151
+++ Src/exec.c	16 Sep 2008 14:41:10 -0000
@@ -518,7 +518,7 @@
 	return 127;
 
     pushnode(args, arg0);
-    return doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags, 1);
+    return doshfunc(shf, args, shf->node.flags, 1);
 }
 
 /* execute an external command */
@@ -4064,7 +4064,7 @@
     cmdsp = 0;
     if ((osfc = sfcontext) == SFC_NONE)
 	sfcontext = SFC_DIRECT;
-    doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags, 0);
+    doshfunc(shf, args, shf->node.flags, 0);
     sfcontext = osfc;
     free(cmdstack);
     cmdstack = ocs;
@@ -4200,18 +4200,20 @@
 
 /**/
 mod_export int
-doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
+doshfunc(Shfunc shfunc, LinkList doshargs, int flags, int noreturnval)
 {
     char **tab, **x, *oargv0;
     int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret;
     int *oldpipestats = NULL;
-    char saveopts[OPT_SIZE], *oldscriptname = scriptname, *fname = dupstring(name);
+    char saveopts[OPT_SIZE], *oldscriptname = scriptname;
+    char *name = shfunc->node.nam;
+    char *fname = dupstring(name);
     int obreaks, saveemulation ;
+    Eprog prog;
     struct funcstack fstack;
 #ifdef MAX_FUNCTION_DEPTH
     static int funcdepth;
 #endif
-    Shfunc shf;
 
     pushheap();
 
@@ -4291,14 +4293,10 @@
     fstack.tp = FS_FUNC;
     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);
-    }
+    fstack.flineno = shfunc->lineno;
+    fstack.filename = dupstring(shfunc->filename);
 
+    prog = shfunc->funcdef;
     if (prog->flags & EF_RUN) {
 	Shfunc shf;
 
Index: Src/init.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/init.c,v
retrieving revision 1.96
diff -u -r1.96 init.c
--- Src/init.c	11 Sep 2008 17:14:39 -0000	1.96
+++ Src/init.c	16 Sep 2008 14:41:10 -0000
@@ -149,7 +149,7 @@
 	    int toksav = tok;
 
 	    if (toplevel &&
-		(getshfunc("preexec") != &dummy_eprog ||
+		(getshfunc("preexec") ||
 		 paramtab->getnode(paramtab, "preexec_functions"))) {
 		LinkList args;
 		char *cmdstr;
Index: Src/math.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/math.c,v
retrieving revision 1.33
diff -u -r1.33 math.c
--- Src/math.c	12 Jun 2008 13:45:06 -0000	1.33
+++ Src/math.c	16 Sep 2008 14:41:10 -0000
@@ -868,11 +868,11 @@
 					   argc <= f->maxargs)) {
 		    if (f->flags & MFF_USERFUNC) {
 			char *shfnam = f->module ? f->module : n;
-			Eprog prog = getshfunc(shfnam);
-			if (prog == &dummy_eprog)
+			Shfunc shfunc = getshfunc(shfnam);
+			if (!shfunc)
 			    zerr("no such function: %s", shfnam);
 			else {
-			    doshfunc(n, prog, l, 0, 1);
+			    doshfunc(shfunc, l, 0, 1);
 			    return lastmathval;
 			}
 		    } else {
Index: Src/prompt.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/prompt.c,v
retrieving revision 1.53
diff -u -r1.53 prompt.c
--- Src/prompt.c	15 Sep 2008 16:18:06 -0000	1.53
+++ Src/prompt.c	16 Sep 2008 14:41:11 -0000
@@ -725,11 +725,37 @@
 		if(Rstring)
 		    stradd(Rstring);
 		break;
+	    case 'I':
+		if (funcstack && funcstack->tp != FS_SOURCE) {
+		    /*
+		     * We're in a function or an eval with
+		     * EVALLINENO.  Calculate the line number in
+		     * the file.
+		     */
+		    zlong flineno = lineno + funcstack->flineno;
+		    /* take account of eval line nos. starting at 1 */
+		    if (funcstack->tp == FS_EVAL)
+			lineno--;
+		    addbufspc(DIGBUFSIZE);
+		    sprintf(bp, "%ld", (long)flineno);
+		    bp += strlen(bp);
+		    break;
+		}
+		/* else we're in a file and lineno is already correct */
+		/* FALLTHROUGH */
 	    case 'i':
 		addbufspc(DIGBUFSIZE);
 		sprintf(bp, "%ld", (long)lineno);
 		bp += strlen(bp);
 		break;
+	    case 'x':
+		if (funcstack && funcstack->tp != FS_SOURCE)
+		    promptpath(funcstack->filename ? funcstack->filename : "",
+			       arg, 0);
+		else
+		    promptpath(scriptfilename ? scriptfilename : argzero,
+			       arg, 0);
+		break;
 	    case '\0':
 		return 0;
 	    case Meta:
Index: Src/signals.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/signals.c,v
retrieving revision 1.50
diff -u -r1.50 signals.c
--- Src/signals.c	11 Aug 2008 19:22:54 -0000	1.50
+++ Src/signals.c	16 Sep 2008 14:41:11 -0000
@@ -963,8 +963,7 @@
     }
 
     if (exittr) {
-	dotrapargs(SIGEXIT, &exittr, (exittr & ZSIG_FUNC) ?
-		   ((Shfunc)exitfn)->funcdef : (Eprog) exitfn);
+	dotrapargs(SIGEXIT, &exittr, exitfn);
 	if (exittr & ZSIG_FUNC)
 	    shfunctab->freenode((HashNode)exitfn);
 	else
@@ -1077,8 +1076,16 @@
 /**/
 int trapisfunc;
 
+/*
+ * sig is the signal number.
+ * *sigtr is the value to be taken as the field in sigtrapped (since
+ *   that may have changed by this point if we are exiting).
+ * sigfn is an Eprog with a non-function eval list, or a Shfunc
+ *   with a function trap.  It may be NULL with an ignored signal.
+ */
+
 /**/
-void
+static void
 dotrapargs(int sig, int *sigtr, void *sigfn)
 {
     LinkList args;
@@ -1153,7 +1160,7 @@
 	trapisfunc = isfunc = 1;
 
 	sfcontext = SFC_SIGNAL;
-	doshfunc(name, sigfn, args, 0, 1);
+	doshfunc((Shfunc)sigfn, args, 0, 1);
 	sfcontext = osc;
 	freelinklist(args, (FreeFunc) NULL);
 	zsfree(name);
@@ -1162,7 +1169,7 @@
 	trap_state = TRAP_STATE_PRIMED;
 	trapisfunc = isfunc = 0;
 
-	execode(sigfn, 1, 0);
+	execode((Eprog)sigfn, 1, 0);
     }
     runhookdef(AFTERTRAPHOOK, NULL);
 
@@ -1215,12 +1222,12 @@
 void
 dotrap(int sig)
 {
-    Eprog funcprog;
+    void *funcprog;
 
     if (sigtrapped[sig] & ZSIG_FUNC) {
 	HashNode hn = gettrapnode(sig, 0);
 	if (hn)
-	    funcprog = ((Shfunc)hn)->funcdef;
+	    funcprog = hn;
 	else {
 #ifdef DEBUG
 	    dputs("BUG: running function trap which has escaped.");
@@ -1230,7 +1237,11 @@
     } else
 	funcprog = siglists[sig];
 
-    /* Copied from dotrapargs(). */
+    /*
+     * Copied from dotrapargs().
+     * (In fact, the gain from duplicating this appears to be virtually
+     * zero.  Not sure why it's here.)
+     */
     if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag)
 	return;
 
Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.199
diff -u -r1.199 utils.c
--- Src/utils.c	11 Aug 2008 19:22:54 -0000	1.199
+++ Src/utils.c	16 Sep 2008 14:41:11 -0000
@@ -35,6 +35,8 @@
 /**/
 mod_export char *scriptname;     /* is sometimes a function name */
 
+/* filename of script or other file containing code source e.g. autoload */
+
 /**/
 mod_export char *scriptfilename;
 
@@ -1134,7 +1136,7 @@
 mod_export int
 callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval)
 {
-    Eprog prog;
+    Shfunc shfunc;
 	/*
 	 * Save stopmsg, since user doesn't get a chance to respond
 	 * to a list of jobs generated in a hook.
@@ -1143,8 +1145,8 @@
 
     sfcontext = SFC_HOOK;
 
-    if ((prog = getshfunc(name)) != &dummy_eprog) {
-	ret = doshfunc(name, prog, lnklst, 0, 1);
+    if ((shfunc = getshfunc(name))) {
+	ret = doshfunc(shfunc, lnklst, 0, 1);
 	stat = 0;
     }
 
@@ -1159,8 +1161,8 @@
 
 	if ((arrptr = getaparam(arrnam))) {
 	    for (; *arrptr; arrptr++) {
-		if ((prog = getshfunc(*arrptr)) != &dummy_eprog) {
-		    int newret = doshfunc(arrnam, prog, lnklst, 0, 1);
+		if ((shfunc = getshfunc(*arrptr))) {
+		    int newret = doshfunc(shfunc, lnklst, 0, 1);
 		    if (!ret)
 			ret = newret;
 		    stat = 0;
@@ -2893,15 +2895,10 @@
 /* Get the definition of a shell function */
 
 /**/
-mod_export Eprog
+mod_export Shfunc
 getshfunc(char *nam)
 {
-    Shfunc shf;
-
-    if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, nam)))
-	return &dummy_eprog;
-
-    return shf->funcdef;
+    return (Shfunc) shfunctab->getnode(shfunctab, nam);
 }
 
 /**/
Index: Src/Modules/zftp.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/zftp.c,v
retrieving revision 1.48
diff -u -r1.48 zftp.c
--- Src/Modules/zftp.c	4 Sep 2008 22:23:52 -0000	1.48
+++ Src/Modules/zftp.c	16 Sep 2008 14:41:11 -0000
@@ -1469,9 +1469,9 @@
     char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr;
     off_t sofar = 0, last_sofar = 0;
     readwrite_t read_ptr = zfread, write_ptr = zfwrite;
-    Eprog prog;
+    Shfunc shfunc;
 
-    if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
+    if (progress && (shfunc = getshfunc("zftp_progress"))) {
 	/*
 	 * progress to set up:  ZFTP_COUNT is zero.
 	 * We do this here in case we needed to wait for a RETR
@@ -1480,7 +1480,7 @@
 	int osc = sfcontext;
 
 	sfcontext = SFC_HOOK;
-	doshfunc("zftp_progress", prog, NULL, 0, 1);
+	doshfunc(shfunc, NULL, 0, 1);
 	sfcontext = osc;
 	/* Now add in the bit of the file we've got/sent already */
 	sofar = last_sofar = startat;
@@ -1608,12 +1608,12 @@
 	} else
 	    break;
 	if (!ret && sofar != last_sofar && progress &&
-	    (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
+	    (shfunc = getshfunc("zftp_progress"))) {
 	    int osc = sfcontext;
 
 	    zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER);
 	    sfcontext = SFC_HOOK;
-	    doshfunc("zftp_progress", prog, NULL, 0, 1);
+	    doshfunc(shfunc, NULL, 0, 1);
 	    sfcontext = osc;
 	    last_sofar = sofar;
 	}
@@ -2364,7 +2364,7 @@
 {
     char *ptr, *eptr;
     int endc;
-    Eprog prog;
+    Shfunc shfunc;
 
     if (zfprefs & ZFPF_DUMB)
 	return 1;
@@ -2391,11 +2391,11 @@
      * front end.  By putting it here, and in close when ZFTP_PWD is unset,
      * we at least cover the bases.
      */
-    if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
+    if ((shfunc = getshfunc("zftp_chpwd"))) {
 	int osc = sfcontext;
 
 	sfcontext = SFC_HOOK;
-	doshfunc("zftp_chpwd", prog, NULL, 0, 1);
+	doshfunc(shfunc, NULL, 0, 1);
 	sfcontext = osc;
     }
     return 0;
@@ -2549,7 +2549,7 @@
 {
     int ret = 0, recv = (flags & ZFTP_RECV), getsize = 0, progress = 1;
     char *cmd = recv ? "RETR " : (flags & ZFTP_APPE) ? "APPE " : "STOR ";
-    Eprog prog;
+    Shfunc shfunc;
 
     /*
      * At this point I'd like to set progress to 0 if we're
@@ -2567,7 +2567,7 @@
     for (; *args; args++) {
 	char *ln, *rest = NULL;
 	off_t startat = 0;
-	if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
+	if (progress && (shfunc = getshfunc("zftp_progress"))) {
 	    off_t sz = -1;
 	    /*
 	     * This calls the SIZE command to get the size for remote
@@ -2608,14 +2608,14 @@
 	 * if and only if we called zfsenddata();
 	 */
 	if (progress && ret != 2 &&
-	    (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
+	    (shfunc = getshfunc("zftp_progress"))) {
 	    /* progress to finish: ZFTP_TRANSFER set to GF or PF */
 	    int osc = sfcontext;
 
 	    zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"),
 		       ZFPM_READONLY);
 	    sfcontext = SFC_HOOK;
-	    doshfunc("zftp_progress", prog, NULL, 0, 1);
+	    doshfunc(shfunc, NULL, 0, 1);
 	    sfcontext = osc;
 	}
 	if (rest) {
@@ -2715,7 +2715,7 @@
 zfclose(int leaveparams)
 {
     char **aptr;
-    Eprog prog;
+    Shfunc shfunc;
 
     if (!zfsess->control)
 	return;
@@ -2766,11 +2766,11 @@
 	    zfunsetparam(*aptr);
 
 	/* Now ZFTP_PWD is unset.  It's up to zftp_chpwd to notice. */
-	if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
+	if ((shfunc = getshfunc("zftp_chpwd"))) {
 	    int osc = sfcontext;
 
 	    sfcontext = SFC_HOOK;
-	    doshfunc("zftp_chpwd", prog, NULL, 0, 1);
+	    doshfunc(shfunc, NULL, 0, 1);
 	    sfcontext = osc;
 	}
     }
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.96
diff -u -r1.96 compcore.c
--- Src/Zle/compcore.c	7 Jul 2008 08:33:28 -0000	1.96
+++ Src/Zle/compcore.c	16 Sep 2008 14:41:12 -0000
@@ -540,13 +540,13 @@
 static void
 callcompfunc(char *s, char *fn)
 {
-    Eprog prog;
+    Shfunc shfunc;
     int lv = lastval;
     char buf[20];
 
     METACHECK();
 
-    if ((prog = getshfunc(fn)) != &dummy_eprog) {
+    if ((shfunc = getshfunc(fn))) {
 	char **p, *tmp;
 	int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
 	unsigned int rset, kset;
@@ -814,7 +814,7 @@
 		while (*p)
 		    addlinknode(largs, dupstring(*p++));
 	    }
-	    doshfunc(fn, prog, largs, 0, 0);
+	    doshfunc(shfunc, largs, 0, 0);
 	    cfret = lastval;
 	    lastval = olv;
 	} OLDHEAPS;
Index: Src/Zle/compctl.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compctl.c,v
retrieving revision 1.35
diff -u -r1.35 compctl.c
--- Src/Zle/compctl.c	3 Oct 2007 16:18:38 -0000	1.35
+++ Src/Zle/compctl.c	16 Sep 2008 14:41:12 -0000
@@ -3635,12 +3635,12 @@
     }
     if (cc->func) {
 	/* This handles the compctl -K flag. */
-	Eprog prog;
+	Shfunc shfunc;
 	char **r;
 	int lv = lastval;
 	    
 	/* Get the function. */
-	if ((prog = getshfunc(cc->func)) != &dummy_eprog) {
+	if ((shfunc = getshfunc(cc->func))) {
 	    /* We have it, so build a argument list. */
 	    LinkList args = newlinklist();
 	    int osc = sfcontext;
@@ -3664,7 +3664,7 @@
 		incompctlfunc = 1;
 	    sfcontext = SFC_COMPLETE;
 	    /* Call the function. */
-	    doshfunc(cc->func, prog, args, 0, 1);
+	    doshfunc(shfunc, args, 0, 1);
 	    sfcontext = osc;
 	    incompctlfunc = 0;
 	    /* And get the result from the reply parameter. */
@@ -3809,12 +3809,12 @@
 	/* generate the user-defined display list: if anything fails, *
 	 * we silently allow the normal completion list to be used.   */
 	char **yaptr = NULL, *uv = NULL;
-	Eprog prog;
+	Shfunc shfunc;
 
 	if (cc->ylist[0] == '$' || cc->ylist[0] == '(') {
 	    /* from variable */
 	    uv = cc->ylist + (cc->ylist[0] == '$');
-	} else if ((prog = getshfunc(cc->ylist)) != &dummy_eprog) {
+	} else if ((shfunc = getshfunc(cc->ylist))) {
 	    /* from function:  pass completions as arg list */
 	    LinkList args = newlinklist();
 	    LinkNode ln;
@@ -3839,7 +3839,7 @@
 	    if (incompfunc != 1)
 		incompctlfunc = 1;
 	    sfcontext = SFC_COMPLETE;
-	    doshfunc(cc->ylist, prog, args, 0, 1);
+	    doshfunc(shfunc, args, 0, 1);
 	    sfcontext = osc;
 	    incompctlfunc = 0;
 	    uv = "reply";
Index: Src/Zle/zle_main.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
retrieving revision 1.115
diff -u -r1.115 zle_main.c
--- Src/Zle/zle_main.c	8 Sep 2008 06:24:23 -0000	1.115
+++ Src/Zle/zle_main.c	16 Sep 2008 14:41:12 -0000
@@ -1304,9 +1304,8 @@
 	r = 1;
     } else {
 	Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam);
-	Eprog prog = (shf ? shf->funcdef : &dummy_eprog);
 
-	if(prog == &dummy_eprog) {
+	if (!shf) {
 	    /* the shell function doesn't exist */
 	    char *nm = nicedup(w->u.fnnam, 0);
 	    char *msg = tricat("No such shell function `", nm, "'");
@@ -1330,7 +1329,7 @@
 	    makezleparams(0);
 	    sfcontext = SFC_WIDGET;
 	    opts[XTRACE] = 0;
-	    ret = doshfunc(w->u.fnnam, prog, largs, shf->node.flags, 1);
+	    ret = doshfunc(shf, largs, shf->node.flags, 1);
 	    opts[XTRACE] = oxt;
 	    sfcontext = osc;
 	    endparamscope();
Index: Src/Zle/zle_misc.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_misc.c,v
retrieving revision 1.54
diff -u -r1.54 zle_misc.c
--- Src/Zle/zle_misc.c	4 May 2008 18:30:04 -0000	1.54
+++ Src/Zle/zle_misc.c	16 Sep 2008 14:41:12 -0000
@@ -1358,9 +1358,9 @@
 iremovesuffix(ZLE_INT_T c, int keep)
 {
     if (suffixfunc) {
-	Eprog prog = getshfunc(suffixfunc);
+	Shfunc shfunc = getshfunc(suffixfunc);
 
-	if (prog != &dummy_eprog) {
+	if (shfunc) {
 	    LinkList args = newlinklist();
 	    char buf[20];
 	    int osc = sfcontext;
@@ -1384,7 +1384,7 @@
 	    startparamscope();
 	    makezleparams(0);
 	    sfcontext = SFC_COMPLETE;
-	    doshfunc(suffixfunc, prog, args, 0, 1);
+	    doshfunc(shfunc, args, 0, 1);
 	    sfcontext = osc;
 	    endparamscope();
 
Index: Test/E02xtrace.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/E02xtrace.ztst,v
retrieving revision 1.7
diff -u -r1.7 E02xtrace.ztst
--- Test/E02xtrace.ztst	11 Aug 2008 08:40:58 -0000	1.7
+++ Test/E02xtrace.ztst	16 Sep 2008 14:41:12 -0000
@@ -90,3 +90,18 @@
 >Tracing: function
 ?+xtf:1> local regression_test_dummy_variable
 ?+xtf:2> print 'Tracing: function'
+
+ echo 'PS4="+%x:%I> "
+ fn() {
+   print This is fn.
+ }
+ :
+ fn
+ ' >fnfile
+ $ZTST_testdir/../Src/zsh -fx ./fnfile
+0:Trace output with sourcefile and line number.
+>This is fn.
+?+./fnfile:1> PS4='+%x:%I> ' 
+?+./fnfile:5> :
+?+./fnfile:6> fn
+?+./fnfile:3> print This is fn.


-- 
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] 9+ messages in thread

* Re: PATCH: source file info from PS4
  2008-09-16 14:50 PATCH: source file info from PS4 Peter Stephenson
@ 2008-09-16 16:17 ` Rocky Bernstein
  2008-09-17 16:39 ` Rocky Bernstein
  1 sibling, 0 replies; 9+ messages in thread
From: Rocky Bernstein @ 2008-09-16 16:17 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

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

Thanks!

This is certainly something I've wanted ever since funcstack was improved
but had been holding back on.

The fretting about what letter to use after % would be reduced and if the
promptsubst option also applied to PS4. In my opinion not only is it more
readable and requires less memory on a users part, but is also more
flexible.


On Tue, Sep 16, 2008 at 10:50 AM, Peter Stephenson <pws@csr.com> wrote:

> Now we have logic for finding the source file and corresponding line
> number of executed code, this adds the prompt escapes %x and %I which
> are like %N and %i but for the file where the code was defined.  %x isn't
> ideal but upper and lower case %s, %f and %n are all used.  It stands
> for "execution file", or something.  The idea is that you set
> PS4='+%x:%I>'
>
> While doing this, I spotted that we could improve the information
> available to funcstack and the interface to doshfunc() by passing in a
> Shfunc instead of an Eprog.  This is a *much* cleaner interface.  Now
> the funcstack entry is guaranteed to get the details of the shell
> function correct.
>
> Index: Doc/Zsh/prompt.yo
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Doc/Zsh/prompt.yo,v
> retrieving revision 1.15
> diff -u -r1.15 prompt.yo
> --- Doc/Zsh/prompt.yo   24 Jun 2008 08:44:16 -0000      1.15
> +++ Doc/Zsh/prompt.yo   16 Sep 2008 14:41:10 -0000
> @@ -113,6 +113,11 @@
>  shell function given by tt(%N).  This is most useful for debugging as part
>  of tt($PS4).
>  )
> +item(tt(%I))(
> +The line number currently being executed in the file tt(%x).  This is
> +similar to tt(%i), but the line number is always a line number in the
> +file where the code was defined, even if the code is a shell function.
> +)
>  item(tt(%j))(
>  The number of jobs.
>  )
> @@ -126,6 +131,11 @@
>  the `tt(%)' to specify a number of trailing path components to show; zero
>  means the full path.  A negative integer specifies leading components.
>  )
> +item(tt(%x))(
> +The name of the file containing the source code currently being
> +executed.  This behaves as tt(%N) except that function and eval command
> +names are not shown, instead the file where they were defined.
> +)
>  xitem(tt(%c))
>  xitem(tt(%.))
>  item(tt(%C))(
> Index: Src/exec.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
> retrieving revision 1.151
> diff -u -r1.151 exec.c
> --- Src/exec.c  11 Sep 2008 17:14:39 -0000      1.151
> +++ Src/exec.c  16 Sep 2008 14:41:10 -0000
> @@ -518,7 +518,7 @@
>        return 127;
>
>     pushnode(args, arg0);
> -    return doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags,
> 1);
> +    return doshfunc(shf, args, shf->node.flags, 1);
>  }
>
>  /* execute an external command */
> @@ -4064,7 +4064,7 @@
>     cmdsp = 0;
>     if ((osfc = sfcontext) == SFC_NONE)
>        sfcontext = SFC_DIRECT;
> -    doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags, 0);
> +    doshfunc(shf, args, shf->node.flags, 0);
>     sfcontext = osfc;
>     free(cmdstack);
>     cmdstack = ocs;
> @@ -4200,18 +4200,20 @@
>
>  /**/
>  mod_export int
> -doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int
> noreturnval)
> +doshfunc(Shfunc shfunc, LinkList doshargs, int flags, int noreturnval)
>  {
>     char **tab, **x, *oargv0;
>     int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret;
>     int *oldpipestats = NULL;
> -    char saveopts[OPT_SIZE], *oldscriptname = scriptname, *fname =
> dupstring(name);
> +    char saveopts[OPT_SIZE], *oldscriptname = scriptname;
> +    char *name = shfunc->node.nam;
> +    char *fname = dupstring(name);
>     int obreaks, saveemulation ;
> +    Eprog prog;
>     struct funcstack fstack;
>  #ifdef MAX_FUNCTION_DEPTH
>     static int funcdepth;
>  #endif
> -    Shfunc shf;
>
>     pushheap();
>
> @@ -4291,14 +4293,10 @@
>     fstack.tp = FS_FUNC;
>     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);
> -    }
> +    fstack.flineno = shfunc->lineno;
> +    fstack.filename = dupstring(shfunc->filename);
>
> +    prog = shfunc->funcdef;
>     if (prog->flags & EF_RUN) {
>        Shfunc shf;
>
> Index: Src/init.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/init.c,v
> retrieving revision 1.96
> diff -u -r1.96 init.c
> --- Src/init.c  11 Sep 2008 17:14:39 -0000      1.96
> +++ Src/init.c  16 Sep 2008 14:41:10 -0000
> @@ -149,7 +149,7 @@
>            int toksav = tok;
>
>            if (toplevel &&
> -               (getshfunc("preexec") != &dummy_eprog ||
> +               (getshfunc("preexec") ||
>                 paramtab->getnode(paramtab, "preexec_functions"))) {
>                LinkList args;
>                char *cmdstr;
> Index: Src/math.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/math.c,v
> retrieving revision 1.33
> diff -u -r1.33 math.c
> --- Src/math.c  12 Jun 2008 13:45:06 -0000      1.33
> +++ Src/math.c  16 Sep 2008 14:41:10 -0000
> @@ -868,11 +868,11 @@
>                                           argc <= f->maxargs)) {
>                    if (f->flags & MFF_USERFUNC) {
>                        char *shfnam = f->module ? f->module : n;
> -                       Eprog prog = getshfunc(shfnam);
> -                       if (prog == &dummy_eprog)
> +                       Shfunc shfunc = getshfunc(shfnam);
> +                       if (!shfunc)
>                            zerr("no such function: %s", shfnam);
>                        else {
> -                           doshfunc(n, prog, l, 0, 1);
> +                           doshfunc(shfunc, l, 0, 1);
>                            return lastmathval;
>                        }
>                    } else {
> Index: Src/prompt.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/prompt.c,v
> retrieving revision 1.53
> diff -u -r1.53 prompt.c
> --- Src/prompt.c        15 Sep 2008 16:18:06 -0000      1.53
> +++ Src/prompt.c        16 Sep 2008 14:41:11 -0000
> @@ -725,11 +725,37 @@
>                if(Rstring)
>                    stradd(Rstring);
>                break;
> +           case 'I':
> +               if (funcstack && funcstack->tp != FS_SOURCE) {
> +                   /*
> +                    * We're in a function or an eval with
> +                    * EVALLINENO.  Calculate the line number in
> +                    * the file.
> +                    */
> +                   zlong flineno = lineno + funcstack->flineno;
> +                   /* take account of eval line nos. starting at 1 */
> +                   if (funcstack->tp == FS_EVAL)
> +                       lineno--;
> +                   addbufspc(DIGBUFSIZE);
> +                   sprintf(bp, "%ld", (long)flineno);
> +                   bp += strlen(bp);
> +                   break;
> +               }
> +               /* else we're in a file and lineno is already correct */
> +               /* FALLTHROUGH */
>            case 'i':
>                addbufspc(DIGBUFSIZE);
>                sprintf(bp, "%ld", (long)lineno);
>                bp += strlen(bp);
>                break;
> +           case 'x':
> +               if (funcstack && funcstack->tp != FS_SOURCE)
> +                   promptpath(funcstack->filename ? funcstack->filename :
> "",
> +                              arg, 0);
> +               else
> +                   promptpath(scriptfilename ? scriptfilename : argzero,
> +                              arg, 0);
> +               break;
>            case '\0':
>                return 0;
>            case Meta:
> Index: Src/signals.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/signals.c,v
> retrieving revision 1.50
> diff -u -r1.50 signals.c
> --- Src/signals.c       11 Aug 2008 19:22:54 -0000      1.50
> +++ Src/signals.c       16 Sep 2008 14:41:11 -0000
> @@ -963,8 +963,7 @@
>     }
>
>     if (exittr) {
> -       dotrapargs(SIGEXIT, &exittr, (exittr & ZSIG_FUNC) ?
> -                  ((Shfunc)exitfn)->funcdef : (Eprog) exitfn);
> +       dotrapargs(SIGEXIT, &exittr, exitfn);
>        if (exittr & ZSIG_FUNC)
>            shfunctab->freenode((HashNode)exitfn);
>        else
> @@ -1077,8 +1076,16 @@
>  /**/
>  int trapisfunc;
>
> +/*
> + * sig is the signal number.
> + * *sigtr is the value to be taken as the field in sigtrapped (since
> + *   that may have changed by this point if we are exiting).
> + * sigfn is an Eprog with a non-function eval list, or a Shfunc
> + *   with a function trap.  It may be NULL with an ignored signal.
> + */
> +
>  /**/
> -void
> +static void
>  dotrapargs(int sig, int *sigtr, void *sigfn)
>  {
>     LinkList args;
> @@ -1153,7 +1160,7 @@
>        trapisfunc = isfunc = 1;
>
>        sfcontext = SFC_SIGNAL;
> -       doshfunc(name, sigfn, args, 0, 1);
> +       doshfunc((Shfunc)sigfn, args, 0, 1);
>        sfcontext = osc;
>        freelinklist(args, (FreeFunc) NULL);
>        zsfree(name);
> @@ -1162,7 +1169,7 @@
>        trap_state = TRAP_STATE_PRIMED;
>        trapisfunc = isfunc = 0;
>
> -       execode(sigfn, 1, 0);
> +       execode((Eprog)sigfn, 1, 0);
>     }
>     runhookdef(AFTERTRAPHOOK, NULL);
>
> @@ -1215,12 +1222,12 @@
>  void
>  dotrap(int sig)
>  {
> -    Eprog funcprog;
> +    void *funcprog;
>
>     if (sigtrapped[sig] & ZSIG_FUNC) {
>        HashNode hn = gettrapnode(sig, 0);
>        if (hn)
> -           funcprog = ((Shfunc)hn)->funcdef;
> +           funcprog = hn;
>        else {
>  #ifdef DEBUG
>            dputs("BUG: running function trap which has escaped.");
> @@ -1230,7 +1237,11 @@
>     } else
>        funcprog = siglists[sig];
>
> -    /* Copied from dotrapargs(). */
> +    /*
> +     * Copied from dotrapargs().
> +     * (In fact, the gain from duplicating this appears to be virtually
> +     * zero.  Not sure why it's here.)
> +     */
>     if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag)
>        return;
>
> Index: Src/utils.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
> retrieving revision 1.199
> diff -u -r1.199 utils.c
> --- Src/utils.c 11 Aug 2008 19:22:54 -0000      1.199
> +++ Src/utils.c 16 Sep 2008 14:41:11 -0000
> @@ -35,6 +35,8 @@
>  /**/
>  mod_export char *scriptname;     /* is sometimes a function name */
>
> +/* filename of script or other file containing code source e.g. autoload
> */
> +
>  /**/
>  mod_export char *scriptfilename;
>
> @@ -1134,7 +1136,7 @@
>  mod_export int
>  callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval)
>  {
> -    Eprog prog;
> +    Shfunc shfunc;
>        /*
>         * Save stopmsg, since user doesn't get a chance to respond
>         * to a list of jobs generated in a hook.
> @@ -1143,8 +1145,8 @@
>
>     sfcontext = SFC_HOOK;
>
> -    if ((prog = getshfunc(name)) != &dummy_eprog) {
> -       ret = doshfunc(name, prog, lnklst, 0, 1);
> +    if ((shfunc = getshfunc(name))) {
> +       ret = doshfunc(shfunc, lnklst, 0, 1);
>        stat = 0;
>     }
>
> @@ -1159,8 +1161,8 @@
>
>        if ((arrptr = getaparam(arrnam))) {
>            for (; *arrptr; arrptr++) {
> -               if ((prog = getshfunc(*arrptr)) != &dummy_eprog) {
> -                   int newret = doshfunc(arrnam, prog, lnklst, 0, 1);
> +               if ((shfunc = getshfunc(*arrptr))) {
> +                   int newret = doshfunc(shfunc, lnklst, 0, 1);
>                    if (!ret)
>                        ret = newret;
>                    stat = 0;
> @@ -2893,15 +2895,10 @@
>  /* Get the definition of a shell function */
>
>  /**/
> -mod_export Eprog
> +mod_export Shfunc
>  getshfunc(char *nam)
>  {
> -    Shfunc shf;
> -
> -    if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, nam)))
> -       return &dummy_eprog;
> -
> -    return shf->funcdef;
> +    return (Shfunc) shfunctab->getnode(shfunctab, nam);
>  }
>
>  /**/
> Index: Src/Modules/zftp.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Modules/zftp.c,v
> retrieving revision 1.48
> diff -u -r1.48 zftp.c
> --- Src/Modules/zftp.c  4 Sep 2008 22:23:52 -0000       1.48
> +++ Src/Modules/zftp.c  16 Sep 2008 14:41:11 -0000
> @@ -1469,9 +1469,9 @@
>     char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr;
>     off_t sofar = 0, last_sofar = 0;
>     readwrite_t read_ptr = zfread, write_ptr = zfwrite;
> -    Eprog prog;
> +    Shfunc shfunc;
>
> -    if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
> +    if (progress && (shfunc = getshfunc("zftp_progress"))) {
>        /*
>         * progress to set up:  ZFTP_COUNT is zero.
>         * We do this here in case we needed to wait for a RETR
> @@ -1480,7 +1480,7 @@
>        int osc = sfcontext;
>
>        sfcontext = SFC_HOOK;
> -       doshfunc("zftp_progress", prog, NULL, 0, 1);
> +       doshfunc(shfunc, NULL, 0, 1);
>        sfcontext = osc;
>        /* Now add in the bit of the file we've got/sent already */
>        sofar = last_sofar = startat;
> @@ -1608,12 +1608,12 @@
>        } else
>            break;
>        if (!ret && sofar != last_sofar && progress &&
> -           (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
> +           (shfunc = getshfunc("zftp_progress"))) {
>            int osc = sfcontext;
>
>            zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER);
>            sfcontext = SFC_HOOK;
> -           doshfunc("zftp_progress", prog, NULL, 0, 1);
> +           doshfunc(shfunc, NULL, 0, 1);
>            sfcontext = osc;
>            last_sofar = sofar;
>        }
> @@ -2364,7 +2364,7 @@
>  {
>     char *ptr, *eptr;
>     int endc;
> -    Eprog prog;
> +    Shfunc shfunc;
>
>     if (zfprefs & ZFPF_DUMB)
>        return 1;
> @@ -2391,11 +2391,11 @@
>      * front end.  By putting it here, and in close when ZFTP_PWD is unset,
>      * we at least cover the bases.
>      */
> -    if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
> +    if ((shfunc = getshfunc("zftp_chpwd"))) {
>        int osc = sfcontext;
>
>        sfcontext = SFC_HOOK;
> -       doshfunc("zftp_chpwd", prog, NULL, 0, 1);
> +       doshfunc(shfunc, NULL, 0, 1);
>        sfcontext = osc;
>     }
>     return 0;
> @@ -2549,7 +2549,7 @@
>  {
>     int ret = 0, recv = (flags & ZFTP_RECV), getsize = 0, progress = 1;
>     char *cmd = recv ? "RETR " : (flags & ZFTP_APPE) ? "APPE " : "STOR ";
> -    Eprog prog;
> +    Shfunc shfunc;
>
>     /*
>      * At this point I'd like to set progress to 0 if we're
> @@ -2567,7 +2567,7 @@
>     for (; *args; args++) {
>        char *ln, *rest = NULL;
>        off_t startat = 0;
> -       if (progress && (prog = getshfunc("zftp_progress")) !=
> &dummy_eprog) {
> +       if (progress && (shfunc = getshfunc("zftp_progress"))) {
>            off_t sz = -1;
>            /*
>             * This calls the SIZE command to get the size for remote
> @@ -2608,14 +2608,14 @@
>         * if and only if we called zfsenddata();
>         */
>        if (progress && ret != 2 &&
> -           (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
> +           (shfunc = getshfunc("zftp_progress"))) {
>            /* progress to finish: ZFTP_TRANSFER set to GF or PF */
>            int osc = sfcontext;
>
>            zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"),
>                       ZFPM_READONLY);
>            sfcontext = SFC_HOOK;
> -           doshfunc("zftp_progress", prog, NULL, 0, 1);
> +           doshfunc(shfunc, NULL, 0, 1);
>            sfcontext = osc;
>        }
>        if (rest) {
> @@ -2715,7 +2715,7 @@
>  zfclose(int leaveparams)
>  {
>     char **aptr;
> -    Eprog prog;
> +    Shfunc shfunc;
>
>     if (!zfsess->control)
>        return;
> @@ -2766,11 +2766,11 @@
>            zfunsetparam(*aptr);
>
>        /* Now ZFTP_PWD is unset.  It's up to zftp_chpwd to notice. */
> -       if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
> +       if ((shfunc = getshfunc("zftp_chpwd"))) {
>            int osc = sfcontext;
>
>            sfcontext = SFC_HOOK;
> -           doshfunc("zftp_chpwd", prog, NULL, 0, 1);
> +           doshfunc(shfunc, NULL, 0, 1);
>            sfcontext = osc;
>        }
>     }
> Index: Src/Zle/compcore.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
> retrieving revision 1.96
> diff -u -r1.96 compcore.c
> --- Src/Zle/compcore.c  7 Jul 2008 08:33:28 -0000       1.96
> +++ Src/Zle/compcore.c  16 Sep 2008 14:41:12 -0000
> @@ -540,13 +540,13 @@
>  static void
>  callcompfunc(char *s, char *fn)
>  {
> -    Eprog prog;
> +    Shfunc shfunc;
>     int lv = lastval;
>     char buf[20];
>
>     METACHECK();
>
> -    if ((prog = getshfunc(fn)) != &dummy_eprog) {
> +    if ((shfunc = getshfunc(fn))) {
>        char **p, *tmp;
>        int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
>        unsigned int rset, kset;
> @@ -814,7 +814,7 @@
>                while (*p)
>                    addlinknode(largs, dupstring(*p++));
>            }
> -           doshfunc(fn, prog, largs, 0, 0);
> +           doshfunc(shfunc, largs, 0, 0);
>            cfret = lastval;
>            lastval = olv;
>        } OLDHEAPS;
> Index: Src/Zle/compctl.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/compctl.c,v
> retrieving revision 1.35
> diff -u -r1.35 compctl.c
> --- Src/Zle/compctl.c   3 Oct 2007 16:18:38 -0000       1.35
> +++ Src/Zle/compctl.c   16 Sep 2008 14:41:12 -0000
> @@ -3635,12 +3635,12 @@
>     }
>     if (cc->func) {
>        /* This handles the compctl -K flag. */
> -       Eprog prog;
> +       Shfunc shfunc;
>        char **r;
>        int lv = lastval;
>
>        /* Get the function. */
> -       if ((prog = getshfunc(cc->func)) != &dummy_eprog) {
> +       if ((shfunc = getshfunc(cc->func))) {
>            /* We have it, so build a argument list. */
>            LinkList args = newlinklist();
>            int osc = sfcontext;
> @@ -3664,7 +3664,7 @@
>                incompctlfunc = 1;
>            sfcontext = SFC_COMPLETE;
>            /* Call the function. */
> -           doshfunc(cc->func, prog, args, 0, 1);
> +           doshfunc(shfunc, args, 0, 1);
>            sfcontext = osc;
>            incompctlfunc = 0;
>            /* And get the result from the reply parameter. */
> @@ -3809,12 +3809,12 @@
>        /* generate the user-defined display list: if anything fails, *
>         * we silently allow the normal completion list to be used.   */
>        char **yaptr = NULL, *uv = NULL;
> -       Eprog prog;
> +       Shfunc shfunc;
>
>        if (cc->ylist[0] == '$' || cc->ylist[0] == '(') {
>            /* from variable */
>            uv = cc->ylist + (cc->ylist[0] == '$');
> -       } else if ((prog = getshfunc(cc->ylist)) != &dummy_eprog) {
> +       } else if ((shfunc = getshfunc(cc->ylist))) {
>            /* from function:  pass completions as arg list */
>            LinkList args = newlinklist();
>            LinkNode ln;
> @@ -3839,7 +3839,7 @@
>            if (incompfunc != 1)
>                incompctlfunc = 1;
>            sfcontext = SFC_COMPLETE;
> -           doshfunc(cc->ylist, prog, args, 0, 1);
> +           doshfunc(shfunc, args, 0, 1);
>            sfcontext = osc;
>            incompctlfunc = 0;
>            uv = "reply";
> Index: Src/Zle/zle_main.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
> retrieving revision 1.115
> diff -u -r1.115 zle_main.c
> --- Src/Zle/zle_main.c  8 Sep 2008 06:24:23 -0000       1.115
> +++ Src/Zle/zle_main.c  16 Sep 2008 14:41:12 -0000
> @@ -1304,9 +1304,8 @@
>        r = 1;
>     } else {
>        Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam);
> -       Eprog prog = (shf ? shf->funcdef : &dummy_eprog);
>
> -       if(prog == &dummy_eprog) {
> +       if (!shf) {
>            /* the shell function doesn't exist */
>            char *nm = nicedup(w->u.fnnam, 0);
>            char *msg = tricat("No such shell function `", nm, "'");
> @@ -1330,7 +1329,7 @@
>            makezleparams(0);
>            sfcontext = SFC_WIDGET;
>            opts[XTRACE] = 0;
> -           ret = doshfunc(w->u.fnnam, prog, largs, shf->node.flags, 1);
> +           ret = doshfunc(shf, largs, shf->node.flags, 1);
>            opts[XTRACE] = oxt;
>            sfcontext = osc;
>            endparamscope();
> Index: Src/Zle/zle_misc.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_misc.c,v
> retrieving revision 1.54
> diff -u -r1.54 zle_misc.c
> --- Src/Zle/zle_misc.c  4 May 2008 18:30:04 -0000       1.54
> +++ Src/Zle/zle_misc.c  16 Sep 2008 14:41:12 -0000
> @@ -1358,9 +1358,9 @@
>  iremovesuffix(ZLE_INT_T c, int keep)
>  {
>     if (suffixfunc) {
> -       Eprog prog = getshfunc(suffixfunc);
> +       Shfunc shfunc = getshfunc(suffixfunc);
>
> -       if (prog != &dummy_eprog) {
> +       if (shfunc) {
>            LinkList args = newlinklist();
>            char buf[20];
>            int osc = sfcontext;
> @@ -1384,7 +1384,7 @@
>            startparamscope();
>            makezleparams(0);
>            sfcontext = SFC_COMPLETE;
> -           doshfunc(suffixfunc, prog, args, 0, 1);
> +           doshfunc(shfunc, args, 0, 1);
>            sfcontext = osc;
>            endparamscope();
>
> Index: Test/E02xtrace.ztst
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Test/E02xtrace.ztst,v
> retrieving revision 1.7
> diff -u -r1.7 E02xtrace.ztst
> --- Test/E02xtrace.ztst 11 Aug 2008 08:40:58 -0000      1.7
> +++ Test/E02xtrace.ztst 16 Sep 2008 14:41:12 -0000
> @@ -90,3 +90,18 @@
>  >Tracing: function
>  ?+xtf:1> local regression_test_dummy_variable
>  ?+xtf:2> print 'Tracing: function'
> +
> + echo 'PS4="+%x:%I> "
> + fn() {
> +   print This is fn.
> + }
> + :
> + fn
> + ' >fnfile
> + $ZTST_testdir/../Src/zsh -fx ./fnfile
> +0:Trace output with sourcefile and line number.
> +>This is fn.
> +?+./fnfile:1> PS4='+%x:%I> '
> +?+./fnfile:5> :
> +?+./fnfile:6> fn
> +?+./fnfile:3> print This is fn.
>
>
> --
> 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
>

[-- Attachment #2: Type: text/html, Size: 34804 bytes --]

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

* Re: PATCH: source file info from PS4
  2008-09-16 14:50 PATCH: source file info from PS4 Peter Stephenson
  2008-09-16 16:17 ` Rocky Bernstein
@ 2008-09-17 16:39 ` Rocky Bernstein
  2008-09-18 12:13   ` Peter Stephenson
  1 sibling, 1 reply; 9+ messages in thread
From: Rocky Bernstein @ 2008-09-17 16:39 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

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

On Tue, Sep 16, 2008 at 10:50 AM, Peter Stephenson <pws@csr.com> wrote:

> Now we have logic for finding the source file and corresponding line
> number of executed code, this adds the prompt escapes %x and %I which
> are like %N and %i but for the file where the code was defined.


Looks like this has problems when used inside trap DEBUG. Consider this test
program:

PS4='%x:%I: '
hook() {
    set -x
    bug a 5 1
}
bug() {
  typeset source_file="$1"
  typeset -ir lineno=$2
  typeset -ir is_temp=$3
}
trap hook DEBUG

a=1
b=2

Here is the output I get:

zsh ./linebug.sh
./linebug.sh:15: bug a 5 1
./linebug.sh:19: typeset 'source_file=a'
./linebug.sh:19: typeset -ir 'lineno=5'
./linebug.sh:19: typeset -ir 'is_temp=1'
./linebug.sh:16: bug a 5 1
./linebug.sh:20: typeset 'source_file=a'
./linebug.sh:20: typeset -ir 'lineno=5'
./linebug.sh:20: typeset -ir 'is_temp=1'

Not sure where 19 and 20 are coming from since the program only has 16
lines. And also curious is why they don't change when commands get run.




> %x isn't
> ideal but upper and lower case %s, %f and %n are all used.  It stands
> for "execution file", or something.  The idea is that you set
> PS4='+%x:%I>'
>
> While doing this, I spotted that we could improve the information
> available to funcstack and the interface to doshfunc() by passing in a
> Shfunc instead of an Eprog.  This is a *much* cleaner interface.  Now
> the funcstack entry is guaranteed to get the details of the shell
> function correct.
>
> Index: Doc/Zsh/prompt.yo
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Doc/Zsh/prompt.yo,v
> retrieving revision 1.15
> diff -u -r1.15 prompt.yo
> --- Doc/Zsh/prompt.yo   24 Jun 2008 08:44:16 -0000      1.15
> +++ Doc/Zsh/prompt.yo   16 Sep 2008 14:41:10 -0000
> @@ -113,6 +113,11 @@
>  shell function given by tt(%N).  This is most useful for debugging as part
>  of tt($PS4).
>  )
> +item(tt(%I))(
> +The line number currently being executed in the file tt(%x).  This is
> +similar to tt(%i), but the line number is always a line number in the
> +file where the code was defined, even if the code is a shell function.
> +)
>  item(tt(%j))(
>  The number of jobs.
>  )
> @@ -126,6 +131,11 @@
>  the `tt(%)' to specify a number of trailing path components to show; zero
>  means the full path.  A negative integer specifies leading components.
>  )
> +item(tt(%x))(
> +The name of the file containing the source code currently being
> +executed.  This behaves as tt(%N) except that function and eval command
> +names are not shown, instead the file where they were defined.
> +)
>  xitem(tt(%c))
>  xitem(tt(%.))
>  item(tt(%C))(
> Index: Src/exec.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
> retrieving revision 1.151
> diff -u -r1.151 exec.c
> --- Src/exec.c  11 Sep 2008 17:14:39 -0000      1.151
> +++ Src/exec.c  16 Sep 2008 14:41:10 -0000
> @@ -518,7 +518,7 @@
>        return 127;
>
>     pushnode(args, arg0);
> -    return doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags,
> 1);
> +    return doshfunc(shf, args, shf->node.flags, 1);
>  }
>
>  /* execute an external command */
> @@ -4064,7 +4064,7 @@
>     cmdsp = 0;
>     if ((osfc = sfcontext) == SFC_NONE)
>        sfcontext = SFC_DIRECT;
> -    doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags, 0);
> +    doshfunc(shf, args, shf->node.flags, 0);
>     sfcontext = osfc;
>     free(cmdstack);
>     cmdstack = ocs;
> @@ -4200,18 +4200,20 @@
>
>  /**/
>  mod_export int
> -doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int
> noreturnval)
> +doshfunc(Shfunc shfunc, LinkList doshargs, int flags, int noreturnval)
>  {
>     char **tab, **x, *oargv0;
>     int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret;
>     int *oldpipestats = NULL;
> -    char saveopts[OPT_SIZE], *oldscriptname = scriptname, *fname =
> dupstring(name);
> +    char saveopts[OPT_SIZE], *oldscriptname = scriptname;
> +    char *name = shfunc->node.nam;
> +    char *fname = dupstring(name);
>     int obreaks, saveemulation ;
> +    Eprog prog;
>     struct funcstack fstack;
>  #ifdef MAX_FUNCTION_DEPTH
>     static int funcdepth;
>  #endif
> -    Shfunc shf;
>
>     pushheap();
>
> @@ -4291,14 +4293,10 @@
>     fstack.tp = FS_FUNC;
>     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);
> -    }
> +    fstack.flineno = shfunc->lineno;
> +    fstack.filename = dupstring(shfunc->filename);
>
> +    prog = shfunc->funcdef;
>     if (prog->flags & EF_RUN) {
>        Shfunc shf;
>
> Index: Src/init.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/init.c,v
> retrieving revision 1.96
> diff -u -r1.96 init.c
> --- Src/init.c  11 Sep 2008 17:14:39 -0000      1.96
> +++ Src/init.c  16 Sep 2008 14:41:10 -0000
> @@ -149,7 +149,7 @@
>            int toksav = tok;
>
>            if (toplevel &&
> -               (getshfunc("preexec") != &dummy_eprog ||
> +               (getshfunc("preexec") ||
>                 paramtab->getnode(paramtab, "preexec_functions"))) {
>                LinkList args;
>                char *cmdstr;
> Index: Src/math.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/math.c,v
> retrieving revision 1.33
> diff -u -r1.33 math.c
> --- Src/math.c  12 Jun 2008 13:45:06 -0000      1.33
> +++ Src/math.c  16 Sep 2008 14:41:10 -0000
> @@ -868,11 +868,11 @@
>                                           argc <= f->maxargs)) {
>                    if (f->flags & MFF_USERFUNC) {
>                        char *shfnam = f->module ? f->module : n;
> -                       Eprog prog = getshfunc(shfnam);
> -                       if (prog == &dummy_eprog)
> +                       Shfunc shfunc = getshfunc(shfnam);
> +                       if (!shfunc)
>                            zerr("no such function: %s", shfnam);
>                        else {
> -                           doshfunc(n, prog, l, 0, 1);
> +                           doshfunc(shfunc, l, 0, 1);
>                            return lastmathval;
>                        }
>                    } else {
> Index: Src/prompt.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/prompt.c,v
> retrieving revision 1.53
> diff -u -r1.53 prompt.c
> --- Src/prompt.c        15 Sep 2008 16:18:06 -0000      1.53
> +++ Src/prompt.c        16 Sep 2008 14:41:11 -0000
> @@ -725,11 +725,37 @@
>                if(Rstring)
>                    stradd(Rstring);
>                break;
> +           case 'I':
> +               if (funcstack && funcstack->tp != FS_SOURCE) {
> +                   /*
> +                    * We're in a function or an eval with
> +                    * EVALLINENO.  Calculate the line number in
> +                    * the file.
> +                    */
> +                   zlong flineno = lineno + funcstack->flineno;
> +                   /* take account of eval line nos. starting at 1 */
> +                   if (funcstack->tp == FS_EVAL)
> +                       lineno--;
> +                   addbufspc(DIGBUFSIZE);
> +                   sprintf(bp, "%ld", (long)flineno);
> +                   bp += strlen(bp);
> +                   break;
> +               }
> +               /* else we're in a file and lineno is already correct */
> +               /* FALLTHROUGH */
>            case 'i':
>                addbufspc(DIGBUFSIZE);
>                sprintf(bp, "%ld", (long)lineno);
>                bp += strlen(bp);
>                break;
> +           case 'x':
> +               if (funcstack && funcstack->tp != FS_SOURCE)
> +                   promptpath(funcstack->filename ? funcstack->filename :
> "",
> +                              arg, 0);
> +               else
> +                   promptpath(scriptfilename ? scriptfilename : argzero,
> +                              arg, 0);
> +               break;
>            case '\0':
>                return 0;
>            case Meta:
> Index: Src/signals.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/signals.c,v
> retrieving revision 1.50
> diff -u -r1.50 signals.c
> --- Src/signals.c       11 Aug 2008 19:22:54 -0000      1.50
> +++ Src/signals.c       16 Sep 2008 14:41:11 -0000
> @@ -963,8 +963,7 @@
>     }
>
>     if (exittr) {
> -       dotrapargs(SIGEXIT, &exittr, (exittr & ZSIG_FUNC) ?
> -                  ((Shfunc)exitfn)->funcdef : (Eprog) exitfn);
> +       dotrapargs(SIGEXIT, &exittr, exitfn);
>        if (exittr & ZSIG_FUNC)
>            shfunctab->freenode((HashNode)exitfn);
>        else
> @@ -1077,8 +1076,16 @@
>  /**/
>  int trapisfunc;
>
> +/*
> + * sig is the signal number.
> + * *sigtr is the value to be taken as the field in sigtrapped (since
> + *   that may have changed by this point if we are exiting).
> + * sigfn is an Eprog with a non-function eval list, or a Shfunc
> + *   with a function trap.  It may be NULL with an ignored signal.
> + */
> +
>  /**/
> -void
> +static void
>  dotrapargs(int sig, int *sigtr, void *sigfn)
>  {
>     LinkList args;
> @@ -1153,7 +1160,7 @@
>        trapisfunc = isfunc = 1;
>
>        sfcontext = SFC_SIGNAL;
> -       doshfunc(name, sigfn, args, 0, 1);
> +       doshfunc((Shfunc)sigfn, args, 0, 1);
>        sfcontext = osc;
>        freelinklist(args, (FreeFunc) NULL);
>        zsfree(name);
> @@ -1162,7 +1169,7 @@
>        trap_state = TRAP_STATE_PRIMED;
>        trapisfunc = isfunc = 0;
>
> -       execode(sigfn, 1, 0);
> +       execode((Eprog)sigfn, 1, 0);
>     }
>     runhookdef(AFTERTRAPHOOK, NULL);
>
> @@ -1215,12 +1222,12 @@
>  void
>  dotrap(int sig)
>  {
> -    Eprog funcprog;
> +    void *funcprog;
>
>     if (sigtrapped[sig] & ZSIG_FUNC) {
>        HashNode hn = gettrapnode(sig, 0);
>        if (hn)
> -           funcprog = ((Shfunc)hn)->funcdef;
> +           funcprog = hn;
>        else {
>  #ifdef DEBUG
>            dputs("BUG: running function trap which has escaped.");
> @@ -1230,7 +1237,11 @@
>     } else
>        funcprog = siglists[sig];
>
> -    /* Copied from dotrapargs(). */
> +    /*
> +     * Copied from dotrapargs().
> +     * (In fact, the gain from duplicating this appears to be virtually
> +     * zero.  Not sure why it's here.)
> +     */
>     if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag)
>        return;
>
> Index: Src/utils.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
> retrieving revision 1.199
> diff -u -r1.199 utils.c
> --- Src/utils.c 11 Aug 2008 19:22:54 -0000      1.199
> +++ Src/utils.c 16 Sep 2008 14:41:11 -0000
> @@ -35,6 +35,8 @@
>  /**/
>  mod_export char *scriptname;     /* is sometimes a function name */
>
> +/* filename of script or other file containing code source e.g. autoload
> */
> +
>  /**/
>  mod_export char *scriptfilename;
>
> @@ -1134,7 +1136,7 @@
>  mod_export int
>  callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval)
>  {
> -    Eprog prog;
> +    Shfunc shfunc;
>        /*
>         * Save stopmsg, since user doesn't get a chance to respond
>         * to a list of jobs generated in a hook.
> @@ -1143,8 +1145,8 @@
>
>     sfcontext = SFC_HOOK;
>
> -    if ((prog = getshfunc(name)) != &dummy_eprog) {
> -       ret = doshfunc(name, prog, lnklst, 0, 1);
> +    if ((shfunc = getshfunc(name))) {
> +       ret = doshfunc(shfunc, lnklst, 0, 1);
>        stat = 0;
>     }
>
> @@ -1159,8 +1161,8 @@
>
>        if ((arrptr = getaparam(arrnam))) {
>            for (; *arrptr; arrptr++) {
> -               if ((prog = getshfunc(*arrptr)) != &dummy_eprog) {
> -                   int newret = doshfunc(arrnam, prog, lnklst, 0, 1);
> +               if ((shfunc = getshfunc(*arrptr))) {
> +                   int newret = doshfunc(shfunc, lnklst, 0, 1);
>                    if (!ret)
>                        ret = newret;
>                    stat = 0;
> @@ -2893,15 +2895,10 @@
>  /* Get the definition of a shell function */
>
>  /**/
> -mod_export Eprog
> +mod_export Shfunc
>  getshfunc(char *nam)
>  {
> -    Shfunc shf;
> -
> -    if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, nam)))
> -       return &dummy_eprog;
> -
> -    return shf->funcdef;
> +    return (Shfunc) shfunctab->getnode(shfunctab, nam);
>  }
>
>  /**/
> Index: Src/Modules/zftp.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Modules/zftp.c,v
> retrieving revision 1.48
> diff -u -r1.48 zftp.c
> --- Src/Modules/zftp.c  4 Sep 2008 22:23:52 -0000       1.48
> +++ Src/Modules/zftp.c  16 Sep 2008 14:41:11 -0000
> @@ -1469,9 +1469,9 @@
>     char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr;
>     off_t sofar = 0, last_sofar = 0;
>     readwrite_t read_ptr = zfread, write_ptr = zfwrite;
> -    Eprog prog;
> +    Shfunc shfunc;
>
> -    if (progress && (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
> +    if (progress && (shfunc = getshfunc("zftp_progress"))) {
>        /*
>         * progress to set up:  ZFTP_COUNT is zero.
>         * We do this here in case we needed to wait for a RETR
> @@ -1480,7 +1480,7 @@
>        int osc = sfcontext;
>
>        sfcontext = SFC_HOOK;
> -       doshfunc("zftp_progress", prog, NULL, 0, 1);
> +       doshfunc(shfunc, NULL, 0, 1);
>        sfcontext = osc;
>        /* Now add in the bit of the file we've got/sent already */
>        sofar = last_sofar = startat;
> @@ -1608,12 +1608,12 @@
>        } else
>            break;
>        if (!ret && sofar != last_sofar && progress &&
> -           (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
> +           (shfunc = getshfunc("zftp_progress"))) {
>            int osc = sfcontext;
>
>            zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER);
>            sfcontext = SFC_HOOK;
> -           doshfunc("zftp_progress", prog, NULL, 0, 1);
> +           doshfunc(shfunc, NULL, 0, 1);
>            sfcontext = osc;
>            last_sofar = sofar;
>        }
> @@ -2364,7 +2364,7 @@
>  {
>     char *ptr, *eptr;
>     int endc;
> -    Eprog prog;
> +    Shfunc shfunc;
>
>     if (zfprefs & ZFPF_DUMB)
>        return 1;
> @@ -2391,11 +2391,11 @@
>      * front end.  By putting it here, and in close when ZFTP_PWD is unset,
>      * we at least cover the bases.
>      */
> -    if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
> +    if ((shfunc = getshfunc("zftp_chpwd"))) {
>        int osc = sfcontext;
>
>        sfcontext = SFC_HOOK;
> -       doshfunc("zftp_chpwd", prog, NULL, 0, 1);
> +       doshfunc(shfunc, NULL, 0, 1);
>        sfcontext = osc;
>     }
>     return 0;
> @@ -2549,7 +2549,7 @@
>  {
>     int ret = 0, recv = (flags & ZFTP_RECV), getsize = 0, progress = 1;
>     char *cmd = recv ? "RETR " : (flags & ZFTP_APPE) ? "APPE " : "STOR ";
> -    Eprog prog;
> +    Shfunc shfunc;
>
>     /*
>      * At this point I'd like to set progress to 0 if we're
> @@ -2567,7 +2567,7 @@
>     for (; *args; args++) {
>        char *ln, *rest = NULL;
>        off_t startat = 0;
> -       if (progress && (prog = getshfunc("zftp_progress")) !=
> &dummy_eprog) {
> +       if (progress && (shfunc = getshfunc("zftp_progress"))) {
>            off_t sz = -1;
>            /*
>             * This calls the SIZE command to get the size for remote
> @@ -2608,14 +2608,14 @@
>         * if and only if we called zfsenddata();
>         */
>        if (progress && ret != 2 &&
> -           (prog = getshfunc("zftp_progress")) != &dummy_eprog) {
> +           (shfunc = getshfunc("zftp_progress"))) {
>            /* progress to finish: ZFTP_TRANSFER set to GF or PF */
>            int osc = sfcontext;
>
>            zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"),
>                       ZFPM_READONLY);
>            sfcontext = SFC_HOOK;
> -           doshfunc("zftp_progress", prog, NULL, 0, 1);
> +           doshfunc(shfunc, NULL, 0, 1);
>            sfcontext = osc;
>        }
>        if (rest) {
> @@ -2715,7 +2715,7 @@
>  zfclose(int leaveparams)
>  {
>     char **aptr;
> -    Eprog prog;
> +    Shfunc shfunc;
>
>     if (!zfsess->control)
>        return;
> @@ -2766,11 +2766,11 @@
>            zfunsetparam(*aptr);
>
>        /* Now ZFTP_PWD is unset.  It's up to zftp_chpwd to notice. */
> -       if ((prog = getshfunc("zftp_chpwd")) != &dummy_eprog) {
> +       if ((shfunc = getshfunc("zftp_chpwd"))) {
>            int osc = sfcontext;
>
>            sfcontext = SFC_HOOK;
> -           doshfunc("zftp_chpwd", prog, NULL, 0, 1);
> +           doshfunc(shfunc, NULL, 0, 1);
>            sfcontext = osc;
>        }
>     }
> Index: Src/Zle/compcore.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
> retrieving revision 1.96
> diff -u -r1.96 compcore.c
> --- Src/Zle/compcore.c  7 Jul 2008 08:33:28 -0000       1.96
> +++ Src/Zle/compcore.c  16 Sep 2008 14:41:12 -0000
> @@ -540,13 +540,13 @@
>  static void
>  callcompfunc(char *s, char *fn)
>  {
> -    Eprog prog;
> +    Shfunc shfunc;
>     int lv = lastval;
>     char buf[20];
>
>     METACHECK();
>
> -    if ((prog = getshfunc(fn)) != &dummy_eprog) {
> +    if ((shfunc = getshfunc(fn))) {
>        char **p, *tmp;
>        int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
>        unsigned int rset, kset;
> @@ -814,7 +814,7 @@
>                while (*p)
>                    addlinknode(largs, dupstring(*p++));
>            }
> -           doshfunc(fn, prog, largs, 0, 0);
> +           doshfunc(shfunc, largs, 0, 0);
>            cfret = lastval;
>            lastval = olv;
>        } OLDHEAPS;
> Index: Src/Zle/compctl.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/compctl.c,v
> retrieving revision 1.35
> diff -u -r1.35 compctl.c
> --- Src/Zle/compctl.c   3 Oct 2007 16:18:38 -0000       1.35
> +++ Src/Zle/compctl.c   16 Sep 2008 14:41:12 -0000
> @@ -3635,12 +3635,12 @@
>     }
>     if (cc->func) {
>        /* This handles the compctl -K flag. */
> -       Eprog prog;
> +       Shfunc shfunc;
>        char **r;
>        int lv = lastval;
>
>        /* Get the function. */
> -       if ((prog = getshfunc(cc->func)) != &dummy_eprog) {
> +       if ((shfunc = getshfunc(cc->func))) {
>            /* We have it, so build a argument list. */
>            LinkList args = newlinklist();
>            int osc = sfcontext;
> @@ -3664,7 +3664,7 @@
>                incompctlfunc = 1;
>            sfcontext = SFC_COMPLETE;
>            /* Call the function. */
> -           doshfunc(cc->func, prog, args, 0, 1);
> +           doshfunc(shfunc, args, 0, 1);
>            sfcontext = osc;
>            incompctlfunc = 0;
>            /* And get the result from the reply parameter. */
> @@ -3809,12 +3809,12 @@
>        /* generate the user-defined display list: if anything fails, *
>         * we silently allow the normal completion list to be used.   */
>        char **yaptr = NULL, *uv = NULL;
> -       Eprog prog;
> +       Shfunc shfunc;
>
>        if (cc->ylist[0] == '$' || cc->ylist[0] == '(') {
>            /* from variable */
>            uv = cc->ylist + (cc->ylist[0] == '$');
> -       } else if ((prog = getshfunc(cc->ylist)) != &dummy_eprog) {
> +       } else if ((shfunc = getshfunc(cc->ylist))) {
>            /* from function:  pass completions as arg list */
>            LinkList args = newlinklist();
>            LinkNode ln;
> @@ -3839,7 +3839,7 @@
>            if (incompfunc != 1)
>                incompctlfunc = 1;
>            sfcontext = SFC_COMPLETE;
> -           doshfunc(cc->ylist, prog, args, 0, 1);
> +           doshfunc(shfunc, args, 0, 1);
>            sfcontext = osc;
>            incompctlfunc = 0;
>            uv = "reply";
> Index: Src/Zle/zle_main.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
> retrieving revision 1.115
> diff -u -r1.115 zle_main.c
> --- Src/Zle/zle_main.c  8 Sep 2008 06:24:23 -0000       1.115
> +++ Src/Zle/zle_main.c  16 Sep 2008 14:41:12 -0000
> @@ -1304,9 +1304,8 @@
>        r = 1;
>     } else {
>        Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, w->u.fnnam);
> -       Eprog prog = (shf ? shf->funcdef : &dummy_eprog);
>
> -       if(prog == &dummy_eprog) {
> +       if (!shf) {
>            /* the shell function doesn't exist */
>            char *nm = nicedup(w->u.fnnam, 0);
>            char *msg = tricat("No such shell function `", nm, "'");
> @@ -1330,7 +1329,7 @@
>            makezleparams(0);
>            sfcontext = SFC_WIDGET;
>            opts[XTRACE] = 0;
> -           ret = doshfunc(w->u.fnnam, prog, largs, shf->node.flags, 1);
> +           ret = doshfunc(shf, largs, shf->node.flags, 1);
>            opts[XTRACE] = oxt;
>            sfcontext = osc;
>            endparamscope();
> Index: Src/Zle/zle_misc.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_misc.c,v
> retrieving revision 1.54
> diff -u -r1.54 zle_misc.c
> --- Src/Zle/zle_misc.c  4 May 2008 18:30:04 -0000       1.54
> +++ Src/Zle/zle_misc.c  16 Sep 2008 14:41:12 -0000
> @@ -1358,9 +1358,9 @@
>  iremovesuffix(ZLE_INT_T c, int keep)
>  {
>     if (suffixfunc) {
> -       Eprog prog = getshfunc(suffixfunc);
> +       Shfunc shfunc = getshfunc(suffixfunc);
>
> -       if (prog != &dummy_eprog) {
> +       if (shfunc) {
>            LinkList args = newlinklist();
>            char buf[20];
>            int osc = sfcontext;
> @@ -1384,7 +1384,7 @@
>            startparamscope();
>            makezleparams(0);
>            sfcontext = SFC_COMPLETE;
> -           doshfunc(suffixfunc, prog, args, 0, 1);
> +           doshfunc(shfunc, args, 0, 1);
>            sfcontext = osc;
>            endparamscope();
>
> Index: Test/E02xtrace.ztst
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Test/E02xtrace.ztst,v
> retrieving revision 1.7
> diff -u -r1.7 E02xtrace.ztst
> --- Test/E02xtrace.ztst 11 Aug 2008 08:40:58 -0000      1.7
> +++ Test/E02xtrace.ztst 16 Sep 2008 14:41:12 -0000
> @@ -90,3 +90,18 @@
>  >Tracing: function
>  ?+xtf:1> local regression_test_dummy_variable
>  ?+xtf:2> print 'Tracing: function'
> +
> + echo 'PS4="+%x:%I> "
> + fn() {
> +   print This is fn.
> + }
> + :
> + fn
> + ' >fnfile
> + $ZTST_testdir/../Src/zsh -fx ./fnfile
> +0:Trace output with sourcefile and line number.
> +>This is fn.
> +?+./fnfile:1> PS4='+%x:%I> '
> +?+./fnfile:5> :
> +?+./fnfile:6> fn
> +?+./fnfile:3> print This is fn.
>
>
> --
> 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
>

[-- Attachment #2: Type: text/html, Size: 35559 bytes --]

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

* Re: PATCH: source file info from PS4
  2008-09-17 16:39 ` Rocky Bernstein
@ 2008-09-18 12:13   ` Peter Stephenson
  2008-09-18 15:05     ` Rocky Bernstein
  0 siblings, 1 reply; 9+ messages in thread
From: Peter Stephenson @ 2008-09-18 12:13 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 17 Sep 2008 12:39:36 -0400
"Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
> On Tue, Sep 16, 2008 at 10:50 AM, Peter Stephenson <pws@csr.com> wrote:
>
> > Now we have logic for finding the source file and corresponding line
> > number of executed code, this adds the prompt escapes %x and %I which
> > are like %N and %i but for the file where the code was defined.
>
> Looks like this has problems when used inside trap DEBUG.

What's happening here is that the current shell logic doesn't update line
numbers when inside a trap, even inside nested functions.  The idea is that
you're interested in the line number of what triggered the trap; this is
particularly true of a DEBUG trap where you might want to examine LINENO to
see what's going on in the code you're debugging, and you're much less
likely to be interested in the line number inside the trap itself.

So the obvious fix is to make the prompt code I added take account of
this.

Another possibility would be to make traps respect the EVALLINENO option,
so that you would get the local line numbers.  However, I think that's less
useful.

It's possible the same problem affects some of the other new features.  In
particular I think funcstack line number info for eval commands inside
traps is going to get thoroughly confused.  I think the simplest fix would
be not to add funcstack info for eval in this case; this is sort of
plausible since it's like the case where eval isn't keep track of its own
line numbers, where we don't add funcstack info, and we don't add funcstack
info for a trap which is like an eval without its own line number.
Otherwise it's not currently obvious to me what the fix would be.

It might be a good idea to add special variables ZSH_SOURCE_LINENO and
ZSH_SOURCE_FILE as more readable alternatives to ${(%):-%I} and
${(%):-%x}.

Index: Src/prompt.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/prompt.c,v
retrieving revision 1.54
diff -u -r1.54 prompt.c
--- Src/prompt.c	16 Sep 2008 15:07:16 -0000	1.54
+++ Src/prompt.c	18 Sep 2008 11:55:04 -0000
@@ -726,7 +726,8 @@
 		    stradd(Rstring);
 		break;
 	    case 'I':
-		if (funcstack && funcstack->tp != FS_SOURCE) {
+		if (funcstack && funcstack->tp != FS_SOURCE &&
+		    (!intrap || trapisfunc)) {
 		    /*
 		     * We're in a function or an eval with
 		     * EVALLINENO.  Calculate the line number in
@@ -749,7 +750,8 @@
 		bp += strlen(bp);
 		break;
 	    case 'x':
-		if (funcstack && funcstack->tp != FS_SOURCE)
+		if (funcstack && funcstack->tp != FS_SOURCE &&
+		    (!intrap || trapisfunc))
 		    promptpath(funcstack->filename ? funcstack->filename : "",
 			       arg, 0);
 		else
-- 
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] 9+ messages in thread

* Re: PATCH: source file info from PS4
  2008-09-18 12:13   ` Peter Stephenson
@ 2008-09-18 15:05     ` Rocky Bernstein
  2008-09-18 15:22       ` Rocky Bernstein
  0 siblings, 1 reply; 9+ messages in thread
From: Rocky Bernstein @ 2008-09-18 15:05 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

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

Thanks for fixing.

On Thu, Sep 18, 2008 at 8:13 AM, Peter Stephenson <pws@csr.com> wrote:

> On Wed, 17 Sep 2008 12:39:36 -0400
> "Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
> > On Tue, Sep 16, 2008 at 10:50 AM, Peter Stephenson <pws@csr.com> wrote:
> >
> > > Now we have logic for finding the source file and corresponding line
> > > number of executed code, this adds the prompt escapes %x and %I which
> > > are like %N and %i but for the file where the code was defined.
> >
> > Looks like this has problems when used inside trap DEBUG.
>
> What's happening here is that the current shell logic doesn't update line
> numbers when inside a trap, even inside nested functions.


Ok. Thanks for the explanation. I don't see how this gives a line number
that is larger than the number of lines in the entire program, but if the
problem is fixed this is moot.


> The idea is that
> you're interested in the line number of what triggered the trap; this is
> particularly true of a DEBUG trap where you might want to examine LINENO to
> see what's going on in the code you're debugging, and you're much less
> likely to be interested in the line number inside the trap itself.


If one wants the line number that triggered the trap, there are two simple
ways to get this:
1. Save the line number in the call
   trap 'int_handler $LINENO'  INT
2. Use funcfiletrace


>
> So the obvious fix is to make the prompt code I added take account of
> this.


Yes, I think this the best thing.


>
>
> Another possibility would be to make traps respect the EVALLINENO option,
> so that you would get the local line numbers.  However, I think that's less
> useful.
>
> It's possible the same problem affects some of the other new features.  In
> particular I think funcstack line number info for eval commands inside
> traps is going to get thoroughly confused.  I think the simplest fix would
> be not to add funcstack info for eval in this case; this is sort of
> plausible since it's like the case where eval isn't keep track of its own
> line numbers, where we don't add funcstack info, and we don't add funcstack
> info for a trap which is like an eval without its own line number.
> Otherwise it's not currently obvious to me what the fix would be.
>
> It might be a good idea to add special variables ZSH_SOURCE_LINENO and
> ZSH_SOURCE_FILE as more readable alternatives to ${(%):-%I} and
> ${(%):-%x}.
>
> Index: Src/prompt.c
> ===================================================================
> RCS file: /cvsroot/zsh/zsh/Src/prompt.c,v
> retrieving revision 1.54
> diff -u -r1.54 prompt.c
> --- Src/prompt.c        16 Sep 2008 15:07:16 -0000      1.54
> +++ Src/prompt.c        18 Sep 2008 11:55:04 -0000
> @@ -726,7 +726,8 @@
>                     stradd(Rstring);
>                break;
>            case 'I':
> -               if (funcstack && funcstack->tp != FS_SOURCE) {
> +               if (funcstack && funcstack->tp != FS_SOURCE &&
> +                   (!intrap || trapisfunc)) {
>                    /*
>                      * We're in a function or an eval with
>                     * EVALLINENO.  Calculate the line number in
> @@ -749,7 +750,8 @@
>                 bp += strlen(bp);
>                break;
>            case 'x':
> -               if (funcstack && funcstack->tp != FS_SOURCE)
> +               if (funcstack && funcstack->tp != FS_SOURCE &&
> +                   (!intrap || trapisfunc))
>                     promptpath(funcstack->filename ? funcstack->filename :
> "",
>                               arg, 0);
>                else
> --
> 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
>

[-- Attachment #2: Type: text/html, Size: 6220 bytes --]

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

* Re: PATCH: source file info from PS4
  2008-09-18 15:05     ` Rocky Bernstein
@ 2008-09-18 15:22       ` Rocky Bernstein
  2008-09-18 15:25         ` Peter Stephenson
  0 siblings, 1 reply; 9+ messages in thread
From: Rocky Bernstein @ 2008-09-18 15:22 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

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

Wrote a little too soon. This patch seems to correctly report the caller
whereas before it didn't. However I do think one still wants locations
inside the trap.

trap DEBUG is a little bit of a misnomer. trap TRACE would be more accurate
and it can be used for example in profiling code. Personally I would like to
be able to debug a debugger, but I realize that's perhaps a bit esoteric
(although in Ruby one can have nested hooks).

But suppose one wrote a profiler, or just some sort of signal handler. Don't
you want to be able to debug via PS4 the same as any other code?

On Thu, Sep 18, 2008 at 11:05 AM, Rocky Bernstein <rocky.bernstein@gmail.com
> wrote:

> Thanks for fixing.
>
> On Thu, Sep 18, 2008 at 8:13 AM, Peter Stephenson <pws@csr.com> wrote:
>
>> On Wed, 17 Sep 2008 12:39:36 -0400
>> "Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
>> > On Tue, Sep 16, 2008 at 10:50 AM, Peter Stephenson <pws@csr.com> wrote:
>> >
>> > > Now we have logic for finding the source file and corresponding line
>> > > number of executed code, this adds the prompt escapes %x and %I which
>> > > are like %N and %i but for the file where the code was defined.
>> >
>> > Looks like this has problems when used inside trap DEBUG.
>>
>> What's happening here is that the current shell logic doesn't update line
>> numbers when inside a trap, even inside nested functions.
>
>
> Ok. Thanks for the explanation. I don't see how this gives a line number
> that is larger than the number of lines in the entire program, but if the
> problem is fixed this is moot.
>
>
>> The idea is that
>> you're interested in the line number of what triggered the trap; this is
>> particularly true of a DEBUG trap where you might want to examine LINENO
>> to
>> see what's going on in the code you're debugging, and you're much less
>> likely to be interested in the line number inside the trap itself.
>
>
> If one wants the line number that triggered the trap, there are two simple
> ways to get this:
> 1. Save the line number in the call
>    trap 'int_handler $LINENO'  INT
> 2. Use funcfiletrace
>
>
>>
>> So the obvious fix is to make the prompt code I added take account of
>> this.
>
>
> Yes, I think this the best thing.
>
>
>>
>>
>> Another possibility would be to make traps respect the EVALLINENO option,
>> so that you would get the local line numbers.  However, I think that's
>> less
>> useful.
>>
>> It's possible the same problem affects some of the other new features.  In
>> particular I think funcstack line number info for eval commands inside
>> traps is going to get thoroughly confused.  I think the simplest fix would
>> be not to add funcstack info for eval in this case; this is sort of
>> plausible since it's like the case where eval isn't keep track of its own
>> line numbers, where we don't add funcstack info, and we don't add
>> funcstack
>> info for a trap which is like an eval without its own line number.
>> Otherwise it's not currently obvious to me what the fix would be.
>>
>> It might be a good idea to add special variables ZSH_SOURCE_LINENO and
>> ZSH_SOURCE_FILE as more readable alternatives to ${(%):-%I} and
>> ${(%):-%x}.
>>
>> Index: Src/prompt.c
>> ===================================================================
>> RCS file: /cvsroot/zsh/zsh/Src/prompt.c,v
>> retrieving revision 1.54
>> diff -u -r1.54 prompt.c
>> --- Src/prompt.c        16 Sep 2008 15:07:16 -0000      1.54
>> +++ Src/prompt.c        18 Sep 2008 11:55:04 -0000
>> @@ -726,7 +726,8 @@
>>                     stradd(Rstring);
>>                break;
>>            case 'I':
>> -               if (funcstack && funcstack->tp != FS_SOURCE) {
>> +               if (funcstack && funcstack->tp != FS_SOURCE &&
>> +                   (!intrap || trapisfunc)) {
>>                    /*
>>                      * We're in a function or an eval with
>>                     * EVALLINENO.  Calculate the line number in
>> @@ -749,7 +750,8 @@
>>                 bp += strlen(bp);
>>                break;
>>            case 'x':
>> -               if (funcstack && funcstack->tp != FS_SOURCE)
>> +               if (funcstack && funcstack->tp != FS_SOURCE &&
>> +                   (!intrap || trapisfunc))
>>                     promptpath(funcstack->filename ? funcstack->filename :
>> "",
>>                               arg, 0);
>>                else
>> --
>> 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
>>
>
>

[-- Attachment #2: Type: text/html, Size: 7283 bytes --]

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

* Re: PATCH: source file info from PS4
  2008-09-18 15:22       ` Rocky Bernstein
@ 2008-09-18 15:25         ` Peter Stephenson
  2008-09-18 15:39           ` Rocky Bernstein
  0 siblings, 1 reply; 9+ messages in thread
From: Peter Stephenson @ 2008-09-18 15:25 UTC (permalink / raw)
  To: Zsh hackers list

"Rocky Bernstein" wrote:
> But suppose one wrote a profiler, or just some sort of signal handler. Don't
> you want to be able to debug via PS4 the same as any other code?

You can do that using the TRAPNAL() { ... } form of trap, which records
line numbers like any other function.  I'll have to make sure this is
documented somewhere.

-- 
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] 9+ messages in thread

* Re: PATCH: source file info from PS4
  2008-09-18 15:25         ` Peter Stephenson
@ 2008-09-18 15:39           ` Rocky Bernstein
  2008-09-18 15:45             ` Peter Stephenson
  0 siblings, 1 reply; 9+ messages in thread
From: Rocky Bernstein @ 2008-09-18 15:39 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

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

How does one use TRAPNAL for the "DEBUG" signal?

On Thu, Sep 18, 2008 at 11:25 AM, Peter Stephenson <pws@csr.com> wrote:

> "Rocky Bernstein" wrote:
> > But suppose one wrote a profiler, or just some sort of signal handler.
> Don't
> > you want to be able to debug via PS4 the same as any other code?
>
> You can do that using the TRAPNAL() { ... } form of trap, which records
> line numbers like any other function.  I'll have to make sure this is
> documented somewhere.
>
> --
> 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
>

[-- Attachment #2: Type: text/html, Size: 1274 bytes --]

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

* Re: PATCH: source file info from PS4
  2008-09-18 15:39           ` Rocky Bernstein
@ 2008-09-18 15:45             ` Peter Stephenson
  0 siblings, 0 replies; 9+ messages in thread
From: Peter Stephenson @ 2008-09-18 15:45 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, 18 Sep 2008 11:39:31 -0400
"Rocky Bernstein" <rocky.bernstein@gmail.com> wrote:
> How does one use TRAPNAL for the "DEBUG" signal?

It's the same as for any signal: defining

TRAPDEBUG() {
  ...
}

is basically the same as defining

trap '...' DEBUG

apart from obvious quoting issues, and apart from the fact that TRAPDEBUG
gets its own full function environment rather than an eval-style
environment.  You can have one or other at any one time, not both.

-- 
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] 9+ messages in thread

end of thread, other threads:[~2008-09-18 15:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-09-16 14:50 PATCH: source file info from PS4 Peter Stephenson
2008-09-16 16:17 ` Rocky Bernstein
2008-09-17 16:39 ` Rocky Bernstein
2008-09-18 12:13   ` Peter Stephenson
2008-09-18 15:05     ` Rocky Bernstein
2008-09-18 15:22       ` Rocky Bernstein
2008-09-18 15:25         ` Peter Stephenson
2008-09-18 15:39           ` Rocky Bernstein
2008-09-18 15:45             ` 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).