fix 'nedit file' segfaults
[nedit-bw.git] / InterpretDebug4.diff
blobf6cbcda77a918fc809a3e9393da05282e2e9a612
1 Provide NEdit Macro stack traces
3 Avaliable as a patch:
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
13 problem lies.
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
23 favorite macros!
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
38 occurs.
40 ---
42 source/interpret.c | 398 ++++++++++++++++++++++++++++++++++++++++++--------
43 source/interpret.h | 2
44 source/macro.c | 10 -
45 source/nedit.c | 2
46 source/parse.h | 2
47 source/parse.y | 9 +
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 @@ -36,11 +36,13 @@ static const char CVSID[] = "$Id: interp
57 #include "nedit.h"
58 #include "menu.h"
59 #include "text.h"
60 #include "rbTree.h"
62 +#include <unistd.h>
63 #include <stdio.h>
64 +#include <stdarg.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <math.h>
68 #include <limits.h>
69 #include <ctype.h>
70 @@ -141,21 +143,25 @@ static SparseArrayEntry *allocateSparseA
71 /*#define DEBUG_ASSEMBLY*/
72 /*#define DEBUG_STACK*/
74 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
75 #define DEBUG_DISASSEMBLER
76 +static const char *printd(const char *f, ...);
77 +static int outPrintd();
78 static void disasm(Inst *inst, int nInstr);
79 +static void disasmInternal(Inst *inst, int nInstr);
80 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
82 #ifdef DEBUG_ASSEMBLY /* for disassembly */
83 #define DISASM(i, n) disasm(i, n)
84 #else /* #ifndef DEBUG_ASSEMBLY */
85 #define DISASM(i, n)
86 #endif /* #ifndef DEBUG_ASSEMBLY */
88 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
89 static void stackdump(int n, int extra);
90 +static void stackdumpInternal(int n, int extra);
91 #define STACKDUMP(n, x) stackdump(n, x)
92 #define DISASM_RT(i, n) disasm(i, n)
93 #else /* #ifndef DEBUG_STACK */
94 #define STACKDUMP(n, x)
95 #define DISASM_RT(i, n)
96 @@ -211,17 +217,21 @@ static int (*OpFns[N_OPS])() = {returnNo
97 branchNever, arrayRef, arrayAssign, beginArrayIter, arrayIter, inArray,
98 deleteArrayElement, pushArraySymVal,
99 arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray};
101 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
102 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
103 +#define FP_ARG_ARRAY_INDEX (-1)
104 #define FP_ARG_COUNT_INDEX (-2)
105 -#define FP_OLD_FP_INDEX (-3)
106 -#define FP_RET_PC_INDEX (-4)
107 -#define FP_TO_ARGS_DIST (4) /* should be 0 - (above index) */
108 +#define FP_FUNCTION_NAME (-3) /* !! */
109 +#define FP_SYMBOL_TABLE (-4) /* !! */
110 +#define FP_OLD_FP_INDEX (-5)
111 +#define FP_RET_PC_INDEX (-6)
113 +#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
115 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
116 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
117 +#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
118 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
119 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
120 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
121 #define FP_ARG_START_INDEX(xFrameP) (-(FP_GET_ARG_COUNT(xFrameP) + FP_TO_ARGS_DIST))
122 #define FP_GET_ARG_N(xFrameP,xN) (FP_GET_ITEM(xFrameP, xN + FP_ARG_START_INDEX(xFrameP)))
123 @@ -298,10 +308,11 @@ Program *FinishCreatingProgram(void)
124 progLen = ((char *)ProgP) - ((char *)Prog);
125 newProg->code = (Inst *)XtMalloc(progLen);
126 memcpy(newProg->code, Prog, progLen);
127 newProg->localSymList = LocalSymList;
128 LocalSymList = NULL;
129 + newProg->name = NULL;
131 /* Local variables' values are stored on the stack. Here we assign
132 frame pointer offsets to them. */
133 for (s = newProg->localSymList; s != NULL; s = s->next)
134 s->value.val.n = fpOffset++;
135 @@ -313,10 +324,13 @@ Program *FinishCreatingProgram(void)
137 void FreeProgram(Program *prog)
139 freeSymbolTable(prog->localSymList);
140 XtFree((char *)prog->code);
141 + if (prog->name) {
142 + XtFree((char *)prog->name);
144 XtFree((char *)prog);
148 ** Add an operator (instruction) to the end of the current program
149 @@ -494,10 +508,19 @@ int ExecuteMacro(WindowInfo *window, Pro
150 context->stackP->tag = NO_TAG;
151 context->stackP++;
153 *(context->stackP++) = noValue; /* old FrameP */
155 + context->stackP->tag = NO_TAG;
156 + context->stackP->val.sym = prog->localSymList; /* symbol table */
157 + context->stackP++;
159 + context->stackP->tag = STRING_TAG;
160 + context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
161 + context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
162 + context->stackP++;
164 context->stackP->tag = NO_TAG; /* nArgs */
165 context->stackP->val.n = nArgs;
166 context->stackP++;
168 *(context->stackP++) = noValue; /* cached arg array */
169 @@ -593,10 +616,19 @@ void RunMacroAsSubrCall(Program *prog)
171 StackP->tag = NO_TAG;
172 StackP->val.dataval = FrameP; /* old FrameP */
173 StackP++;
175 + StackP->tag = NO_TAG;
176 + StackP->val.sym = prog->localSymList; /* symbol table */
177 + StackP++;
179 + StackP->tag = STRING_TAG;
180 + StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
181 + StackP->val.str.len = strlen(StackP->val.str.rep);
182 + StackP++;
184 StackP->tag = NO_TAG; /* nArgs */
185 StackP->val.n = 0;
186 StackP++;
188 *(StackP++) = noValue; /* cached arg array */
189 @@ -2050,26 +2082,36 @@ static int callSubroutine(void)
190 ** Push all of the required information to resume, and make space on the
191 ** stack for local variables (and initialize them), on top of the argument
192 ** values which are already there.
194 if (sym->type == MACRO_FUNCTION_SYM) {
195 + prog = (Program *)sym->value.val.str.rep;
197 StackP->tag = NO_TAG; /* return PC */
198 StackP->val.inst = PC;
199 StackP++;
201 StackP->tag = NO_TAG; /* old FrameP */
202 StackP->val.dataval = FrameP;
203 StackP++;
205 + StackP->tag = NO_TAG;
206 + StackP->val.sym = prog->localSymList; /* symbol table */
207 + StackP++;
209 + StackP->tag = STRING_TAG;
210 + StackP->val.str.rep = sym->name; /* function name */
211 + StackP->val.str.len = strlen(sym->name);
212 + StackP++;
214 StackP->tag = NO_TAG; /* nArgs */
215 StackP->val.n = nArgs;
216 StackP++;
218 *(StackP++) = noValue; /* cached arg array */
220 FrameP = StackP;
221 - prog = (Program *)sym->value.val.str.rep;
222 PC = prog->code;
223 for (s = prog->localSymList; s != NULL; s = s->next) {
224 FP_GET_SYM_VAL(FrameP, s) = noValue;
225 StackP++;
227 @@ -2532,11 +2574,11 @@ static int arrayRef(void)
229 nDim = PC->value;
230 PC++;
232 DISASM_RT(PC-2, 2);
233 - STACKDUMP(nDim, 3);
234 + STACKDUMP(nDim+1, 3);
236 if (nDim > 0) {
237 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
238 if (errNum != STAT_OK) {
239 return(errNum);
240 @@ -2583,11 +2625,11 @@ static int arrayAssign(void)
242 nDim = PC->value;
243 PC++;
245 DISASM_RT(PC-2, 1);
246 - STACKDUMP(nDim, 3);
247 + STACKDUMP(nDim+2, 3);
249 if (nDim > 0) {
250 POP(srcValue)
252 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
253 @@ -2621,13 +2663,13 @@ static int arrayAssign(void)
256 ** for use with assign-op operators (eg a[i,j] += k
258 ** Before: Prog-> [binOp], nDim, next, ...
259 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
260 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
261 ** After: Prog-> binOp, nDim, [next], ...
262 -** TheStack-> [rhs], arrayValue, next, ...
263 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
265 static int arrayRefAndAssignSetup(void)
267 int errNum;
268 DataValue srcArray, valueItem, moveExpr;
269 @@ -2638,11 +2680,11 @@ static int arrayRefAndAssignSetup(void)
270 PC++;
271 nDim = PC->value;
272 PC++;
274 DISASM_RT(PC-3, 3);
275 - STACKDUMP(nDim + 1, 3);
276 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
278 if (binaryOp) {
279 POP(moveExpr)
282 @@ -2892,20 +2934,75 @@ static int errCheck(const char *s)
283 else
284 return STAT_OK;
288 +** build a stack dump string, reallocating s as necessary.
290 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
292 + int len;
293 + const char *op;
294 + char *np;
295 + DataValue *nfp = fp;
297 +#ifdef DEBUG_STACK
298 + const char *dump;
299 + printd("\n\n");
300 + disasmInternal(PC - 1, 1);
301 + stackdumpInternal(0, 50);
302 + dump = printd(NULL);
303 +#endif
305 + /* first measure the lengths */
306 + len = strlen(msg) + 1;
307 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
308 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
310 +#ifdef DEBUG_STACK
311 + len += strlen(dump);
312 +#endif
313 + if (*pLen < len)
315 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
316 + *pLen = len;
318 + /* now copy */
319 + np = *s;
320 + op = msg;
321 + while (*op)
322 + *np++ = *op++;
324 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
325 + *np++ = '\n';
326 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
327 + while (*op)
328 + *np++ = *op++;
330 +#ifdef DEBUG_STACK
331 + op = dump;
332 + while (*op)
333 + *np++ = *op++;
334 +#endif
336 + *np = 0;
337 + return *s;
341 ** combine two strings in a static area and set ErrMsg to point to the
342 ** result. Returns false so a single return execError() statement can
343 ** be used to both process the message and return.
345 static int execError(const char *s1, const char *s2)
347 static char msg[MAX_ERR_MSG_LEN];
348 + static char *err = NULL;
349 + static int errlen = 0;
351 sprintf(msg, s1, s2);
352 - ErrMsg = msg;
353 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
354 return STAT_ERROR;
357 int StringToNum(const char *string, int *number)
359 @@ -2935,54 +3032,126 @@ int StringToNum(const char *string, int
361 return True;
364 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
365 +static char *printdBuffer = NULL;
366 +static int printdPos = 0;
367 +static int printdSize = 0;
369 +static const char *printd(const char *f, ...)
371 + char buffer[4096];
372 + int len;
373 + va_list args;
375 + if (!f)
377 + printdPos = 0; /* reset for next time */
378 + return printdBuffer;
381 + va_start(args, f);
382 + vsprintf(buffer, f, args);
383 + va_end(args);
385 + len = strlen(buffer);
386 + if (!printdBuffer)
388 + printdSize = 4096;
389 + printdBuffer = XtMalloc(printdSize);
390 + printdPos = 0;
392 + else
394 + int needSize = printdPos + len + 1;
395 + if (needSize > printdSize)
397 + int newSize = printdSize;
398 + while (newSize < needSize)
399 + newSize *= 2;
400 + printdBuffer = XtRealloc(printdBuffer, newSize);
401 + printdSize = newSize;
404 + strcpy(&printdBuffer[printdPos], buffer);
405 + printdPos += len;
407 + return printdBuffer;
410 +int outPrintd()
412 + const char *s = printd(NULL);
413 + const char *cp;
415 + static int outIsTTY = -1;
416 + if (outIsTTY == -1)
417 + outIsTTY = isatty(fileno(stdout));
419 + if (outIsTTY)
421 + for (cp = s; *cp; cp++)
422 + if (*cp == '\n')
423 + printf("\033[K\n");
424 + else
425 + putchar(*cp);
427 + else
429 + for (cp = s; *cp; cp++)
430 + putchar(*cp);
432 + return cp - s;
434 +#endif /* #ifdef DEBUG_DISASSEMBLER */
436 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
437 static void dumpVal(DataValue dv)
439 switch (dv.tag) {
440 case INT_TAG:
441 - printf("i=%d", dv.val.n);
442 + printd("i=%d", dv.val.n);
443 break;
444 case STRING_TAG:
446 int k;
447 char s[21];
448 char *src = dv.val.str.rep;
449 if (!src) {
450 - printf("s=<NULL>");
451 + printd("s=<NULL>");
453 else {
454 for (k = 0; src[k] && k < sizeof s - 1; k++) {
455 s[k] = isprint(src[k]) ? src[k] : '?';
457 s[k] = 0;
458 - printf("s=\"%s\"%s[%d]", s,
459 + printd("s=\"%s\"%s[%d]", s,
460 src[k] ? "..." : "", strlen(src));
463 break;
464 case ARRAY_TAG:
465 - printf("<array>");
466 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
467 break;
468 case NO_TAG:
469 if (!dv.val.inst) {
470 - printf("<no value>");
471 + printd("<no value>");
473 else {
474 - printf("?%8p", dv.val.inst);
475 + printd("?%8p", dv.val.inst);
477 break;
478 default:
479 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
480 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
481 break;
484 #endif /* #ifdef DEBUG_DISASSEMBLER */
486 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
487 -static void disasm(Inst *inst, int nInstr)
488 +static void disasmInternal(Inst *inst, int nInstr)
490 static const char *opNames[N_OPS] = {
491 "RETURN_NO_VAL", /* returnNoVal */
492 "RETURN", /* returnVal */
493 "PUSH_SYM", /* pushSymVal */
494 @@ -3027,111 +3196,224 @@ static void disasm(Inst *inst, int nInst
495 "PUSH_ARG_COUNT", /* $arg[] */
496 "PUSH_ARG_ARRAY" /* $arg */
498 int i, j;
500 - printf("\n");
501 + printd("\n");
502 for (i = 0; i < nInstr; ++i) {
503 - printf("Prog %8p ", &inst[i]);
504 + printd("Prog %8p ", &inst[i]);
505 for (j = 0; j < N_OPS; ++j) {
506 if (inst[i].func == OpFns[j]) {
507 - printf("%22s ", opNames[j]);
508 + printd("%22s ", opNames[j]);
509 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
510 Symbol *sym = inst[i+1].sym;
511 - printf("%s", sym->name);
512 + printd("%s", sym->name);
513 if (sym->value.tag == STRING_TAG &&
514 strncmp(sym->name, "string #", 8) == 0) {
515 dumpVal(sym->value);
517 ++i;
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);
524 ++i;
526 else if (j == OP_CONCAT) {
527 printd("nExpr=%d", inst[i+1].value);
528 ++i;
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);
533 i += 2;
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);
538 ++i;
540 else if (j == OP_ARRAY_ITER) {
541 - printf("%s = %s++ end-loop=(%d) %p",
542 + printd("%s = %s++ end-loop=(%d) %p",
543 inst[i+1].sym->name,
544 inst[i+2].sym->name,
545 inst[i+3].value, &inst[i+3] + inst[i+3].value);
546 i += 3;
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);
552 ++i;
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);
559 i += 2;
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");
566 ++i;
569 - printf("\n");
570 + printd("\n");
571 break;
574 if (j == N_OPS) {
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);
587 + outPrintd();
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);
599 - int i, offset;
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++) {
603 - char *pos = "";
604 - DataValue *dv = &StackP[-i - 1];
605 - if (dv < TheStack) {
606 - printf("--------------Stack base--------------\n");
607 - break;
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);
612 + DataValue *dv;
613 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
614 + int nArgs = FP_GET_ARG_COUNT(fp);
616 + int nSyms;
617 + static int symLen = 0;
618 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
619 + Symbol *sym;
621 +#ifdef DEBUG_STACK_HEADFIRST
622 +#else
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) {
631 + nSyms++;
632 + if (symLen < 27) {
633 + int len = strlen(sym->name);
634 + if (len > 27)
635 + len = 27;
636 + if (len > symLen)
637 + symLen = len;
640 - offset = dv - FrameP;
642 - printf("%4.4s", i < n ? ">>>>" : "");
643 - printf("%8p ", dv);
644 + /* output instructions between endDv and sp - 1 inclusive */
645 +#ifdef DEBUG_STACK_HEADFIRST
646 + dv = sp;
647 + while (--dv >= endDv)
648 +#else
649 + for (dv = endDv; dv < sp; dv++)
650 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
652 + const char *posFmt = "%-6s ";
653 + const char *symName = "";
655 + char *pos = "";
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);
663 switch (offset) {
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_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
670 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
671 + case FP_FUNCTION_NAME: pos = "FnName"; break;
672 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
673 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
674 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
675 default:
676 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
677 + if (offset < -FP_TO_ARGS_DIST &&
678 + offset >= -FP_TO_ARGS_DIST - nArgs)
680 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
681 offset + FP_TO_ARGS_DIST + nArgs + 1);
683 + else if (0 <= offset && offset < nSyms) {
684 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
685 + posFmt = "%6s ";
687 + else if (offset == 0) {
688 + pos = "FrameP";
690 break;
692 - printf("%-6s ", pos);
693 + printd(posFmt, pos);
695 + /* local symbol names? */
696 + if (offset < nSyms) {
697 + for (sym = syms; sym != NULL; sym = sym->next) {
698 + if (sym->value.val.n == offset) {
699 + symName = sym->name;
700 + break;
704 + printd("%-*.*s ", symLen, symLen, symName);
706 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
707 + printd("%s", dv->val.str.rep);
708 + else
709 dumpVal(*dv);
710 - printf("\n");
712 + printd("\n");
715 +#ifdef DEBUG_STACK_HEADFIRST
716 + /* do caller's frame */
717 + if (oldFP || arg1 > endDv)
718 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
719 +#else
720 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
723 +static void stackdumpInternal(int n, int extra)
725 + DataValue *arrow = StackP - n;
726 + DataValue *outpt = StackP - n - extra;
728 +#ifdef DEBUG_STACK_HEADFIRST
729 + printd("Stack ----->\n");
730 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
731 + if (outpt < TheStack)
732 + printd("--------------Stack base--------------\n");
733 +#else
734 + if (outpt < TheStack)
735 + printd("--------------Stack base--------------\n");
736 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
737 + printd("Stack ----->\n");
738 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
741 +static void stackdump(int n, int extra)
743 + static int outIsTTY = -1;
744 + if (outIsTTY == -1)
745 + outIsTTY = isatty(fileno(stdout));
747 + stackdumpInternal(n, extra);
749 + if (outIsTTY)
750 + printd("\033[J\n");
752 + outPrintd();
753 + fflush(stdout);
756 #endif /* ifdef DEBUG_STACK */
757 diff --quilt old/source/interpret.h new/source/interpret.h
758 --- old/source/interpret.h
759 +++ new/source/interpret.h
760 @@ -84,10 +84,11 @@ typedef struct DataValueTag {
761 struct ProgramTag* prog;
762 XtActionProc xtproc;
763 Inst* inst;
764 struct DataValueTag* dataval;
765 struct SparseArrayEntryTag *arrayPtr;
766 + struct SymbolRec *sym;
767 } val;
768 } DataValue;
770 typedef struct SparseArrayEntryTag {
771 rbTreeNode nodePtrs; /* MUST BE FIRST ENTRY */
772 @@ -104,10 +105,11 @@ typedef struct SymbolRec {
773 } Symbol;
775 typedef struct ProgramTag {
776 Symbol *localSymList;
777 Inst *code;
778 + char *name;
779 } Program;
781 /* Information needed to re-start a preempted macro */
782 typedef struct {
783 DataValue *stack;
784 diff --quilt old/source/macro.c new/source/macro.c
785 --- old/source/macro.c
786 +++ new/source/macro.c
787 @@ -829,11 +829,11 @@ void Replay(WindowInfo *window)
788 if (ReplayMacro != NULL &&
789 ReplayMacro[0] != 0 &&
790 window->macroCmdData == NULL) {
791 /* Parse the replay macro (it's stored in text form) and compile it into
792 an executable program "prog" */
793 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt);
794 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, "replay macro");
795 if (prog == NULL) {
796 fprintf(stderr,
797 "NEdit internal error, learn/replay macro syntax error: %s\n",
798 errMsg);
799 return;
800 @@ -963,11 +963,11 @@ static int readCheckMacroString(Widget d
801 if (*inPtr != '{') {
802 if (errPos != NULL) *errPos = stoppedAt;
803 return ParseError(dialogParent, string, inPtr,
804 errIn, "expected '{'");
806 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
807 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, subrName);
808 if (prog == NULL) {
809 if (errPos != NULL) *errPos = stoppedAt;
810 return ParseError(dialogParent, string, stoppedAt,
811 errIn, errMsg);
813 @@ -991,11 +991,11 @@ static int readCheckMacroString(Widget d
814 and WAIT for them to finish executing before proceeding. Note that
815 the code below is not perfect. If you interleave code blocks with
816 definitions in a file which is loaded from another macro file, it
817 will probably run the code blocks in reverse order! */
818 } else {
819 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
820 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, errIn);
821 if (prog == NULL) {
822 if (errPos != NULL) {
823 *errPos = stoppedAt;
826 @@ -1294,11 +1294,11 @@ void DoMacro(WindowInfo *window, const c
827 strncpy(tMacro, macro, macroLen);
828 tMacro[macroLen] = '\n';
829 tMacro[macroLen+1] = '\0';
831 /* Parse the macro and report errors if it fails */
832 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
833 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, errInName);
834 if (prog == NULL) {
835 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
836 XtFree(tMacro);
837 return;
839 @@ -1558,11 +1558,11 @@ selEnd += $text_length - startLength\n}\
840 sprintf(loopedCmd, loopMacro, command);
841 else
842 sprintf(loopedCmd, loopMacro, how, command);
844 /* Parse the resulting macro into an executable program "prog" */
845 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt);
846 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, "repeat macro");
847 if (prog == NULL) {
848 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
849 errMsg);
850 return;
852 diff --quilt old/source/nedit.c new/source/nedit.c
853 --- old/source/nedit.c
854 +++ new/source/nedit.c
855 @@ -830,11 +830,11 @@ static int checkDoMacroArg(const char *m
856 strncpy(tMacro, macro, macroLen);
857 tMacro[macroLen] = '\n';
858 tMacro[macroLen+1] = '\0';
860 /* Do a test parse */
861 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
862 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, "-do Argument");
863 XtFree(tMacro);
864 if (prog == NULL) {
865 ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
866 return False;
868 diff --quilt old/source/parse.h new/source/parse.h
869 --- old/source/parse.h
870 +++ new/source/parse.h
871 @@ -28,8 +28,8 @@
872 #ifndef NEDIT_PARSE_H_INCLUDED
873 #define NEDIT_PARSE_H_INCLUDED
875 #include "interpret.h"
877 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt);
878 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name);
880 #endif /* NEDIT_PARSE_H_INCLUDED */
881 diff --quilt old/source/parse.y new/source/parse.y
882 --- old/source/parse.y
883 +++ new/source/parse.y
884 @@ -546,13 +546,14 @@ blank: /* nothing */
885 ** executed using ExecuteProgram. Returns program on success, or NULL
886 ** on failure. If the command failed, the error message is returned
887 ** as a pointer to a static string in msg, and the length of the string up
888 ** to where parsing failed in stoppedAt.
890 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
891 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
893 Program *prog;
894 + static const char *prefix = ">> ";
896 BeginCreatingProgram();
898 /* call yyparse to parse the string and check for success. If the parse
899 failed, return the error message and string index (the grammar aborts
900 @@ -566,10 +567,16 @@ Program *ParseMacro(char *expr, char **m
903 /* get the newly created program */
904 prog = FinishCreatingProgram();
906 + if (!name)
907 + name = "--unknown--";
909 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
910 + strcat(strcpy(prog->name, prefix), name);
912 /* parse succeeded */
913 *msg = "";
914 *stoppedAt = InPtr;
915 return prog;
917 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
918 --- old/source/parse_noyacc.c
919 +++ new/source/parse_noyacc.c
920 @@ -744,13 +744,14 @@ int yystacksize;
921 ** executed using ExecuteProgram. Returns program on success, or NULL
922 ** on failure. If the command failed, the error message is returned
923 ** as a pointer to a static string in msg, and the length of the string up
924 ** to where parsing failed in stoppedAt.
926 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
927 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
929 Program *prog;
930 + static const char *prefix = ">> ";
932 BeginCreatingProgram();
934 /* call yyparse to parse the string and check for success. If the parse
935 failed, return the error message and string index (the grammar aborts
936 @@ -764,10 +765,16 @@ Program *ParseMacro(char *expr, char **m
939 /* get the newly created program */
940 prog = FinishCreatingProgram();
942 + if (!name)
943 + name = "--unknown--";
945 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
946 + strcat(strcpy(prog->name, prefix), name);
948 /* parse succeeded */
949 *msg = "";
950 *stoppedAt = InPtr;
951 return prog;
953 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
954 --- old/source/smartIndent.c
955 +++ new/source/smartIndent.c
956 @@ -745,21 +745,21 @@ void BeginSmartIndent(WindowInfo *window
957 /* Compile the newline and modify macros and attach them to the window */
958 winData = (windowSmartIndentData *)XtMalloc(sizeof(windowSmartIndentData));
959 winData->inNewLineMacro = 0;
960 winData->inModMacro = 0;
961 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
962 - &stoppedAt);
963 + &stoppedAt, "smart indent newline macro");
964 if (winData->newlineMacro == NULL) {
965 ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
966 - "newline macro", errMsg);
967 + "smart indent newline macro", errMsg);
968 return;
970 if (indentMacros->modMacro == NULL)
971 winData->modMacro = NULL;
972 else {
973 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
974 - &stoppedAt);
975 + &stoppedAt, "smart indent modify macro");
976 if (winData->modMacro == NULL) {
977 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
978 "smart indent modify macro", errMsg);
979 return;
981 @@ -1429,11 +1429,12 @@ static int checkSmartIndentDialogData(vo
982 "Newline macro required", "OK");
983 return False;
986 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
987 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
988 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
989 + "smart indent newline macro");
990 if (prog == NULL) {
991 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
992 "newline macro", errMsg);
993 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
994 stoppedAt - widgetText);
995 @@ -1445,11 +1446,12 @@ static int checkSmartIndentDialogData(vo
996 FreeProgram(prog);
998 /* Test compile the modify macro */
999 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
1000 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
1001 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
1002 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
1003 + "smart indent modify macro");
1004 if (prog == NULL) {
1005 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1006 "modify macro", errMsg);
1007 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
1008 stoppedAt - widgetText);
1009 diff --quilt old/source/userCmds.c new/source/userCmds.c
1010 --- old/source/userCmds.c
1011 +++ new/source/userCmds.c
1012 @@ -239,10 +239,12 @@ static Widget MacroPasteReplayBtn = NULL
1013 static Widget BGMenuPasteReplayBtn = NULL;
1015 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
1016 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
1017 int nMenuItems, int sensitive);
1018 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1019 + menuItemRec **menu, int nMenu, const char *menuName);
1020 static void rebuildMenuOfAllWindows(int menuType);
1021 static void rebuildMenu(WindowInfo *window, int menuType);
1022 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
1023 const char *hierName);
1024 static char *copySubstring(const char *string, int length);
1025 @@ -1258,34 +1260,41 @@ int DoNamedShellMenuCmd(WindowInfo *wind
1027 ** Search through the Macro or background menu and execute the first command
1028 ** with menu item name "itemName". Returns True on successs and False on
1029 ** failure.
1031 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1032 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1033 + menuItemRec **menu, int nMenu, const char *menuName)
1035 int i;
1037 - for (i=0; i<NMacroMenuItems; i++) {
1038 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
1039 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
1040 - return True;
1042 + char *name = NULL;
1043 + Boolean result = False;
1045 + for (i = 0; i < nMenu; i++) {
1046 + if (!strcmp(menu[i]->name, itemName)) {
1047 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
1048 + strcat(strcpy(name, menuName), itemName);
1049 + DoMacro(window, menu[i]->cmd, name);
1050 + result = True;
1053 - return False;
1054 + if (name) {
1055 + XtFree(name);
1057 + return result;
1060 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1062 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
1063 + "macro-menu>");
1066 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
1068 - int i;
1070 - for (i=0; i<NBGMenuItems; i++) {
1071 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
1072 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
1073 - return True;
1076 - return False;
1077 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
1078 + "background-menu>");
1082 ** Cache user menus:
1083 ** Rebuild all of the Shell, Macro, Background menus of given editor window.
1084 @@ -2078,11 +2087,11 @@ static int checkMacro(userCmdDialog *ucd
1085 static int checkMacroText(char *macro, Widget errorParent, Widget errFocus)
1087 Program *prog;
1088 char *errMsg, *stoppedAt;
1090 - prog = ParseMacro(macro, &errMsg, &stoppedAt);
1091 + prog = ParseMacro(macro, &errMsg, &stoppedAt, "macro");
1092 if (prog == NULL) {
1093 if (errorParent != NULL) {
1094 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
1095 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1096 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1097 @@ -3017,11 +3026,11 @@ static char *copyMacroToEnd(char **inPtr
1098 ParseError(NULL, *inPtr, *inPtr-1, "macro menu item", "expecting '{'");
1099 return NULL;
1102 /* Parse the input */
1103 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt);
1104 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, "macro menu item");
1105 if (prog == NULL) {
1106 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);
1107 return NULL;
1109 FreeProgram(prog);