NULL terminate string bulk list
[nedit-bw.git] / InterpretDebug5.diff
blobbb69390d6b7f5642cae940bd60b4315984eb6578
1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Provide NEdit Macro stack traces
4 Avaliable as a patch:
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
14 lies.
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
28 favorite macros!
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.
43 ---
45 source/interpret.c | 404 +++++++++++++++++++++++++++++++++++++++++---------
46 source/interpret.h | 2
47 source/macro.c | 9 -
48 source/nedit.c | 4
49 source/parse.h | 3
50 source/parse.y | 10 +
51 source/parse_noyacc.c | 9 -
52 source/smartIndent.c | 20 +-
53 source/userCmds.c | 49 +++---
54 9 files changed, 403 insertions(+), 107 deletions(-)
56 diff --quilt old/source/interpret.c new/source/interpret.c
57 --- old/source/interpret.c
58 +++ new/source/interpret.c
59 @@ -38,7 +38,9 @@ static const char CVSID[] = "$Id: interp
60 #include "text.h"
61 #include "rbTree.h"
63 +#include <unistd.h>
64 #include <stdio.h>
65 +#include <stdarg.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <math.h>
69 @@ -104,7 +106,10 @@ static const char *tagToStr(enum typeTag
71 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
72 #define DEBUG_DISASSEMBLER
73 +static const char *printd(const char *f, ...);
74 +static int outPrintd();
75 static void disasm(Inst *inst, int nInstr);
76 +static void disasmInternal(Inst *inst, int nInstr);
77 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
79 #ifdef DEBUG_ASSEMBLY /* for disassembly */
80 @@ -115,6 +120,7 @@ static void disasm(Inst *inst, int nInst
82 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
83 static void stackdump(int n, int extra);
84 +static void stackdumpInternal(int n, int extra);
85 #define STACKDUMP(n, x) stackdump(n, x)
86 #define DISASM_RT(i, n) disasm(i, n)
87 #else /* #ifndef DEBUG_STACK */
88 @@ -172,14 +178,18 @@ static int (*OpFns[])() = {
91 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
92 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
93 +#define FP_ARG_ARRAY_INDEX (-1)
94 #define FP_ARG_COUNT_INDEX (-2)
95 -#define FP_OLD_FP_INDEX (-3)
96 -#define FP_RET_PC_INDEX (-4)
97 -#define FP_PROG_INDEX (-5)
98 -#define FP_TO_ARGS_DIST (5) /* should be 0 - (above index) */
99 +#define FP_FUNCTION_NAME (-3) /* !! */
100 +#define FP_SYMBOL_TABLE (-4) /* !! */
101 +#define FP_OLD_FP_INDEX (-5)
102 +#define FP_RET_PC_INDEX (-6)
103 +#define FP_PROG_INDEX (-7)
105 +#define FP_TO_ARGS_DIST (0 - FP_PROG_INDEX) /* should be 0 - (above index) */
107 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
108 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
109 +#define FP_GET_ARG_ARRAY(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
110 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
111 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
112 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
113 @@ -267,6 +277,7 @@ Program *FinishCreatingProgram(Accumulat
114 newProg->code = (Inst *)XtMalloc(progLen);
115 memcpy(newProg->code, Prog, progLen);
116 newProg->localSymList = LocalSymList;
117 + newProg->name = NULL;
118 newProg->refcount = 1;
120 /* Local variables' values are stored on the stack. Here we assign
121 @@ -291,6 +302,7 @@ void FreeProgram(Program *prog)
122 if (--prog->refcount == 0) {
123 freeSymbolTable(prog->localSymList);
124 XtFree((char *)prog->code);
125 + XtFree((char *)prog->name);
126 XtFree((char *)prog);
129 @@ -441,7 +453,8 @@ void FillLoopAddrs(Inst *breakAddr, Inst
130 ** helper function to setup the next frame
132 static void setupFrame(DataValue **frameP, DataValue **stackP,
133 - Inst **pc, Program *prog, int nArgs, DataValue *args)
134 + Inst **pc, Program *prog, int nArgs, DataValue *args,
135 + const char *name)
137 static DataValue noValue = {NO_TAG, {0}};
138 int i;
139 @@ -475,6 +488,17 @@ static void setupFrame(DataValue **frame
140 (*stackP)->val.dataval = *frameP;
141 (*stackP)++;
143 + /* symbol table */
144 + (*stackP)->tag = NO_TAG;
145 + (*stackP)->val.sym = prog->localSymList;
146 + (*stackP)++;
148 + /* macro name */
149 + (*stackP)->tag = STRING_TAG;
150 + (*stackP)->val.str.rep = name;
151 + (*stackP)->val.str.len = strlen(name);
152 + (*stackP)++;
154 /* nArgs */
155 (*stackP)->tag = NO_TAG;
156 (*stackP)->val.n = nArgs;
157 @@ -551,7 +575,7 @@ int ExecuteMacro(WindowInfo *window, Pro
158 /* prog will be freed by cller, but by stack also, so inc refcount */
159 prog->refcount++;
160 setupFrame(&context->frameP, &context->stackP, &context->pc,
161 - prog, nArgs, args);
162 + prog, nArgs, args, prog->name ? prog->name : "<exec-macro>");
164 /* Begin execution, return on error or preemption */
165 return ContinueMacro(context, result, msg);
166 @@ -627,7 +651,8 @@ int ContinueMacro(RestartData *continuat
168 void RunMacroAsSubrCall(Program *prog)
170 - setupFrame(&FrameP, &StackP, &PC, prog, 0, NULL);
171 + setupFrame(&FrameP, &StackP, &PC, prog, 0, NULL,
172 + prog->name ? prog->name : "<run-macro>");
175 void FreeRestartData(RestartData *context)
176 @@ -1419,7 +1444,7 @@ static int pushArgArray(void)
177 STACKDUMP(0, 3);
179 nArgs = FP_GET_ARG_COUNT(FrameP);
180 - resultArray = &FP_GET_ARG_ARRAY_CACHE(FrameP);
181 + resultArray = &FP_GET_ARG_ARRAY(FrameP);
182 if (resultArray->tag != ARRAY_TAG) {
183 resultArray->tag = ARRAY_TAG;
184 resultArray->val.arrayPtr = ArrayNew();
185 @@ -2184,7 +2209,7 @@ static int callSubroutine(void)
186 prog = sym->value.val.prog;
187 prog->refcount++;
188 /* -nArgs means 'arguments are on stack' */
189 - setupFrame(&FrameP, &StackP, &PC, prog, -nArgs, NULL);
190 + setupFrame(&FrameP, &StackP, &PC, prog, -nArgs, NULL, sym->name);
191 return STAT_OK;
194 @@ -2712,7 +2737,7 @@ static int arrayRef(void)
195 PC++;
197 DISASM_RT(PC-2, 2);
198 - STACKDUMP(nDim, 3);
199 + STACKDUMP(nDim+1, 3);
201 if (nDim > 0) {
202 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
203 @@ -2763,7 +2788,7 @@ static int arrayAssign(void)
204 PC++;
206 DISASM_RT(PC-2, 1);
207 - STACKDUMP(nDim, 3);
208 + STACKDUMP(nDim+2, 3);
210 if (nDim > 0) {
211 POP(srcValue);
212 @@ -2801,9 +2826,9 @@ static int arrayAssign(void)
213 ** for use with assign-op operators (eg a[i,j] += k
215 ** Before: Prog-> [binOp], nDim, next, ...
216 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
217 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
218 ** After: Prog-> binOp, nDim, [next], ...
219 -** TheStack-> [rhs], arrayValue, next, ...
220 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
222 static int arrayRefAndAssignSetup(void)
224 @@ -2818,7 +2843,7 @@ static int arrayRefAndAssignSetup(void)
225 PC++;
227 DISASM_RT(PC-3, 3);
228 - STACKDUMP(nDim + 1, 3);
229 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
231 if (binaryOp) {
232 POP(moveExpr);
233 @@ -3072,6 +3097,59 @@ static int errCheck(const char *s)
237 +** build a stack dump string, reallocating s as necessary.
239 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
241 + int len;
242 + const char *op;
243 + char *np;
244 + DataValue *nfp = fp;
246 +#ifdef DEBUG_STACK
247 + const char *dump;
248 + printd("\n\n");
249 + disasmInternal(PC - 1, 1);
250 + stackdumpInternal(0, 50);
251 + dump = printd(NULL);
252 +#endif
254 + /* first measure the lengths */
255 + len = strlen(msg) + 1;
256 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
257 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
259 +#ifdef DEBUG_STACK
260 + len += strlen(dump);
261 +#endif
262 + if (*pLen < len)
264 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
265 + *pLen = len;
267 + /* now copy */
268 + np = *s;
269 + op = msg;
270 + while (*op)
271 + *np++ = *op++;
273 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
274 + *np++ = '\n';
275 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
276 + while (*op)
277 + *np++ = *op++;
279 +#ifdef DEBUG_STACK
280 + op = dump;
281 + while (*op)
282 + *np++ = *op++;
283 +#endif
285 + *np = 0;
286 + return *s;
290 ** combine two strings in a static area and set ErrMsg to point to the
291 ** result. Returns false so a single return execError() statement can
292 ** be used to both process the message and return.
293 @@ -3079,9 +3157,11 @@ static int errCheck(const char *s)
294 static int execError(const char *s1, const char *s2)
296 static char msg[MAX_ERR_MSG_LEN];
297 + static char *err = NULL;
298 + static int errlen = 0;
300 sprintf(msg, s1, s2);
301 - ErrMsg = msg;
302 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
303 return STAT_ERROR;
306 @@ -3131,11 +3211,83 @@ static const char *tagToStr(enum typeTag
309 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
310 +static char *printdBuffer = NULL;
311 +static int printdPos = 0;
312 +static int printdSize = 0;
314 +static const char *printd(const char *f, ...)
316 + char buffer[4096];
317 + int len;
318 + va_list args;
320 + if (!f)
322 + printdPos = 0; /* reset for next time */
323 + return printdBuffer;
326 + va_start(args, f);
327 + vsprintf(buffer, f, args);
328 + va_end(args);
330 + len = strlen(buffer);
331 + if (!printdBuffer)
333 + printdSize = 4096;
334 + printdBuffer = XtMalloc(printdSize);
335 + printdPos = 0;
337 + else
339 + int needSize = printdPos + len + 1;
340 + if (needSize > printdSize)
342 + int newSize = printdSize;
343 + while (newSize < needSize)
344 + newSize *= 2;
345 + printdBuffer = XtRealloc(printdBuffer, newSize);
346 + printdSize = newSize;
349 + strcpy(&printdBuffer[printdPos], buffer);
350 + printdPos += len;
352 + return printdBuffer;
355 +int outPrintd()
357 + const char *s = printd(NULL);
358 + const char *cp;
360 + static int outIsTTY = -1;
361 + if (outIsTTY == -1)
362 + outIsTTY = isatty(fileno(stdout));
364 + if (outIsTTY)
366 + for (cp = s; *cp; cp++)
367 + if (*cp == '\n')
368 + printf("\033[K\n");
369 + else
370 + putchar(*cp);
372 + else
374 + for (cp = s; *cp; cp++)
375 + putchar(*cp);
377 + return cp - s;
379 +#endif /* #ifdef DEBUG_DISASSEMBLER */
381 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
382 static void dumpVal(DataValue dv)
384 switch (dv.tag) {
385 case INT_TAG:
386 - printf("i=%d", dv.val.n);
387 + printd("i=%d", dv.val.n);
388 break;
389 case STRING_TAG:
391 @@ -3143,38 +3295,38 @@ static void dumpVal(DataValue dv)
392 char s[21];
393 char *src = dv.val.str.rep;
394 if (!src) {
395 - printf("s=<NULL>");
396 + printd("s=<NULL>");
398 else {
399 for (k = 0; src[k] && k < sizeof s - 1; k++) {
400 s[k] = isprint(src[k]) ? src[k] : '?';
402 s[k] = 0;
403 - printf("s=\"%s\"%s[%d]", s,
404 + printd("s=\"%s\"%s[%d]", s,
405 src[k] ? "..." : "", strlen(src));
408 break;
409 case ARRAY_TAG:
410 - printf("<array>");
411 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
412 break;
413 case NO_TAG:
414 if (!dv.val.inst) {
415 - printf("<no value>");
416 + printd("<no value>");
418 else {
419 - printf("?%8p", dv.val.inst);
420 + printd("?%8p", dv.val.inst);
422 break;
423 default:
424 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
425 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
426 break;
429 #endif /* #ifdef DEBUG_DISASSEMBLER */
431 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
432 -static void disasm(Inst *inst, int nInstr)
433 +static void disasmInternal(Inst *inst, int nInstr)
435 static const char *opNames[] = {
436 #define OP(name, fn) #name,
437 @@ -3183,15 +3335,15 @@ static void disasm(Inst *inst, int nInst
439 int i, j;
441 - printf("\n");
442 + printd("\n");
443 for (i = 0; i < nInstr; ++i) {
444 - printf("Prog %8p ", &inst[i]);
445 + printd("Prog %8p ", &inst[i]);
446 for (j = 0; j < N_OPS; ++j) {
447 if (inst[i].func == OpFns[j]) {
448 - printf("%22s ", opNames[j]);
449 + printd("%22s ", opNames[j]);
450 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
451 Symbol *sym = inst[i+1].sym;
452 - printf("%s", sym->name);
453 + printd("%s", sym->name);
454 if (sym->value.tag == STRING_TAG &&
455 strncmp(sym->name, "string #", 8) == 0) {
456 dumpVal(sym->value);
457 @@ -3199,29 +3351,29 @@ static void disasm(Inst *inst, int nInst
458 ++i;
460 else if (j == OP_PUSH_IMMED) {
461 - printf("%d", inst[i+1].value);
462 + printd("%d", inst[i+1].value);
463 ++i;
465 else if (j == OP_BRANCH || j == OP_BRANCH_FALSE ||
466 j == OP_BRANCH_NEVER || j == OP_BRANCH_TRUE) {
467 - printf("to=(%d) %p", inst[i+1].value,
468 + printd("to=(%d) %p", inst[i+1].value,
469 &inst[i+1] + inst[i+1].value);
470 ++i;
472 else if (j == OP_CONCAT) {
473 - printf("nExpr=%d", inst[i+1].value);
474 + printd("nExpr=%d", inst[i+1].value);
475 ++i;
477 else if (j == OP_SUBR_CALL) {
478 - printf("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
479 + printd("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
480 i += 2;
482 else if (j == OP_BEGIN_ARRAY_ITER) {
483 - printf("%s in", inst[i+1].sym->name);
484 + printd("%s in", inst[i+1].sym->name);
485 ++i;
487 else if (j == OP_ARRAY_ITER) {
488 - printf("%s = %s++ end-loop=(%d) %p",
489 + printd("%s = %s++ end-loop=(%d) %p",
490 inst[i+1].sym->name,
491 inst[i+2].sym->name,
492 inst[i+3].value, &inst[i+3] + inst[i+3].value);
493 @@ -3229,68 +3381,182 @@ static void disasm(Inst *inst, int nInst
495 else if (j == OP_ARRAY_REF || j == OP_ARRAY_DELETE ||
496 j == OP_ARRAY_ASSIGN) {
497 - printf("nDim=%d", inst[i+1].value);
498 + printd("nDim=%d", inst[i+1].value);
499 ++i;
501 else if (j == OP_ARRAY_REF_ASSIGN_SETUP) {
502 - printf("binOp=%s ", inst[i+1].value ? "true" : "false");
503 - printf("nDim=%d", inst[i+2].value);
504 + printd("binOp=%s ", inst[i+1].value ? "true" : "false");
505 + printd("nDim=%d", inst[i+2].value);
506 i += 2;
508 else if (j == OP_PUSH_ARRAY_SYM) {
509 - printf("%s", inst[++i].sym->name);
510 - printf(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
511 + printd("%s", inst[++i].sym->name);
512 + printd(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
513 ++i;
516 - printf("\n");
517 + printd("\n");
518 break;
521 if (j == N_OPS) {
522 - printf("%x\n", inst[i].value);
523 + printd("%x\n", inst[i].value);
528 +static void disasm(Inst *inst, int nInstr)
530 + static int outIsTTY = -1;
531 + if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
532 + if (outIsTTY) { printd("\033[H"); }
533 + disasmInternal(inst, nInstr);
534 + if (outIsTTY) { printd("\033[J\n"); }
535 + outPrintd();
537 #endif /* #ifdef DEBUG_DISASSEMBLER */
539 #ifdef DEBUG_STACK /* for run-time stack dumping */
540 -#define STACK_DUMP_ARG_PREFIX "Arg"
541 -static void stackdump(int n, int extra)
543 - /* TheStack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
544 - int nArgs = FP_GET_ARG_COUNT(FrameP);
545 - int i, offset;
546 - char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
547 - printf("Stack ----->\n");
548 - for (i = 0; i < n + extra; i++) {
549 - char *pos = "";
550 - DataValue *dv = &StackP[-i - 1];
551 - if (dv < TheStack) {
552 - printf("--------------Stack base--------------\n");
553 - break;
554 +#define STACK_DUMP_ARG_PREFIX " $"
555 +static void stackdumpframe(DataValue *arrow, DataValue *outpt, DataValue *fp,
556 + DataValue *sp, char topMark)
558 + DataValue *baseF = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
559 + DataValue *oldFP = baseF ? baseF->val.dataval : NULL;
560 + DataValue *arg1 = &FP_GET_ARG_N(fp, 0);
561 + DataValue *fnNm = &FP_GET_ITEM(fp, FP_FUNCTION_NAME);
562 + DataValue *dv;
563 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
564 + int nArgs = FP_GET_ARG_COUNT(fp);
566 + int nSyms;
567 + static int symLen = 0;
568 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
569 + Symbol *sym;
571 +#ifdef DEBUG_STACK_HEADFIRST
572 +#else
573 + /* do caller's frame */
574 + if (oldFP || arg1 > endDv)
575 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
576 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
578 + /* do current frame */
579 + /* how many symbols are there? */
580 + for (sym = syms, nSyms = 0; sym != NULL; sym = sym->next) {
581 + nSyms++;
582 + if (symLen < 27) {
583 + int len = strlen(sym->name);
584 + if (len > 27)
585 + len = 27;
586 + if (len > symLen)
587 + symLen = len;
589 - offset = dv - FrameP;
592 + /* output instructions between endDv and sp - 1 inclusive */
593 +#ifdef DEBUG_STACK_HEADFIRST
594 + dv = sp;
595 + while (--dv >= endDv)
596 +#else
597 + for (dv = endDv; dv < sp; dv++)
598 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
600 + const char *posFmt = "%-6s ";
601 + const char *symName = "";
603 - printf("%4.4s", i < n ? ">>>>" : "");
604 - printf("%8p ", dv);
605 + char *pos = "";
606 + char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
607 + int offset = dv - fp;
608 + const char *leadIn = (dv >= arrow) ? ">>>>" :
609 + (dv == arg1) ? "----" :
610 + (dv == fnNm) ? "====" : "";
611 + printd("%4.4s", leadIn);
612 + printd("%8p%c", dv, topMark);
613 switch (offset) {
614 - case 0: pos = "FrameP"; break; /* first local symbol value */
615 - case FP_ARG_ARRAY_CACHE_INDEX: pos = "args"; break; /* arguments array */
616 - case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* number of arguments */
617 - case FP_OLD_FP_INDEX: pos = "OldFP"; break;
618 - case FP_RET_PC_INDEX: pos = "RetPC"; break;
619 - case FP_PROG_INDEX: pos = "Prog"; break;
620 + case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
621 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
622 + case FP_FUNCTION_NAME: pos = "FnName"; break;
623 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
624 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
625 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
626 + case FP_PROG_INDEX: pos = "Prog"; break;
627 default:
628 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
629 + if (offset < -FP_TO_ARGS_DIST &&
630 + offset >= -FP_TO_ARGS_DIST - nArgs)
632 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
633 offset + FP_TO_ARGS_DIST + nArgs + 1);
635 + else if (0 <= offset && offset < nSyms) {
636 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
637 + posFmt = "%6s ";
639 + else if (offset == 0) {
640 + pos = "FrameP";
642 break;
644 - printf("%-6s ", pos);
645 - dumpVal(*dv);
646 - printf("\n");
647 + printd(posFmt, pos);
649 + /* local symbol names? */
650 + if (0 <= offset && offset < nSyms) {
651 + for (sym = syms; sym != NULL; sym = sym->next) {
652 + if (sym->value.val.n == offset) {
653 + symName = sym->name;
654 + break;
658 + printd("%-*.*s ", symLen, symLen, symName);
660 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
661 + printd("%s", dv->val.str.rep);
662 + else
663 + dumpVal(*dv);
665 + printd("\n");
668 +#ifdef DEBUG_STACK_HEADFIRST
669 + /* do caller's frame */
670 + if (oldFP || arg1 > endDv)
671 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
672 +#else
673 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
676 +static void stackdumpInternal(int n, int extra)
678 + DataValue *arrow = StackP - n;
679 + DataValue *outpt = StackP - n - extra;
681 +#ifdef DEBUG_STACK_HEADFIRST
682 + printd("Stack ----->\n");
683 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
684 + if (outpt < TheStack)
685 + printd("--------------Stack base--------------\n");
686 +#else
687 + if (outpt < TheStack)
688 + printd("--------------Stack base--------------\n");
689 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
690 + printd("Stack ----->\n");
691 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
694 +static void stackdump(int n, int extra)
696 + static int outIsTTY = -1;
697 + if (outIsTTY == -1)
698 + outIsTTY = isatty(fileno(stdout));
700 + stackdumpInternal(n, extra);
702 + if (outIsTTY)
703 + printd("\033[J\n");
705 + outPrintd();
706 + fflush(stdout);
709 #endif /* ifdef DEBUG_STACK */
710 diff --quilt old/source/interpret.h new/source/interpret.h
711 --- old/source/interpret.h
712 +++ new/source/interpret.h
713 @@ -86,6 +86,7 @@ typedef struct DataValueTag {
714 Inst* inst;
715 struct DataValueTag* dataval;
716 struct SparseArrayEntryTag *arrayPtr;
717 + struct SymbolRec *sym;
718 } val;
719 } DataValue;
721 @@ -107,6 +108,7 @@ typedef struct ProgramTag {
722 Symbol *localSymList;
723 Inst *code;
724 unsigned refcount;
725 + char *name;
726 } Program;
728 /* Information needed to re-start a preempted macro */
729 diff --quilt old/source/macro.c new/source/macro.c
730 --- old/source/macro.c
731 +++ new/source/macro.c
732 @@ -842,7 +842,8 @@ void Replay(WindowInfo *window)
733 window->macroCmdData == NULL) {
734 /* Parse the replay macro (it's stored in text form) and compile it into
735 an executable program "prog" */
736 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False);
737 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False,
738 + "replay macro");
739 if (prog == NULL) {
740 fprintf(stderr,
741 "NEdit internal error, learn/replay macro syntax error: %s\n",
742 @@ -940,7 +941,7 @@ static int readCheckMacroString(Widget d
743 char *stoppedAt, *errMsg;
744 Program *prog;
746 - prog = ParseMacro(string, &errMsg, &stoppedAt, True);
747 + prog = ParseMacro(string, &errMsg, &stoppedAt, True, errIn);
748 if (prog == NULL) {
749 if (errPos != NULL) {
750 *errPos = stoppedAt;
751 @@ -1222,7 +1223,7 @@ void DoMacro(WindowInfo *window, const c
752 tMacro[macroLen+1] = '\0';
754 /* Parse the macro and report errors if it fails */
755 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
756 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, errInName);
757 if (prog == NULL) {
758 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
759 XtFree(tMacro);
760 @@ -1486,7 +1487,7 @@ selEnd += $text_length - startLength\n}\
761 sprintf(loopedCmd, loopMacro, how, command);
763 /* Parse the resulting macro into an executable program "prog" */
764 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False);
765 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False, "repeat macro");
766 if (prog == NULL) {
767 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
768 errMsg);
769 diff --quilt old/source/nedit.c new/source/nedit.c
770 --- old/source/nedit.c
771 +++ new/source/nedit.c
772 @@ -832,10 +832,10 @@ static int checkDoMacroArg(const char *m
773 tMacro[macroLen+1] = '\0';
775 /* Do a test parse */
776 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
777 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, "-do macro");
778 XtFree(tMacro);
779 if (prog == NULL) {
780 - ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
781 + ParseError(NULL, tMacro, stoppedAt, "-do macro", errMsg);
782 return False;
784 FreeProgram(prog);
785 diff --quilt old/source/parse.h new/source/parse.h
786 --- old/source/parse.h
787 +++ new/source/parse.h
788 @@ -30,6 +30,7 @@
790 #include "interpret.h"
792 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine);
793 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
794 + const char *name);
796 #endif /* NEDIT_PARSE_H_INCLUDED */
797 diff --quilt old/source/parse.y new/source/parse.y
798 --- old/source/parse.y
799 +++ new/source/parse.y
800 @@ -632,10 +632,12 @@ blank: /* nothing */
801 ** as a pointer to a static string in msg, and the length of the string up
802 ** to where parsing failed in stoppedAt.
804 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine)
805 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
806 + const char *name)
808 Program *prog;
809 AccumulatorData *acc = (AccumulatorData *)XtMalloc(sizeof(*acc));
810 + static const char *prefix = ">> ";
812 #if YYDEBUG
813 int oldyydebug = yydebug;
814 @@ -670,6 +672,12 @@ Program *ParseMacro(char *expr, char **m
815 prog = FinishCreatingProgram(acc);
816 XtFree((char *)acc);
818 + if (!name)
819 + name = "--unknown--";
821 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
822 + strcat(strcpy(prog->name, prefix), name);
824 /* parse succeeded */
825 *msg = "";
826 *stoppedAt = InPtr;
827 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
828 --- old/source/parse_noyacc.c
829 +++ new/source/parse_noyacc.c
830 @@ -746,9 +746,10 @@ int yystacksize;
831 ** as a pointer to a static string in msg, and the length of the string up
832 ** to where parsing failed in stoppedAt.
834 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
835 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
837 Program *prog;
838 + static const char *prefix = ">> ";
840 BeginCreatingProgram();
842 @@ -766,6 +767,12 @@ Program *ParseMacro(char *expr, char **m
843 /* get the newly created program */
844 prog = FinishCreatingProgram();
846 + if (!name)
847 + name = "--unknown--";
849 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
850 + strcat(strcpy(prog->name, prefix), name);
852 /* parse succeeded */
853 *msg = "";
854 *stoppedAt = InPtr;
855 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
856 --- old/source/smartIndent.c
857 +++ new/source/smartIndent.c
858 @@ -747,18 +747,18 @@ void BeginSmartIndent(WindowInfo *window
859 winData->inNewLineMacro = 0;
860 winData->inModMacro = 0;
861 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
862 - &stoppedAt, False);
863 + &stoppedAt, False, "smart indent newline macro");
864 if (winData->newlineMacro == NULL) {
865 XtFree((char *)winData);
866 - ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
867 - "newline macro", errMsg);
868 + ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
869 + "smart indent newline macro", errMsg);
870 return;
872 if (indentMacros->modMacro == NULL)
873 winData->modMacro = NULL;
874 else {
875 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
876 - &stoppedAt, False);
877 + &stoppedAt, False, "smart indent modify macro");
878 if (winData->modMacro == NULL) {
879 FreeProgram(winData->newlineMacro);
880 XtFree((char *)winData);
881 @@ -1415,7 +1415,7 @@ static int checkSmartIndentDialogData(vo
882 if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) {
883 widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
884 if (!CheckMacroString(SmartIndentDialog.shell, widgetText,
885 - "initialization macro", &stoppedAt)) {
886 + "smart indent initialization macro", &stoppedAt)) {
887 XmTextSetInsertionPosition(SmartIndentDialog.initMacro,
888 stoppedAt - widgetText);
889 XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT);
890 @@ -1434,10 +1434,11 @@ static int checkSmartIndentDialogData(vo
893 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
894 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
895 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
896 + "smart indent newline macro");
897 if (prog == NULL) {
898 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
899 - "newline macro", errMsg);
900 + "smart indent newline macro", errMsg);
901 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
902 stoppedAt - widgetText);
903 XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT);
904 @@ -1450,10 +1451,11 @@ static int checkSmartIndentDialogData(vo
905 /* Test compile the modify macro */
906 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
907 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
908 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
909 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
910 + "smart indent modify macro");
911 if (prog == NULL) {
912 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
913 - "modify macro", errMsg);
914 + "smart indent modify macro", errMsg);
915 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
916 stoppedAt - widgetText);
917 XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT);
918 diff --quilt old/source/userCmds.c new/source/userCmds.c
919 --- old/source/userCmds.c
920 +++ new/source/userCmds.c
921 @@ -241,6 +241,8 @@ static Widget BGMenuPasteReplayBtn = NUL
922 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
923 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
924 int nMenuItems, int sensitive);
925 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
926 + menuItemRec **menu, int nMenu, const char *menuName);
927 static void rebuildMenuOfAllWindows(int menuType);
928 static void rebuildMenu(WindowInfo *window, int menuType);
929 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
930 @@ -1260,30 +1262,37 @@ int DoNamedShellMenuCmd(WindowInfo *wind
931 ** with menu item name "itemName". Returns True on successs and False on
932 ** failure.
934 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
935 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
936 + menuItemRec **menu, int nMenu, const char *menuName)
938 int i;
940 - for (i=0; i<NMacroMenuItems; i++) {
941 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
942 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
943 - return True;
945 + char *name = NULL;
946 + Boolean result = False;
948 + for (i = 0; i < nMenu; i++) {
949 + if (!strcmp(menu[i]->name, itemName)) {
950 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
951 + strcat(strcpy(name, menuName), itemName);
952 + DoMacro(window, menu[i]->cmd, name);
953 + result = True;
956 - return False;
957 + if (name) {
958 + XtFree(name);
960 + return result;
963 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
965 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
966 + "macro-menu>");
969 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
971 - int i;
973 - for (i=0; i<NBGMenuItems; i++) {
974 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
975 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
976 - return True;
979 - return False;
980 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
981 + "background-menu>");
985 @@ -2080,7 +2089,7 @@ static int checkMacroText(char *macro, W
986 Program *prog;
987 char *errMsg, *stoppedAt;
989 - prog = ParseMacro(macro, &errMsg, &stoppedAt, False);
990 + prog = ParseMacro(macro, &errMsg, &stoppedAt, False, "macro");
991 if (prog == NULL) {
992 if (errorParent != NULL) {
993 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
994 @@ -2092,7 +2101,7 @@ static int checkMacroText(char *macro, W
995 FreeProgram(prog);
996 if (*stoppedAt != '\0') {
997 if (errorParent != NULL) {
998 - ParseError(errorParent, macro, stoppedAt,"macro","syntax error");
999 + ParseError(errorParent, macro, stoppedAt, "macro", "syntax error");
1000 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1001 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1003 @@ -3019,7 +3028,7 @@ static char *copyMacroToEnd(char **inPtr
1006 /* Parse the input */
1007 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False);
1008 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False, "macro menu item");
1009 if (prog == NULL) {
1010 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);
1011 return NULL;