/* nl-debug.c --- debugging functions for newLISP Copyright (C) 2007 Lutz Mueller This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "newlisp.h" #include "protos.h" #ifdef WIN_32 #define fgets win32_fgets #endif extern FILE * IOchannel; extern int evalSilent; int matchString(char * buffer, char * string, int * length); int stringComp(char * buffer, char * string); int printFunction(CELL * cell); void getDebuggerInput(char * msg); void allocateDebugStack(void); extern SYMBOL * currentFunc; extern SYMBOL * timerEvent; extern SYMBOL * symHandler[]; extern int currentSignal; int currentLevel = 0; int debugStackIdx = 0; UINT * debugStack; char preStr[8] = "#"; char postStr[8] = "#"; char headerStr[16] = "\n-----\n\n"; char footerStr[32] = " s|tep n|ext c|ont q|uit > "; #define pushDebugStack(A) (*(debugStack + debugStackIdx++) = (UINT)(A)) #define popDebugStack() (*(debugStack + --debugStackIdx)) #define DEBUG_ENTRY "->" #define DEBUG_EXIT "<-" void openTrace(void) { if(traceFlag) return; traceFlag = TRUE; currentFunc = nilSymbol; debugStackIdx = 0; allocateDebugStack(); } void closeTrace(void) { /* printf("closing trace\n"); */ traceFlag = 0; if(debugStack) free(debugStack); debugStack = NULL; } CELL * p_debug(CELL * params) { CELL * result; openTrace(); result = copyCell(evaluateExpression(params)); closeTrace(); return(result); } CELL * p_trace(CELL * params) { if(params != nilCell) { if(getFlag(params)) openTrace(); else closeTrace(); } return((traceFlag == 0 ? nilCell : trueCell)); } CELL * p_traceHighlight(CELL * params) { char * pre, * post, * header, * footer; params = getString(params, &pre); params = getString(params, &post); strncpy(preStr, pre, 7); strncpy(postStr, post, 7); if(params != nilCell) { params = getString(params, &header); strncpy(headerStr, header, 15); } if(params != nilCell) { getString(params, &footer); strncpy(footerStr, footer, 31); } return(trueCell); } void traceEntry(CELL * cell, CELL * pCell, CELL * args) { int defaultFuncFlag = FALSE; if(traceFlag & (TRACE_IN_ENTRY | TRACE_IN_EXIT | TRACE_DEBUG_NEXT)) return; traceFlag |= TRACE_IN_ENTRY; if(traceFlag & TRACE_SIGNAL) { traceFlag &= ~TRACE_SIGNAL; executeSymbol(symHandler[currentSignal - 1], stuffInteger(currentSignal)); traceFlag &= ~TRACE_IN_ENTRY; return; } if(traceFlag & TRACE_SIGINT) { traceFlag &= ~TRACE_SIGINT; longjmp(errorJump, ERR_USER_RESET); } if(traceFlag & TRACE_TIMER) { traceFlag &= ~TRACE_TIMER; executeSymbol(timerEvent, NULL); traceFlag &= ~TRACE_IN_ENTRY; return; } if(debugStackIdx > 1) { if(printFunction(cell)) getDebuggerInput(DEBUG_ENTRY); if(!traceFlag) return; } if(traceFlag & TRACE_DEBUG_NEXT) { traceFlag &= ~TRACE_IN_ENTRY; return; } if(pCell->type == CELL_CONTEXT) { defaultFuncFlag = TRUE; currentFunc = translateCreateSymbol( ((SYMBOL*)pCell->contents)->name, CELL_NIL, (SYMBOL*)pCell->contents, TRUE); pCell = (CELL *)currentFunc->contents; } if((pCell->type == CELL_LAMBDA || pCell->type == CELL_MACRO) && args->type == CELL_SYMBOL) { if(debugStackIdx == 0) /* startup */ traceFlag &= ~TRACE_DEBUG_NEXT; if(!defaultFuncFlag) currentFunc = (SYMBOL *)args->contents; pushDebugStack(recursionCount); pushDebugStack(currentFunc); } traceFlag &= ~TRACE_IN_ENTRY; } void traceExit(CELL * result, CELL * cell, CELL * pCell, CELL * args) { if(traceFlag & (TRACE_IN_ENTRY | TRACE_IN_EXIT | TRACE_SIGNAL | TRACE_SIGINT | TRACE_TIMER)) return; traceFlag |= TRACE_IN_EXIT; if(traceFlag & TRACE_DEBUG_NEXT) { if(currentLevel >= recursionCount) traceFlag &= ~TRACE_DEBUG_NEXT; else { traceFlag &= ~TRACE_IN_EXIT; return; } } if( (pCell->type == CELL_LAMBDA || pCell->type == CELL_MACRO) && args->type == CELL_SYMBOL) { if((UINT)recursionCount == *(debugStack + debugStackIdx - 2) ) { debugStackIdx -= 2; if(debugStackIdx > 0) currentFunc = (SYMBOL *)*(debugStack + debugStackIdx - 1); if(debugStackIdx == 0) traceFlag &= ~TRACE_DEBUG_NEXT; } } if(printFunction(cell)) { varPrintf(OUT_CONSOLE, "\nRESULT: "); printCell(result, TRUE, OUT_CONSOLE); varPrintf(OUT_CONSOLE, "\n"); if(debugStackIdx > 0) { getDebuggerInput(DEBUG_EXIT); if(!traceFlag) return; } } if(traceFlag & TRACE_DEBUG_NEXT) currentLevel = recursionCount; traceFlag &= ~TRACE_IN_EXIT; } void getDebuggerInput(char * msg) { char command[MAX_LINE]; char * context; jmp_buf errorJumpSave; int resultStackIdxSave; SYMBOL * contextSave; while(TRUE) { if(currentContext != mainContext) context = currentContext->name; else context = ""; if(!evalSilent) varPrintf(OUT_CONSOLE, "\n[%s %d %s]%s", msg, recursionCount, context, footerStr); else evalSilent = FALSE; fgets(command, MAX_LINE - 1, IOchannel); if( (strcmp(command, "n\n") == 0) || (strcmp(command, "n\r\n") == 0)) { traceFlag |= TRACE_DEBUG_NEXT; currentLevel = recursionCount; break; } else if( (strcmp(command, "s\n") == 0) || (strcmp(command, "s\r\n") == 0)) { traceFlag &= ~TRACE_DEBUG_NEXT; break; } else if( (strcmp(command, "q\n") == 0) || (strcmp(command, "q\r\n") == 0)) { closeTrace(); longjmp(errorJump, ERR_USER_RESET); } else if( (strcmp(command, "c\n") == 0) || (strcmp(command, "c\r\n") == 0)) { closeTrace(); break; } resultStackIdxSave = resultStackIdx; memcpy(errorJumpSave, errorJump, sizeof(jmp_buf)); contextSave = currentContext; currentContext = currentFunc->context; if(setjmp(errorJump)) { cleanupResults(resultStackIdxSave); goto DEBUG_EVAL_END; } executeCommandLine(command, OUT_CONSOLE, NULL); DEBUG_EVAL_END: currentContext = contextSave; memcpy(errorJump, errorJumpSave, sizeof(jmp_buf)); } } int printFunction(CELL * cell) { char * funcStr; char * expStr; int start, length; STREAM strStream; if(currentFunc == nilSymbol) return FALSE; openStrStream(&strStream, MAX_STRING, 0); printSymbol(currentFunc, (UINT)&strStream); length = strlen(strStream.buffer); funcStr = allocMemory(length + 1); memcpy(funcStr, strStream.buffer, length + 1); *(funcStr + length) = 0; openStrStream(&strStream, MAX_STRING, 0); printCell((CELL *)cell, TRUE, (UINT)&strStream); expStr = strStream.buffer; start = matchString(funcStr, expStr, &length); closeStrStream(&strStream); if(start == -1 || length == 0) { free(funcStr); return FALSE; } varPrintf(OUT_CONSOLE, headerStr); expStr = allocMemory(length + 1); strncpy(expStr, funcStr + start, length); *(expStr + length) = 0; *(funcStr + start) = 0; varPrintf(OUT_CONSOLE, "%s%s%s%s%s", funcStr, preStr, expStr, postStr, funcStr + start + length); free(funcStr); return TRUE; } void allocateDebugStack(void) { debugStack = (UINT *)allocMemory(MAX_CPU_STACK * 2 * sizeof(UINT)); } /* search for a string skipping white space */ int matchString(char * buffer, char * string, int * length) { int position, flag; /* strip leading white space */ while(*string <= ' ' && *string > 0) string++; position = flag = 0; while(*buffer) { if(*buffer > ' ') if((*length = stringComp(buffer, string)) > 0) { flag = TRUE; break; } position++; buffer++; } if(!flag) return(-1); return(position); } /* compare strings skipping white space */ int stringComp(char * buffer, char * string) { char * start; start = buffer; while(*string && *buffer) { if(*string > ' ') { if(*buffer > ' ') { if(*string != *buffer) return(0); string++; buffer++; } else buffer++; } else string++; } if(*string == 0) return(buffer - start); return(0); } /* eof */