2000-10-11 08:55:02 +00:00
/*
* xpointer . c : Code to handle XML Pointer
*
* World Wide Web Consortium Working Draft 03 - March - 1998
* http : //www.w3.org/TR/2000/CR-xptr-20000607
*
* See Copyright for the status of this software .
*
* Daniel . Veillard @ w3 . org
*/
# ifdef WIN32
# include "win32config.h"
# else
# include "config.h"
# endif
/**
* TODO : better handling of error cases , the full expression should
* be parsed beforehand instead of a progressive evaluation
2000-10-12 23:15:24 +00:00
* TODO : Access into entities references are not supported now . . .
* need a start to be able to pop out of entities refs since
* parent is the endity declaration , not the ref .
* TODO : some functions are still missing !
2000-10-11 08:55:02 +00:00
*/
# include <stdio.h>
# include <libxml/xpointer.h>
# include <libxml/xmlmemory.h>
# include <libxml/parserInternals.h>
# include <libxml/xpath.h>
2000-10-12 23:15:24 +00:00
# ifdef LIBXML_DEBUG_ENABLED
# include <libxml/debugXML.h>
# endif
2000-10-11 08:55:02 +00:00
# ifdef LIBXML_XPTR_ENABLED
2000-10-12 23:15:24 +00:00
/* #define DEBUG_RANGES */
2000-10-11 08:55:02 +00:00
extern FILE * xmlXPathDebug ;
# define TODO \
fprintf ( xmlXPathDebug , " Unimplemented block at %s:%d \n " , \
__FILE__ , __LINE__ ) ;
# define STRANGE \
fprintf ( xmlXPathDebug , " Internal error at %s:%d \n " , \
__FILE__ , __LINE__ ) ;
2000-10-15 20:38:39 +00:00
/************************************************************************
* *
* A few helper functions for child sequences *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPtrGetArity :
* @ cur : the node
*
* Returns the number of child for an element , - 1 in case of error
*/
int
xmlXPtrGetArity ( xmlNodePtr cur ) {
int i ;
if ( cur = = NULL )
return ( - 1 ) ;
cur = cur - > children ;
for ( i = 0 ; cur ! = NULL ; cur = cur - > next ) {
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
i + + ;
}
}
return ( i ) ;
}
/**
* xmlXPtrGetIndex :
* @ cur : the node
*
* Returns the index of the node in its parent children list , - 1
* in case of error
*/
int
xmlXPtrGetIndex ( xmlNodePtr cur ) {
int i ;
if ( cur = = NULL )
return ( - 1 ) ;
for ( i = 1 ; cur ! = NULL ; cur = cur - > prev ) {
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
i + + ;
}
}
return ( i ) ;
}
/**
* xmlXPtrGetNthChild :
* @ cur : the node
* @ no : the child number
*
* Returns the @ no ' th element child of @ cur or NULL
*/
xmlNodePtr
xmlXPtrGetNthChild ( xmlNodePtr cur , int no ) {
int i ;
if ( cur = = NULL )
return ( cur ) ;
cur = cur - > children ;
for ( i = 0 ; i < = no ; cur = cur - > next ) {
if ( cur = = NULL )
return ( cur ) ;
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
i + + ;
if ( i = = no )
break ;
}
}
return ( cur ) ;
}
2000-10-11 08:55:02 +00:00
/************************************************************************
* *
* Handling of XPointer specific types *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-10-13 16:38:25 +00:00
/**
* xmlXPtrCmpPoints :
* @ node1 : the first node
* @ index1 : the first index
* @ node2 : the second node
* @ index2 : the second index
*
* Compare two points w . r . t document order
*
* Returns - 2 in case of error 1 if first point < second point , 0 if
* that ' s the same point , - 1 otherwise
*/
int
xmlXPtrCmpPoints ( xmlNodePtr node1 , int index1 , xmlNodePtr node2 , int index2 ) {
int depth1 , depth2 ;
xmlNodePtr cur , root ;
if ( ( node1 = = NULL ) | | ( node2 = = NULL ) )
return ( - 2 ) ;
/*
* a couple of optimizations which will avoid computations in most cases
*/
if ( node1 = = node2 ) {
if ( index1 < index2 )
return ( 1 ) ;
if ( index1 > index2 )
return ( - 1 ) ;
return ( 0 ) ;
}
if ( node1 = = node2 - > prev )
return ( 1 ) ;
if ( node1 = = node2 - > next )
return ( - 1 ) ;
/*
* compute depth to root
*/
for ( depth2 = 0 , cur = node2 ; cur - > parent ! = NULL ; cur = cur - > parent ) {
if ( cur = = node1 )
return ( 1 ) ;
depth2 + + ;
}
root = cur ;
for ( depth1 = 0 , cur = node1 ; cur - > parent ! = NULL ; cur = cur - > parent ) {
if ( cur = = node2 )
return ( - 1 ) ;
depth1 + + ;
}
/*
* Distinct document ( or distinct entities : - ( ) case .
*/
if ( root ! = cur ) {
return ( - 2 ) ;
}
/*
* get the nearest common ancestor .
*/
while ( depth1 > depth2 ) {
depth1 - - ;
node1 = node1 - > parent ;
}
while ( depth2 > depth1 ) {
depth2 - - ;
node2 = node2 - > parent ;
}
while ( node1 - > parent ! = node2 - > parent ) {
node1 = node1 - > parent ;
node2 = node2 - > parent ;
/* should not happen but just in case ... */
if ( ( node1 = = NULL ) | | ( node2 = = NULL ) )
return ( - 2 ) ;
}
/*
* Find who ' s first .
*/
if ( node1 = = node2 - > next )
return ( - 1 ) ;
for ( cur = node1 - > next ; cur ! = NULL ; cur = cur - > next )
if ( cur = = node2 )
return ( 1 ) ;
return ( - 1 ) ; /* assume there is no sibling list corruption */
}
2000-10-11 08:55:02 +00:00
/**
* xmlXPtrNewPoint :
* @ node : the xmlNodePtr
* @ index : the index within the node
*
* Create a new xmlXPathObjectPtr of type point
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewPoint ( xmlNodePtr node , int index ) {
xmlXPathObjectPtr ret ;
if ( node = = NULL )
return ( NULL ) ;
if ( index < 0 )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewPoint: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_POINT ;
ret - > user = ( void * ) node ;
ret - > index = index ;
return ( ret ) ;
}
2000-10-13 16:38:25 +00:00
/**
* xmlXPtrRangeCheckOrder :
* @ range : an object range
*
* Make sure the points in the range are in the right order
*/
void
xmlXPtrRangeCheckOrder ( xmlXPathObjectPtr range ) {
int tmp ;
xmlNodePtr tmp2 ;
if ( range = = NULL )
return ;
if ( range - > type ! = XPATH_RANGE )
return ;
if ( range - > user2 = = NULL )
return ;
tmp = xmlXPtrCmpPoints ( range - > user , range - > index ,
range - > user2 , range - > index2 ) ;
if ( tmp = = - 1 ) {
tmp2 = range - > user ;
range - > user = range - > user2 ;
range - > user2 = tmp2 ;
tmp = range - > index ;
range - > index = range - > index2 ;
range - > index2 = tmp ;
}
}
2000-10-12 23:15:24 +00:00
/**
* xmlXPtrNewRange :
* @ start : the starting node
* @ startindex : the start index
* @ end : the ending point
* @ endindex : the ending index
*
* Create a new xmlXPathObjectPtr of type range
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRange ( xmlNodePtr start , int startindex ,
xmlNodePtr end , int endindex ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( startindex < 0 )
return ( NULL ) ;
if ( endindex < 0 )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangePoints: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = startindex ;
ret - > user2 = end ;
ret - > index2 = endindex ;
2000-10-13 16:38:25 +00:00
xmlXPtrRangeCheckOrder ( ret ) ;
2000-10-12 23:15:24 +00:00
return ( ret ) ;
}
2000-10-11 08:55:02 +00:00
/**
* xmlXPtrNewRangePoints :
* @ start : the starting point
* @ end : the ending point
*
* Create a new xmlXPathObjectPtr of type range using 2 Points
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangePoints ( xmlXPathObjectPtr start , xmlXPathObjectPtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( start - > type ! = XPATH_POINT )
return ( NULL ) ;
if ( end - > type ! = XPATH_POINT )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangePoints: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start - > user ;
ret - > index = start - > index ;
ret - > user2 = end - > user ;
ret - > index2 = end - > index ;
2000-10-13 16:38:25 +00:00
xmlXPtrRangeCheckOrder ( ret ) ;
2000-10-11 08:55:02 +00:00
return ( ret ) ;
}
/**
* xmlXPtrNewRangePointNode :
* @ start : the starting point
* @ end : the ending node
*
* Create a new xmlXPathObjectPtr of type range from a point to a node
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangePointNode ( xmlXPathObjectPtr start , xmlNodePtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( start - > type ! = XPATH_POINT )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangePointNode: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start - > user ;
ret - > index = start - > index ;
ret - > user2 = end ;
ret - > index2 = - 1 ;
2000-10-13 16:38:25 +00:00
xmlXPtrRangeCheckOrder ( ret ) ;
2000-10-11 08:55:02 +00:00
return ( ret ) ;
}
/**
* xmlXPtrNewRangeNodePoint :
* @ start : the starting node
* @ end : the ending point
*
* Create a new xmlXPathObjectPtr of type range from a node to a point
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodePoint ( xmlNodePtr start , xmlXPathObjectPtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
if ( start - > type ! = XPATH_POINT )
return ( NULL ) ;
if ( end - > type ! = XPATH_POINT )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangeNodePoint: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
ret - > user2 = end - > user ;
ret - > index2 = end - > index ;
2000-10-13 16:38:25 +00:00
xmlXPtrRangeCheckOrder ( ret ) ;
2000-10-11 08:55:02 +00:00
return ( ret ) ;
}
/**
* xmlXPtrNewRangeNodes :
* @ start : the starting node
* @ end : the ending node
*
* Create a new xmlXPathObjectPtr of type range using 2 nodes
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodes ( xmlNodePtr start , xmlNodePtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangeNodes: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
ret - > user2 = end ;
ret - > index2 = - 1 ;
2000-10-13 16:38:25 +00:00
xmlXPtrRangeCheckOrder ( ret ) ;
2000-10-11 08:55:02 +00:00
return ( ret ) ;
}
/**
* xmlXPtrNewCollapsedRange :
* @ start : the starting and ending node
*
* Create a new xmlXPathObjectPtr of type range using a single nodes
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewCollapsedRange ( xmlNodePtr start ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangeNodes: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
ret - > user2 = NULL ;
ret - > index2 = - 1 ;
return ( ret ) ;
}
/**
* xmlXPtrNewRangeNodeObject :
* @ start : the starting node
* @ end : the ending object
*
* Create a new xmlXPathObjectPtr of type range from a not to an object
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewRangeNodeObject ( xmlNodePtr start , xmlXPathObjectPtr end ) {
xmlXPathObjectPtr ret ;
if ( start = = NULL )
return ( NULL ) ;
if ( end = = NULL )
return ( NULL ) ;
switch ( end - > type ) {
case XPATH_POINT :
break ;
case XPATH_NODESET :
/*
* Empty set . . .
*/
if ( end - > nodesetval - > nodeNr < = 0 )
return ( NULL ) ;
break ;
default :
TODO
return ( NULL ) ;
}
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewRangeNodeObject: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_RANGE ;
ret - > user = start ;
ret - > index = - 1 ;
switch ( end - > type ) {
case XPATH_POINT :
ret - > user2 = end - > user ;
ret - > index2 = end - > index ;
case XPATH_NODESET : {
ret - > user2 = end - > nodesetval - > nodeTab [ end - > nodesetval - > nodeNr - 1 ] ;
ret - > index2 = - 1 ;
break ;
}
default :
STRANGE
return ( NULL ) ;
}
2000-10-13 16:38:25 +00:00
xmlXPtrRangeCheckOrder ( ret ) ;
2000-10-11 08:55:02 +00:00
return ( ret ) ;
}
# define XML_RANGESET_DEFAULT 10
/**
* xmlXPtrLocationSetCreate :
* @ val : an initial xmlXPathObjectPtr , or NULL
*
* Create a new xmlLocationSetPtr of type double and of value @ val
*
* Returns the newly created object .
*/
xmlLocationSetPtr
xmlXPtrLocationSetCreate ( xmlXPathObjectPtr val ) {
xmlLocationSetPtr ret ;
ret = ( xmlLocationSetPtr ) xmlMalloc ( sizeof ( xmlLocationSet ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrLocationSetCreate: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlLocationSet ) ) ;
if ( val ! = NULL ) {
ret - > locTab = ( xmlXPathObjectPtr * ) xmlMalloc ( XML_RANGESET_DEFAULT *
sizeof ( xmlXPathObjectPtr ) ) ;
if ( ret - > locTab = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrLocationSetCreate: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret - > locTab , 0 ,
XML_RANGESET_DEFAULT * ( size_t ) sizeof ( xmlXPathObjectPtr ) ) ;
ret - > locMax = XML_RANGESET_DEFAULT ;
ret - > locTab [ ret - > locNr + + ] = val ;
}
return ( ret ) ;
}
/**
* xmlXPtrLocationSetAdd :
* @ cur : the initial range set
* @ val : a new xmlXPathObjectPtr
*
* add a new xmlXPathObjectPtr ot an existing LocationSet
*/
void
xmlXPtrLocationSetAdd ( xmlLocationSetPtr cur , xmlXPathObjectPtr val ) {
int i ;
if ( val = = NULL ) return ;
/*
* check against doublons
*/
for ( i = 0 ; i < cur - > locNr ; i + + )
if ( cur - > locTab [ i ] = = val ) return ;
/*
* grow the locTab if needed
*/
if ( cur - > locMax = = 0 ) {
cur - > locTab = ( xmlXPathObjectPtr * ) xmlMalloc ( XML_RANGESET_DEFAULT *
sizeof ( xmlXPathObjectPtr ) ) ;
if ( cur - > locTab = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrLocationSetAdd: out of memory \n " ) ;
return ;
}
memset ( cur - > locTab , 0 ,
XML_RANGESET_DEFAULT * ( size_t ) sizeof ( xmlXPathObjectPtr ) ) ;
cur - > locMax = XML_RANGESET_DEFAULT ;
} else if ( cur - > locNr = = cur - > locMax ) {
xmlXPathObjectPtr * temp ;
cur - > locMax * = 2 ;
temp = ( xmlXPathObjectPtr * ) xmlRealloc ( cur - > locTab , cur - > locMax *
sizeof ( xmlXPathObjectPtr ) ) ;
if ( temp = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrLocationSetAdd: out of memory \n " ) ;
return ;
}
cur - > locTab = temp ;
}
cur - > locTab [ cur - > locNr + + ] = val ;
}
/**
* xmlXPtrLocationSetMerge :
2000-10-12 23:15:24 +00:00
* @ val1 : the first LocationSet
2000-10-11 08:55:02 +00:00
* @ val2 : the second LocationSet
*
* Merges two rangesets , all ranges from @ val2 are added to @ val1
*
* Returns val1 once extended or NULL in case of error .
*/
xmlLocationSetPtr
xmlXPtrLocationSetMerge ( xmlLocationSetPtr val1 , xmlLocationSetPtr val2 ) {
int i ;
2000-10-12 23:15:24 +00:00
if ( val1 = = NULL ) return ( NULL ) ;
2000-10-11 08:55:02 +00:00
if ( val2 = = NULL ) return ( val1 ) ;
/*
* ! ! ! ! ! this can be optimized a lot , knowing that both
* val1 and val2 already have unicity of their values .
*/
for ( i = 0 ; i < val2 - > locNr ; i + + )
xmlXPtrLocationSetAdd ( val1 , val2 - > locTab [ i ] ) ;
return ( val1 ) ;
}
/**
* xmlXPtrLocationSetDel :
* @ cur : the initial range set
* @ val : an xmlXPathObjectPtr
*
* Removes an xmlXPathObjectPtr from an existing LocationSet
*/
void
xmlXPtrLocationSetDel ( xmlLocationSetPtr cur , xmlXPathObjectPtr val ) {
int i ;
if ( cur = = NULL ) return ;
if ( val = = NULL ) return ;
/*
* check against doublons
*/
for ( i = 0 ; i < cur - > locNr ; i + + )
if ( cur - > locTab [ i ] = = val ) break ;
if ( i > = cur - > locNr ) {
# ifdef DEBUG
fprintf ( xmlXPathDebug ,
" xmlXPtrLocationSetDel: Range %s wasn't found in RangeList \n " ,
val - > name ) ;
# endif
return ;
}
cur - > locNr - - ;
for ( ; i < cur - > locNr ; i + + )
cur - > locTab [ i ] = cur - > locTab [ i + 1 ] ;
cur - > locTab [ cur - > locNr ] = NULL ;
}
/**
* xmlXPtrLocationSetRemove :
* @ cur : the initial range set
* @ val : the index to remove
*
* Removes an entry from an existing LocationSet list .
*/
void
xmlXPtrLocationSetRemove ( xmlLocationSetPtr cur , int val ) {
if ( cur = = NULL ) return ;
if ( val > = cur - > locNr ) return ;
cur - > locNr - - ;
for ( ; val < cur - > locNr ; val + + )
cur - > locTab [ val ] = cur - > locTab [ val + 1 ] ;
cur - > locTab [ cur - > locNr ] = NULL ;
}
/**
* xmlXPtrFreeLocationSet :
* @ obj : the xmlLocationSetPtr to free
*
* Free the LocationSet compound ( not the actual ranges ! ) .
*/
void
xmlXPtrFreeLocationSet ( xmlLocationSetPtr obj ) {
int i ;
if ( obj = = NULL ) return ;
if ( obj - > locTab ! = NULL ) {
for ( i = 0 ; i < obj - > locNr ; i + + ) {
xmlXPathFreeObject ( obj - > locTab [ i ] ) ;
}
# ifdef DEBUG
memset ( obj - > locTab , 0xB ,
( size_t ) sizeof ( xmlXPathObjectPtr ) * obj - > locMax ) ;
# endif
xmlFree ( obj - > locTab ) ;
}
# ifdef DEBUG
memset ( obj , 0xB , ( size_t ) sizeof ( xmlLocationSet ) ) ;
# endif
xmlFree ( obj ) ;
}
/**
* xmlXPtrNewLocationSetNodes :
* @ start : the start NodePtr value
* @ end : the end NodePtr value or NULL
*
* Create a new xmlXPathObjectPtr of type LocationSet and initialize
* it with the single range made of the two nodes @ start and @ end
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewLocationSetNodes ( xmlNodePtr start , xmlNodePtr end ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewLocationSetNodes: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_LOCATIONSET ;
if ( end = = NULL )
ret - > user = xmlXPtrLocationSetCreate ( xmlXPtrNewCollapsedRange ( start ) ) ;
else
ret - > user = xmlXPtrLocationSetCreate ( xmlXPtrNewRangeNodes ( start , end ) ) ;
return ( ret ) ;
}
/**
* xmlXPtrNewLocationSetNodeSet :
* @ set : a node set
*
* Create a new xmlXPathObjectPtr of type LocationSet and initialize
* it with all the nodes from @ set
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrNewLocationSetNodeSet ( xmlNodeSetPtr set ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrNewLocationSetNodes: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_LOCATIONSET ;
if ( set ! = NULL ) {
int i ;
xmlLocationSetPtr newset ;
newset = xmlXPtrLocationSetCreate ( NULL ) ;
if ( newset = = NULL )
return ( ret ) ;
for ( i = 0 ; i < set - > nodeNr ; i + + )
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewCollapsedRange ( set - > nodeTab [ i ] ) ) ;
ret - > user = ( void * ) newset ;
}
return ( ret ) ;
}
/**
* xmlXPtrWrapLocationSet :
* @ val : the LocationSet value
*
* Wrap the LocationSet @ val in a new xmlXPathObjectPtr
*
* Returns the newly created object .
*/
xmlXPathObjectPtr
xmlXPtrWrapLocationSet ( xmlLocationSetPtr val ) {
xmlXPathObjectPtr ret ;
ret = ( xmlXPathObjectPtr ) xmlMalloc ( sizeof ( xmlXPathObject ) ) ;
if ( ret = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrWrapLocationSet: out of memory \n " ) ;
return ( NULL ) ;
}
memset ( ret , 0 , ( size_t ) sizeof ( xmlXPathObject ) ) ;
ret - > type = XPATH_LOCATIONSET ;
ret - > user = ( void * ) val ;
return ( ret ) ;
}
/************************************************************************
* *
* The parser *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Macros for accessing the content . Those should be used only by the parser ,
* and not exported .
*
* Dirty macros , i . e . one need to make assumption on the context to use them
*
* CUR_PTR return the current pointer to the xmlChar to be parsed .
* CUR returns the current xmlChar value , i . e . a 8 bit value
* in ISO - Latin or UTF - 8.
* This should be used internally by the parser
* only to compare to ASCII values otherwise it would break when
* running with UTF - 8 encoding .
* NXT ( n ) returns the n ' th next xmlChar . Same as CUR is should be used only
* to compare on ASCII based substring .
* SKIP ( n ) Skip n xmlChar , and must also be used only to skip ASCII defined
* strings within the parser .
* CURRENT Returns the current char value , with the full decoding of
* UTF - 8 if we are using this mode . It returns an int .
* NEXT Skip to the next character , this does the proper decoding
* in UTF - 8 mode . It also pop - up unfinished entities on the fly .
* It returns the pointer to the current xmlChar .
*/
# define CUR (*ctxt->cur)
# define SKIP(val) ctxt->cur += (val)
# define NXT(val) ctxt->cur[(val)]
# define CUR_PTR ctxt->cur
# define SKIP_BLANKS \
while ( IS_BLANK ( * ( ctxt - > cur ) ) ) NEXT
# define CURRENT (*ctxt->cur)
# define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
/*
* xmlXPtrGetChildNo :
* @ ctxt : the XPointer Parser context
* @ index : the child number
*
* Move the current node of the nodeset on the stack to the
* given child if found
*/
void
xmlXPtrGetChildNo ( xmlXPathParserContextPtr ctxt , int index ) {
xmlNodePtr cur = NULL ;
xmlXPathObjectPtr obj ;
xmlNodeSetPtr oldset ;
CHECK_TYPE ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > nodesetval ;
if ( ( index < = 0 ) | | ( oldset = = NULL ) | | ( oldset - > nodeNr ! = 1 ) ) {
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPathNewNodeSet ( NULL ) ) ;
return ;
}
2000-10-12 23:15:24 +00:00
cur = xmlXPtrGetNthChild ( oldset - > nodeTab [ 0 ] , index ) ;
2000-10-11 08:55:02 +00:00
if ( cur = = NULL ) {
xmlXPathFreeObject ( obj ) ;
valuePush ( ctxt , xmlXPathNewNodeSet ( NULL ) ) ;
return ;
}
oldset - > nodeTab [ 0 ] = cur ;
valuePush ( ctxt , obj ) ;
}
/**
* xmlXPtrEvalXPtrPart :
* @ ctxt : the XPointer Parser context
* @ name : the preparsed Scheme for the XPtrPart
*
* XPtrPart : : = ' xpointer ' ' ( ' XPtrExpr ' ) '
* | Scheme ' ( ' SchemeSpecificExpr ' ) '
*
* Scheme : : = NCName - ' xpointer ' [ VC : Non - XPointer schemes ]
*
* SchemeSpecificExpr : : = StringWithBalancedParens
*
* StringWithBalancedParens : : =
* [ ^ ( ) ] * ( ' ( ' StringWithBalancedParens ' ) ' [ ^ ( ) ] * ) *
* [ VC : Parenthesis escaping ]
*
* XPtrExpr : : = Expr [ VC : Parenthesis escaping ]
*
* VC : Parenthesis escaping :
* The end of an XPointer part is signaled by the right parenthesis " ) "
* character that is balanced with the left parenthesis " ( " character
* that began the part . Any unbalanced parenthesis character inside the
* expression , even within literals , must be escaped with a circumflex ( ^ )
* character preceding it . If the expression contains any literal
* occurrences of the circumflex , each must be escaped with an additional
* circumflex ( that is , ^ ^ ) . If the unescaped parentheses in the expression
* are not balanced , a syntax error results .
*
* Parse and evaluate an XPtrPart . Basically it generates the unescaped
* string and if the scheme is ' xpointer ' it will call the XPath interprter .
*
* TODO : there is no new scheme registration mechanism
*/
void
xmlXPtrEvalXPtrPart ( xmlXPathParserContextPtr ctxt , xmlChar * name ) {
xmlChar * buffer , * cur ;
int len ;
int level ;
if ( name = = NULL )
2000-10-11 10:54:10 +00:00
name = xmlXPathParseName ( ctxt ) ;
2000-10-11 08:55:02 +00:00
if ( name = = NULL )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
if ( CUR ! = ' ( ' )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
NEXT ;
level = 1 ;
len = xmlStrlen ( ctxt - > cur ) ;
len + + ;
buffer = ( xmlChar * ) xmlMalloc ( len * sizeof ( xmlChar ) ) ;
if ( buffer = = NULL ) {
fprintf ( xmlXPathDebug , " xmlXPtrEvalXPtrPart: out of memory \n " ) ;
return ;
}
cur = buffer ;
while ( CUR ! = ' 0 ' ) {
if ( CUR = = ' ) ' ) {
level - - ;
if ( level = = 0 ) {
NEXT ;
break ;
}
* cur + + = CUR ;
} else if ( CUR = = ' ( ' ) {
level + + ;
* cur + + = CUR ;
} else if ( CUR = = ' ^ ' ) {
NEXT ;
if ( ( CUR = = ' ) ' ) | | ( CUR = = ' ( ' ) | | ( CUR = = ' ^ ' ) ) {
* cur + + = CUR ;
} else {
* cur + + = ' ^ ' ;
* cur + + = CUR ;
}
} else {
* cur + + = CUR ;
}
NEXT ;
}
* cur = 0 ;
if ( ( level ! = 0 ) & & ( CUR = = 0 ) ) {
xmlFree ( buffer ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
if ( xmlStrEqual ( name , ( xmlChar * ) " xpointer " ) ) {
const xmlChar * left = CUR_PTR ;
CUR_PTR = buffer ;
2000-10-12 23:15:24 +00:00
xmlXPathRoot ( ctxt ) ;
2000-10-11 08:55:02 +00:00
xmlXPathEvalExpr ( ctxt ) ;
CUR_PTR = left ;
} else {
fprintf ( xmlXPathDebug , " unsupported scheme '%s' \n " , name ) ;
}
xmlFree ( buffer ) ;
xmlFree ( name ) ;
}
/**
* xmlXPtrEvalFullXPtr :
* @ ctxt : the XPointer Parser context
* @ name : the preparsed Scheme for the first XPtrPart
*
* FullXPtr : : = XPtrPart ( S ? XPtrPart ) *
*
* As the specs says :
* - - - - - - - - - - -
* When multiple XPtrParts are provided , they must be evaluated in
* left - to - right order . If evaluation of one part fails , the nexti
* is evaluated . The following conditions cause XPointer part failure :
*
* - An unknown scheme
* - A scheme that does not locate any sub - resource present in the resource
* - A scheme that is not applicable to the media type of the resource
*
* The XPointer application must consume a failed XPointer part and
* attempt to evaluate the next one , if any . The result of the first
* XPointer part whose evaluation succeeds is taken to be the fragment
* located by the XPointer as a whole . If all the parts fail , the result
* for the XPointer as a whole is a sub - resource error .
* - - - - - - - - - - -
*
* Parse and evaluate a Full XPtr i . e . possibly a cascade of XPath based
* expressions or other shemes .
*/
void
xmlXPtrEvalFullXPtr ( xmlXPathParserContextPtr ctxt , xmlChar * name ) {
if ( name = = NULL )
2000-10-11 10:54:10 +00:00
name = xmlXPathParseName ( ctxt ) ;
2000-10-11 08:55:02 +00:00
if ( name = = NULL )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
while ( name ! = NULL ) {
xmlXPtrEvalXPtrPart ( ctxt , name ) ;
/* in case of syntax error, break here */
if ( ctxt - > error ! = XPATH_EXPRESSION_OK )
return ;
/*
* If the returned value is a non - empty nodeset
* or location set , return here .
*/
if ( ctxt - > value ! = NULL ) {
xmlXPathObjectPtr obj = ctxt - > value ;
switch ( obj - > type ) {
case XPATH_LOCATIONSET : {
xmlLocationSetPtr loc = ctxt - > value - > user ;
if ( ( loc ! = NULL ) & & ( loc - > locNr > 0 ) )
return ;
break ;
}
case XPATH_NODESET : {
xmlNodeSetPtr loc = ctxt - > value - > nodesetval ;
if ( ( loc ! = NULL ) & & ( loc - > nodeNr > 0 ) )
return ;
break ;
}
default :
break ;
}
/*
* Evaluating to improper values is equivalent to
* a sub - resource error , clean - up the stack
*/
do {
obj = valuePop ( ctxt ) ;
if ( obj ! = NULL ) {
xmlXPathFreeObject ( obj ) ;
}
} while ( obj ! = NULL ) ;
}
/*
* Is there another XPoointer part .
*/
SKIP_BLANKS ;
2000-10-11 10:54:10 +00:00
name = xmlXPathParseName ( ctxt ) ;
2000-10-11 08:55:02 +00:00
}
}
/**
* xmlXPtrEvalChildSeq :
* @ ctxt : the XPointer Parser context
* @ name : a possible ID name of the child sequence
*
* ChildSeq : : = ' / 1 ' ( ' / ' [ 0 - 9 ] * ) *
* | Name ( ' / ' [ 0 - 9 ] * ) +
*
* Parse and evaluate a Child Sequence . This routine also handle the
* case of a Bare Name used to get a document ID .
*/
void
xmlXPtrEvalChildSeq ( xmlXPathParserContextPtr ctxt , xmlChar * name ) {
/*
* XPointer don ' t allow by syntax to adress in mutirooted trees
* this might prove useful in some cases , warn about it .
*/
if ( ( name = = NULL ) & & ( CUR = = ' / ' ) & & ( NXT ( 1 ) ! = ' 1 ' ) ) {
fprintf ( xmlXPathDebug , " warning: ChildSeq not starting by /1 \n " ) ;
}
if ( name ! = NULL ) {
valuePush ( ctxt , xmlXPathNewString ( name ) ) ;
xmlFree ( name ) ;
xmlXPathIdFunction ( ctxt , 1 ) ;
CHECK_ERROR ;
}
while ( CUR = = ' / ' ) {
int child = 0 ;
NEXT ;
while ( ( CUR > = ' 0 ' ) & & ( CUR < = ' 9 ' ) ) {
child = child * 10 + ( CUR - ' 0 ' ) ;
NEXT ;
}
xmlXPtrGetChildNo ( ctxt , child ) ;
}
}
/**
* xmlXPtrEvalXPointer :
* @ ctxt : the XPointer Parser context
*
* XPointer : : = Name
* | ChildSeq
* | FullXPtr
*
* Parse and evaluate an XPointer
*/
void
xmlXPtrEvalXPointer ( xmlXPathParserContextPtr ctxt ) {
SKIP_BLANKS ;
if ( CUR = = ' / ' ) {
xmlXPathRoot ( ctxt ) ;
xmlXPtrEvalChildSeq ( ctxt , NULL ) ;
} else {
xmlChar * name ;
2000-10-11 10:54:10 +00:00
name = xmlXPathParseName ( ctxt ) ;
2000-10-11 08:55:02 +00:00
if ( name = = NULL )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
if ( CUR = = ' ( ' ) {
xmlXPtrEvalFullXPtr ( ctxt , name ) ;
/* Short evaluation */
return ;
} else {
/* this handle both Bare Names and Child Sequences */
xmlXPtrEvalChildSeq ( ctxt , name ) ;
}
}
SKIP_BLANKS ;
if ( CUR ! = 0 )
XP_ERROR ( XPATH_EXPR_ERROR ) ;
}
/************************************************************************
* *
* General routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-10-12 23:15:24 +00:00
void xmlXPtrRangeToFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrStringRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrStartPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrEndPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrHereFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrOriginFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
2000-10-15 20:38:39 +00:00
void xmlXPtrRangeInsideFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
void xmlXPtrRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) ;
2000-10-12 23:15:24 +00:00
2000-10-11 08:55:02 +00:00
/**
* xmlXPtrNewContext :
* @ doc : the XML document
* @ here : the node that directly contains the XPointer being evaluated or NULL
* @ origin : the element from which a user or program initiated traversal of
* the link , or NULL .
*
* Create a new XPointer context
*
* Returns the xmlXPathContext just allocated .
*/
xmlXPathContextPtr
xmlXPtrNewContext ( xmlDocPtr doc , xmlNodePtr here , xmlNodePtr origin ) {
xmlXPathContextPtr ret ;
ret = xmlXPathNewContext ( doc ) ;
if ( ret = = NULL )
return ( ret ) ;
ret - > xptr = 1 ;
ret - > here = here ;
ret - > origin = origin ;
2000-10-12 23:15:24 +00:00
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " range-to " ,
xmlXPtrRangeToFunction ) ;
2000-10-15 20:38:39 +00:00
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " range " ,
xmlXPtrRangeFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " range-inside " ,
xmlXPtrRangeInsideFunction ) ;
2000-10-12 23:15:24 +00:00
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " string-range " ,
xmlXPtrStringRangeFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " start-point " ,
xmlXPtrStartPointFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " end-point " ,
xmlXPtrEndPointFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " here " ,
xmlXPtrHereFunction ) ;
xmlXPathRegisterFunc ( ret , ( xmlChar * ) " origin " ,
xmlXPtrOriginFunction ) ;
2000-10-11 08:55:02 +00:00
return ( ret ) ;
}
/**
* xmlXPtrEval :
* @ str : the XPointer expression
* @ ctx : the XPointer context
*
* Evaluate the XPath Location Path in the given context .
*
* Returns the xmlXPathObjectPtr resulting from the eveluation or NULL .
* the caller has to free the object .
*/
xmlXPathObjectPtr
xmlXPtrEval ( const xmlChar * str , xmlXPathContextPtr ctx ) {
xmlXPathParserContextPtr ctxt ;
xmlXPathObjectPtr res = NULL , tmp ;
xmlXPathObjectPtr init = NULL ;
int stack = 0 ;
xmlXPathInit ( ) ;
if ( ( ctx = = NULL ) | | ( str = = NULL ) )
return ( NULL ) ;
if ( xmlXPathDebug = = NULL )
xmlXPathDebug = stderr ;
ctxt = xmlXPathNewParserContext ( str , ctx ) ;
if ( ctx - > node ! = NULL ) {
init = xmlXPathNewNodeSet ( ctx - > node ) ;
valuePush ( ctxt , init ) ;
}
xmlXPtrEvalXPointer ( ctxt ) ;
if ( ( ctxt - > value ! = NULL ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) & &
( ctxt - > value - > type ! = XPATH_LOCATIONSET ) ) {
fprintf ( xmlXPathDebug ,
" xmlXPtrEval: evaluation failed to return a node set \n " ) ;
} else {
res = valuePop ( ctxt ) ;
}
do {
tmp = valuePop ( ctxt ) ;
if ( tmp ! = NULL ) {
2000-10-12 23:15:24 +00:00
if ( tmp ! = init ) {
if ( tmp - > type = = XPATH_NODESET ) {
/*
* Evaluation may push a root nodeset which is unused
*/
xmlNodeSetPtr set ;
set = tmp - > nodesetval ;
if ( ( set - > nodeNr ! = 1 ) | |
( set - > nodeTab [ 0 ] ! = ( xmlNodePtr ) ctx - > doc ) )
stack + + ;
} else
stack + + ;
}
2000-10-11 08:55:02 +00:00
xmlXPathFreeObject ( tmp ) ;
}
} while ( tmp ! = NULL ) ;
if ( stack ! = 0 ) {
fprintf ( xmlXPathDebug , " xmlXPtrEval: %d object left on the stack \n " ,
stack ) ;
}
if ( ctxt - > error ! = XPATH_EXPRESSION_OK ) {
xmlXPathFreeObject ( res ) ;
res = NULL ;
}
xmlXPathFreeParserContext ( ctxt ) ;
return ( res ) ;
}
/************************************************************************
* *
* XPointer functions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* xmlXPtrNbLocChildren :
* @ node : an xmlNodePtr
*
* Count the number of location children of @ node or the lenght of the
* string value in case of text / PI / Comments nodes
*
* Returns the number of location children
*/
int
xmlXPtrNbLocChildren ( xmlNodePtr node ) {
int ret = 0 ;
if ( node = = NULL )
return ( - 1 ) ;
switch ( node - > type ) {
case XML_HTML_DOCUMENT_NODE :
case XML_DOCUMENT_NODE :
case XML_ELEMENT_NODE :
node = node - > children ;
while ( node ! = NULL ) {
if ( node - > type = = XML_ELEMENT_NODE )
ret + + ;
node = node - > next ;
}
break ;
case XML_ATTRIBUTE_NODE :
return ( - 1 ) ;
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
# ifndef XML_USE_BUFFER_CONTENT
ret = xmlStrlen ( node - > content ) ;
# else
ret = xmlBufferLength ( node - > content ) ;
# endif
break ;
default :
return ( - 1 ) ;
}
return ( ret ) ;
}
/**
2000-10-12 23:15:24 +00:00
* xmlXPtrHereFunction :
2000-10-11 08:55:02 +00:00
* @ ctxt : the XPointer Parser context
*
* Function implementing here ( ) operation
* as described in 5.4 .3
*/
void
2000-10-12 23:15:24 +00:00
xmlXPtrHereFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2000-10-11 08:55:02 +00:00
if ( ctxt - > context - > here = = NULL )
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
valuePush ( ctxt , xmlXPtrNewLocationSetNodes ( ctxt - > context - > here , NULL ) ) ;
}
/**
2000-10-12 23:15:24 +00:00
* xmlXPtrOriginFunction :
2000-10-11 08:55:02 +00:00
* @ ctxt : the XPointer Parser context
*
* Function implementing origin ( ) operation
* as described in 5.4 .3
*/
void
2000-10-12 23:15:24 +00:00
xmlXPtrOriginFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2000-10-11 08:55:02 +00:00
if ( ctxt - > context - > origin = = NULL )
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
valuePush ( ctxt , xmlXPtrNewLocationSetNodes ( ctxt - > context - > origin , NULL ) ) ;
}
/**
2000-10-12 23:15:24 +00:00
* xmlXPtrStartPointFunction :
2000-10-11 08:55:02 +00:00
* @ ctxt : the XPointer Parser context
*
* Function implementing start - point ( ) operation
* as described in 5.4 .3
* - - - - - - - - - - - - - - - -
* location - set start - point ( location - set )
*
* For each location x in the argument location - set , start - point adds a
* location of type point to the result location - set . That point represents
* the start point of location x and is determined by the following rules :
*
* - If x is of type point , the start point is x .
* - If x is of type range , the start point is the start point of x .
* - If x is of type root , element , text , comment , or processing instruction ,
* - the container node of the start point is x and the index is 0.
* - If x is of type attribute or namespace , the function must signal a
* syntax error .
* - - - - - - - - - - - - - - - -
*
*/
void
2000-10-12 23:15:24 +00:00
xmlXPtrStartPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2000-10-11 08:55:02 +00:00
xmlXPathObjectPtr tmp , obj , point ;
xmlLocationSetPtr newset = NULL ;
xmlLocationSetPtr oldset = NULL ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
obj = valuePop ( ctxt ) ;
if ( obj - > type = = XPATH_NODESET ) {
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( obj - > nodesetval ) ;
xmlXPathFreeObject ( obj ) ;
obj = tmp ;
}
newset = xmlXPtrLocationSetCreate ( NULL ) ;
oldset = ( xmlLocationSetPtr ) obj - > user ;
if ( oldset ! = NULL ) {
int i ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
tmp = oldset - > locTab [ i ] ;
if ( tmp = = NULL )
continue ;
point = NULL ;
switch ( tmp - > type ) {
case XPATH_POINT :
point = xmlXPtrNewPoint ( tmp - > user , tmp - > index ) ;
break ;
case XPATH_RANGE : {
xmlNodePtr node = tmp - > user ;
if ( node ! = NULL ) {
if ( node - > type = = XML_ATTRIBUTE_NODE ) {
/* TODO: Namespace Nodes ??? */
xmlXPathFreeObject ( obj ) ;
xmlXPtrFreeLocationSet ( newset ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
point = xmlXPtrNewPoint ( node , tmp - > index ) ;
}
if ( tmp - > user2 = = NULL ) {
point = xmlXPtrNewPoint ( node , 0 ) ;
} else
point = xmlXPtrNewPoint ( node , tmp - > index ) ;
break ;
}
default :
/*** Should we raise an error ?
xmlXPathFreeObject ( obj ) ;
xmlXPathFreeObject ( newset ) ;
XP_ERROR ( XPATH_INVALID_TYPE )
* * */
break ;
}
if ( point ! = NULL )
xmlXPtrLocationSetAdd ( newset , point ) ;
}
}
xmlXPathFreeObject ( obj ) ;
}
/**
2000-10-12 23:15:24 +00:00
* xmlXPtrEndPointFunction :
2000-10-11 08:55:02 +00:00
* @ ctxt : the XPointer Parser context
*
* Function implementing end - point ( ) operation
* as described in 5.4 .3
* - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* location - set end - point ( location - set )
*
* For each location x in the argument location - set , end - point adds a
* location of type point to the result location - set . That point representsi
* the end point of location x and is determined by the following rules :
*
* - If x is of type point , the resulting point is x .
* - If x is of type range , the resulting point is the end point of x .
* - If x is of type root or element , the container node of the resulting
* point is x and the index is the number of location children of x .
* - If x is of type text , comment , or processing instruction , the container
* node of the resulting point is x and the index is the length of thei
* string - value of x .
* - If x is of type attribute or namespace , the function must signal a
* syntax error .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
2000-10-12 23:15:24 +00:00
xmlXPtrEndPointFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
2000-10-11 08:55:02 +00:00
xmlXPathObjectPtr tmp , obj , point ;
xmlLocationSetPtr newset = NULL ;
xmlLocationSetPtr oldset = NULL ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
obj = valuePop ( ctxt ) ;
if ( obj - > type = = XPATH_NODESET ) {
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( obj - > nodesetval ) ;
xmlXPathFreeObject ( obj ) ;
obj = tmp ;
}
newset = xmlXPtrLocationSetCreate ( NULL ) ;
oldset = ( xmlLocationSetPtr ) obj - > user ;
if ( oldset ! = NULL ) {
int i ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
tmp = oldset - > locTab [ i ] ;
if ( tmp = = NULL )
continue ;
point = NULL ;
switch ( tmp - > type ) {
case XPATH_POINT :
point = xmlXPtrNewPoint ( tmp - > user , tmp - > index ) ;
break ;
case XPATH_RANGE : {
xmlNodePtr node = tmp - > user ;
if ( node ! = NULL ) {
if ( node - > type = = XML_ATTRIBUTE_NODE ) {
/* TODO: Namespace Nodes ??? */
xmlXPathFreeObject ( obj ) ;
xmlXPtrFreeLocationSet ( newset ) ;
XP_ERROR ( XPTR_SYNTAX_ERROR ) ;
}
point = xmlXPtrNewPoint ( node , tmp - > index ) ;
}
if ( tmp - > user2 = = NULL ) {
point = xmlXPtrNewPoint ( node ,
xmlXPtrNbLocChildren ( node ) ) ;
} else
point = xmlXPtrNewPoint ( node , tmp - > index ) ;
break ;
}
default :
/*** Should we raise an error ?
xmlXPathFreeObject ( obj ) ;
xmlXPathFreeObject ( newset ) ;
XP_ERROR ( XPATH_INVALID_TYPE )
* * */
break ;
}
if ( point ! = NULL )
xmlXPtrLocationSetAdd ( newset , point ) ;
}
}
xmlXPathFreeObject ( obj ) ;
}
2000-10-15 20:38:39 +00:00
2000-10-11 08:55:02 +00:00
/**
* xmlXPtrCoveringRange :
* @ ctxt : the XPointer Parser context
2000-10-15 20:38:39 +00:00
* @ loc : the location for which the covering range must be computed
*
* A covering range is a range that wholly encompasses a location
* Section 5.3 .3 . Covering Ranges for All Location Types
* http : //www.w3.org/TR/xptr#N2267
*
* Returns a new location or NULL in case of error
*/
xmlXPathObjectPtr
xmlXPtrCoveringRange ( xmlXPathParserContextPtr ctxt , xmlXPathObjectPtr loc ) {
if ( loc = = NULL )
return ( NULL ) ;
if ( ( ctxt = = NULL ) | | ( ctxt - > context = = NULL ) | |
( ctxt - > context - > doc = = NULL ) )
return ( NULL ) ;
switch ( loc - > type ) {
case XPATH_POINT :
return ( xmlXPtrNewRange ( loc - > user , loc - > index ,
loc - > user , loc - > index ) ) ;
case XPATH_RANGE :
if ( loc - > user2 ! = NULL ) {
return ( xmlXPtrNewRange ( loc - > user , loc - > index ,
loc - > user2 , loc - > index2 ) ) ;
} else {
xmlNodePtr node = ( xmlNodePtr ) loc - > user ;
if ( node = = ( xmlNodePtr ) ctxt - > context - > doc ) {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
} else {
switch ( node - > type ) {
case XML_ATTRIBUTE_NODE :
/* !!! our model is slightly different than XPath */
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
case XML_ELEMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE :
case XML_ENTITY_REF_NODE :
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_DOCUMENT_NODE :
case XML_NOTATION_NODE :
case XML_HTML_DOCUMENT_NODE : {
int index = xmlXPtrGetIndex ( node ) ;
node = node - > parent ;
return ( xmlXPtrNewRange ( node , index - 1 ,
node , index + 1 ) ) ;
}
default :
return ( NULL ) ;
}
}
}
default :
TODO /* missed one case ??? */
}
return ( NULL ) ;
}
/**
* xmlXPtrRangeFunction :
* @ ctxt : the XPointer Parser context
*
* Function implementing the range ( ) function 5.4 .3
* location - set range ( location - set )
*
* The range function returns ranges covering the locations in
* the argument location - set . For each location x in the argument
* location - set , a range location representing the covering range of
* x is added to the result location - set .
*/
void
xmlXPtrRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
int i ;
xmlXPathObjectPtr set ;
xmlLocationSetPtr oldset ;
xmlLocationSetPtr newset ;
CHECK_ARITY ( 1 ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
set = valuePop ( ctxt ) ;
if ( set - > type = = XPATH_NODESET ) {
xmlXPathObjectPtr tmp ;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( set - > nodesetval ) ;
xmlXPathFreeObject ( set ) ;
set = tmp ;
}
oldset = ( xmlLocationSetPtr ) set - > user ;
/*
* The loop is to compute the covering range for each item and add it
*/
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrCoveringRange ( ctxt , oldset - > locTab [ i ] ) ) ;
}
/*
* Save the new value and cleanup
*/
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
xmlXPathFreeObject ( set ) ;
}
/**
* xmlXPtrInsideRange :
* @ ctxt : the XPointer Parser context
* @ loc : the location for which the inside range must be computed
*
* A inside range is a range described in the range - inside ( ) description
*
* Returns a new location or NULL in case of error
*/
xmlXPathObjectPtr
xmlXPtrInsideRange ( xmlXPathParserContextPtr ctxt , xmlXPathObjectPtr loc ) {
if ( loc = = NULL )
return ( NULL ) ;
if ( ( ctxt = = NULL ) | | ( ctxt - > context = = NULL ) | |
( ctxt - > context - > doc = = NULL ) )
return ( NULL ) ;
switch ( loc - > type ) {
case XPATH_POINT : {
xmlNodePtr node = ( xmlNodePtr ) loc - > user ;
switch ( node - > type ) {
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE : {
if ( node - > content = = NULL ) {
return ( xmlXPtrNewRange ( node , 0 , node , 0 ) ) ;
} else {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlStrlen ( node - > content ) ) ) ;
}
}
case XML_ATTRIBUTE_NODE :
case XML_ELEMENT_NODE :
case XML_ENTITY_REF_NODE :
case XML_DOCUMENT_NODE :
case XML_NOTATION_NODE :
case XML_HTML_DOCUMENT_NODE : {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
}
default :
return ( NULL ) ;
}
return ( NULL ) ;
}
case XPATH_RANGE : {
xmlNodePtr node = ( xmlNodePtr ) loc - > user ;
if ( loc - > user2 ! = NULL ) {
return ( xmlXPtrNewRange ( node , loc - > index ,
loc - > user2 , loc - > index2 ) ) ;
} else {
switch ( node - > type ) {
case XML_PI_NODE :
case XML_COMMENT_NODE :
case XML_TEXT_NODE :
case XML_CDATA_SECTION_NODE : {
if ( node - > content = = NULL ) {
return ( xmlXPtrNewRange ( node , 0 , node , 0 ) ) ;
} else {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlStrlen ( node - > content ) ) ) ;
}
}
case XML_ATTRIBUTE_NODE :
case XML_ELEMENT_NODE :
case XML_ENTITY_REF_NODE :
case XML_DOCUMENT_NODE :
case XML_NOTATION_NODE :
case XML_HTML_DOCUMENT_NODE : {
return ( xmlXPtrNewRange ( node , 0 , node ,
xmlXPtrGetArity ( node ) ) ) ;
}
default :
return ( NULL ) ;
}
return ( NULL ) ;
}
}
default :
TODO /* missed one case ??? */
}
return ( NULL ) ;
}
/**
* xmlXPtrRangeInsideFunction :
* @ ctxt : the XPointer Parser context
*
* Function implementing the range - inside ( ) function 5.4 .3
* location - set range - inside ( location - set )
*
* The range - inside function returns ranges covering the contents of
* the locations in the argument location - set . For each location x in
* the argument location - set , a range location is added to the result
* location - set . If x is a range location , then x is added to the
* result location - set . If x is not a range location , then x is used
* as the container location of the start and end points of the range
* location to be added ; the index of the start point of the range is
* zero ; if the end point is a character point then its index is the
* length of the string - value of x , and otherwise is the number of
* location children of x .
2000-10-11 08:55:02 +00:00
*
*/
void
2000-10-15 20:38:39 +00:00
xmlXPtrRangeInsideFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
int i ;
xmlXPathObjectPtr set ;
xmlLocationSetPtr oldset ;
xmlLocationSetPtr newset ;
2000-10-11 08:55:02 +00:00
CHECK_ARITY ( 1 ) ;
2000-10-15 20:38:39 +00:00
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
set = valuePop ( ctxt ) ;
if ( set - > type = = XPATH_NODESET ) {
xmlXPathObjectPtr tmp ;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( set - > nodesetval ) ;
xmlXPathFreeObject ( set ) ;
set = tmp ;
}
oldset = ( xmlLocationSetPtr ) set - > user ;
/*
* The loop is to compute the covering range for each item and add it
*/
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrInsideRange ( ctxt , oldset - > locTab [ i ] ) ) ;
}
/*
* Save the new value and cleanup
*/
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
xmlXPathFreeObject ( set ) ;
2000-10-11 08:55:02 +00:00
}
/**
* xmlXPtrRangeToFunction :
* @ ctxt : the XPointer Parser context
*
* Implement the range - to ( ) XPointer function
*/
void
xmlXPtrRangeToFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
xmlXPathObjectPtr range ;
const xmlChar * cur ;
xmlXPathObjectPtr res , obj ;
xmlXPathObjectPtr tmp ;
xmlLocationSetPtr newset = NULL ;
xmlNodeSetPtr oldset ;
int i ;
CHECK_ARITY ( 1 ) ;
/*
* Save the expression pointer since we will have to evaluate
* it multiple times . Initialize the new set .
*/
CHECK_TYPE ( XPATH_NODESET ) ;
obj = valuePop ( ctxt ) ;
oldset = obj - > nodesetval ;
ctxt - > context - > node = NULL ;
cur = ctxt - > cur ;
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > nodeNr ; i + + ) {
ctxt - > cur = cur ;
/*
* Run the evaluation with a node list made of a single item
* in the nodeset .
*/
ctxt - > context - > node = oldset - > nodeTab [ i ] ;
tmp = xmlXPathNewNodeSet ( ctxt - > context - > node ) ;
valuePush ( ctxt , tmp ) ;
xmlXPathEvalExpr ( ctxt ) ;
CHECK_ERROR ;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop ( ctxt ) ;
range = xmlXPtrNewRangeNodeObject ( oldset - > nodeTab [ i ] , res ) ;
if ( range ! = NULL ) {
xmlXPtrLocationSetAdd ( newset , range ) ;
}
/*
* Cleanup
*/
if ( res ! = NULL )
xmlXPathFreeObject ( res ) ;
if ( ctxt - > value = = tmp ) {
res = valuePop ( ctxt ) ;
xmlXPathFreeObject ( res ) ;
}
ctxt - > context - > node = NULL ;
}
/*
* The result is used as the new evaluation set .
*/
xmlXPathFreeObject ( obj ) ;
ctxt - > context - > node = NULL ;
ctxt - > context - > contextSize = - 1 ;
ctxt - > context - > proximityPosition = - 1 ;
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
}
2000-10-12 23:15:24 +00:00
/**
* xmlXPtrAdvanceNode :
* @ cur : the node
*
* Advance to the next element or text node in document order
* TODO : add a stack for entering / exiting entities
*
* Returns - 1 in case of failure , 0 otherwise
*/
xmlNodePtr
xmlXPtrAdvanceNode ( xmlNodePtr cur ) {
next :
if ( cur = = NULL )
return ( NULL ) ;
if ( cur - > children ! = NULL ) {
cur = cur - > children ;
goto found ;
}
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
goto found ;
}
do {
cur = cur - > parent ;
if ( cur = = NULL ) return ( NULL ) ;
if ( cur - > next ! = NULL ) {
cur = cur - > next ;
goto found ;
}
} while ( cur ! = NULL ) ;
found :
if ( ( cur - > type ! = XML_ELEMENT_NODE ) & &
( cur - > type ! = XML_TEXT_NODE ) & &
( cur - > type ! = XML_DOCUMENT_NODE ) & &
( cur - > type ! = XML_HTML_DOCUMENT_NODE ) & &
( cur - > type ! = XML_CDATA_SECTION_NODE ) )
goto next ;
if ( cur - > type = = XML_ENTITY_REF_NODE ) {
TODO
}
return ( cur ) ;
}
/**
* xmlXPtrAdvanceChar :
* @ node : the node
* @ index : the index
* @ bytes : the number of bytes
*
* Advance a point of the associated number of bytes ( not UTF8 chars )
*
* Returns - 1 in case of failure , 0 otherwise
*/
int
xmlXPtrAdvanceChar ( xmlNodePtr * node , int * index , int bytes ) {
xmlNodePtr cur ;
int pos ;
int len ;
if ( ( node = = NULL ) | | ( index = = NULL ) )
return ( - 1 ) ;
cur = * node ;
if ( cur = = NULL )
return ( - 1 ) ;
pos = * index ;
while ( bytes > = 0 ) {
/*
* First position to the beginning of the first text node
* corresponding to this point
*/
while ( ( cur ! = NULL ) & &
( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) ) {
if ( pos > 0 ) {
cur = xmlXPtrGetNthChild ( cur , pos ) ;
pos = 0 ;
} else {
cur = xmlXPtrAdvanceNode ( cur ) ;
pos = 0 ;
}
}
if ( cur = = NULL ) {
* node = NULL ;
* index = 0 ;
return ( - 1 ) ;
}
/*
* if there is no move needed return the current value .
*/
if ( pos = = 0 ) pos = 1 ;
if ( bytes = = 0 ) {
* node = cur ;
* index = pos ;
return ( 0 ) ;
}
/*
* We should have a text ( or cdata ) node . . .
*/
len = 0 ;
if ( cur - > content ! = NULL ) {
len = xmlStrlen ( cur - > content ) ;
}
if ( pos > len ) {
/* Strange, the index in the text node is greater than it's len */
STRANGE
pos = len ;
}
if ( pos + bytes > = len ) {
bytes - = ( len - pos ) ;
cur = xmlXPtrAdvanceNode ( cur ) ;
cur = 0 ;
}
}
return ( - 1 ) ;
}
/**
* xmlXPtrMatchString :
* @ string : the string to search
* @ start : the start textnode
* @ startindex : the start index
* @ end : the end textnode IN / OUT
* @ endindex : the end index IN / OUT
*
* Check whether the document contains @ string at the position
* ( @ start , @ startindex ) and limited by the ( @ end , @ endindex ) point
*
* Returns - 1 in case of failure , 0 if not found , 1 if found in which case
* ( @ start , @ startindex ) will indicate the position of the beginning
* of the range and ( @ end , @ endindex ) will endicate the end
* of the range
*/
int
xmlXPtrMatchString ( const xmlChar * string , xmlNodePtr start , int startindex ,
xmlNodePtr * end , int * endindex ) {
xmlNodePtr cur ;
int pos ; /* 0 based */
int len ; /* in bytes */
int stringlen ; /* in bytes */
int match ;
if ( string = = NULL )
return ( - 1 ) ;
if ( start = = NULL )
return ( - 1 ) ;
if ( ( end = = NULL ) | | ( endindex = = NULL ) )
return ( - 1 ) ;
cur = start ;
if ( cur = = NULL )
return ( - 1 ) ;
pos = startindex - 1 ;
stringlen = xmlStrlen ( string ) ;
while ( stringlen > 0 ) {
if ( ( cur = = * end ) & & ( pos + stringlen > * endindex ) )
return ( 0 ) ;
if ( cur - > content ! = NULL ) {
len = xmlStrlen ( cur - > content ) ;
if ( len > = pos + stringlen ) {
match = ( ! xmlStrncmp ( & cur - > content [ pos ] , string , stringlen ) ) ;
if ( match ) {
# ifdef DEBUG_RANGES
fprintf ( stdout , " found range %d bytes at index %d of -> " ,
stringlen , pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
fprintf ( stdout , " \n " ) ;
# endif
* end = cur ;
* endindex = pos + stringlen ;
return ( 1 ) ;
} else {
return ( 0 ) ;
}
} else {
int sub = len - pos ;
match = ( ! xmlStrncmp ( & cur - > content [ pos ] , string , sub ) ) ;
if ( match ) {
# ifdef DEBUG_RANGES
fprintf ( stdout , " found subrange %d bytes at index %d of -> " ,
sub , pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
fprintf ( stdout , " \n " ) ;
# endif
string = & string [ sub ] ;
stringlen - = sub ;
} else {
return ( 0 ) ;
}
}
}
cur = xmlXPtrAdvanceNode ( cur ) ;
if ( cur = = NULL )
return ( 0 ) ;
pos = 0 ;
}
return ( 1 ) ;
}
/**
* xmlXPtrSearchString :
* @ string : the string to search
* @ start : the start textnode IN / OUT
* @ startindex : the start index IN / OUT
* @ end : the end textnode
* @ endindex : the end index
*
* Search the next occurence of @ string within the document content
* until the ( @ end , @ endindex ) point is reached
*
* Returns - 1 in case of failure , 0 if not found , 1 if found in which case
* ( @ start , @ startindex ) will indicate the position of the beginning
* of the range and ( @ end , @ endindex ) will endicate the end
* of the range
*/
int
xmlXPtrSearchString ( const xmlChar * string , xmlNodePtr * start , int * startindex ,
xmlNodePtr * end , int * endindex ) {
xmlNodePtr cur ;
const xmlChar * str ;
int pos ; /* 0 based */
int len ; /* in bytes */
int stringlen ; /* in bytes */
xmlChar first ;
if ( string = = NULL )
return ( - 1 ) ;
if ( ( start = = NULL ) | | ( startindex = = NULL ) )
return ( - 1 ) ;
if ( ( end = = NULL ) | | ( endindex = = NULL ) )
return ( - 1 ) ;
cur = * start ;
if ( cur = = NULL )
return ( - 1 ) ;
pos = * startindex - 1 ;
first = string [ 0 ] ;
stringlen = xmlStrlen ( string ) ;
while ( cur ! = NULL ) {
if ( cur - > content ! = NULL ) {
len = xmlStrlen ( cur - > content ) ;
while ( pos < = len ) {
2000-10-13 16:38:25 +00:00
if ( first ! = 0 ) {
str = xmlStrchr ( & cur - > content [ pos ] , first ) ;
if ( str ! = NULL ) {
pos = ( str - cur - > content ) ;
2000-10-12 23:15:24 +00:00
# ifdef DEBUG_RANGES
2000-10-13 16:38:25 +00:00
fprintf ( stdout , " found '%c' at index %d of -> " ,
first , pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
fprintf ( stdout , " \n " ) ;
2000-10-12 23:15:24 +00:00
# endif
2000-10-13 16:38:25 +00:00
if ( xmlXPtrMatchString ( string , cur , pos + 1 ,
end , endindex ) ) {
* start = cur ;
* startindex = pos + 1 ;
return ( 1 ) ;
}
pos + + ;
} else {
pos = len + 1 ;
2000-10-12 23:15:24 +00:00
}
} else {
2000-10-13 16:38:25 +00:00
/*
* An empty string is considered to match before each
* character of the string - value and after the final
* character .
*/
# ifdef DEBUG_RANGES
fprintf ( stdout , " found '' at index %d of -> " ,
pos + 1 ) ;
xmlDebugDumpString ( stdout , cur - > content ) ;
fprintf ( stdout , " \n " ) ;
# endif
* start = cur ;
* startindex = pos + 1 ;
* end = cur ;
* endindex = pos + 1 ;
return ( 1 ) ;
2000-10-12 23:15:24 +00:00
}
}
}
if ( ( cur = = * end ) & & ( pos > = * endindex ) )
return ( 0 ) ;
cur = xmlXPtrAdvanceNode ( cur ) ;
if ( cur = = NULL )
return ( 0 ) ;
pos = 1 ;
}
return ( 0 ) ;
}
/**
* xmlXPtrGetLastChar :
* @ node : the node
* @ index : the index
*
* Computes the point coordinates of the last char of this point
*
* Returns - 1 in case of failure , 0 otherwise
*/
int
xmlXPtrGetLastChar ( xmlNodePtr * node , int * index ) {
xmlNodePtr cur ;
int pos , len = 0 ;
if ( ( node = = NULL ) | | ( index = = NULL ) )
return ( - 1 ) ;
cur = * node ;
pos = * index ;
if ( cur = = NULL )
return ( - 1 ) ;
if ( ( cur - > type = = XML_ELEMENT_NODE ) | |
( cur - > type = = XML_DOCUMENT_NODE ) | |
( cur - > type = = XML_HTML_DOCUMENT_NODE ) ) {
if ( pos > 0 ) {
cur = xmlXPtrGetNthChild ( cur , pos ) ;
pos = 0 ;
}
}
while ( cur ! = NULL ) {
if ( cur - > last ! = NULL )
cur = cur - > last ;
else if ( cur - > content ! = NULL ) {
len = xmlStrlen ( cur - > content ) ;
break ;
}
}
if ( cur = = NULL )
return ( - 1 ) ;
* node = cur ;
* index = len ;
return ( 0 ) ;
}
/**
* xmlXPtrGetStartPoint :
* @ obj : an range
* @ node : the resulting node
* @ index : the resulting index
*
* read the object and return the start point coordinates .
*
* Returns - 1 in case of failure , 0 otherwise
*/
int
xmlXPtrGetStartPoint ( xmlXPathObjectPtr obj , xmlNodePtr * node , int * index ) {
if ( ( obj = = NULL ) | | ( node = = NULL ) | | ( index = = NULL ) )
return ( - 1 ) ;
switch ( obj - > type ) {
case XPATH_POINT :
* node = obj - > user ;
if ( obj - > index < = 0 )
* index = 0 ;
else
* index = obj - > index ;
return ( 0 ) ;
case XPATH_RANGE :
* node = obj - > user ;
if ( obj - > index < = 0 )
* index = 0 ;
else
* index = obj - > index ;
return ( 0 ) ;
default :
return ( - 1 ) ;
}
return ( - 1 ) ;
}
/**
* xmlXPtrGetEndPoint :
* @ obj : an range
* @ node : the resulting node
* @ index : the resulting index
*
* read the object and return the end point coordinates .
*
* Returns - 1 in case of failure , 0 otherwise
*/
int
xmlXPtrGetEndPoint ( xmlXPathObjectPtr obj , xmlNodePtr * node , int * index ) {
if ( ( obj = = NULL ) | | ( node = = NULL ) | | ( index = = NULL ) )
return ( - 1 ) ;
switch ( obj - > type ) {
case XPATH_POINT :
* node = obj - > user ;
if ( obj - > index < = 0 )
* index = 0 ;
else
* index = obj - > index ;
return ( 0 ) ;
case XPATH_RANGE :
* node = obj - > user ;
if ( obj - > index < = 0 )
* index = 0 ;
else
* index = obj - > index ;
return ( 0 ) ;
default :
return ( - 1 ) ;
}
return ( - 1 ) ;
}
/**
* xmlXPtrStringRangeFunction :
* @ ctxt : the XPointer Parser context
*
* Function implementing the string - range ( ) function
* range as described in 5.4 .2
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* [ Definition : For each location in the location - set argument ,
* string - range returns a set of string ranges , a set of substrings in a
* string . Specifically , the string - value of the location is searched for
* substrings that match the string argument , and the resulting location - set
* will contain a range location for each non - overlapping match . ]
* An empty string is considered to match before each character of the
* string - value and after the final character . Whitespace in a string
* is matched literally , with no normalization except that provided by
* XML for line ends . The third argument gives the position of the first
* character to be in the resulting range , relative to the start of the
* match . The default value is 1 , which makes the range start immediately
* before the first character of the matched string . The fourth argument
* gives the number of characters in the range ; the default is that the
* range extends to the end of the matched string .
*
* Element boundaries , as well as entire embedded nodes such as processing
* instructions and comments , are ignored as defined in [ XPath ] .
*
* If the string in the second argument is not found in the string - value
* of the location , or if a value in the third or fourth argument indicates
* a string that is beyond the beginning or end of the document , the
* expression fails .
*
* The points of the range - locations in the returned location - set will
* all be character points .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
void
xmlXPtrStringRangeFunction ( xmlXPathParserContextPtr ctxt , int nargs ) {
int i , startindex , endindex , fendindex ;
xmlNodePtr start , end , fend ;
xmlXPathObjectPtr set ;
xmlLocationSetPtr oldset ;
xmlLocationSetPtr newset ;
xmlXPathObjectPtr string ;
xmlXPathObjectPtr position = NULL ;
xmlXPathObjectPtr number = NULL ;
int found ;
/*
* Grab the arguments
*/
if ( ( nargs < 2 ) | | ( nargs > 4 ) )
XP_ERROR ( XPATH_INVALID_ARITY ) ;
if ( nargs > = 4 ) {
CHECK_TYPE ( XPATH_NUMBER ) ;
number = valuePop ( ctxt ) ;
}
if ( nargs > = 3 ) {
CHECK_TYPE ( XPATH_NUMBER ) ;
position = valuePop ( ctxt ) ;
}
CHECK_TYPE ( XPATH_STRING ) ;
string = valuePop ( ctxt ) ;
if ( ( ctxt - > value = = NULL ) | |
( ( ctxt - > value - > type ! = XPATH_LOCATIONSET ) & &
( ctxt - > value - > type ! = XPATH_NODESET ) ) )
XP_ERROR ( XPATH_INVALID_TYPE )
set = valuePop ( ctxt ) ;
if ( set - > type = = XPATH_NODESET ) {
xmlXPathObjectPtr tmp ;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet ( set - > nodesetval ) ;
xmlXPathFreeObject ( set ) ;
set = tmp ;
}
oldset = ( xmlLocationSetPtr ) set - > user ;
/*
* The loop is to search for each element in the location set
* the list of location set corresponding to that search
*/
newset = xmlXPtrLocationSetCreate ( NULL ) ;
for ( i = 0 ; i < oldset - > locNr ; i + + ) {
# ifdef DEBUG_RANGES
xmlXPathDebugDumpObject ( stdout , oldset - > locTab [ i ] , 0 ) ;
# endif
xmlXPtrGetStartPoint ( oldset - > locTab [ i ] , & start , & startindex ) ;
xmlXPtrGetEndPoint ( oldset - > locTab [ i ] , & end , & endindex ) ;
xmlXPtrAdvanceChar ( & start , & startindex , 0 ) ;
xmlXPtrGetLastChar ( & end , & endindex ) ;
# ifdef DEBUG_RANGES
fprintf ( stdout , " from index %d of -> " , startindex ) ;
xmlDebugDumpString ( stdout , start - > content ) ;
fprintf ( stdout , " \n " ) ;
fprintf ( stdout , " to index %d of -> " , endindex ) ;
xmlDebugDumpString ( stdout , end - > content ) ;
fprintf ( stdout , " \n " ) ;
# endif
do {
fend = end ;
fendindex = endindex ;
found = xmlXPtrSearchString ( string - > stringval , & start , & startindex ,
& fend , & fendindex ) ;
if ( found = = 1 ) {
xmlXPtrLocationSetAdd ( newset ,
xmlXPtrNewRange ( start , startindex , fend , fendindex ) ) ;
start = fend ;
startindex = fendindex ;
2000-10-13 16:38:25 +00:00
if ( string - > stringval [ 0 ] = = 0 )
startindex + + ;
2000-10-12 23:15:24 +00:00
}
} while ( found = = 1 ) ;
}
/*
* Save the new value and cleanup
*/
valuePush ( ctxt , xmlXPtrWrapLocationSet ( newset ) ) ;
xmlXPathFreeObject ( set ) ;
xmlXPathFreeObject ( string ) ;
if ( position ) xmlXPathFreeObject ( position ) ;
if ( number ) xmlXPathFreeObject ( number ) ;
}
2000-10-11 08:55:02 +00:00
# else
# endif