    Provide NEdit Macro stack traces

    Avaliable as a patch:

    http://sourceforge.net/tracker/index.php?func=detail&aid=970501&group_id=11005&atid=311005
	    [ 970501 ] Provide NEdit Macro stack traces
	    InterpretDebug.diff 2004-06-10 11:51

    Macro function names are listed when a crash occurs in one of your macros.
    The usual error message is followed by a list of the NEdit macro functions
    called before getting there. (It doesn't tell you how the macro was invoked
    however.) This provides a good clue as to where  a macro programming
    problem lies.

    Also, debug tracing enhanced to show symbol values in stack traces listed to
    terminal output: a boon to interpret.c hackers.

    Try changing the definition
	  #define STACKDUMP(n, x) stackdump(n, x)
    to
	  #define STACKDUMP(n, x) stackdump(n, x + 50)
    and watching the output of NEdit in an xterm generated while running your
    favorite macros!

    (You will need to add -DDEBUG_STACK and -DDEBUG_ASSEMBLY in your compilation
    flags to enable the debug tracing.)

    Thanks to Eddy De Greef!

	    InterpretDebug2.diff	2004-06-11 17:13

    This version passes an extra "name" string to ParseMacro().
    This name is used as a "function name" in the stack dumps,
    when there is no available function symbol name available
    (usually at the top level of invocation from NEdit's user
    interface). It allows the user to determine which macro is
    being invoked or which file is being interpreted when an error
    occurs.

diff -ur nedit_official nedit_mod
diff -ur nedit_official/source/interpret.c nedit_mod/source/interpret.c
--- nedit_official/source/interpret.c	2008-03-09 20:29:38.000000000 +0100
+++ nedit_mod/source/interpret.c	2008-05-21 02:00:54.000000000 +0200
@@ -39,6 +39,7 @@
 #include "rbTree.h"
 
 #include <stdio.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
@@ -141,7 +142,10 @@
 
 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
 #define DEBUG_DISASSEMBLER
+static const char *printd(const char *f, ...);
+static int outPrintd();
 static void disasm(Inst *inst, int nInstr);
+static void disasmInternal(Inst *inst, int nInstr);
 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
 
 #ifdef DEBUG_ASSEMBLY   /* for disassembly */
@@ -152,6 +156,7 @@
 
 #ifdef DEBUG_STACK      /* for run-time instruction and stack trace */
 static void stackdump(int n, int extra);
+static void stackdumpInternal(int n, int extra);
 #define STACKDUMP(n, x) stackdump(n, x)
 #define DISASM_RT(i, n) disasm(i, n)
 #else /* #ifndef DEBUG_STACK */
@@ -211,13 +216,17 @@
     arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray};
 
 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
-#define FP_ARG_ARRAY_CACHE_INDEX (-1)
+#define FP_ARG_ARRAY_INDEX (-1)
 #define FP_ARG_COUNT_INDEX (-2)
-#define FP_OLD_FP_INDEX (-3)
-#define FP_RET_PC_INDEX (-4)
-#define FP_TO_ARGS_DIST (4) /* should be 0 - (above index) */
+#define FP_FUNCTION_NAME   (-3) /* !! */
+#define FP_SYMBOL_TABLE    (-4) /* !! */
+#define FP_OLD_FP_INDEX    (-5)
+#define FP_RET_PC_INDEX    (-6)
+
+#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
+
 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
-#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
+#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
@@ -298,6 +307,7 @@
     memcpy(newProg->code, Prog, progLen);
     newProg->localSymList = LocalSymList;
     LocalSymList = NULL;
+    newProg->name = NULL;
     
     /* Local variables' values are stored on the stack.  Here we assign
        frame pointer offsets to them. */
@@ -313,6 +323,7 @@
 {
     freeSymbolTable(prog->localSymList);
     XtFree((char *)prog->code);
+    XtFree((char *)prog->name);
     XtFree((char *)prog);    
 }
 
@@ -494,6 +505,15 @@
     
     *(context->stackP++) = noValue; /* old FrameP */
     
+    context->stackP->tag = NO_TAG;
+    context->stackP->val.sym = prog->localSymList; /* symbol table */
+    context->stackP++;
+    
+    context->stackP->tag = STRING_TAG;
+    context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
+    context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
+    context->stackP++;
+    
     context->stackP->tag = NO_TAG; /* nArgs */
     context->stackP->val.n = nArgs;
     context->stackP++;
@@ -593,6 +613,15 @@
     StackP->val.dataval = FrameP; /* old FrameP */
     StackP++;
     
+    StackP->tag = NO_TAG;
+    StackP->val.sym = prog->localSymList; /* symbol table */
+    StackP++;
+    
+    StackP->tag = STRING_TAG;
+    StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
+    StackP->val.str.len = strlen(StackP->val.str.rep);
+    StackP++;
+    
     StackP->tag = NO_TAG; /* nArgs */
     StackP->val.n = 0;
     StackP++;
@@ -1949,6 +1978,8 @@
     ** values which are already there.
     */
     if (sym->type == MACRO_FUNCTION_SYM) {
+    	prog = sym->value.val.prog;
+
     	StackP->tag = NO_TAG; /* return PC */
     	StackP->val.inst = PC;
     	StackP++;
@@ -1957,6 +1988,15 @@
     	StackP->val.dataval = FrameP;
     	StackP++;
         
+    	StackP->tag = NO_TAG;
+    	StackP->val.sym = prog->localSymList; /* symbol table */
+    	StackP++;
+    
+    	StackP->tag = STRING_TAG;
+    	StackP->val.str.rep = sym->name; /* function name */
+    	StackP->val.str.len = strlen(sym->name);
+    	StackP++;
+
     	StackP->tag = NO_TAG; /* nArgs */
     	StackP->val.n = nArgs;
     	StackP++;
@@ -1964,7 +2004,6 @@
         *(StackP++) = noValue; /* cached arg array */
         
     	FrameP = StackP;
-    	prog = sym->value.val.prog;
     	PC = prog->code;
 	for (s = prog->localSymList; s != NULL; s = s->next) {
 	    FP_GET_SYM_VAL(FrameP, s) = noValue;
@@ -2465,7 +2504,7 @@
     PC++;
 
     DISASM_RT(PC-2, 2);
-    STACKDUMP(nDim, 3);
+    STACKDUMP(nDim+1, 3);
 
     if (nDim > 0) {
         errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
@@ -2516,7 +2555,7 @@
     PC++;
 
     DISASM_RT(PC-2, 1);
-    STACKDUMP(nDim, 3);
+    STACKDUMP(nDim+2, 3);
 
     if (nDim > 0) {
         POP(srcValue)
@@ -2554,9 +2593,9 @@
 ** for use with assign-op operators (eg a[i,j] += k
 **
 ** Before: Prog->  [binOp], nDim, next, ...
-**         TheStack-> [rhs], indnDim, ... ind1, next, ...
+**         TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
 ** After:  Prog->  binOp, nDim, [next], ...
-**         TheStack-> [rhs], arrayValue, next, ...
+**         TheStack-> [rhs], arrayValue, ArraySym, next, ...
 */
 static int arrayRefAndAssignSetup(void)
 {
@@ -2571,7 +2610,7 @@
     PC++;
 
     DISASM_RT(PC-3, 3);
-    STACKDUMP(nDim + 1, 3);
+    STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
 
     if (binaryOp) {
         POP(moveExpr)
@@ -2825,6 +2864,59 @@
 }
 
 /*
+** build a stack dump string, reallocating s as necessary.
+*/
+static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
+{
+    int len;
+    const char *op;
+    char *np;
+    DataValue *nfp = fp;
+
+#ifdef DEBUG_STACK
+    const char *dump;
+    printd("\n\n");
+    disasmInternal(PC - 1, 1);
+    stackdumpInternal(0, 50);
+    dump = printd(NULL);
+#endif
+
+    /* first measure the lengths */
+    len = strlen(msg) + 1;
+    for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
+        len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
+    }
+#ifdef DEBUG_STACK
+    len += strlen(dump);
+#endif
+    if (*pLen < len)
+    {
+        *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
+        *pLen = len;
+    }
+    /* now copy */
+    np = *s;
+    op = msg;
+    while (*op)
+        *np++ = *op++;
+
+    for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
+        *np++ = '\n';
+        op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
+        while (*op)
+            *np++ = *op++;
+    }
+#ifdef DEBUG_STACK
+    op = dump;
+    while (*op)
+        *np++ = *op++;
+#endif
+
+    *np = 0;
+    return *s;
+}
+
+/*
 ** combine two strings in a static area and set ErrMsg to point to the
 ** result.  Returns false so a single return execError() statement can
 ** be used to both process the message and return.
@@ -2832,9 +2924,11 @@
 static int execError(const char *s1, const char *s2)
 {
     static char msg[MAX_ERR_MSG_LEN];
+    static char *err = NULL;
+    static int errlen = 0;
     
     sprintf(msg, s1, s2);
-    ErrMsg = msg;
+    ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
     return STAT_ERROR;
 }
 
@@ -2868,11 +2962,83 @@
 }
 
 #ifdef DEBUG_DISASSEMBLER   /* dumping values in disassembly or stack dump */
+static char *printdBuffer = NULL;
+static int printdPos = 0;
+static int printdSize = 0;
+
+static const char *printd(const char *f, ...)
+{
+    char buffer[4096];
+    int len;
+    va_list args;
+
+    if (!f)
+    {
+      printdPos = 0;        /* reset for next time */
+      return printdBuffer;
+    }
+
+    va_start(args, f);
+    vsprintf(buffer, f, args);
+    va_end(args);
+
+    len = strlen(buffer);
+    if (!printdBuffer)
+    {
+        printdSize = 4096;
+        printdBuffer = XtMalloc(printdSize);
+        printdPos = 0;
+    }
+    else
+    {
+        int needSize = printdPos + len + 1;
+        if (needSize > printdSize)
+        {
+            int newSize = printdSize;
+            while (newSize < needSize)
+                newSize *= 2;
+            printdBuffer = XtRealloc(printdBuffer, newSize);
+            printdSize = newSize;
+        }
+    }
+    strcpy(&printdBuffer[printdPos], buffer);
+    printdPos += len;
+
+    return printdBuffer;
+}
+
+int outPrintd()
+{
+    const char *s = printd(NULL);
+    const char *cp;
+
+    static int outIsTTY = -1;
+    if (outIsTTY == -1)
+      outIsTTY = isatty(fileno(stdout));
+
+    if (outIsTTY)
+    {
+        for (cp = s; *cp; cp++)
+            if (*cp == '\n')
+                printf("\033[K\n");
+            else
+                putchar(*cp);
+    }
+    else
+    {
+        for (cp = s; *cp; cp++)
+            putchar(*cp);
+    }
+    return cp - s;
+}
+#endif /* #ifdef DEBUG_DISASSEMBLER */
+
+#ifdef DEBUG_DISASSEMBLER   /* dumping values in disassembly or stack dump */
 static void dumpVal(DataValue dv)
 {
     switch (dv.tag) {
         case INT_TAG:
-            printf("i=%d", dv.val.n);
+            printd("i=%d", dv.val.n);
             break;
         case STRING_TAG:
             {
@@ -2880,38 +3046,38 @@
                 char s[21];
                 char *src = dv.val.str.rep;
                 if (!src) {
-                    printf("s=<NULL>");
+                    printd("s=<NULL>");
                 }
                 else {
                     for (k = 0; src[k] && k < sizeof s - 1; k++) {
                         s[k] = isprint(src[k]) ? src[k] : '?';
                     }
                     s[k] = 0;
-                    printf("s=\"%s\"%s[%d]", s,
+                    printd("s=\"%s\"%s[%d]", s,
                            src[k] ? "..." : "", strlen(src));
                 }
             }
             break;
         case ARRAY_TAG:
-            printf("<array>");
+            printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
             break;
         case NO_TAG:
             if (!dv.val.inst) {
-                printf("<no value>");
+                printd("<no value>");
             }
             else {
-                printf("?%8p", dv.val.inst);
+                printd("?%8p", dv.val.inst);
             }
             break;
         default:
-            printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
+            printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
             break;
     }
 }
 #endif /* #ifdef DEBUG_DISASSEMBLER */
 
 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
-static void disasm(Inst *inst, int nInstr)
+static void disasmInternal(Inst *inst, int nInstr)
 {
     static const char *opNames[N_OPS] = {
         "RETURN_NO_VAL",                /* returnNoVal */
@@ -2960,37 +3126,38 @@
     };
     int i, j;
     
-    printf("\n");
+    printd("\n");
     for (i = 0; i < nInstr; ++i) {
-        printf("Prog %8p ", &inst[i]);
+        printd("Prog %8p ", &inst[i]);
         for (j = 0; j < N_OPS; ++j) {
             if (inst[i].func == OpFns[j]) {
-                printf("%22s ", opNames[j]);
+                printd("%22s ", opNames[j]);
                 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
                     Symbol *sym = inst[i+1].sym;
-                    printf("%s", sym->name);
+                    printd("%s", sym->name);
                     if (sym->value.tag == STRING_TAG &&
                         strncmp(sym->name, "string #", 8) == 0) {
+                        printd(" ");
                         dumpVal(sym->value);
                     }
                     ++i;
                 }
                 else if (j == OP_BRANCH || j == OP_BRANCH_FALSE ||
                         j == OP_BRANCH_NEVER || j == OP_BRANCH_TRUE) {
-                    printf("to=(%d) %p", inst[i+1].value,
+                    printd("to=(%d) %p", inst[i+1].value,
                             &inst[i+1] + inst[i+1].value);
                     ++i;
                 }
                 else if (j == OP_SUBR_CALL) {
-                    printf("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
+                    printd("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
                     i += 2;
                 }
                 else if (j == OP_BEGIN_ARRAY_ITER) {
-                    printf("%s in", inst[i+1].sym->name);
+                    printd("%s in", inst[i+1].sym->name);
                     ++i;
                 }
                 else if (j == OP_ARRAY_ITER) {
-                    printf("%s = %s++ end-loop=(%d) %p",
+                    printd("%s = %s++ end-loop=(%d) %p",
                             inst[i+1].sym->name,
                             inst[i+2].sym->name,
                             inst[i+3].value, &inst[i+3] + inst[i+3].value);
@@ -2998,67 +3165,180 @@
                 }
                 else if (j == OP_ARRAY_REF || j == OP_ARRAY_DELETE ||
                             j == OP_ARRAY_ASSIGN) {
-                    printf("nDim=%d", inst[i+1].value);
+                    printd("nDim=%d", inst[i+1].value);
                     ++i;
                 }
                 else if (j == OP_ARRAY_REF_ASSIGN_SETUP) {
-                    printf("binOp=%s ", inst[i+1].value ? "true" : "false");
-                    printf("nDim=%d", inst[i+2].value);
+                    printd("binOp=%s ", inst[i+1].value ? "true" : "false");
+                    printd("nDim=%d", inst[i+2].value);
                     i += 2;
                 }
                 else if (j == OP_PUSH_ARRAY_SYM) {
-                    printf("%s", inst[++i].sym->name);
-                    printf(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
+                    printd("%s", inst[++i].sym->name);
+                    printd(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
                     ++i;
                 }
 
-                printf("\n");
+                printd("\n");
                 break;
             }
         }
         if (j == N_OPS) {
-            printf("%x\n", inst[i].value);
+            printd("%x\n", inst[i].value);
         }
     }
 }
+
+static void disasm(Inst *inst, int nInstr)
+{
+    static int outIsTTY = -1;
+    if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
+    if (outIsTTY) { printd("\033[H"); }
+    disasmInternal(inst, nInstr);
+    outPrintd();
+}
 #endif /* #ifdef DEBUG_DISASSEMBLER */
 
 #ifdef DEBUG_STACK  /* for run-time stack dumping */
 #define STACK_DUMP_ARG_PREFIX "Arg"
-static void stackdump(int n, int extra)
+static void stackdumpframe(DataValue *arrow, DataValue *outpt, DataValue *fp,
+    DataValue *sp, char topMark)
 {
-    /* TheStack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
-    int nArgs = FP_GET_ARG_COUNT(FrameP);
-    int i, offset;
-    char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
-    printf("Stack ----->\n");
-    for (i = 0; i < n + extra; i++) {
-        char *pos = "";
-        DataValue *dv = &StackP[-i - 1];
-        if (dv < TheStack) {
-            printf("--------------Stack base--------------\n");
-            break;
+    DataValue *baseF = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
+    DataValue *oldFP = baseF ? baseF->val.dataval : NULL;
+    DataValue *arg1 = &FP_GET_ARG_N(fp, 0);
+    DataValue *fnNm = &FP_GET_ITEM(fp, FP_FUNCTION_NAME);
+    DataValue *dv;
+    DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
+    int nArgs = FP_GET_ARG_COUNT(fp);
+
+    int nSyms;
+    static int symLen = 0;
+    Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
+    Symbol *sym;
+
+#ifdef DEBUG_STACK_HEADFIRST
+#else
+    /* do caller's frame */
+    if (oldFP || arg1 > endDv)
+        stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
+#endif /* #ifdef DEBUG_STACK_HEADFIRST */
+
+    /* do current frame */
+    /* how many symbols are there? */
+    for (sym = syms, nSyms = 0; sym != NULL; sym = sym->next) {
+        nSyms++;
+        if (symLen < 27) {
+            int len = strlen(sym->name);
+            if (len > 27)
+                len = 27;
+            if (len > symLen)
+                symLen = len;
+        }
         }
-        offset = dv - FrameP;
 
-        printf("%4.4s", i < n ? ">>>>" : "");
-        printf("%8p ", dv);
+    /* output instructions between endDv and sp - 1 inclusive */
+#ifdef DEBUG_STACK_HEADFIRST
+    dv = sp;
+    while (--dv >= endDv)
+#else
+    for (dv = endDv; dv < sp; dv++)
+#endif /* #ifdef DEBUG_STACK_HEADFIRST */
+    {
+        const char *posFmt = "%-6s ";
+        const char *symName = "";
+
+        char *pos = "";
+        char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
+        int offset = dv - fp;
+        const char *leadIn = (dv >= arrow) ? ">>>>" :
+                             (dv ==  arg1) ? "----" :
+                             (dv ==  fnNm) ? "====" : "";
+        printd("%4.4s", leadIn);
+        printd("%8p%c", dv, topMark);
         switch (offset) {
-            case 0:                         pos = "FrameP"; break;  /* first local symbol value */
-            case FP_ARG_ARRAY_CACHE_INDEX:  pos = "args";   break;  /* arguments array */
-            case FP_ARG_COUNT_INDEX:        pos = "NArgs";  break;  /* number of arguments */
-            case FP_OLD_FP_INDEX:           pos = "OldFP";  break;
-            case FP_RET_PC_INDEX:           pos = "RetPC";  break;
+            case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
+            case FP_ARG_COUNT_INDEX: pos = "NArgs";  break; /* num. arguments */
+            case FP_FUNCTION_NAME:   pos = "FnName"; break;
+            case FP_SYMBOL_TABLE:    pos = "FnSyms"; break;
+            case FP_OLD_FP_INDEX:    pos = "OldFP";  break;
+            case FP_RET_PC_INDEX:    pos = "RetPC";  break;
             default:
-                if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
+                if (offset < -FP_TO_ARGS_DIST &&
+                    offset >= -FP_TO_ARGS_DIST - nArgs)
+                {
                     sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
                             offset + FP_TO_ARGS_DIST + nArgs + 1);
                 }
+                else if (0 <= offset && offset < nSyms) {
+                    sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
+                    posFmt = "%6s ";
+                }
+                else if (offset == 0) {
+                    pos = "FrameP";
+                }
                 break;
         }
-        printf("%-6s ", pos);
+        printd(posFmt, pos);
+
+        /* local symbol names? */
+        if (offset < nSyms) {
+            for (sym = syms; sym != NULL; sym = sym->next) {
+                if (sym->value.val.n == offset) {
+                    symName = sym->name;
+                    break;
+                }
+            }
+        }
+        printd("%-*.*s ", symLen, symLen, symName);
+
+        if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
+            printd("%s", dv->val.str.rep);
+        else
         dumpVal(*dv);
-        printf("\n");
+
+        printd("\n");
     }
+
+#ifdef DEBUG_STACK_HEADFIRST
+    /* do caller's frame */
+    if (oldFP || arg1 > endDv)
+        stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
+#else
+#endif /* #ifdef DEBUG_STACK_HEADFIRST */
 }
+
+static void stackdumpInternal(int n, int extra)
+{
+    DataValue *arrow = StackP - n;
+    DataValue *outpt = StackP - n - extra;
+
+#ifdef DEBUG_STACK_HEADFIRST
+    printd("Stack ----->\n");
+    stackdumpframe(arrow, outpt, FrameP, StackP, '*');
+    if (outpt < TheStack)
+        printd("--------------Stack base--------------\n");
+#else
+    if (outpt < TheStack)
+        printd("--------------Stack base--------------\n");
+    stackdumpframe(arrow, outpt, FrameP, StackP, '*');
+    printd("Stack ----->\n");
+#endif /* #ifdef DEBUG_STACK_HEADFIRST */
+}
+
+static void stackdump(int n, int extra)
+{
+    static int outIsTTY = -1;
+    if (outIsTTY == -1)
+        outIsTTY = isatty(fileno(stdout));
+
+    stackdumpInternal(n, extra);
+
+    if (outIsTTY)
+        printd("\033[J\n");
+
+    outPrintd();
+    fflush(stdout);
+}
+
 #endif /* ifdef DEBUG_STACK */
diff -ur nedit_official/source/interpret.h nedit_mod/source/interpret.h
--- nedit_official/source/interpret.h	2008-03-09 20:29:38.000000000 +0100
+++ nedit_mod/source/interpret.h	2008-05-21 02:00:54.000000000 +0200
@@ -86,6 +86,7 @@
         Inst* inst;
         struct DataValueTag* dataval;
         struct SparseArrayEntryTag *arrayPtr;
+        struct SymbolRec *sym;
     } val;
 } DataValue;
 
@@ -106,6 +107,7 @@
 typedef struct ProgramTag {
     Symbol *localSymList;
     Inst *code;
+    char *name;
 } Program;
 
 /* Information needed to re-start a preempted macro */
diff -ur nedit_official/source/macro.c nedit_mod/source/macro.c
--- nedit_official/source/macro.c	2007-10-04 18:04:25.000000000 +0200
+++ nedit_mod/source/macro.c	2008-05-21 02:00:54.000000000 +0200
@@ -745,7 +745,7 @@
             window->macroCmdData == NULL) {
         /* Parse the replay macro (it's stored in text form) and compile it into
         an executable program "prog" */
-        prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt);
+        prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, "replay macro");
         if (prog == NULL) {
             fprintf(stderr,
                 "NEdit internal error, learn/replay macro syntax error: %s\n",
@@ -879,7 +879,7 @@
 		return ParseError(dialogParent, string, inPtr,
 	    	    	errIn, "expected '{'");
 	    }
-	    prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
+	    prog = ParseMacro(inPtr, &errMsg, &stoppedAt, subrName);
 	    if (prog == NULL) {
 	    	if (errPos != NULL) *errPos = stoppedAt;
 	    	return ParseError(dialogParent, string, stoppedAt,
@@ -907,7 +907,7 @@
 	   definitions in a file which is loaded from another macro file, it
 	   will probably run the code blocks in reverse order! */
 	} else {
-	    prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
+	    prog = ParseMacro(inPtr, &errMsg, &stoppedAt, errIn);
 	    if (prog == NULL) {
                 if (errPos != NULL) {
                     *errPos = stoppedAt;
@@ -1210,7 +1210,7 @@
     tMacro[macroLen+1] = '\0';
     
     /* Parse the macro and report errors if it fails */
-    prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
+    prog = ParseMacro(tMacro, &errMsg, &stoppedAt, errInName);
     if (prog == NULL) {
     	ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
 	XtFree(tMacro);
@@ -1474,7 +1474,7 @@
 	sprintf(loopedCmd, loopMacro, how, command);
     
     /* Parse the resulting macro into an executable program "prog" */
-    prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt);
+    prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, "repeat macro");
     if (prog == NULL) {
 	fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
     		errMsg);
diff -ur nedit_official/source/nedit.c nedit_mod/source/nedit.c
--- nedit_official/source/nedit.c	2007-11-29 23:18:09.000000000 +0100
+++ nedit_mod/source/nedit.c	2008-05-21 02:00:54.000000000 +0200
@@ -832,7 +832,7 @@
     tMacro[macroLen+1] = '\0';
     
     /* Do a test parse */
-    prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
+    prog = ParseMacro(tMacro, &errMsg, &stoppedAt, "-do Argument");
     XtFree(tMacro);
     if (prog == NULL) {
     	ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
diff -ur nedit_official/source/parse.h nedit_mod/source/parse.h
--- nedit_official/source/parse.h	2004-11-09 22:58:44.000000000 +0100
+++ nedit_mod/source/parse.h	2008-05-21 02:00:54.000000000 +0200
@@ -30,6 +30,6 @@
 
 #include "interpret.h"
 
-Program *ParseMacro(char *expr, char **msg, char **stoppedAt);
+Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name);
 
 #endif /* NEDIT_PARSE_H_INCLUDED */
diff -ur nedit_official/source/parse.y nedit_mod/source/parse.y
--- nedit_official/source/parse.y	2007-01-12 17:17:42.000000000 +0100
+++ nedit_mod/source/parse.y	2008-05-21 02:00:54.000000000 +0200
@@ -451,9 +451,10 @@
 ** as a pointer to a static string in msg, and the length of the string up
 ** to where parsing failed in stoppedAt.
 */
-Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
+Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
 {
     Program *prog;
+    static const char *prefix = ">> ";
 
     BeginCreatingProgram();
 
@@ -471,6 +472,12 @@
     /* get the newly created program */
     prog = FinishCreatingProgram();
 
+    if (!name)
+        name = "--unknown--";
+
+    prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
+    strcat(strcpy(prog->name, prefix), name);
+
     /* parse succeeded */
     *msg = "";
     *stoppedAt = InPtr;
diff -ur nedit_official/source/parse_noyacc.c nedit_mod/source/parse_noyacc.c
--- nedit_official/source/parse_noyacc.c	2007-01-12 17:19:35.000000000 +0100
+++ nedit_mod/source/parse_noyacc.c	2008-05-21 02:00:54.000000000 +0200
@@ -746,9 +746,10 @@
 ** as a pointer to a static string in msg, and the length of the string up
 ** to where parsing failed in stoppedAt.
 */
-Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
+Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
 {
     Program *prog;
+    static const char *prefix = ">> ";
 
     BeginCreatingProgram();
 
@@ -766,6 +767,12 @@
     /* get the newly created program */
     prog = FinishCreatingProgram();
 
+    if (!name)
+        name = "--unknown--";
+
+    prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
+    strcat(strcpy(prog->name, prefix), name);
+
     /* parse succeeded */
     *msg = "";
     *stoppedAt = InPtr;
diff -ur nedit_official/source/smartIndent.c nedit_mod/source/smartIndent.c
--- nedit_official/source/smartIndent.c	2006-12-02 11:27:06.000000000 +0100
+++ nedit_mod/source/smartIndent.c	2008-05-21 02:00:54.000000000 +0200
@@ -747,17 +747,17 @@
     winData->inNewLineMacro = 0;
     winData->inModMacro = 0;
     winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
-    	    &stoppedAt);
+    	    &stoppedAt, "smart indent newline macro");
     if (winData->newlineMacro == NULL) {
     	ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
-    	    	"newline macro", errMsg);
+    	    	"smart indent newline macro", errMsg);
     	return;
     }
     if (indentMacros->modMacro == NULL)
     	winData->modMacro = NULL;
     else {
     	winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
-    	    	&stoppedAt);
+    	    	&stoppedAt, "smart indent modify macro");
     	if (winData->modMacro == NULL) {
     	    ParseError(window->shell, indentMacros->modMacro, stoppedAt,
     	    	    "smart indent modify macro", errMsg);
@@ -1437,7 +1437,8 @@
     }
 
     widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
-    prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
+    prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
+                      "smart indent newline macro");
     if (prog == NULL) {
  	ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
     	    	"newline macro", errMsg);
@@ -1453,7 +1454,8 @@
     /* Test compile the modify macro */
     if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
     	widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
-    	prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
+    	prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
+                          "smart indent modify macro");
 	if (prog == NULL) {
     	    ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
     	    	    "modify macro", errMsg);
diff -ur nedit_official/source/userCmds.c nedit_mod/source/userCmds.c
--- nedit_official/source/userCmds.c	2007-10-02 17:47:09.000000000 +0200
+++ nedit_mod/source/userCmds.c	2008-05-21 02:00:54.000000000 +0200
@@ -241,6 +241,8 @@
 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
 	int nMenuItems, int sensitive);
+static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
+        menuItemRec **menu, int nMenu, const char *menuName);
 static void rebuildMenuOfAllWindows(int menuType);
 static void rebuildMenu(WindowInfo *window, int menuType);
 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
@@ -1260,30 +1262,37 @@
 ** with menu item name "itemName".  Returns True on successs and False on
 ** failure.
 */
-int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
+static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
+        menuItemRec **menu, int nMenu, const char *menuName)
 {
     int i;
-    
-    for (i=0; i<NMacroMenuItems; i++) {
-    	if (!strcmp(MacroMenuItems[i]->name, itemName)) {
-    	    DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
-    	    return True;
-    	}
+    char *name = NULL;
+    Boolean result = False;
+
+    for (i = 0; i < nMenu; i++) {
+        if (!strcmp(menu[i]->name, itemName)) {
+            name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
+            strcat(strcpy(name, menuName), itemName);
+            DoMacro(window, menu[i]->cmd, name);
+            result = True;
+        }
     }
-    return False;
+    if (name) {
+        XtFree(name);
+    }
+    return result;
+}
+    
+int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
+{
+    return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
+                          "macro-menu>");
 }
 
 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
 {
-    int i;
-    
-    for (i=0; i<NBGMenuItems; i++) {
-    	if (!strcmp(BGMenuItems[i]->name, itemName)) {
-    	    DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
-    	    return True;
-    	}
-    }
-    return False;
+    return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
+                          "background-menu>");
 }
 
 /*
@@ -2080,7 +2089,7 @@
     Program *prog;
     char *errMsg, *stoppedAt;
 
-    prog = ParseMacro(macro, &errMsg, &stoppedAt);
+    prog = ParseMacro(macro, &errMsg, &stoppedAt, "macro");
     if (prog == NULL) {
 	if (errorParent != NULL) {
 	    ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
@@ -3019,7 +3028,7 @@
     }
 
     /* Parse the input */
-    prog = ParseMacro(*inPtr, &errMsg, &stoppedAt);
+    prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, "macro menu item");
     if (prog == NULL) {
     	ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);
     	return NULL;
