/***************************************************************************
nodeview_cmds . c - node viewing commands for xsldbg
- - - - - - - - - - - - - - - - - - -
begin : Wed Nov 21 2001
copyright : ( C ) 2001 by Keith Isdale
email : k_isdale @ tpg . com . au
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************************************************
* *
* 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 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "xsldbg.h"
# include <libxml/xpathInternals.h>
# include <libxml/HTMLparser.h>
# include <libxml/HTMLtree.h>
# include <ctype.h> /* for isspace*/
# include "debugXSL.h"
# include "arraylist.h"
# include "breakpoint.h"
# include "xsldbgmsg.h"
# include "xsldbgthread.h" /* for getThreadtqStatus */
# include "files.h"
# include "options.h"
/* -----------------------------------------
Private function declarations for nodeview_cmds . c
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static xmlChar nodeViewBuffer [ 500 ] ;
static int printVariableValue = 0 ;
/*
* xslDbgShellPrintNames :
* Print a name of variable found by scanning variable table
* It is used by print_variable function .
* @ payload : not used
* @ data : not used
* @ name : the variable name
*/
void * xslDbgShellPrintNames ( void * payload ,
void * data , xmlChar * name ) ;
/**
* xslDbgCatToFile :
* @ node : Is valid
* @ file : Is valid
*
* Send the results of cat command in @ node to @ file
*/
static void xslDbgCatToFile ( xmlNodePtr node , FILE * file ) ;
/**
* printXPathObject :
* @ item : XPath object to print
* @ xPath : The XPath used to find item
*
* Print an XPath object
*
* Returns 1 on success ,
* 0 otherwise
*/
static int printXPathObject ( xmlXPathObjectPtr item , xmlChar * xPath ) ;
/* -------------------------------------
End private functions
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/**
* xslDbgShellPrintList :
* @ ctxt : The current shell context
* @ arg : What xpath to display and in UTF - 8
* @ dir : If 1 print in dir mode ? ,
* otherwise ls mode
*
* Print list of nodes in either ls or dir format
*
* Returns 1 on success ,
* 0 otherwise
*/
int
xslDbgShellPrintList ( xmlShellCtxtPtr ctxt , xmlChar * arg , int dir )
{
xmlXPathObjectPtr list ;
int result = 0 ;
if ( ! ctxt | | ! arg ) {
# ifdef WITH_XSLDBG_DEBUG_PROCESS
xsltGenericError ( xsltGenericErrorContext ,
" Error: NULL arguments provided \n " ) ;
# endif
return result ;
}
if ( arg [ 0 ] = = 0 ) {
if ( dir )
xmlShellDir ( ctxt , NULL , ctxt - > node , NULL ) ;
else
xmlShellList ( ctxt , NULL , ctxt - > node , NULL ) ;
result = 1 ; /*assume that this worked */
} else {
ctxt - > pctxt - > node = ctxt - > node ;
ctxt - > pctxt - > node = ctxt - > node ;
if ( ! xmlXPathNsLookup ( ctxt - > pctxt , ( xmlChar * ) " xsl " ) )
xmlXPathRegisterNs ( ctxt - > pctxt , ( xmlChar * ) " xsl " ,
XSLT_NAMESPACE ) ;
list = xmlXPathEval ( arg , ctxt - > pctxt ) ;
if ( list ! = NULL ) {
switch ( list - > type ) {
case XPATH_NODESET : {
int indx ;
for ( indx = 0 ;
indx < list - > nodesetval - > nodeNr ; indx + + ) {
if ( dir )
xmlShellList ( ctxt , NULL ,
list - > nodesetval - >
nodeTab [ indx ] , NULL ) ;
else
xmlShellList ( ctxt , NULL ,
list - > nodesetval - >
nodeTab [ indx ] , NULL ) ;
}
result = 1 ;
break ;
}
default :
xmlShellPrintXPathError ( list - > type , ( char * ) arg ) ;
}
xmlXPathFreeObject ( list ) ;
} else {
xsldbgGenericErrorFunc ( i18n ( " Error: XPath %1 results in an empty Node Set. \n " ) . tqarg ( xsldbgText ( arg ) ) ) ;
}
ctxt - > pctxt - > node = NULL ;
}
return result ;
}
/**
* xslDbgCatToFile :
* @ node : Is valid
* @ file : Is valid
*
* Send the results of cat command in @ node to @ file
*/
void
xslDbgCatToFile ( xmlNodePtr node , FILE * file )
{
if ( ! node | | ! file )
return ;
/* assume that HTML usage is enabled */
if ( node - > doc - > type = = XML_HTML_DOCUMENT_NODE ) {
if ( node - > type = = XML_HTML_DOCUMENT_NODE )
htmlDocDump ( file , ( htmlDocPtr ) node ) ;
else
htmlNodeDumpFile ( file , node - > doc , node ) ;
} else if ( node - > type = = XML_DOCUMENT_NODE ) {
/* turn off encoding for the moment and just dump UTF-8
* which will be converted by xsldbgGeneralErrorFunc */
xmlDocPtr doc = ( xmlDocPtr ) node ;
const xmlChar * encoding = doc - > encoding ;
if ( encoding ) {
xsldbgGenericErrorFunc ( i18n ( " Information: Temporarily setting document's encoding to UTF-8. Previously was %1. \n " ) . tqarg ( xsldbgText ( encoding ) ) ) ;
}
doc - > encoding = ( xmlChar * ) " UTF-8 " ;
xmlDocDump ( file , ( xmlDocPtr ) node ) ;
doc - > encoding = encoding ;
} else {
xmlElemDump ( file , node - > doc , node ) ;
}
}
/**
* printXPathObject :
* @ item : XPath object to print
* @ xPath : The XPath used to find item
*
* Print an XPath object
*
* Returns 1 on success ,
* 0 otherwise
*/
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 " ) . tqarg ( 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 " ) . tqarg ( 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 ( getThreadtqStatus ( ) = = 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 ;
}
/**
* xslDbgShellCat :
* @ styleCtxt : the current stylesheet context
* @ ctxt : The current shell context
* @ arg : The xpath to print ( in UTF - 8 )
*
* Print the result of an xpath expression . This can include variables
* if styleCtxt is not NULL
*
* Returns 1 on success ,
* 0 otherwise
*/
int
xslDbgShellCat ( xsltTransformContextPtr styleCtxt , xmlShellCtxtPtr ctxt ,
xmlChar * arg )
{
xmlXPathObjectPtr list ;
int result = 0 ;
static const char * TQUIET_STR = " -q " ;
bool silenceCtxtErrors = false ;
if ( ( arg = = NULL ) | | ( xmlStrLen ( arg ) = = 0 ) )
arg = ( xmlChar * ) " . " ;
/* Do we quietly ingore style context errors */
if ( strncasecmp ( ( char * ) arg , TQUIET_STR , strlen ( TQUIET_STR ) ) = = 0 ) {
silenceCtxtErrors = true ;
arg = arg + strlen ( TQUIET_STR ) ;
while ( isspace ( * arg ) ) {
arg + + ;
}
}
if ( ! styleCtxt | | ! ctxt | | ! ctxt - > node ) {
if ( ! ( ! xsldbgReachedFirstTemplate & & silenceCtxtErrors ) )
xsldbgGenericErrorFunc ( i18n ( " Warning: Unable to print expression. No stylesheet was properly loaded. \n " ) ) ;
return 0 ;
}
if ( ( arg = = NULL ) | | ( xmlStrLen ( arg ) = = 0 ) )
arg = ( xmlChar * ) " . " ;
ctxt - > pctxt - > node = ctxt - > node ;
if ( ! styleCtxt ) {
list = xmlXPathEval ( ( xmlChar * ) arg , ctxt - > pctxt ) ;
} else {
xmlNodePtr savenode = styleCtxt - > xpathCtxt - > node ;
ctxt - > pctxt - > node = ctxt - > node ;
styleCtxt - > xpathCtxt - > node = ctxt - > node ;
if ( ! xmlXPathNsLookup ( styleCtxt - > xpathCtxt , ( xmlChar * ) " xsl " ) )
xmlXPathRegisterNs ( styleCtxt - > xpathCtxt , ( xmlChar * ) " xsl " ,
XSLT_NAMESPACE ) ;
list = xmlXPathEval ( ( xmlChar * ) arg , styleCtxt - > xpathCtxt ) ;
styleCtxt - > xpathCtxt - > node = savenode ;
}
if ( list ! = NULL ) {
result = printXPathObject ( list , arg ) ;
xmlXPathFreeObject ( list ) ;
} else {
xsldbgGenericErrorFunc ( i18n ( " Error: XPath %1 results in an empty Node Set. \n " ) . tqarg ( xsldbgText ( arg ) ) ) ;
}
ctxt - > pctxt - > node = NULL ;
return result ;
}
/* only used by xslDbgPrintNames and xslDbgPrintVariable cound number of variables */
static int varCount ;
/*
* xslDbgShellPrintNames :
* Print a name of variable found by scanning variable table
* It is used by print_variable function .
* @ payload : Global variable of type xsltStackElemPtr
* @ data : not used
* @ name : the variable name
*/
void *
xslDbgShellPrintNames ( void * payload ,
void * data , xmlChar * name )
{
Q_UNUSED ( payload ) ;
Q_UNUSED ( data ) ;
if ( getThreadtqStatus ( ) = = XSLDBG_MSG_THREAD_RUN ) {
notifyListQueue ( payload ) ;
} else if ( payload & & name ) {
xmlChar * fullQualifiedName = nodeViewBuffer ;
xsltStackElemPtr item = ( xsltStackElemPtr ) payload ;
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 ( " Global %1 \n " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) ) ;
} else {
if ( item - > computed = = 1 ) {
xsldbgGenericErrorFunc ( i18n ( " Global " ) ) ;
printXPathObject ( item - > value , fullQualifiedName ) ;
} else if ( item - > tree ) {
xsldbgGenericErrorFunc ( i18n ( " Global = %1 \n " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) ) ;
xslDbgCatToFile ( item - > tree , stderr ) ;
} else if ( item - > select ) {
xsldbgGenericErrorFunc ( i18n ( " Global = %1 \n %2 " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) . tqarg ( xsldbgText ( item - > select ) ) ) ;
} else {
/* can't find a value give only a variable name an error message */
xsldbgGenericErrorFunc ( i18n ( " Global = %1 \n %2 " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) . tqarg ( i18n ( " Warning: No value assigned to variable. \n " ) ) ) ;
}
xsltGenericError ( xsltGenericErrorContext , " \n \032 \032 \n " ) ;
}
varCount + + ;
}
return NULL ;
}
/**
* 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 * TQUIET_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 , TQUIET_STR , strlen ( TQUIET_STR ) ) = = 0 ) {
silenceCtxtErrors = true ;
arg = arg + strlen ( TQUIET_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. \n Try 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 ( getThreadtqStatus ( ) = = 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 ( getThreadtqStatus ( ) ! = 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 ( getThreadtqStatus ( ) = = 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 " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) ) ;
} else {
if ( item - > computed = = 1 ) {
xsldbgGenericErrorFunc ( i18n ( " Local " ) ) ;
printXPathObject ( item - > value , fullQualifiedName ) ;
} else if ( item - > tree ) {
xsldbgGenericErrorFunc ( i18n ( " Local = %1 \n " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) ) ;
xslDbgCatToFile ( item - > tree , stderr ) ;
} else if ( item - > select ) {
xsldbgGenericErrorFunc ( i18n ( " Local = %1 \n %2 " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) . tqarg ( xsldbgText ( item - > select ) ) ) ;
} else {
/* can't find a value give only a variable name and an error */
xsldbgGenericErrorFunc ( i18n ( " Local = %1 \n %2 " ) . tqarg ( xsldbgText ( fullQualifiedName ) ) . tqarg ( i18n ( " Warning: No value assigned to variable. \n " ) ) ) ;
}
}
xsltGenericError ( xsltGenericErrorContext , " \n \032 \032 \n " ) ;
}
item = item - > next ;
}
}
}
result = 1 ;
xsltGenericError ( xsltGenericErrorContext , " \n " ) ;
} else {
if ( getThreadtqStatus ( ) ! = 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 ;
}