1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Provide NEdit Macro stack traces
6 http://sourceforge.net/tracker/index.php?func=detail&aid=970501&group_id=11005&atid=311005
7 [ 970501 ] Provide NEdit Macro stack traces
8 InterpretDebug.diff 2004-06-10 11:51
10 Macro function names are listed when a crash occurs in one of your macros.
11 The usual error message is followed by a list of the NEdit macro functions
12 called before getting there. (It doesn't tell you how the macro was invoked
13 however.) This provides a good clue as to where a macro programming problem
16 Also, debug tracing enhanced to show symbol values in stack traces listed to
17 terminal output: a boon to interpret.c hackers.
19 Try changing the definition
21 #define STACKDUMP(n, x) stackdump(n, x)
25 #define STACKDUMP(n, x) stackdump(n, x + 50)
27 and watching the output of NEdit in an xterm generated while running your
30 (You will need to add -DDEBUG_STACK and -DDEBUG_ASSEMBLY in your compilation
31 flags to enable the debug tracing.)
33 Thanks to Eddy De Greef!
35 InterpretDebug2.diff 2004-06-11 17:13
37 This version passes an extra "name" string to ParseMacro(). This name is
38 used as a "function name" in the stack dumps, when there is no available
39 function symbol name available (usually at the top level of invocation from
40 NEdit's user interface). It allows the user to determine which macro is
41 being invoked or which file is being interpreted when an error occurs.
45 source/interpret.c | 403 ++++++++++++++++++++++++++++++++++++++++++--------
46 source/interpret.h | 2
51 source/parse_noyacc.c | 9 -
52 source/smartIndent.c | 22 +-
53 source/userCmds.c | 49 +++---
54 9 files changed, 410 insertions(+), 101 deletions(-)
56 diff --quilt old/source/interpret.c new/source/interpret.c
57 --- old/source/interpret.c
58 +++ new/source/interpret.c
59 @@ -36,11 +36,13 @@ static const char CVSID[] = "$Id: interp
73 @@ -102,21 +104,25 @@ static const char *tagToStr(enum typeTag
74 /*#define DEBUG_ASSEMBLY*/
75 /*#define DEBUG_STACK*/
77 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
78 #define DEBUG_DISASSEMBLER
79 +static const char *printd(const char *f, ...);
80 +static int outPrintd();
81 static void disasm(Inst *inst, int nInstr);
82 +static void disasmInternal(Inst *inst, int nInstr);
83 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
85 #ifdef DEBUG_ASSEMBLY /* for disassembly */
86 #define DISASM(i, n) disasm(i, n)
87 #else /* #ifndef DEBUG_ASSEMBLY */
89 #endif /* #ifndef DEBUG_ASSEMBLY */
91 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
92 static void stackdump(int n, int extra);
93 +static void stackdumpInternal(int n, int extra);
94 #define STACKDUMP(n, x) stackdump(n, x)
95 #define DISASM_RT(i, n) disasm(i, n)
96 #else /* #ifndef DEBUG_STACK */
97 #define STACKDUMP(n, x)
98 #define DISASM_RT(i, n)
99 @@ -170,18 +176,22 @@ static int (*OpFns[])() = {
104 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
105 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
106 +#define FP_ARG_ARRAY_INDEX (-1)
107 #define FP_ARG_COUNT_INDEX (-2)
108 -#define FP_OLD_FP_INDEX (-3)
109 -#define FP_RET_PC_INDEX (-4)
110 -#define FP_PROG_INDEX (-5)
111 -#define FP_TO_ARGS_DIST (5) /* should be 0 - (above index) */
112 +#define FP_FUNCTION_NAME (-3) /* !! */
113 +#define FP_SYMBOL_TABLE (-4) /* !! */
114 +#define FP_OLD_FP_INDEX (-5)
115 +#define FP_RET_PC_INDEX (-6)
116 +#define FP_PROG_INDEX (-7)
118 +#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
120 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
121 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
122 +#define FP_GET_ARG_ARRAY(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
123 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
124 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
125 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
126 #define FP_GET_PROG(xFrameP) ((FP_GET_ITEM(xFrameP, FP_PROG_INDEX)).val.prog)
127 #define FP_ARG_START_INDEX(xFrameP) (-(FP_GET_ARG_COUNT(xFrameP) + FP_TO_ARGS_DIST))
128 @@ -265,10 +275,11 @@ Program *FinishCreatingProgram(Accumulat
129 newProg = (Program *)XtMalloc(sizeof(Program));
130 progLen = ((char *)ProgP) - ((char *)Prog);
131 newProg->code = (Inst *)XtMalloc(progLen);
132 memcpy(newProg->code, Prog, progLen);
133 newProg->localSymList = LocalSymList;
134 + newProg->name = NULL;
135 newProg->refcount = 1;
137 /* Local variables' values are stored on the stack. Here we assign
138 frame pointer offsets to them. */
139 for (s = newProg->localSymList; s != NULL; s = s->next)
140 @@ -289,10 +300,11 @@ Program *FinishCreatingProgram(Accumulat
141 void FreeProgram(Program *prog)
143 if (--prog->refcount == 0) {
144 freeSymbolTable(prog->localSymList);
145 XtFree((char *)prog->code);
146 + XtFree((char *)prog->name);
147 XtFree((char *)prog);
152 @@ -475,10 +487,19 @@ int ExecuteMacro(WindowInfo *window, Pro
153 context->stackP->tag = NO_TAG;
156 *(context->stackP++) = noValue; /* old FrameP */
158 + context->stackP->tag = NO_TAG;
159 + context->stackP->val.sym = prog->localSymList; /* symbol table */
162 + context->stackP->tag = STRING_TAG;
163 + context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
164 + context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
167 context->stackP->tag = NO_TAG; /* nArgs */
168 context->stackP->val.n = nArgs;
171 *(context->stackP++) = noValue; /* cached arg array */
172 @@ -578,10 +599,19 @@ void RunMacroAsSubrCall(Program *prog)
174 StackP->tag = NO_TAG;
175 StackP->val.dataval = FrameP; /* old FrameP */
178 + StackP->tag = NO_TAG;
179 + StackP->val.sym = prog->localSymList; /* symbol table */
182 + StackP->tag = STRING_TAG;
183 + StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
184 + StackP->val.str.len = strlen(StackP->val.str.rep);
187 StackP->tag = NO_TAG; /* nArgs */
191 *(StackP++) = noValue; /* cached arg array */
192 @@ -1380,11 +1410,11 @@ static int pushArgArray(void)
197 nArgs = FP_GET_ARG_COUNT(FrameP);
198 - resultArray = &FP_GET_ARG_ARRAY_CACHE(FrameP);
199 + resultArray = &FP_GET_ARG_ARRAY(FrameP);
200 if (resultArray->tag != ARRAY_TAG) {
201 resultArray->tag = ARRAY_TAG;
202 resultArray->val.arrayPtr = ArrayNew();
204 for (argNum = 0; argNum < nArgs; ++argNum) {
205 @@ -2157,10 +2187,19 @@ static int callSubroutine(void)
207 StackP->tag = NO_TAG; /* old FrameP */
208 StackP->val.dataval = FrameP;
211 + StackP->tag = NO_TAG;
212 + StackP->val.sym = prog->localSymList; /* symbol table */
215 + StackP->tag = STRING_TAG;
216 + StackP->val.str.rep = sym->name; /* function name */
217 + StackP->val.str.len = strlen(sym->name);
220 StackP->tag = NO_TAG; /* nArgs */
221 StackP->val.n = nArgs;
224 *(StackP++) = noValue; /* cached arg array */
225 @@ -2704,11 +2743,11 @@ static int arrayRef(void)
231 - STACKDUMP(nDim, 3);
232 + STACKDUMP(nDim+1, 3);
235 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
236 if (errNum != STAT_OK) {
238 @@ -2755,11 +2794,11 @@ static int arrayAssign(void)
244 - STACKDUMP(nDim, 3);
245 + STACKDUMP(nDim+2, 3);
250 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
251 @@ -2793,13 +2832,13 @@ static int arrayAssign(void)
254 ** for use with assign-op operators (eg a[i,j] += k
256 ** Before: Prog-> [binOp], nDim, next, ...
257 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
258 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
259 ** After: Prog-> binOp, nDim, [next], ...
260 -** TheStack-> [rhs], arrayValue, next, ...
261 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
263 static int arrayRefAndAssignSetup(void)
266 DataValue srcArray, valueItem, moveExpr;
267 @@ -2810,11 +2849,11 @@ static int arrayRefAndAssignSetup(void)
273 - STACKDUMP(nDim + 1, 3);
274 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
280 @@ -3064,20 +3103,75 @@ static int errCheck(const char *s)
286 +** build a stack dump string, reallocating s as necessary.
288 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
293 + DataValue *nfp = fp;
298 + disasmInternal(PC - 1, 1);
299 + stackdumpInternal(0, 50);
300 + dump = printd(NULL);
303 + /* first measure the lengths */
304 + len = strlen(msg) + 1;
305 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
306 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
309 + len += strlen(dump);
313 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
322 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
324 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
339 ** combine two strings in a static area and set ErrMsg to point to the
340 ** result. Returns false so a single return execError() statement can
341 ** be used to both process the message and return.
343 static int execError(const char *s1, const char *s2)
345 static char msg[MAX_ERR_MSG_LEN];
346 + static char *err = NULL;
347 + static int errlen = 0;
349 sprintf(msg, s1, s2);
351 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
355 int StringToNum(const char *string, int *number)
357 @@ -3123,168 +3217,353 @@ static const char *tagToStr(enum typeTag
362 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
363 +static char *printdBuffer = NULL;
364 +static int printdPos = 0;
365 +static int printdSize = 0;
367 +static const char *printd(const char *f, ...)
375 + printdPos = 0; /* reset for next time */
376 + return printdBuffer;
380 + vsprintf(buffer, f, args);
383 + len = strlen(buffer);
387 + printdBuffer = XtMalloc(printdSize);
392 + int needSize = printdPos + len + 1;
393 + if (needSize > printdSize)
395 + int newSize = printdSize;
396 + while (newSize < needSize)
398 + printdBuffer = XtRealloc(printdBuffer, newSize);
399 + printdSize = newSize;
402 + strcpy(&printdBuffer[printdPos], buffer);
405 + return printdBuffer;
410 + const char *s = printd(NULL);
413 + static int outIsTTY = -1;
414 + if (outIsTTY == -1)
415 + outIsTTY = isatty(fileno(stdout));
419 + for (cp = s; *cp; cp++)
421 + printf("\033[K\n");
427 + for (cp = s; *cp; cp++)
432 +#endif /* #ifdef DEBUG_DISASSEMBLER */
434 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
435 static void dumpVal(DataValue dv)
439 - printf("i=%d", dv.val.n);
440 + printd("i=%d", dv.val.n);
446 char *src = dv.val.str.rep;
448 - printf("s=<NULL>");
449 + printd("s=<NULL>");
452 for (k = 0; src[k] && k < sizeof s - 1; k++) {
453 s[k] = isprint(src[k]) ? src[k] : '?';
456 - printf("s=\"%s\"%s[%d]", s,
457 + printd("s=\"%s\"%s[%d]", s,
458 src[k] ? "..." : "", strlen(src));
464 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
468 - printf("<no value>");
469 + printd("<no value>");
472 - printf("?%8p", dv.val.inst);
473 + printd("?%8p", dv.val.inst);
477 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
478 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
482 #endif /* #ifdef DEBUG_DISASSEMBLER */
484 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
485 -static void disasm(Inst *inst, int nInstr)
486 +static void disasmInternal(Inst *inst, int nInstr)
488 static const char *opNames[] = {
489 #define OP(name, fn) #name,
497 for (i = 0; i < nInstr; ++i) {
498 - printf("Prog %8p ", &inst[i]);
499 + printd("Prog %8p ", &inst[i]);
500 for (j = 0; j < N_OPS; ++j) {
501 if (inst[i].func == OpFns[j]) {
502 - printf("%22s ", opNames[j]);
503 + printd("%22s ", opNames[j]);
504 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
505 Symbol *sym = inst[i+1].sym;
506 - printf("%s", sym->name);
507 + printd("%s", sym->name);
508 if (sym->value.tag == STRING_TAG &&
509 strncmp(sym->name, "string #", 8) == 0) {
514 else if (j == OP_PUSH_IMMED) {
515 - printf("%d", inst[i+1].value);
516 + printd("%d", inst[i+1].value);
519 else if (j == OP_BRANCH || j == OP_BRANCH_FALSE ||
520 j == OP_BRANCH_NEVER || j == OP_BRANCH_TRUE) {
521 - printf("to=(%d) %p", inst[i+1].value,
522 + printd("to=(%d) %p", inst[i+1].value,
523 &inst[i+1] + inst[i+1].value);
526 else if (j == OP_CONCAT) {
527 printd("nExpr=%d", inst[i+1].value);
530 else if (j == OP_SUBR_CALL) {
531 - printf("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
532 + printd("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
535 else if (j == OP_BEGIN_ARRAY_ITER) {
536 - printf("%s in", inst[i+1].sym->name);
537 + printd("%s in", inst[i+1].sym->name);
540 else if (j == OP_ARRAY_ITER) {
541 - printf("%s = %s++ end-loop=(%d) %p",
542 + printd("%s = %s++ end-loop=(%d) %p",
545 inst[i+3].value, &inst[i+3] + inst[i+3].value);
548 else if (j == OP_ARRAY_REF || j == OP_ARRAY_DELETE ||
549 j == OP_ARRAY_ASSIGN) {
550 - printf("nDim=%d", inst[i+1].value);
551 + printd("nDim=%d", inst[i+1].value);
554 else if (j == OP_ARRAY_REF_ASSIGN_SETUP) {
555 - printf("binOp=%s ", inst[i+1].value ? "true" : "false");
556 - printf("nDim=%d", inst[i+2].value);
557 + printd("binOp=%s ", inst[i+1].value ? "true" : "false");
558 + printd("nDim=%d", inst[i+2].value);
561 else if (j == OP_PUSH_ARRAY_SYM) {
562 - printf("%s", inst[++i].sym->name);
563 - printf(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
564 + printd("%s", inst[++i].sym->name);
565 + printd(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
575 - printf("%x\n", inst[i].value);
576 + printd("%x\n", inst[i].value);
581 +static void disasm(Inst *inst, int nInstr)
583 + static int outIsTTY = -1;
584 + if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
585 + if (outIsTTY) { printd("\033[H"); }
586 + disasmInternal(inst, nInstr);
589 #endif /* #ifdef DEBUG_DISASSEMBLER */
591 #ifdef DEBUG_STACK /* for run-time stack dumping */
592 #define STACK_DUMP_ARG_PREFIX "Arg"
593 -static void stackdump(int n, int extra)
594 +static void stackdumpframe(DataValue *arrow, DataValue *outpt, DataValue *fp,
595 + DataValue *sp, char topMark)
597 - /* TheStack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
598 - int nArgs = FP_GET_ARG_COUNT(FrameP);
600 - char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
601 - printf("Stack ----->\n");
602 - for (i = 0; i < n + extra; i++) {
604 - DataValue *dv = &StackP[-i - 1];
605 - if (dv < TheStack) {
606 - printf("--------------Stack base--------------\n");
608 + DataValue *baseF = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
609 + DataValue *oldFP = baseF ? baseF->val.dataval : NULL;
610 + DataValue *arg1 = &FP_GET_ARG_N(fp, 0);
611 + DataValue *fnNm = &FP_GET_ITEM(fp, FP_FUNCTION_NAME);
613 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
614 + int nArgs = FP_GET_ARG_COUNT(fp);
617 + static int symLen = 0;
618 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
621 +#ifdef DEBUG_STACK_HEADFIRST
623 + /* do caller's frame */
624 + if (oldFP || arg1 > endDv)
625 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
626 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
628 + /* do current frame */
629 + /* how many symbols are there? */
630 + for (sym = syms, nSyms = 0; sym != NULL; sym = sym->next) {
633 + int len = strlen(sym->name);
639 - offset = dv - FrameP;
642 + /* output instructions between endDv and sp - 1 inclusive */
643 +#ifdef DEBUG_STACK_HEADFIRST
645 + while (--dv >= endDv)
647 + for (dv = endDv; dv < sp; dv++)
648 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
650 + const char *posFmt = "%-6s ";
651 + const char *symName = "";
653 - printf("%4.4s", i < n ? ">>>>" : "");
654 - printf("%8p ", dv);
656 + char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
657 + int offset = dv - fp;
658 + const char *leadIn = (dv >= arrow) ? ">>>>" :
659 + (dv == arg1) ? "----" :
660 + (dv == fnNm) ? "====" : "";
661 + printd("%4.4s", leadIn);
662 + printd("%8p%c", dv, topMark);
664 - case 0: pos = "FrameP"; break; /* first local symbol value */
665 - case FP_ARG_ARRAY_CACHE_INDEX: pos = "args"; break; /* arguments array */
666 - case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* number of arguments */
667 - case FP_OLD_FP_INDEX: pos = "OldFP"; break;
668 - case FP_RET_PC_INDEX: pos = "RetPC"; break;
669 - case FP_PROG_INDEX: pos = "Prog"; break;
670 + case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
671 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
672 + case FP_FUNCTION_NAME: pos = "FnName"; break;
673 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
674 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
675 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
676 + case FP_PROG_INDEX: pos = "Prog"; break;
678 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
679 + if (offset < -FP_TO_ARGS_DIST &&
680 + offset >= -FP_TO_ARGS_DIST - nArgs)
682 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
683 offset + FP_TO_ARGS_DIST + nArgs + 1);
685 + else if (0 <= offset && offset < nSyms) {
686 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
689 + else if (offset == 0) {
694 - printf("%-6s ", pos);
697 + printd(posFmt, pos);
699 + /* local symbol names? */
700 + if (offset < nSyms) {
701 + for (sym = syms; sym != NULL; sym = sym->next) {
702 + if (sym->value.val.n == offset) {
703 + symName = sym->name;
708 + printd("%-*.*s ", symLen, symLen, symName);
710 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
711 + printd("%s", dv->val.str.rep);
718 +#ifdef DEBUG_STACK_HEADFIRST
719 + /* do caller's frame */
720 + if (oldFP || arg1 > endDv)
721 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
723 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
726 +static void stackdumpInternal(int n, int extra)
728 + DataValue *arrow = StackP - n;
729 + DataValue *outpt = StackP - n - extra;
731 +#ifdef DEBUG_STACK_HEADFIRST
732 + printd("Stack ----->\n");
733 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
734 + if (outpt < TheStack)
735 + printd("--------------Stack base--------------\n");
737 + if (outpt < TheStack)
738 + printd("--------------Stack base--------------\n");
739 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
740 + printd("Stack ----->\n");
741 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
744 +static void stackdump(int n, int extra)
746 + static int outIsTTY = -1;
747 + if (outIsTTY == -1)
748 + outIsTTY = isatty(fileno(stdout));
750 + stackdumpInternal(n, extra);
753 + printd("\033[J\n");
759 #endif /* ifdef DEBUG_STACK */
760 diff --quilt old/source/interpret.h new/source/interpret.h
761 --- old/source/interpret.h
762 +++ new/source/interpret.h
763 @@ -84,10 +84,11 @@ typedef struct DataValueTag {
764 struct ProgramTag* prog;
767 struct DataValueTag* dataval;
768 struct SparseArrayEntryTag *arrayPtr;
769 + struct SymbolRec *sym;
773 typedef struct SparseArrayEntryTag {
774 rbTreeNode nodePtrs; /* MUST BE FIRST ENTRY */
775 @@ -105,10 +106,11 @@ typedef struct SymbolRec {
777 typedef struct ProgramTag {
778 Symbol *localSymList;
784 /* Information needed to re-start a preempted macro */
787 diff --quilt old/source/macro.c new/source/macro.c
788 --- old/source/macro.c
789 +++ new/source/macro.c
790 @@ -840,11 +840,12 @@ void Replay(WindowInfo *window)
791 if (ReplayMacro != NULL &&
792 ReplayMacro[0] != 0 &&
793 window->macroCmdData == NULL) {
794 /* Parse the replay macro (it's stored in text form) and compile it into
795 an executable program "prog" */
796 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False);
797 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False,
801 "NEdit internal error, learn/replay macro syntax error: %s\n",
804 @@ -938,11 +939,11 @@ static int readCheckMacroString(Widget d
805 WindowInfo *runWindow, const char *errIn, char **errPos)
807 char *stoppedAt, *errMsg;
810 - prog = ParseMacro(string, &errMsg, &stoppedAt, True);
811 + prog = ParseMacro(string, &errMsg, &stoppedAt, True, errIn);
813 if (errPos != NULL) {
816 return ParseError(dialogParent, string, stoppedAt, errIn, errMsg);
817 @@ -1224,11 +1225,11 @@ void DoMacro(WindowInfo *window, const c
818 strncpy(tMacro, macro, macroLen);
819 tMacro[macroLen] = '\n';
820 tMacro[macroLen+1] = '\0';
822 /* Parse the macro and report errors if it fails */
823 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
824 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, errInName);
826 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
830 @@ -1488,11 +1489,11 @@ selEnd += $text_length - startLength\n}\
831 sprintf(loopedCmd, loopMacro, command);
833 sprintf(loopedCmd, loopMacro, how, command);
835 /* Parse the resulting macro into an executable program "prog" */
836 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False);
837 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False, "repeat macro");
839 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
843 diff --quilt old/source/nedit.c new/source/nedit.c
844 --- old/source/nedit.c
845 +++ new/source/nedit.c
846 @@ -830,14 +830,14 @@ static int checkDoMacroArg(const char *m
847 strncpy(tMacro, macro, macroLen);
848 tMacro[macroLen] = '\n';
849 tMacro[macroLen+1] = '\0';
851 /* Do a test parse */
852 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
853 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, "-do macro");
856 - ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
857 + ParseError(NULL, tMacro, stoppedAt, "-do macro", errMsg);
863 diff --quilt old/source/parse.h new/source/parse.h
864 --- old/source/parse.h
865 +++ new/source/parse.h
867 #ifndef NEDIT_PARSE_H_INCLUDED
868 #define NEDIT_PARSE_H_INCLUDED
870 #include "interpret.h"
872 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine);
873 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
876 #endif /* NEDIT_PARSE_H_INCLUDED */
877 diff --quilt old/source/parse.y new/source/parse.y
878 --- old/source/parse.y
879 +++ new/source/parse.y
880 @@ -617,14 +617,16 @@ blank: /* nothing */
881 ** executed using ExecuteProgram. Returns program on success, or NULL
882 ** on failure. If the command failed, the error message is returned
883 ** as a pointer to a static string in msg, and the length of the string up
884 ** to where parsing failed in stoppedAt.
886 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine)
887 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
891 AccumulatorData *acc = (AccumulatorData *)XtMalloc(sizeof(*acc));
892 + static const char *prefix = ">> ";
894 BeginCreatingProgram(acc);
896 /* whether we allow the "define" keyword */
897 AllowDefine = allowDefine;
898 @@ -643,10 +645,16 @@ Program *ParseMacro(char *expr, char **m
900 /* get the newly created program */
901 prog = FinishCreatingProgram(acc);
905 + name = "--unknown--";
907 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
908 + strcat(strcpy(prog->name, prefix), name);
910 /* parse succeeded */
915 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
916 --- old/source/parse_noyacc.c
917 +++ new/source/parse_noyacc.c
918 @@ -744,13 +744,14 @@ int yystacksize;
919 ** executed using ExecuteProgram. Returns program on success, or NULL
920 ** on failure. If the command failed, the error message is returned
921 ** as a pointer to a static string in msg, and the length of the string up
922 ** to where parsing failed in stoppedAt.
924 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
925 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
928 + static const char *prefix = ">> ";
930 BeginCreatingProgram();
932 /* call yyparse to parse the string and check for success. If the parse
933 failed, return the error message and string index (the grammar aborts
934 @@ -764,10 +765,16 @@ Program *ParseMacro(char *expr, char **m
937 /* get the newly created program */
938 prog = FinishCreatingProgram();
941 + name = "--unknown--";
943 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
944 + strcat(strcpy(prog->name, prefix), name);
946 /* parse succeeded */
951 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
952 --- old/source/smartIndent.c
953 +++ new/source/smartIndent.c
954 @@ -745,21 +745,21 @@ void BeginSmartIndent(WindowInfo *window
955 /* Compile the newline and modify macros and attach them to the window */
956 winData = (windowSmartIndentData *)XtMalloc(sizeof(windowSmartIndentData));
957 winData->inNewLineMacro = 0;
958 winData->inModMacro = 0;
959 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
960 - &stoppedAt, False);
961 + &stoppedAt, False, "smart indent newline macro");
962 if (winData->newlineMacro == NULL) {
963 - ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
964 - "newline macro", errMsg);
965 + ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
966 + "smart indent newline macro", errMsg);
969 if (indentMacros->modMacro == NULL)
970 winData->modMacro = NULL;
972 - winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
973 - &stoppedAt, False);
974 + winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
975 + &stoppedAt, False, "smart indent modify macro");
976 if (winData->modMacro == NULL) {
977 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
978 "smart indent modify macro", errMsg);
981 @@ -1410,11 +1410,11 @@ static int checkSmartIndentDialogData(vo
983 /* Check the initialization macro */
984 if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) {
985 widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
986 if (!CheckMacroString(SmartIndentDialog.shell, widgetText,
987 - "initialization macro", &stoppedAt)) {
988 + "smart indent initialization macro", &stoppedAt)) {
989 XmTextSetInsertionPosition(SmartIndentDialog.initMacro,
990 stoppedAt - widgetText);
991 XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT);
994 @@ -1429,14 +1429,15 @@ static int checkSmartIndentDialogData(vo
995 "Newline macro required", "OK");
999 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
1000 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
1001 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
1002 + "smart indent newline macro");
1004 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1005 - "newline macro", errMsg);
1006 + "smart indent newline macro", errMsg);
1007 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
1008 stoppedAt - widgetText);
1009 XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT);
1012 @@ -1445,14 +1446,15 @@ static int checkSmartIndentDialogData(vo
1015 /* Test compile the modify macro */
1016 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
1017 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
1018 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
1019 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
1020 + "smart indent modify macro");
1022 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1023 - "modify macro", errMsg);
1024 + "smart indent modify macro", errMsg);
1025 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
1026 stoppedAt - widgetText);
1027 XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT);
1030 diff --quilt old/source/userCmds.c new/source/userCmds.c
1031 --- old/source/userCmds.c
1032 +++ new/source/userCmds.c
1033 @@ -239,10 +239,12 @@ static Widget MacroPasteReplayBtn = NULL
1034 static Widget BGMenuPasteReplayBtn = NULL;
1036 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
1037 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
1038 int nMenuItems, int sensitive);
1039 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1040 + menuItemRec **menu, int nMenu, const char *menuName);
1041 static void rebuildMenuOfAllWindows(int menuType);
1042 static void rebuildMenu(WindowInfo *window, int menuType);
1043 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
1044 const char *hierName);
1045 static char *copySubstring(const char *string, int length);
1046 @@ -1258,34 +1260,41 @@ int DoNamedShellMenuCmd(WindowInfo *wind
1048 ** Search through the Macro or background menu and execute the first command
1049 ** with menu item name "itemName". Returns True on successs and False on
1052 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1053 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1054 + menuItemRec **menu, int nMenu, const char *menuName)
1058 - for (i=0; i<NMacroMenuItems; i++) {
1059 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
1060 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
1063 + char *name = NULL;
1064 + Boolean result = False;
1066 + for (i = 0; i < nMenu; i++) {
1067 + if (!strcmp(menu[i]->name, itemName)) {
1068 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
1069 + strcat(strcpy(name, menuName), itemName);
1070 + DoMacro(window, menu[i]->cmd, name);
1081 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1083 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
1087 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
1091 - for (i=0; i<NBGMenuItems; i++) {
1092 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
1093 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
1098 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
1099 + "background-menu>");
1103 ** Cache user menus:
1104 ** Rebuild all of the Shell, Macro, Background menus of given editor window.
1105 @@ -2078,11 +2087,11 @@ static int checkMacro(userCmdDialog *ucd
1106 static int checkMacroText(char *macro, Widget errorParent, Widget errFocus)
1109 char *errMsg, *stoppedAt;
1111 - prog = ParseMacro(macro, &errMsg, &stoppedAt, False);
1112 + prog = ParseMacro(macro, &errMsg, &stoppedAt, False, "macro");
1114 if (errorParent != NULL) {
1115 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
1116 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1117 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1118 @@ -2090,11 +2099,11 @@ static int checkMacroText(char *macro, W
1122 if (*stoppedAt != '\0') {
1123 if (errorParent != NULL) {
1124 - ParseError(errorParent, macro, stoppedAt,"macro","syntax error");
1125 + ParseError(errorParent, macro, stoppedAt, "macro", "syntax error");
1126 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1127 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1131 @@ -3017,11 +3026,11 @@ static char *copyMacroToEnd(char **inPtr
1132 ParseError(NULL, *inPtr, *inPtr-1, "macro menu item", "expecting '{'");
1136 /* Parse the input */
1137 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False);
1138 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False, "macro menu item");
1140 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);