/** * debugHandleDebugger: * @cur : source node being executed * @node : data node being processed * @templ : temlate that applies to node * @ctxt : the xslt transform context * * If either cur or node are a breakpoint, or xslDebugStatus in state * where debugging must occcur at this time then transfer control * to the debugXSLBreak function */ void debugHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ, xsltTransformContextPtr ctxt) { if (!cur && !node) { xsldbgGenericErrorFunc(i18n("Error: XSLT source and XML data are empty. Cannot enter the debugger.\n")); } else { if (optionsGetIntOption(OPTIONS_GDB)){ int doValidation = 0; switch(xsldbgValidateBreakpoints){ case BREAKPOINTS_ARE_VALID: if (!filesGetStylesheet() || !filesGetMainDoc()) { xsldbgValidateBreakpoints = BREAKPOINTS_NEED_VALIDATION; doValidation = 1; } break; case BREAKPOINTS_NEED_VALIDATION: if (filesGetStylesheet() && filesGetMainDoc() && templ){ xsldbgValidateBreakpoints = BREAKPOINTS_BEING_VALIDATED; doValidation = 1; } break; case BREAKPOINTS_BEING_VALIDATED: /*should never be in the state for any length of time */ #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Unexpected breakpoint validation state %d", xsldbgValidateBreakpoints); #endif break; } if (doValidation){ /* breakpoints will either be marked as orphaned or not as needed */ xsldbgValidateBreakpoints = BREAKPOINTS_BEING_VALIDATED; walkBreakPoints((xmlHashScanner) xslDbgShellValidateBreakPoint, ctxt); if (filesGetStylesheet() && filesGetMainDoc() && templ){ xsldbgValidateBreakpoints = BREAKPOINTS_ARE_VALID; }else{ xsldbgValidateBreakpoints = BREAKPOINTS_NEED_VALIDATION; } } } switch (xslDebugStatus) { /* A temparary stopping point */ case DEBUG_WALK: case DEBUG_TRACE: /* only allow breakpoints at xml elements */ if (xmlGetLineNo(cur) != -1) debugXSLBreak(cur, node, templ, ctxt); break; case DEBUG_STOP: xslDebugStatus = DEBUG_CONT; /* only allow breakpoints at xml elements */ if (xmlGetLineNo(cur) != -1) debugXSLBreak(cur, node, templ, ctxt); break; case DEBUG_STEP: /* only allow breakpoints at xml elements */ if (xmlGetLineNo(cur) != -1) debugXSLBreak(cur, node, templ, ctxt); break; case DEBUG_CONT: { breakPointPtr breakPtr = NULL; xmlChar *baseUri = NULL; if (cur) { breakPtr = breakPointGet(cur->doc->URL, xmlGetLineNo(cur)); if (breakPtr && (breakPtr->flags & BREAKPOINT_ENABLED) ){ debugXSLBreak(cur, node, templ, ctxt); return; } } if (node) { baseUri = filesGetBaseUri(node); if (baseUri != NULL) { breakPtr = breakPointGet(baseUri, xmlGetLineNo(node)); } else { breakPtr = breakPointGet(node->doc->URL, xmlGetLineNo(node)); } if (breakPtr) { if (breakPtr->flags & BREAKPOINT_ENABLED) { debugXSLBreak(cur, node, templ, ctxt); } } if (baseUri) xmlFree(baseUri); } } break; } } }
/** * xslShellReadline: * @prompt: the prompt value * * Read a string * * Returns a copy of the text inputed or NULL if EOF in stdin found. * The caller is expected to free the returned string. */ xmlChar * xslDbgShellReadlineSimple(xmlChar * prompt) { static char last_read[DEBUG_BUFFER_SIZE] = { '\0' }; #ifdef HAVE_READLINE xmlChar *line_read; if (optionsGetIntOption(OPTIONS_STDOUT) == 0){ /* Get a line from the user. */ line_read = (xmlChar *) readline((char *) prompt); /* If the line has any text in it, save it on the history. */ if (line_read && *line_read) { char *temp = (char*)line_read; add_history((char *) line_read); strncpy((char*)last_read, (char*)line_read, DEBUG_BUFFER_SIZE - 1); /* we must ensure that the data is free properly */ line_read = xmlStrdup((xmlChar*)line_read); free(temp); } else { free(line_read); /* if only <Enter>is pressed then try last saved command line */ line_read = xmlStrdup((xmlChar*)last_read); } }else{ /* readline library will/may echo its output which is not wanted when running in gdb mode.*/ char line_buffer[DEBUG_BUFFER_SIZE]; if (prompt != NULL) xsltGenericError(xsltGenericErrorContext, "%s", prompt); if (!fgets(line_buffer, sizeof(line_buffer) - 1, stdin)){ line_read = NULL; }else{ line_buffer[DEBUG_BUFFER_SIZE - 1] = 0; if ((strlen(line_buffer) == 0) || (line_buffer[0] == '\n')){ line_read = xmlStrdup((xmlChar*)last_read); }else{ add_history((char *) line_buffer); line_read = xmlStrdup((xmlChar*)line_buffer); strncpy((char*)last_read, (char*)line_read, sizeof(last_read) - 1); } } } return (line_read); #else char line_read[DEBUG_BUFFER_SIZE]; if (prompt != NULL) xsltGenericError(xsltGenericErrorContext, "%s", prompt); fflush(stderr); if (!fgets(line_read, DEBUG_BUFFER_SIZE - 1, stdin)) return (NULL); line_read[DEBUG_BUFFER_SIZE - 1] = 0; /* if only <Enter>is pressed then try last saved command line */ if ((strlen(line_read) == 0) || (line_read[0] == '\n')) { strncpy(line_read, last_read, sizeof(line_read) - 1); } else { strcpy(last_read, line_read); } return xmlStrdup((xmlChar*)line_read); #endif }
/** * xslDbgShellPrintVariable: * @styleCtxt: The current stylesheet context * @arg: The name of variable to look for '$' prefix is optional and in UTF-8 * @type: A valid VariableTypeEnum * * Print the value variable specified by args. * * Returns 1 on success, * 0 otherwise */ int xslDbgShellPrintVariable(xsltTransformContextPtr styleCtxt, xmlChar * arg, VariableTypeEnum type) { int result = 0; /* command argument to include both name and its value */ static const char * FULLNAME_STR = "-f"; /* Quietly exit if an invalid stylesheet is provided */ static const char * QUIET_STR = "-q"; bool silenceCtxtErrors = false; if (!arg) { #ifdef WITH_XSLDBG_DEBUG_PROCESS xsltGenericError(xsltGenericErrorContext, "Error: NULL argument provided\n"); #endif return result; } varCount = 0; /* Do we quietly ingore style context errors */ if (strncasecmp((char*)arg, QUIET_STR, strlen(QUIET_STR))== 0){ silenceCtxtErrors = true; arg = arg + strlen(QUIET_STR); while (isspace(*arg)){ arg++; } } if (!styleCtxt) { if (!(!xsldbgReachedFirstTemplate && silenceCtxtErrors)) xsldbgGenericErrorFunc(i18n("Error: Debugger has no files loaded or libxslt has not reached a template.\nTry reloading files or taking more steps.\n")); return result; } /* Do we include the name as well as its value */ if (strncasecmp((char*)arg, FULLNAME_STR, strlen(FULLNAME_STR))== 0){ printVariableValue = 1; arg = arg + strlen(FULLNAME_STR); while (isspace(*arg)){ arg++; } } if (arg[0] == 0) { /* list variables of type requested */ if (type == DEBUG_GLOBAL_VAR) { if (styleCtxt->globalVars) { if (getThreadStatus() == XSLDBG_MSG_THREAD_RUN) { notifyListStart(XSLDBG_MSG_GLOBALVAR_CHANGED); /* list global variables */ xmlHashScan(styleCtxt->globalVars, (xmlHashScanner) xslDbgShellPrintNames, NULL); notifyListSend(); } else /* list global variables */ xmlHashScan(styleCtxt->globalVars, (xmlHashScanner) xslDbgShellPrintNames, NULL); result = 1; /* ensure that the locals follow imediately after the * globals when in gdb mode */ if (optionsGetIntOption(OPTIONS_GDB) == 0) xsltGenericError(xsltGenericErrorContext, "\n"); } else { if (getThreadStatus() != XSLDBG_MSG_THREAD_RUN) { /* Don't show this message when running as a thread as it * is annoying */ xsldbgGenericErrorFunc(i18n("Error: Libxslt has not initialized variables yet; try stepping to a template.\n")); } else { /* send an empty list */ notifyListStart(XSLDBG_MSG_GLOBALVAR_CHANGED); notifyListSend(); result = 1; } } } else { /* list local variables */ if (styleCtxt->varsNr && styleCtxt->varsTab) { if (getThreadStatus() == XSLDBG_MSG_THREAD_RUN) { notifyListStart(XSLDBG_MSG_LOCALVAR_CHANGED); for (int i = styleCtxt->varsNr; i > styleCtxt->varsBase; i--) { xsltStackElemPtr item = styleCtxt->varsTab[i-1]; while (item) { notifyListQueue(item); item = item->next; } } notifyListSend(); } else { xmlChar * fullQualifiedName = nodeViewBuffer; for (int i = styleCtxt->varsNr; i > styleCtxt->varsBase; i--) { xsltStackElemPtr item = styleCtxt->varsTab[i-1]; while (item) { if (item->name) { if (item->nameURI == NULL){ snprintf((char*)fullQualifiedName, sizeof(nodeViewBuffer), "$%s", item->name); }else{ snprintf((char*)fullQualifiedName, sizeof(nodeViewBuffer), "$%s:%s", item->nameURI, item->name); } if (printVariableValue == 0){ xsldbgGenericErrorFunc(i18n(" Local %1").arg(xsldbgText(fullQualifiedName))); }else{ if (item->computed == 1){ xsldbgGenericErrorFunc(i18n(" Local ")); printXPathObject(item->value, fullQualifiedName); }else if (item->tree){ xsldbgGenericErrorFunc(i18n(" Local = %1\n").arg(xsldbgText(fullQualifiedName))); xslDbgCatToFile(item->tree, stderr); }else if (item->select){ xsldbgGenericErrorFunc(i18n(" Local = %1\n%2").arg(xsldbgText(fullQualifiedName)).arg(xsldbgText(item->select))); }else{ /* can't find a value give only a variable name and an error */ xsldbgGenericErrorFunc(i18n(" Local = %1\n%2").arg(xsldbgText(fullQualifiedName)).arg(i18n("Warning: No value assigned to variable.\n"))); } } xsltGenericError(xsltGenericErrorContext, "\n\032\032\n"); } item = item->next; } } } result = 1; xsltGenericError(xsltGenericErrorContext, "\n"); } else { if (getThreadStatus() != XSLDBG_MSG_THREAD_RUN) { /* Don't show this message when running as a thread as it * is annoying */ xsldbgGenericErrorFunc(i18n("Error: Libxslt has not initialized variables yet; try stepping past the xsl:param elements in the template.\n")); } else { /* send an empty list */ notifyListStart(XSLDBG_MSG_LOCALVAR_CHANGED); notifyListSend(); result = 1; } } } } else { /* Display the value of variable */ if (arg[0] == '$') { printXPathObject(xmlXPathEval(arg, styleCtxt->xpathCtxt), arg); xsltGenericError(xsltGenericErrorContext, "\032\032\n"); } else { xmlStrCpy(nodeViewBuffer, "$"); xmlStrCat(nodeViewBuffer, arg); printXPathObject(xmlXPathEval((xmlChar*)nodeViewBuffer,styleCtxt->xpathCtxt), (xmlChar*)nodeViewBuffer); xsltGenericError(xsltGenericErrorContext, "\032\032\n"); } } printVariableValue = 0; return result; }
/** * breakPointAdd: * @url: Non-null, non-empty file name that has been loaded by * debugger * @lineNumber: @lineNumber >= 0 and is available in url specified and * points to an xml element * @templateName: The template name of breakPoint or NULL * @modeName : The mode of breakpoint or NULL * @type: Valid BreakPointTypeEnum * * Add break point at file and line number specified * * Returns 1 if successful, * 0 otherwise */ int breakPointAdd(const xmlChar * url, long lineNumber, const xmlChar * templateName, const xmlChar * modeName, BreakPointTypeEnum type) { int result = 0, breakPointType = type; xmlHashTablePtr breakPointHash = NULL; /* hash of breakPoints */ breakPointPtr breakPtr; if (!breakList) { #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Breakpoints structures not initialized\n"); #endif return result; } if (!url || (lineNumber == -1)) { #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Invalid url or line number to breakPointAdd\n"); #endif return result; } /* if breakpoint already exists then don;t add it */ if (breakPointIsPresent(url, lineNumber)) { #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Warning: Breakpoint at file %s: line %d exists\n", url, lineNumber); #endif return result; } breakPtr = breakPointItemNew(); if (breakPtr) { breakPtr->url = (xmlChar *) xmlMemStrdup((char *) url); breakPtr->lineNo = lineNumber; if (templateName) breakPtr->templateName = xmlStrdup( templateName); else breakPtr->templateName = NULL; if (modeName) breakPtr->modeName = xmlStrdup(modeName); else breakPtr->modeName = NULL; breakPtr->type = BreakPointTypeEnum(breakPointType); /* add new breakPoint to the right hash table */ breakPointHash = breakPointGetLineNoHash(lineNumber); if (breakPointHash) { result = lineNoItemAdd(breakPointHash, breakPtr); } else { /* Grow breakList size */ int lineIndex; int newEntries = breakList->count; xmlHashTablePtr hash; result = 1; if ((lineNumber < breakList->count) && breakList->count) { #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Unable to find breakpoint line hash at %d\n", lineNumber); #endif } else { if (breakList->count + newEntries < lineNumber) newEntries = lineNumber - breakList->count + 1; #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS /* * xsltGenericError(xsltGenericErrorContext, * "Size of line list was %d adding %d entries\n", * breakList->count, newEntries); */ #endif lineIndex = 0; while ((lineIndex < newEntries) && result) { hash = lineNoItemNew(); if (hash) { result = result && arrayListAdd(breakList, hash); } else { result = 0; #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Unable to create hash table breakPoint list: memory error\n"); #endif return result; } lineIndex++; } /* find the newly added hashtable of breakpoints */ breakPointHash = breakPointGetLineNoHash(lineNumber); if (breakPointHash) { result = lineNoItemAdd(breakPointHash, breakPtr); } else { #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Unable to create new breakPoint:interal error\n"); #endif return result; } } } } else { #ifdef WITH_XSLDBG_DEBUG_BREAKPOINTS xsltGenericError(xsltGenericErrorContext, "Error: Unable to create new breakPoint: memory error\n"); #endif } if (result && (optionsGetIntOption(OPTIONS_GDB) > 1) && (xsldbgValidateBreakpoints != BREAKPOINTS_BEING_VALIDATED)){ breakPointPrint(breakPtr); xsldbgGenericErrorFunc("\n"); } return result; }
static int printXPathObject(xmlXPathObjectPtr item, xmlChar* xPath){ int result = 0; if (item){ switch (item->type) { case XPATH_BOOLEAN: xsltGenericError(xsltGenericErrorContext, "= %s\n%s\n", xPath, xmlBoolToText(item->boolval)); result = 1; break; case XPATH_NUMBER: xsltGenericError(xsltGenericErrorContext, "= %s\n%0g\n", xPath, item->floatval); result = 1; break; /* case XPATH_NODESET:*/ default:{ /* We may need to convert this XPath to a string, plus ensure that we print required the number of lines of text */ int indx; const char *fileName = filesTempFileName(0); FILE *file = NULL; if (!fileName) break; file = fopen(fileName, "w+"); if (!file) { xsldbgGenericErrorFunc(i18n("Error: Unable to save temporary results to %1.\n").arg(xsldbgText(fileName))); break; } else { fprintf(file, "= %s\n", xPath); switch(item->type){ case XPATH_NODESET: if (item->nodesetval){ for (indx = 0; indx < item->nodesetval->nodeNr; indx++){ xslDbgCatToFile(item->nodesetval-> nodeTab[indx], file); } } else { xsldbgGenericErrorFunc(i18n("Error: XPath %1 results in an empty Node Set.\n").arg(xsldbgText(xPath))); } break; case XPATH_STRING: if (item->stringval) fprintf(file, "\'%s\'", item->stringval); else fprintf(file, "%s", i18n("NULL string value supplied.").utf8().data()); break; default:{ xmlXPathObjectPtr tempObj = xmlXPathObjectCopy(item); if (tempObj) tempObj = xmlXPathConvertString(tempObj); if (tempObj && tempObj->stringval){ fprintf(file, "%s", tempObj->stringval); }else{ fprintf(file, "%s", i18n("Unable to convert XPath to string.").utf8().data()); } if (tempObj) xmlXPathFreeObject(tempObj); } break; fprintf(file,"\n"); } /* inner switch statement */ if (getThreadStatus() == XSLDBG_MSG_THREAD_RUN) { fclose(file); file = NULL; /* send the data to application */ notifyXsldbgApp(XSLDBG_MSG_FILEOUT, fileName); } else { int lineCount = 0, gdbModeEnabled = 0; /* save the value of option to speed things up * a bit */ gdbModeEnabled = optionsGetIntOption(OPTIONS_GDB); rewind(file); /* when gdb mode is enable then only print the first * GDB_LINES_TO_PRINT lines */ while (!feof(file)) { if (fgets ((char *) nodeViewBuffer, sizeof(nodeViewBuffer), file)) xsltGenericError (xsltGenericErrorContext, "%s", nodeViewBuffer); if (gdbModeEnabled) { lineCount++; /* there is an overhead of two lines * when print expression values */ if (lineCount == GDB_LINES_TO_PRINT + 2) { xsltGenericError (xsltGenericErrorContext, "..."); break; } } } xsltGenericError (xsltGenericErrorContext, "\n"); } if (file) fclose(file); result = 1; break; } } } } return result; }