1 Provide NEdit Macro stack traces
5 http://sourceforge.net/tracker/index.php?func=detail&aid=970501&group_id=11005&atid=311005
6 [ 970501 ] Provide NEdit Macro stack traces
7 InterpretDebug.diff 2004-06-10 11:51
9 Macro function names are listed when a crash occurs in one of your macros.
10 The usual error message is followed by a list of the NEdit macro functions
11 called before getting there. (It doesn't tell you how the macro was invoked
12 however.) This provides a good clue as to where a macro programming
15 Also, debug tracing enhanced to show symbol values in stack traces listed to
16 terminal output: a boon to interpret.c hackers.
18 Try changing the definition
19 #define STACKDUMP(n, x) stackdump(n, x)
21 #define STACKDUMP(n, x) stackdump(n, x + 50)
22 and watching the output of NEdit in an xterm generated while running your
25 (You will need to add -DDEBUG_STACK and -DDEBUG_ASSEMBLY in your compilation
26 flags to enable the debug tracing.)
28 Thanks to Eddy De Greef!
30 InterpretDebug2.diff 2004-06-11 17:13
32 This version passes an extra "name" string to ParseMacro().
33 This name is used as a "function name" in the stack dumps,
34 when there is no available function symbol name available
35 (usually at the top level of invocation from NEdit's user
36 interface). It allows the user to determine which macro is
37 being invoked or which file is being interpreted when an error
42 source/interpret.c | 398 ++++++++++++++++++++++++++++++++++++++++++--------
43 source/interpret.h | 2
48 source/parse_noyacc.c | 9 +
49 source/smartIndent.c | 12 -
50 source/userCmds.c | 47 +++--
51 9 files changed, 400 insertions(+), 91 deletions(-)
53 diff --quilt old/source/interpret.c new/source/interpret.c
54 --- old/source/interpret.c
55 +++ new/source/interpret.c
56 @@ -38,7 +38,9 @@ static const char CVSID[] = "$Id: interp
66 @@ -143,7 +145,10 @@ static SparseArrayEntry *allocateSparseA
68 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
69 #define DEBUG_DISASSEMBLER
70 +static const char *printd(const char *f, ...);
71 +static int outPrintd();
72 static void disasm(Inst *inst, int nInstr);
73 +static void disasmInternal(Inst *inst, int nInstr);
74 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
76 #ifdef DEBUG_ASSEMBLY /* for disassembly */
77 @@ -154,6 +159,7 @@ static void disasm(Inst *inst, int nInst
79 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
80 static void stackdump(int n, int extra);
81 +static void stackdumpInternal(int n, int extra);
82 #define STACKDUMP(n, x) stackdump(n, x)
83 #define DISASM_RT(i, n) disasm(i, n)
84 #else /* #ifndef DEBUG_STACK */
85 @@ -213,13 +219,17 @@ static int (*OpFns[N_OPS])() = {returnNo
86 arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray};
88 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
89 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
90 +#define FP_ARG_ARRAY_INDEX (-1)
91 #define FP_ARG_COUNT_INDEX (-2)
92 -#define FP_OLD_FP_INDEX (-3)
93 -#define FP_RET_PC_INDEX (-4)
94 -#define FP_TO_ARGS_DIST (4) /* should be 0 - (above index) */
95 +#define FP_FUNCTION_NAME (-3) /* !! */
96 +#define FP_SYMBOL_TABLE (-4) /* !! */
97 +#define FP_OLD_FP_INDEX (-5)
98 +#define FP_RET_PC_INDEX (-6)
100 +#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
102 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
103 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
104 +#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
105 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
106 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
107 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
108 @@ -300,6 +310,7 @@ Program *FinishCreatingProgram(void)
109 memcpy(newProg->code, Prog, progLen);
110 newProg->localSymList = LocalSymList;
112 + newProg->name = NULL;
114 /* Local variables' values are stored on the stack. Here we assign
115 frame pointer offsets to them. */
116 @@ -315,6 +326,9 @@ void FreeProgram(Program *prog)
118 freeSymbolTable(prog->localSymList);
119 XtFree((char *)prog->code);
121 + XtFree((char *)prog->name);
123 XtFree((char *)prog);
126 @@ -496,6 +510,15 @@ int ExecuteMacro(WindowInfo *window, Pro
128 *(context->stackP++) = noValue; /* old FrameP */
130 + context->stackP->tag = NO_TAG;
131 + context->stackP->val.sym = prog->localSymList; /* symbol table */
134 + context->stackP->tag = STRING_TAG;
135 + context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
136 + context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
139 context->stackP->tag = NO_TAG; /* nArgs */
140 context->stackP->val.n = nArgs;
142 @@ -595,6 +618,15 @@ void RunMacroAsSubrCall(Program *prog)
143 StackP->val.dataval = FrameP; /* old FrameP */
146 + StackP->tag = NO_TAG;
147 + StackP->val.sym = prog->localSymList; /* symbol table */
150 + StackP->tag = STRING_TAG;
151 + StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
152 + StackP->val.str.len = strlen(StackP->val.str.rep);
155 StackP->tag = NO_TAG; /* nArgs */
158 @@ -2082,6 +2114,8 @@ static int callSubroutine(void)
159 ** values which are already there.
161 if (sym->type == MACRO_FUNCTION_SYM) {
162 + prog = sym->value.val.prog;
164 StackP->tag = NO_TAG; /* return PC */
165 StackP->val.inst = PC;
167 @@ -2090,6 +2124,15 @@ static int callSubroutine(void)
168 StackP->val.dataval = FrameP;
171 + StackP->tag = NO_TAG;
172 + StackP->val.sym = prog->localSymList; /* symbol table */
175 + StackP->tag = STRING_TAG;
176 + StackP->val.str.rep = sym->name; /* function name */
177 + StackP->val.str.len = strlen(sym->name);
180 StackP->tag = NO_TAG; /* nArgs */
181 StackP->val.n = nArgs;
183 @@ -2097,7 +2140,6 @@ static int callSubroutine(void)
184 *(StackP++) = noValue; /* cached arg array */
187 - prog = sym->value.val.prog;
189 for (s = prog->localSymList; s != NULL; s = s->next) {
190 FP_GET_SYM_VAL(FrameP, s) = noValue;
191 @@ -2564,7 +2606,7 @@ static int arrayRef(void)
195 - STACKDUMP(nDim, 3);
196 + STACKDUMP(nDim+1, 3);
199 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
200 @@ -2615,7 +2657,7 @@ static int arrayAssign(void)
204 - STACKDUMP(nDim, 3);
205 + STACKDUMP(nDim+2, 3);
209 @@ -2653,9 +2695,9 @@ static int arrayAssign(void)
210 ** for use with assign-op operators (eg a[i,j] += k
212 ** Before: Prog-> [binOp], nDim, next, ...
213 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
214 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
215 ** After: Prog-> binOp, nDim, [next], ...
216 -** TheStack-> [rhs], arrayValue, next, ...
217 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
219 static int arrayRefAndAssignSetup(void)
221 @@ -2670,7 +2712,7 @@ static int arrayRefAndAssignSetup(void)
225 - STACKDUMP(nDim + 1, 3);
226 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
230 @@ -2924,6 +2966,59 @@ static int errCheck(const char *s)
234 +** build a stack dump string, reallocating s as necessary.
236 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
241 + DataValue *nfp = fp;
246 + disasmInternal(PC - 1, 1);
247 + stackdumpInternal(0, 50);
248 + dump = printd(NULL);
251 + /* first measure the lengths */
252 + len = strlen(msg) + 1;
253 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
254 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
257 + len += strlen(dump);
261 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
270 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
272 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
287 ** combine two strings in a static area and set ErrMsg to point to the
288 ** result. Returns false so a single return execError() statement can
289 ** be used to both process the message and return.
290 @@ -2931,9 +3026,11 @@ static int errCheck(const char *s)
291 static int execError(const char *s1, const char *s2)
293 static char msg[MAX_ERR_MSG_LEN];
294 + static char *err = NULL;
295 + static int errlen = 0;
297 sprintf(msg, s1, s2);
299 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
303 @@ -2967,11 +3064,83 @@ int StringToNum(const char *string, int
306 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
307 +static char *printdBuffer = NULL;
308 +static int printdPos = 0;
309 +static int printdSize = 0;
311 +static const char *printd(const char *f, ...)
319 + printdPos = 0; /* reset for next time */
320 + return printdBuffer;
324 + vsprintf(buffer, f, args);
327 + len = strlen(buffer);
331 + printdBuffer = XtMalloc(printdSize);
336 + int needSize = printdPos + len + 1;
337 + if (needSize > printdSize)
339 + int newSize = printdSize;
340 + while (newSize < needSize)
342 + printdBuffer = XtRealloc(printdBuffer, newSize);
343 + printdSize = newSize;
346 + strcpy(&printdBuffer[printdPos], buffer);
349 + return printdBuffer;
354 + const char *s = printd(NULL);
357 + static int outIsTTY = -1;
358 + if (outIsTTY == -1)
359 + outIsTTY = isatty(fileno(stdout));
363 + for (cp = s; *cp; cp++)
365 + printf("\033[K\n");
371 + for (cp = s; *cp; cp++)
376 +#endif /* #ifdef DEBUG_DISASSEMBLER */
378 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
379 static void dumpVal(DataValue dv)
383 - printf("i=%d", dv.val.n);
384 + printd("i=%d", dv.val.n);
388 @@ -2979,38 +3148,38 @@ static void dumpVal(DataValue dv)
390 char *src = dv.val.str.rep;
392 - printf("s=<NULL>");
393 + printd("s=<NULL>");
396 for (k = 0; src[k] && k < sizeof s - 1; k++) {
397 s[k] = isprint(src[k]) ? src[k] : '?';
400 - printf("s=\"%s\"%s[%d]", s,
401 + printd("s=\"%s\"%s[%d]", s,
402 src[k] ? "..." : "", strlen(src));
408 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
412 - printf("<no value>");
413 + printd("<no value>");
416 - printf("?%8p", dv.val.inst);
417 + printd("?%8p", dv.val.inst);
421 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
422 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
426 #endif /* #ifdef DEBUG_DISASSEMBLER */
428 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
429 -static void disasm(Inst *inst, int nInstr)
430 +static void disasmInternal(Inst *inst, int nInstr)
432 static const char *opNames[N_OPS] = {
433 "RETURN_NO_VAL", /* returnNoVal */
434 @@ -3059,15 +3228,15 @@ static void disasm(Inst *inst, int nInst
440 for (i = 0; i < nInstr; ++i) {
441 - printf("Prog %8p ", &inst[i]);
442 + printd("Prog %8p ", &inst[i]);
443 for (j = 0; j < N_OPS; ++j) {
444 if (inst[i].func == OpFns[j]) {
445 - printf("%22s ", opNames[j]);
446 + printd("%22s ", opNames[j]);
447 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
448 Symbol *sym = inst[i+1].sym;
449 - printf("%s", sym->name);
450 + printd("%s", sym->name);
451 if (sym->value.tag == STRING_TAG &&
452 strncmp(sym->name, "string #", 8) == 0) {
454 @@ -3076,7 +3245,7 @@ static void disasm(Inst *inst, int nInst
456 else if (j == OP_BRANCH || j == OP_BRANCH_FALSE ||
457 j == OP_BRANCH_NEVER || j == OP_BRANCH_TRUE) {
458 - printf("to=(%d) %p", inst[i+1].value,
459 + printd("to=(%d) %p", inst[i+1].value,
460 &inst[i+1] + inst[i+1].value);
463 @@ -3085,15 +3254,15 @@ static void disasm(Inst *inst, int nInst
466 else if (j == OP_SUBR_CALL) {
467 - printf("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
468 + printd("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
471 else if (j == OP_BEGIN_ARRAY_ITER) {
472 - printf("%s in", inst[i+1].sym->name);
473 + printd("%s in", inst[i+1].sym->name);
476 else if (j == OP_ARRAY_ITER) {
477 - printf("%s = %s++ end-loop=(%d) %p",
478 + printd("%s = %s++ end-loop=(%d) %p",
481 inst[i+3].value, &inst[i+3] + inst[i+3].value);
482 @@ -3101,67 +3270,180 @@ static void disasm(Inst *inst, int nInst
484 else if (j == OP_ARRAY_REF || j == OP_ARRAY_DELETE ||
485 j == OP_ARRAY_ASSIGN) {
486 - printf("nDim=%d", inst[i+1].value);
487 + printd("nDim=%d", inst[i+1].value);
490 else if (j == OP_ARRAY_REF_ASSIGN_SETUP) {
491 - printf("binOp=%s ", inst[i+1].value ? "true" : "false");
492 - printf("nDim=%d", inst[i+2].value);
493 + printd("binOp=%s ", inst[i+1].value ? "true" : "false");
494 + printd("nDim=%d", inst[i+2].value);
497 else if (j == OP_PUSH_ARRAY_SYM) {
498 - printf("%s", inst[++i].sym->name);
499 - printf(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
500 + printd("%s", inst[++i].sym->name);
501 + printd(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
511 - printf("%x\n", inst[i].value);
512 + printd("%x\n", inst[i].value);
517 +static void disasm(Inst *inst, int nInstr)
519 + static int outIsTTY = -1;
520 + if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
521 + if (outIsTTY) { printd("\033[H"); }
522 + disasmInternal(inst, nInstr);
525 #endif /* #ifdef DEBUG_DISASSEMBLER */
527 #ifdef DEBUG_STACK /* for run-time stack dumping */
528 #define STACK_DUMP_ARG_PREFIX "Arg"
529 -static void stackdump(int n, int extra)
530 +static void stackdumpframe(DataValue *arrow, DataValue *outpt, DataValue *fp,
531 + DataValue *sp, char topMark)
533 - /* TheStack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
534 - int nArgs = FP_GET_ARG_COUNT(FrameP);
536 - char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
537 - printf("Stack ----->\n");
538 - for (i = 0; i < n + extra; i++) {
540 - DataValue *dv = &StackP[-i - 1];
541 - if (dv < TheStack) {
542 - printf("--------------Stack base--------------\n");
544 + DataValue *baseF = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
545 + DataValue *oldFP = baseF ? baseF->val.dataval : NULL;
546 + DataValue *arg1 = &FP_GET_ARG_N(fp, 0);
547 + DataValue *fnNm = &FP_GET_ITEM(fp, FP_FUNCTION_NAME);
549 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
550 + int nArgs = FP_GET_ARG_COUNT(fp);
553 + static int symLen = 0;
554 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
557 +#ifdef DEBUG_STACK_HEADFIRST
559 + /* do caller's frame */
560 + if (oldFP || arg1 > endDv)
561 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
562 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
564 + /* do current frame */
565 + /* how many symbols are there? */
566 + for (sym = syms, nSyms = 0; sym != NULL; sym = sym->next) {
569 + int len = strlen(sym->name);
576 - offset = dv - FrameP;
578 - printf("%4.4s", i < n ? ">>>>" : "");
579 - printf("%8p ", dv);
580 + /* output instructions between endDv and sp - 1 inclusive */
581 +#ifdef DEBUG_STACK_HEADFIRST
583 + while (--dv >= endDv)
585 + for (dv = endDv; dv < sp; dv++)
586 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
588 + const char *posFmt = "%-6s ";
589 + const char *symName = "";
592 + char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
593 + int offset = dv - fp;
594 + const char *leadIn = (dv >= arrow) ? ">>>>" :
595 + (dv == arg1) ? "----" :
596 + (dv == fnNm) ? "====" : "";
597 + printd("%4.4s", leadIn);
598 + printd("%8p%c", dv, topMark);
600 - case 0: pos = "FrameP"; break; /* first local symbol value */
601 - case FP_ARG_ARRAY_CACHE_INDEX: pos = "args"; break; /* arguments array */
602 - case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* number of arguments */
603 - case FP_OLD_FP_INDEX: pos = "OldFP"; break;
604 - case FP_RET_PC_INDEX: pos = "RetPC"; break;
605 + case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
606 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
607 + case FP_FUNCTION_NAME: pos = "FnName"; break;
608 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
609 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
610 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
612 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
613 + if (offset < -FP_TO_ARGS_DIST &&
614 + offset >= -FP_TO_ARGS_DIST - nArgs)
616 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
617 offset + FP_TO_ARGS_DIST + nArgs + 1);
619 + else if (0 <= offset && offset < nSyms) {
620 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
623 + else if (offset == 0) {
628 - printf("%-6s ", pos);
629 + printd(posFmt, pos);
631 + /* local symbol names? */
632 + if (offset < nSyms) {
633 + for (sym = syms; sym != NULL; sym = sym->next) {
634 + if (sym->value.val.n == offset) {
635 + symName = sym->name;
640 + printd("%-*.*s ", symLen, symLen, symName);
642 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
643 + printd("%s", dv->val.str.rep);
651 +#ifdef DEBUG_STACK_HEADFIRST
652 + /* do caller's frame */
653 + if (oldFP || arg1 > endDv)
654 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
656 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
659 +static void stackdumpInternal(int n, int extra)
661 + DataValue *arrow = StackP - n;
662 + DataValue *outpt = StackP - n - extra;
664 +#ifdef DEBUG_STACK_HEADFIRST
665 + printd("Stack ----->\n");
666 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
667 + if (outpt < TheStack)
668 + printd("--------------Stack base--------------\n");
670 + if (outpt < TheStack)
671 + printd("--------------Stack base--------------\n");
672 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
673 + printd("Stack ----->\n");
674 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
677 +static void stackdump(int n, int extra)
679 + static int outIsTTY = -1;
680 + if (outIsTTY == -1)
681 + outIsTTY = isatty(fileno(stdout));
683 + stackdumpInternal(n, extra);
686 + printd("\033[J\n");
692 #endif /* ifdef DEBUG_STACK */
693 diff --quilt old/source/interpret.h new/source/interpret.h
694 --- old/source/interpret.h
695 +++ new/source/interpret.h
696 @@ -86,6 +86,7 @@ typedef struct DataValueTag {
698 struct DataValueTag* dataval;
699 struct SparseArrayEntryTag *arrayPtr;
700 + struct SymbolRec *sym;
704 @@ -106,6 +107,7 @@ typedef struct SymbolRec {
705 typedef struct ProgramTag {
706 Symbol *localSymList;
711 /* Information needed to re-start a preempted macro */
712 diff --quilt old/source/macro.c new/source/macro.c
713 --- old/source/macro.c
714 +++ new/source/macro.c
715 @@ -831,7 +831,7 @@ void Replay(WindowInfo *window)
716 window->macroCmdData == NULL) {
717 /* Parse the replay macro (it's stored in text form) and compile it into
718 an executable program "prog" */
719 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt);
720 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, "replay macro");
723 "NEdit internal error, learn/replay macro syntax error: %s\n",
724 @@ -965,7 +965,7 @@ static int readCheckMacroString(Widget d
725 return ParseError(dialogParent, string, inPtr,
726 errIn, "expected '{'");
728 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
729 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, subrName);
731 if (errPos != NULL) *errPos = stoppedAt;
732 return ParseError(dialogParent, string, stoppedAt,
733 @@ -993,7 +993,7 @@ static int readCheckMacroString(Widget d
734 definitions in a file which is loaded from another macro file, it
735 will probably run the code blocks in reverse order! */
737 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
738 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, errIn);
740 if (errPos != NULL) {
742 @@ -1296,7 +1296,7 @@ void DoMacro(WindowInfo *window, const c
743 tMacro[macroLen+1] = '\0';
745 /* Parse the macro and report errors if it fails */
746 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
747 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, errInName);
749 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
751 @@ -1560,7 +1560,7 @@ selEnd += $text_length - startLength\n}\
752 sprintf(loopedCmd, loopMacro, how, command);
754 /* Parse the resulting macro into an executable program "prog" */
755 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt);
756 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, "repeat macro");
758 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
760 diff --quilt old/source/nedit.c new/source/nedit.c
761 --- old/source/nedit.c
762 +++ new/source/nedit.c
763 @@ -832,7 +832,7 @@ static int checkDoMacroArg(const char *m
764 tMacro[macroLen+1] = '\0';
766 /* Do a test parse */
767 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
768 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, "-do Argument");
771 ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
772 diff --quilt old/source/parse.h new/source/parse.h
773 --- old/source/parse.h
774 +++ new/source/parse.h
777 #include "interpret.h"
779 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt);
780 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name);
782 #endif /* NEDIT_PARSE_H_INCLUDED */
783 diff --quilt old/source/parse.y new/source/parse.y
784 --- old/source/parse.y
785 +++ new/source/parse.y
786 @@ -548,9 +548,10 @@ blank: /* nothing */
787 ** as a pointer to a static string in msg, and the length of the string up
788 ** to where parsing failed in stoppedAt.
790 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
791 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
794 + static const char *prefix = ">> ";
796 BeginCreatingProgram();
798 @@ -568,6 +569,12 @@ Program *ParseMacro(char *expr, char **m
799 /* get the newly created program */
800 prog = FinishCreatingProgram();
803 + name = "--unknown--";
805 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
806 + strcat(strcpy(prog->name, prefix), name);
808 /* parse succeeded */
811 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
812 --- old/source/parse_noyacc.c
813 +++ new/source/parse_noyacc.c
814 @@ -746,9 +746,10 @@ int yystacksize;
815 ** as a pointer to a static string in msg, and the length of the string up
816 ** to where parsing failed in stoppedAt.
818 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
819 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
822 + static const char *prefix = ">> ";
824 BeginCreatingProgram();
826 @@ -766,6 +767,12 @@ Program *ParseMacro(char *expr, char **m
827 /* get the newly created program */
828 prog = FinishCreatingProgram();
831 + name = "--unknown--";
833 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
834 + strcat(strcpy(prog->name, prefix), name);
836 /* parse succeeded */
839 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
840 --- old/source/smartIndent.c
841 +++ new/source/smartIndent.c
842 @@ -747,17 +747,17 @@ void BeginSmartIndent(WindowInfo *window
843 winData->inNewLineMacro = 0;
844 winData->inModMacro = 0;
845 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
847 + &stoppedAt, "smart indent newline macro");
848 if (winData->newlineMacro == NULL) {
849 ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
850 - "newline macro", errMsg);
851 + "smart indent newline macro", errMsg);
854 if (indentMacros->modMacro == NULL)
855 winData->modMacro = NULL;
857 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
859 + &stoppedAt, "smart indent modify macro");
860 if (winData->modMacro == NULL) {
861 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
862 "smart indent modify macro", errMsg);
863 @@ -1431,7 +1431,8 @@ static int checkSmartIndentDialogData(vo
866 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
867 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
868 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
869 + "smart indent newline macro");
871 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
872 "newline macro", errMsg);
873 @@ -1447,7 +1448,8 @@ static int checkSmartIndentDialogData(vo
874 /* Test compile the modify macro */
875 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
876 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
877 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
878 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
879 + "smart indent modify macro");
881 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
882 "modify macro", errMsg);
883 diff --quilt old/source/userCmds.c new/source/userCmds.c
884 --- old/source/userCmds.c
885 +++ new/source/userCmds.c
886 @@ -241,6 +241,8 @@ static Widget BGMenuPasteReplayBtn = NUL
887 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
888 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
889 int nMenuItems, int sensitive);
890 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
891 + menuItemRec **menu, int nMenu, const char *menuName);
892 static void rebuildMenuOfAllWindows(int menuType);
893 static void rebuildMenu(WindowInfo *window, int menuType);
894 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
895 @@ -1260,30 +1262,37 @@ int DoNamedShellMenuCmd(WindowInfo *wind
896 ** with menu item name "itemName". Returns True on successs and False on
899 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
900 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
901 + menuItemRec **menu, int nMenu, const char *menuName)
905 - for (i=0; i<NMacroMenuItems; i++) {
906 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
907 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
911 + Boolean result = False;
913 + for (i = 0; i < nMenu; i++) {
914 + if (!strcmp(menu[i]->name, itemName)) {
915 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
916 + strcat(strcpy(name, menuName), itemName);
917 + DoMacro(window, menu[i]->cmd, name);
928 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
930 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
934 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
938 - for (i=0; i<NBGMenuItems; i++) {
939 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
940 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
945 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
946 + "background-menu>");
950 @@ -2080,7 +2089,7 @@ static int checkMacroText(char *macro, W
952 char *errMsg, *stoppedAt;
954 - prog = ParseMacro(macro, &errMsg, &stoppedAt);
955 + prog = ParseMacro(macro, &errMsg, &stoppedAt, "macro");
957 if (errorParent != NULL) {
958 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
959 @@ -3019,7 +3028,7 @@ static char *copyMacroToEnd(char **inPtr
962 /* Parse the input */
963 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt);
964 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, "macro menu item");
966 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);