xpath.c
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:123k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /*
  2.  * xpath.c: XML Path Language implementation
  3.  *          XPath is a language for addressing parts of an XML document,
  4.  *          designed to be used by both XSLT and XPointer.
  5.  *
  6.  * Reference: W3C Working Draft internal 5 July 1999
  7.  *     http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
  8.  * Public reference:
  9.  *     http://www.w3.org/TR/WD-xpath/
  10.  *
  11.  * See COPYRIGHT for the status of this software
  12.  *
  13.  * Author: Daniel.Veillard@w3.org
  14.  */
  15. #ifdef WIN32
  16. #include "win32config.h"
  17. #else
  18. #include "config.h"
  19. #endif
  20. #include "xmlversion.h"
  21. #ifdef LIBXML_XPATH_ENABLED
  22. #include <stdio.h>
  23. #include <string.h>
  24. #ifdef HAVE_SYS_TYPES_H
  25. #include <sys/types.h>
  26. #endif
  27. #ifdef HAVE_MATH_H
  28. #include <math.h>
  29. #endif
  30. #ifdef HAVE_MATH_H
  31. #include <float.h>
  32. #endif
  33. #ifdef HAVE_IEEEFP_H
  34. #include <ieeefp.h>
  35. #endif
  36. #ifdef HAVE_NAN_H
  37. #include <nan.h>
  38. #endif
  39. #ifdef HAVE_CTYPE_H
  40. #include <ctype.h>
  41. #endif
  42. #include <libxml/xmlmemory.h>
  43. #include <libxml/tree.h>
  44. #include <libxml/valid.h>
  45. #include <libxml/xpath.h>
  46. #include <libxml/parserInternals.h>
  47. /* #define DEBUG */
  48. /* #define DEBUG_STEP */
  49. /* #define DEBUG_EXPR */
  50. /*
  51.  * Setup stuff for floating point
  52.  * The lack of portability of this section of the libc is annoying !
  53.  */
  54. double xmlXPathNAN = 0;
  55. double xmlXPathPINF = 1;
  56. double xmlXPathMINF = -1;
  57. #ifndef isinf
  58. #ifndef HAVE_ISINF
  59. #if HAVE_FPCLASS
  60. int isinf(double d) {
  61.     fpclass_t type = fpclass(d);
  62.     switch (type) {
  63. case FP_NINF:
  64.     return(-1);
  65. case FP_PINF:
  66.     return(1);
  67.     }
  68.     return(0);
  69. }
  70. #elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
  71. #if HAVE_FP_CLASS_H
  72. #include <fp_class.h>
  73. #endif
  74. int isinf(double d) {
  75. #if HAVE_FP_CLASS
  76.     int fpclass = fp_class(d);
  77. #else
  78.     int fpclass = fp_class_d(d);
  79. #endif
  80.     if (fpclass == FP_POS_INF)
  81. return(1);
  82.     if (fpclass == FP_NEG_INF)
  83. return(-1);
  84.     return(0);
  85. }
  86. #elif defined(HAVE_CLASS)
  87. int isinf(double d) {
  88.     int fpclass = class(d);
  89.     if (fpclass == FP_PLUS_INF)
  90. return(1);
  91.     if (fpclass == FP_MINUS_INF)
  92. return(-1);
  93.     return(0);
  94. }
  95. #elif defined(finite) || defined(HAVE_FINITE)
  96. int isinf(double x) { return !finite(x) && x==x; }
  97. #elif defined(HUGE_VAL)
  98. int isinf(double x)
  99. {
  100.     if (x == HUGE_VAL)
  101.         return(1);
  102.     if (x == -HUGE_VAL)
  103.         return(-1);
  104.     return(0);
  105. }
  106. #endif 
  107. #endif /* ! HAVE_ISINF */
  108. #endif /* ! defined(isinf) */
  109. #ifndef isnan
  110. #ifndef HAVE_ISNAN
  111. #ifdef HAVE_ISNAND
  112. #define isnan(f) isnand(f)
  113. #endif /* HAVE_iSNAND */
  114. #endif /* ! HAVE_iSNAN */
  115. #endif /* ! defined(isnan) */
  116. /**
  117.  * xmlXPathInit:
  118.  *
  119.  * Initialize the XPath environment
  120.  */
  121. void
  122. xmlXPathInit(void) {
  123.     static int initialized = 0;
  124.     if (initialized) return;
  125.     xmlXPathNAN = 0;
  126.     xmlXPathNAN /= 0;
  127.     xmlXPathPINF = 1;
  128.     xmlXPathPINF /= 0;
  129.     xmlXPathMINF = -1;
  130.     xmlXPathMINF /= 0;
  131.     initialized = 1;
  132. }
  133. FILE *xmlXPathDebug = NULL;
  134. #define TODO 
  135.     fprintf(xmlXPathDebug, "Unimplemented block at %s:%dn",
  136.             __FILE__, __LINE__);
  137. #define STRANGE 
  138.     fprintf(xmlXPathDebug, "Internal error at %s:%dn",
  139.             __FILE__, __LINE__);
  140. double xmlXPathStringEvalNumber(const xmlChar *str);
  141. void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
  142. /************************************************************************
  143.  * *
  144.  *  Parser stacks related functions and macros *
  145.  * *
  146.  ************************************************************************/
  147. /*
  148.  * Generic function for accessing stacks in the Parser Context
  149.  */
  150. #define PUSH_AND_POP(type, name)
  151. extern int name##Push(xmlXPathParserContextPtr ctxt, type value) {
  152.     if (ctxt->name##Nr >= ctxt->name##Max) {
  153. ctxt->name##Max *= 2;
  154.         ctxt->name##Tab = (void *) xmlRealloc(ctxt->name##Tab,
  155.              ctxt->name##Max * sizeof(ctxt->name##Tab[0]));
  156.         if (ctxt->name##Tab == NULL) {
  157.     fprintf(xmlXPathDebug, "realloc failed !n");
  158.     return(0);
  159. }
  160.     }
  161.     ctxt->name##Tab[ctxt->name##Nr] = value;
  162.     ctxt->name = value;
  163.     return(ctxt->name##Nr++);
  164. }
  165. extern type name##Pop(xmlXPathParserContextPtr ctxt) {
  166.     type ret;
  167.     if (ctxt->name##Nr <= 0) return(0);
  168.     ctxt->name##Nr--;
  169.     if (ctxt->name##Nr > 0)
  170. ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];
  171.     else
  172.         ctxt->name = NULL;
  173.     ret = ctxt->name##Tab[ctxt->name##Nr];
  174.     ctxt->name##Tab[ctxt->name##Nr] = 0;
  175.     return(ret);
  176. }
  177. PUSH_AND_POP(xmlXPathObjectPtr, value)
  178. /*
  179.  * Macros for accessing the content. Those should be used only by the parser,
  180.  * and not exported.
  181.  *
  182.  * Dirty macros, i.e. one need to make assumption on the context to use them
  183.  *
  184.  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
  185.  *   CUR     returns the current xmlChar value, i.e. a 8 bit value
  186.  *           in ISO-Latin or UTF-8.
  187.  *           This should be used internally by the parser
  188.  *           only to compare to ASCII values otherwise it would break when
  189.  *           running with UTF-8 encoding.
  190.  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
  191.  *           to compare on ASCII based substring.
  192.  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  193.  *           strings within the parser.
  194.  *   CURRENT Returns the current char value, with the full decoding of
  195.  *           UTF-8 if we are using this mode. It returns an int.
  196.  *   NEXT    Skip to the next character, this does the proper decoding
  197.  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
  198.  *           It returns the pointer to the current xmlChar.
  199.  */
  200. #define CUR (*ctxt->cur)
  201. #define SKIP(val) ctxt->cur += (val)
  202. #define NXT(val) ctxt->cur[(val)]
  203. #define CUR_PTR ctxt->cur
  204. #define SKIP_BLANKS 
  205.     while (IS_BLANK(*(ctxt->cur))) NEXT
  206. #define CURRENT (*ctxt->cur)
  207. #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
  208. /************************************************************************
  209.  * *
  210.  * Error handling routines *
  211.  * *
  212.  ************************************************************************/
  213. #define XPATH_EXPRESSION_OK 0
  214. #define XPATH_NUMBER_ERROR 1
  215. #define XPATH_UNFINISHED_LITERAL_ERROR 2
  216. #define XPATH_START_LITERAL_ERROR 3
  217. #define XPATH_VARIABLE_REF_ERROR 4
  218. #define XPATH_UNDEF_VARIABLE_ERROR 5
  219. #define XPATH_INVALID_PREDICATE_ERROR 6
  220. #define XPATH_EXPR_ERROR 7
  221. #define XPATH_UNCLOSED_ERROR 8
  222. #define XPATH_UNKNOWN_FUNC_ERROR 9
  223. #define XPATH_INVALID_OPERAND 10
  224. #define XPATH_INVALID_TYPE 11
  225. #define XPATH_INVALID_ARITY 12
  226. const char *xmlXPathErrorMessages[] = {
  227.     "Ok",
  228.     "Number encoding",
  229.     "Unfinished litteral",
  230.     "Start of litteral",
  231.     "Expected $ for variable reference",
  232.     "Undefined variable",
  233.     "Invalid predicate",
  234.     "Invalid expression",
  235.     "Missing closing curly brace",
  236.     "Unregistered function",
  237.     "Invalid operand",
  238.     "Invalid type",
  239.     "Invalid number of arguments",
  240. };
  241. /**
  242.  * xmlXPathError:
  243.  * @ctxt:  the XPath Parser context
  244.  * @file:  the file name
  245.  * @line:  the line number
  246.  * @no:  the error number
  247.  *
  248.  * Create a new xmlNodeSetPtr of type double and of value @val
  249.  *
  250.  * Returns the newly created object.
  251.  */
  252. void
  253. xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
  254.               int line, int no) {
  255.     int n;
  256.     const xmlChar *cur;
  257.     const xmlChar *base;
  258.     fprintf(xmlXPathDebug, "Error %s:%d: %sn", file, line,
  259.             xmlXPathErrorMessages[no]);
  260.     cur = ctxt->cur;
  261.     base = ctxt->base;
  262.     while ((cur > base) && ((*cur == 'n') || (*cur == 'r'))) {
  263. cur--;
  264.     }
  265.     n = 0;
  266.     while ((n++ < 80) && (cur > base) && (*cur != 'n') && (*cur != 'r'))
  267.         cur--;
  268.     if ((*cur == 'n') || (*cur == 'r')) cur++;
  269.     base = cur;
  270.     n = 0;
  271.     while ((*cur != 0) && (*cur != 'n') && (*cur != 'r') && (n < 79)) {
  272.         fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
  273. n++;
  274.     }
  275.     fprintf(xmlXPathDebug, "n");
  276.     cur = ctxt->cur;
  277.     while ((*cur == 'n') || (*cur == 'r'))
  278. cur--;
  279.     n = 0;
  280.     while ((cur != base) && (n++ < 80)) {
  281.         fprintf(xmlXPathDebug, " ");
  282.         base++;
  283.     }
  284.     fprintf(xmlXPathDebug,"^n");
  285. }
  286. #define CHECK_ERROR
  287.     if (ctxt->error != XPATH_EXPRESSION_OK) return
  288. #define ERROR(X)
  289.     { xmlXPatherror(ctxt, __FILE__, __LINE__, X);
  290.       ctxt->error = (X); return; }
  291. #define ERROR0(X)
  292.     { xmlXPatherror(ctxt, __FILE__, __LINE__, X);
  293.       ctxt->error = (X); return(0); }
  294. #define CHECK_TYPE(typeval)
  295.     if ((ctxt->value == NULL) || (ctxt->value->type != typeval))
  296.         ERROR(XPATH_INVALID_TYPE)
  297. /************************************************************************
  298.  * *
  299.  * Routines to handle NodeSets *
  300.  * *
  301.  ************************************************************************/
  302. #define XML_NODESET_DEFAULT 10
  303. /**
  304.  * xmlXPathNodeSetCreate:
  305.  * @val:  an initial xmlNodePtr, or NULL
  306.  *
  307.  * Create a new xmlNodeSetPtr of type double and of value @val
  308.  *
  309.  * Returns the newly created object.
  310.  */
  311. xmlNodeSetPtr
  312. xmlXPathNodeSetCreate(xmlNodePtr val) {
  313.     xmlNodeSetPtr ret;
  314.     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
  315.     if (ret == NULL) {
  316.         fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memoryn");
  317. return(NULL);
  318.     }
  319.     memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
  320.     if (val != NULL) {
  321.         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  322.      sizeof(xmlNodePtr));
  323. if (ret->nodeTab == NULL) {
  324.     fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memoryn");
  325.     return(NULL);
  326. }
  327. memset(ret->nodeTab, 0 ,
  328.        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  329.         ret->nodeMax = XML_NODESET_DEFAULT;
  330. ret->nodeTab[ret->nodeNr++] = val;
  331.     }
  332.     return(ret);
  333. }
  334. /**
  335.  * xmlXPathNodeSetAdd:
  336.  * @cur:  the initial node set
  337.  * @val:  a new xmlNodePtr
  338.  *
  339.  * add a new xmlNodePtr ot an existing NodeSet
  340.  */
  341. void
  342. xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
  343.     int i;
  344.     if (val == NULL) return;
  345.     /*
  346.      * check against doublons
  347.      */
  348.     for (i = 0;i < cur->nodeNr;i++)
  349.         if (cur->nodeTab[i] == val) return;
  350.     /*
  351.      * grow the nodeTab if needed
  352.      */
  353.     if (cur->nodeMax == 0) {
  354.         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  355.      sizeof(xmlNodePtr));
  356. if (cur->nodeTab == NULL) {
  357.     fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memoryn");
  358.     return;
  359. }
  360. memset(cur->nodeTab, 0 ,
  361.        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  362.         cur->nodeMax = XML_NODESET_DEFAULT;
  363.     } else if (cur->nodeNr == cur->nodeMax) {
  364.         xmlNodePtr *temp;
  365.         cur->nodeMax *= 2;
  366. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
  367.       sizeof(xmlNodePtr));
  368. if (temp == NULL) {
  369.     fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memoryn");
  370.     return;
  371. }
  372. cur->nodeTab = temp;
  373.     }
  374.     cur->nodeTab[cur->nodeNr++] = val;
  375. }
  376. /**
  377.  * xmlXPathNodeSetMerge:
  378.  * @val1:  the first NodeSet
  379.  * @val2:  the second NodeSet
  380.  *
  381.  * Merges two nodesets, all nodes from @val2 are added to @val1
  382.  *
  383.  * Returns val1 once extended or NULL in case of error.
  384.  */
  385. xmlNodeSetPtr
  386. xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
  387.     int i;
  388.     if (val1 == NULL) return(NULL);
  389.     if (val2 == NULL) return(val1);
  390.     /*
  391.      * !!!!! this can be optimized a lot, knowing that both
  392.      *       val1 and val2 already have unicity of their values.
  393.      */
  394.     for (i = 0;i < val2->nodeNr;i++)
  395.         xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
  396.     return(val1);
  397. }
  398. /**
  399.  * xmlXPathNodeSetDel:
  400.  * @cur:  the initial node set
  401.  * @val:  an xmlNodePtr
  402.  *
  403.  * Removes an xmlNodePtr from an existing NodeSet
  404.  */
  405. void
  406. xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
  407.     int i;
  408.     if (cur == NULL) return;
  409.     if (val == NULL) return;
  410.     /*
  411.      * check against doublons
  412.      */
  413.     for (i = 0;i < cur->nodeNr;i++)
  414.         if (cur->nodeTab[i] == val) break;
  415.     if (i >= cur->nodeNr) {
  416. #ifdef DEBUG
  417.         fprintf(xmlXPathDebug, 
  418.         "xmlXPathNodeSetDel: Node %s wasn't found in NodeListn",
  419. val->name);
  420. #endif
  421.         return;
  422.     }
  423.     cur->nodeNr--;
  424.     for (;i < cur->nodeNr;i++)
  425.         cur->nodeTab[i] = cur->nodeTab[i + 1];
  426.     cur->nodeTab[cur->nodeNr] = NULL;
  427. }
  428. /**
  429.  * xmlXPathNodeSetRemove:
  430.  * @cur:  the initial node set
  431.  * @val:  the index to remove
  432.  *
  433.  * Removes an entry from an existing NodeSet list.
  434.  */
  435. void
  436. xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
  437.     if (cur == NULL) return;
  438.     if (val >= cur->nodeNr) return;
  439.     cur->nodeNr--;
  440.     for (;val < cur->nodeNr;val++)
  441.         cur->nodeTab[val] = cur->nodeTab[val + 1];
  442.     cur->nodeTab[cur->nodeNr] = NULL;
  443. }
  444. /**
  445.  * xmlXPathFreeNodeSet:
  446.  * @obj:  the xmlNodeSetPtr to free
  447.  *
  448.  * Free the NodeSet compound (not the actual nodes !).
  449.  */
  450. void
  451. xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
  452.     if (obj == NULL) return;
  453.     if (obj->nodeTab != NULL) {
  454. #ifdef DEBUG
  455. memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
  456. #endif
  457. xmlFree(obj->nodeTab);
  458.     }
  459. #ifdef DEBUG
  460.     memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
  461. #endif
  462.     xmlFree(obj);
  463. }
  464. #if defined(DEBUG) || defined(DEBUG_STEP)
  465. /**
  466.  * xmlXPathDebugNodeSet:
  467.  * @output:  a FILE * for the output
  468.  * @obj:  the xmlNodeSetPtr to free
  469.  *
  470.  * Quick display of a NodeSet
  471.  */
  472. void
  473. xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
  474.     int i;
  475.     if (output == NULL) output = xmlXPathDebug;
  476.     if (obj == NULL)  {
  477.         fprintf(output, "NodeSet == NULL !n");
  478. return;
  479.     }
  480.     if (obj->nodeNr == 0) {
  481.         fprintf(output, "NodeSet is emptyn");
  482. return;
  483.     }
  484.     if (obj->nodeTab == NULL) {
  485. fprintf(output, " nodeTab == NULL !n");
  486. return;
  487.     }
  488.     for (i = 0; i < obj->nodeNr; i++) {
  489.         if (obj->nodeTab[i] == NULL) {
  490.     fprintf(output, " NULL !n");
  491.     return;
  492.         }
  493. if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
  494.     (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
  495.     fprintf(output, " /");
  496. else if (obj->nodeTab[i]->name == NULL)
  497.     fprintf(output, " noname!");
  498. else fprintf(output, " %s", obj->nodeTab[i]->name);
  499.     }
  500.     fprintf(output, "n");
  501. }
  502. #endif
  503. /************************************************************************
  504.  * *
  505.  * Routines to handle Variable *
  506.  * *
  507.  * UNIMPLEMENTED CURRENTLY *
  508.  * *
  509.  ************************************************************************/
  510. /**
  511.  * xmlXPathVariablelookup:
  512.  * @ctxt:  the XPath Parser context
  513.  * @prefix:  the variable name namespace if any
  514.  * @name:  the variable name
  515.  *
  516.  * Search in the Variable array of the context for the given
  517.  * variable value.
  518.  *
  519.  * UNIMPLEMENTED: always return NULL.
  520.  *
  521.  * Returns the value or NULL if not found
  522.  */
  523. xmlXPathObjectPtr
  524. xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
  525.                        const xmlChar *prefix, const xmlChar *name) {
  526.     return(NULL);
  527. }
  528. /************************************************************************
  529.  * *
  530.  * Routines to handle Values *
  531.  * *
  532.  ************************************************************************/
  533. /* Allocations are terrible, one need to optimize all this !!! */
  534. /**
  535.  * xmlXPathNewFloat:
  536.  * @val:  the double value
  537.  *
  538.  * Create a new xmlXPathObjectPtr of type double and of value @val
  539.  *
  540.  * Returns the newly created object.
  541.  */
  542. xmlXPathObjectPtr
  543. xmlXPathNewFloat(double val) {
  544.     xmlXPathObjectPtr ret;
  545.     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  546.     if (ret == NULL) {
  547.         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memoryn");
  548. return(NULL);
  549.     }
  550.     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  551.     ret->type = XPATH_NUMBER;
  552.     ret->floatval = val;
  553.     return(ret);
  554. }
  555. /**
  556.  * xmlXPathNewBoolean:
  557.  * @val:  the boolean value
  558.  *
  559.  * Create a new xmlXPathObjectPtr of type boolean and of value @val
  560.  *
  561.  * Returns the newly created object.
  562.  */
  563. xmlXPathObjectPtr
  564. xmlXPathNewBoolean(int val) {
  565.     xmlXPathObjectPtr ret;
  566.     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  567.     if (ret == NULL) {
  568.         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memoryn");
  569. return(NULL);
  570.     }
  571.     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  572.     ret->type = XPATH_BOOLEAN;
  573.     ret->boolval = (val != 0);
  574.     return(ret);
  575. }
  576. /**
  577.  * xmlXPathNewString:
  578.  * @val:  the xmlChar * value
  579.  *
  580.  * Create a new xmlXPathObjectPtr of type string and of value @val
  581.  *
  582.  * Returns the newly created object.
  583.  */
  584. xmlXPathObjectPtr
  585. xmlXPathNewString(const xmlChar *val) {
  586.     xmlXPathObjectPtr ret;
  587.     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  588.     if (ret == NULL) {
  589.         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memoryn");
  590. return(NULL);
  591.     }
  592.     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  593.     ret->type = XPATH_STRING;
  594.     ret->stringval = xmlStrdup(val);
  595.     return(ret);
  596. }
  597. /**
  598.  * xmlXPathNewCString:
  599.  * @val:  the char * value
  600.  *
  601.  * Create a new xmlXPathObjectPtr of type string and of value @val
  602.  *
  603.  * Returns the newly created object.
  604.  */
  605. xmlXPathObjectPtr
  606. xmlXPathNewCString(const char *val) {
  607.     xmlXPathObjectPtr ret;
  608.     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  609.     if (ret == NULL) {
  610.         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memoryn");
  611. return(NULL);
  612.     }
  613.     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  614.     ret->type = XPATH_STRING;
  615.     ret->stringval = xmlStrdup(BAD_CAST val);
  616.     return(ret);
  617. }
  618. /**
  619.  * xmlXPathNewNodeSet:
  620.  * @val:  the NodePtr value
  621.  *
  622.  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  623.  * it with the single Node @val
  624.  *
  625.  * Returns the newly created object.
  626.  */
  627. xmlXPathObjectPtr
  628. xmlXPathNewNodeSet(xmlNodePtr val) {
  629.     xmlXPathObjectPtr ret;
  630.     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  631.     if (ret == NULL) {
  632.         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memoryn");
  633. return(NULL);
  634.     }
  635.     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  636.     ret->type = XPATH_NODESET;
  637.     ret->nodesetval = xmlXPathNodeSetCreate(val);
  638.     return(ret);
  639. }
  640. /**
  641.  * xmlXPathNewNodeSetList:
  642.  * @val:  an existing NodeSet
  643.  *
  644.  * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  645.  * it with the Nodeset @val
  646.  *
  647.  * Returns the newly created object.
  648.  */
  649. xmlXPathObjectPtr
  650. xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
  651.     xmlXPathObjectPtr ret;
  652.     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  653.     if (ret == NULL) {
  654.         fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memoryn");
  655. return(NULL);
  656.     }
  657.     memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  658.     ret->type = XPATH_NODESET;
  659.     ret->nodesetval = val;
  660.     return(ret);
  661. }
  662. /**
  663.  * xmlXPathFreeNodeSetList:
  664.  * @obj:  an existing NodeSetList object
  665.  *
  666.  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
  667.  * the list contrary to xmlXPathFreeObject().
  668.  */
  669. void
  670. xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
  671.     if (obj == NULL) return;
  672. #ifdef DEBUG
  673.     memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
  674. #endif
  675.     xmlFree(obj);
  676. }
  677. /**
  678.  * xmlXPathFreeObject:
  679.  * @obj:  the object to free
  680.  *
  681.  * Free up an xmlXPathObjectPtr object.
  682.  */
  683. void
  684. xmlXPathFreeObject(xmlXPathObjectPtr obj) {
  685.     if (obj == NULL) return;
  686.     if (obj->nodesetval != NULL)
  687.         xmlXPathFreeNodeSet(obj->nodesetval);
  688.     if (obj->stringval != NULL)
  689.         xmlFree(obj->stringval);
  690. #ifdef DEBUG
  691.     memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
  692. #endif
  693.     xmlFree(obj);
  694. }
  695. /************************************************************************
  696.  * *
  697.  * Routines to handle XPath contexts *
  698.  * *
  699.  ************************************************************************/
  700. /**
  701.  * xmlXPathNewContext:
  702.  * @doc:  the XML document
  703.  *
  704.  * Create a new xmlXPathContext
  705.  *
  706.  * Returns the xmlXPathContext just allocated.
  707.  */
  708. xmlXPathContextPtr
  709. xmlXPathNewContext(xmlDocPtr doc) {
  710.     xmlXPathContextPtr ret;
  711.     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
  712.     if (ret == NULL) {
  713.         fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memoryn");
  714. return(NULL);
  715.     }
  716.     memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
  717.     ret->doc = doc;
  718.  /***********   
  719.     ret->node = (xmlNodePtr) doc;
  720.     ret->nodelist = xmlXPathNodeSetCreate(ret->node);
  721.   ***********/  
  722.     ret->node = NULL;
  723.     ret->nodelist = NULL;
  724.     ret->nb_variables = 0;
  725.     ret->max_variables = 0;
  726.     ret->variables = NULL;
  727.     ret->nb_types = 0;
  728.     ret->max_types = 0;
  729.     ret->types = NULL;
  730.     ret->nb_funcs = 0;
  731.     ret->max_funcs = 0;
  732.     ret->funcs = NULL;
  733.     ret->nb_axis = 0;
  734.     ret->max_axis = 0;
  735.     ret->axis = NULL;
  736.     ret->namespaces = NULL;
  737.     ret->user = NULL;
  738.     ret->nsNr = 0;
  739.     return(ret);
  740. }
  741. /**
  742.  * xmlXPathFreeContext:
  743.  * @ctxt:  the context to free
  744.  *
  745.  * Free up an xmlXPathContext
  746.  */
  747. void
  748. xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
  749.     if (ctxt->namespaces != NULL)
  750.         xmlFree(ctxt->namespaces);
  751.  /***********   
  752.     if (ctxt->nodelist != NULL) 
  753.         xmlXPathFreeNodeSet(ctxt->nodelist);
  754.   ***********/  
  755. #ifdef DEBUG
  756.     memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
  757. #endif
  758.     xmlFree(ctxt);
  759. }
  760. /************************************************************************
  761.  * *
  762.  * Routines to handle XPath parser contexts *
  763.  * *
  764.  ************************************************************************/
  765. #define CHECK_CTXT
  766.     if (ctxt == NULL) { 
  767.         fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULLn",
  768.         __FILE__, __LINE__);
  769.     }
  770. #define CHECK_CONTEXT
  771.     if (ctxt == NULL) { 
  772.         fprintf(xmlXPathDebug, "%s:%d Internal error: no contextn",
  773.         __FILE__, __LINE__);
  774.     }
  775.     if (ctxt->doc == NULL) { 
  776.         fprintf(xmlXPathDebug, "%s:%d Internal error: no documentn",
  777.         __FILE__, __LINE__);
  778.     }
  779.     if (ctxt->doc->children == NULL) { 
  780.         fprintf(xmlXPathDebug,
  781.         "%s:%d Internal error: document without rootn",
  782.         __FILE__, __LINE__);
  783.     }
  784. /**
  785.  * xmlXPathNewParserContext:
  786.  * @str:  the XPath expression
  787.  * @ctxt:  the XPath context
  788.  *
  789.  * Create a new xmlXPathParserContext
  790.  *
  791.  * Returns the xmlXPathParserContext just allocated.
  792.  */
  793. xmlXPathParserContextPtr
  794. xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
  795.     xmlXPathParserContextPtr ret;
  796.     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  797.     if (ret == NULL) {
  798.         fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memoryn");
  799. return(NULL);
  800.     }
  801.     memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  802.     ret->cur = ret->base = str;
  803.     ret->context = ctxt;
  804.     /* Allocate the value stack */
  805.     ret->valueTab = (xmlXPathObjectPtr *) 
  806.                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  807.     ret->valueNr = 0;
  808.     ret->valueMax = 10;
  809.     ret->value = NULL;
  810.     return(ret);
  811. }
  812. /**
  813.  * xmlXPathFreeParserContext:
  814.  * @ctxt:  the context to free
  815.  *
  816.  * Free up an xmlXPathParserContext
  817.  */
  818. void
  819. xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
  820.     if (ctxt->valueTab != NULL) {
  821. #ifdef DEBUG
  822.         memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
  823. #endif
  824.         xmlFree(ctxt->valueTab);
  825.     }
  826. #ifdef DEBUG
  827.     memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
  828. #endif
  829.     xmlFree(ctxt);
  830. }
  831. /************************************************************************
  832.  * *
  833.  * The implicit core function library *
  834.  * *
  835.  ************************************************************************/
  836. /*
  837.  * Auto-pop and cast to a number
  838.  */
  839. void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
  840. #define CHECK_ARITY(x)
  841.     if (nargs != (x)) {
  842.         ERROR(XPATH_INVALID_ARITY);
  843.     }
  844. #define POP_FLOAT
  845.     arg = valuePop(ctxt);
  846.     if (arg == NULL) {
  847. ERROR(XPATH_INVALID_OPERAND);
  848.     }
  849.     if (arg->type != XPATH_NUMBER) {
  850.         valuePush(ctxt, arg);
  851.         xmlXPathNumberFunction(ctxt, 1);
  852. arg = valuePop(ctxt);
  853.     }
  854. /**
  855.  * xmlXPathEqualNodeSetString
  856.  * @arg:  the nodeset object argument
  857.  * @str:  the string to compare to.
  858.  *
  859.  * Implement the equal operation on XPath objects content: @arg1 == @arg2
  860.  * If one object to be compared is a node-set and the other is a string,
  861.  * then the comparison will be true if and only if there is a node in
  862.  * the node-set such that the result of performing the comparison on the
  863.  * string-value of the node and the other string is true.
  864.  *
  865.  * Returns 0 or 1 depending on the results of the test.
  866.  */
  867. int
  868. xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
  869.     int i;
  870.     xmlNodeSetPtr ns;
  871.     xmlChar *str2;
  872.     if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
  873.         return(0);
  874.     ns = arg->nodesetval;
  875.     for (i = 0;i < ns->nodeNr;i++) {
  876.          str2 = xmlNodeGetContent(ns->nodeTab[i]);
  877.  if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
  878.      xmlFree(str2);
  879.      return(1);
  880.  }
  881.  xmlFree(str2);
  882.     }
  883.     return(0);
  884. }
  885. /**
  886.  * xmlXPathEqualNodeSetFloat
  887.  * @arg:  the nodeset object argument
  888.  * @f:  the float to compare to
  889.  *
  890.  * Implement the equal operation on XPath objects content: @arg1 == @arg2
  891.  * If one object to be compared is a node-set and the other is a number,
  892.  * then the comparison will be true if and only if there is a node in
  893.  * the node-set such that the result of performing the comparison on the
  894.  * number to be compared and on the result of converting the string-value
  895.  * of that node to a number using the number function is true.
  896.  *
  897.  * Returns 0 or 1 depending on the results of the test.
  898.  */
  899. int
  900. xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
  901.     char buf[100] = "";
  902.     if ((arg == NULL) || (arg->type != XPATH_NODESET))
  903.         return(0);
  904.     if (isnan(f))
  905. sprintf(buf, "NaN");
  906.     else if (isinf(f) > 0)
  907. sprintf(buf, "+Infinity");
  908.     else if (isinf(f) < 0)
  909. sprintf(buf, "-Infinity");
  910.     else
  911. sprintf(buf, "%0g", f);
  912.     return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
  913. }
  914. /**
  915.  * xmlXPathEqualNodeSets
  916.  * @arg1:  first nodeset object argument
  917.  * @arg2:  second nodeset object argument
  918.  *
  919.  * Implement the equal operation on XPath nodesets: @arg1 == @arg2
  920.  * If both objects to be compared are node-sets, then the comparison
  921.  * will be true if and only if there is a node in the first node-set and
  922.  * a node in the second node-set such that the result of performing the
  923.  * comparison on the string-values of the two nodes is true.
  924.  *
  925.  * (needless to say, this is a costly operation)
  926.  *
  927.  * Returns 0 or 1 depending on the results of the test.
  928.  */
  929. int
  930. xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  931.     int i;
  932.     xmlNodeSetPtr ns;
  933.     xmlChar *str;
  934.     if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
  935.         return(0);
  936.     if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
  937.         return(0);
  938.     ns = arg1->nodesetval;
  939.     for (i = 0;i < ns->nodeNr;i++) {
  940.          str = xmlNodeGetContent(ns->nodeTab[i]);
  941.  if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
  942.      xmlFree(str);
  943.      return(1);
  944.  }
  945.  xmlFree(str);
  946.     }
  947.     return(0);
  948. }
  949. /**
  950.  * xmlXPathEqualValues:
  951.  * @ctxt:  the XPath Parser context
  952.  *
  953.  * Implement the equal operation on XPath objects content: @arg1 == @arg2
  954.  *
  955.  * Returns 0 or 1 depending on the results of the test.
  956.  */
  957. int
  958. xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
  959.     xmlXPathObjectPtr arg1, arg2;
  960.     int ret = 0;
  961.     arg1 = valuePop(ctxt);
  962.     if (arg1 == NULL)
  963. ERROR0(XPATH_INVALID_OPERAND);
  964.     arg2 = valuePop(ctxt);
  965.     if (arg2 == NULL) {
  966. xmlXPathFreeObject(arg1);
  967. ERROR0(XPATH_INVALID_OPERAND);
  968.     }
  969.   
  970.     if (arg1 == arg2) {
  971. #ifdef DEBUG_EXPR
  972.         fprintf(xmlXPathDebug, "Equal: by pointern");
  973. #endif
  974.         return(1);
  975.     }
  976.     switch (arg1->type) {
  977.         case XPATH_UNDEFINED:
  978. #ifdef DEBUG_EXPR
  979.     fprintf(xmlXPathDebug, "Equal: undefinedn");
  980. #endif
  981.     break;
  982.         case XPATH_NODESET:
  983.     switch (arg2->type) {
  984.         case XPATH_UNDEFINED:
  985. #ifdef DEBUG_EXPR
  986.     fprintf(xmlXPathDebug, "Equal: undefinedn");
  987. #endif
  988.     break;
  989. case XPATH_NODESET:
  990.     ret = xmlXPathEqualNodeSets(arg1, arg2);
  991.     break;
  992. case XPATH_BOOLEAN:
  993.     if ((arg1->nodesetval == NULL) ||
  994. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  995.     else 
  996. ret = 1;
  997.     ret = (ret == arg2->boolval);
  998.     break;
  999. case XPATH_NUMBER:
  1000.     ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
  1001.     break;
  1002. case XPATH_STRING:
  1003.     ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
  1004.     break;
  1005.     }
  1006.     break;
  1007.         case XPATH_BOOLEAN:
  1008.     switch (arg2->type) {
  1009.         case XPATH_UNDEFINED:
  1010. #ifdef DEBUG_EXPR
  1011.     fprintf(xmlXPathDebug, "Equal: undefinedn");
  1012. #endif
  1013.     break;
  1014. case XPATH_NODESET:
  1015.     if ((arg2->nodesetval == NULL) ||
  1016. (arg2->nodesetval->nodeNr == 0)) ret = 0;
  1017.     else 
  1018. ret = 1;
  1019.     break;
  1020. case XPATH_BOOLEAN:
  1021. #ifdef DEBUG_EXPR
  1022.     fprintf(xmlXPathDebug, "Equal: %d boolean %d n",
  1023.     arg1->boolval, arg2->boolval);
  1024. #endif
  1025.     ret = (arg1->boolval == arg2->boolval);
  1026.     break;
  1027. case XPATH_NUMBER:
  1028.     if (arg2->floatval) ret = 1;
  1029.     else ret = 0;
  1030.     ret = (arg1->boolval == ret);
  1031.     break;
  1032. case XPATH_STRING:
  1033.     if ((arg2->stringval == NULL) ||
  1034. (arg2->stringval[0] == 0)) ret = 0;
  1035.     else 
  1036. ret = 1;
  1037.     ret = (arg1->boolval == ret);
  1038.     break;
  1039.     }
  1040.     break;
  1041.         case XPATH_NUMBER:
  1042.     switch (arg2->type) {
  1043.         case XPATH_UNDEFINED:
  1044. #ifdef DEBUG_EXPR
  1045.     fprintf(xmlXPathDebug, "Equal: undefinedn");
  1046. #endif
  1047.     break;
  1048. case XPATH_NODESET:
  1049.     ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
  1050.     break;
  1051. case XPATH_BOOLEAN:
  1052.     if (arg1->floatval) ret = 1;
  1053.     else ret = 0;
  1054.     ret = (arg2->boolval == ret);
  1055.     break;
  1056. case XPATH_STRING:
  1057.     valuePush(ctxt, arg2);
  1058.     xmlXPathNumberFunction(ctxt, 1);
  1059.     arg2 = valuePop(ctxt);
  1060.     /* no break on purpose */
  1061. case XPATH_NUMBER:
  1062.     ret = (arg1->floatval == arg2->floatval);
  1063.     break;
  1064.     }
  1065.     break;
  1066.         case XPATH_STRING:
  1067.     switch (arg2->type) {
  1068.         case XPATH_UNDEFINED:
  1069. #ifdef DEBUG_EXPR
  1070.     fprintf(xmlXPathDebug, "Equal: undefinedn");
  1071. #endif
  1072.     break;
  1073. case XPATH_NODESET:
  1074.     ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
  1075.     break;
  1076. case XPATH_BOOLEAN:
  1077.     if ((arg1->stringval == NULL) ||
  1078. (arg1->stringval[0] == 0)) ret = 0;
  1079.     else 
  1080. ret = 1;
  1081.     ret = (arg2->boolval == ret);
  1082.     break;
  1083. case XPATH_STRING:
  1084.     ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
  1085.     break;
  1086. case XPATH_NUMBER:
  1087.     valuePush(ctxt, arg1);
  1088.     xmlXPathNumberFunction(ctxt, 1);
  1089.     arg1 = valuePop(ctxt);
  1090.     ret = (arg1->floatval == arg2->floatval);
  1091.     break;
  1092.     }
  1093.     break;
  1094.     }
  1095.     xmlXPathFreeObject(arg1);
  1096.     xmlXPathFreeObject(arg2);
  1097.     return(ret);
  1098. }
  1099. /**
  1100.  * xmlXPathCompareValues:
  1101.  * @ctxt:  the XPath Parser context
  1102.  * @inf:  less than (1) or greater than (2)
  1103.  * @strict:  is the comparison strict
  1104.  *
  1105.  * Implement the compare operation on XPath objects: 
  1106.  *     @arg1 < @arg2    (1, 1, ...
  1107.  *     @arg1 <= @arg2   (1, 0, ...
  1108.  *     @arg1 > @arg2    (0, 1, ...
  1109.  *     @arg1 >= @arg2   (0, 0, ...
  1110.  *
  1111.  * When neither object to be compared is a node-set and the operator is
  1112.  * <=, <, >=, >, then the objects are compared by converted both objects
  1113.  * to numbers and comparing the numbers according to IEEE 754. The <
  1114.  * comparison will be true if and only if the first number is less than the
  1115.  * second number. The <= comparison will be true if and only if the first
  1116.  * number is less than or equal to the second number. The > comparison
  1117.  * will be true if and only if the first number is greater than the second
  1118.  * number. The >= comparison will be true if and only if the first number
  1119.  * is greater than or equal to the second number.
  1120.  */
  1121. int
  1122. xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
  1123.     int ret = 0;
  1124.     xmlXPathObjectPtr arg1, arg2;
  1125.     arg2 = valuePop(ctxt);
  1126.     if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
  1127.         if (arg2 != NULL)
  1128.     xmlXPathFreeObject(arg2);
  1129. ERROR0(XPATH_INVALID_OPERAND);
  1130.     }
  1131.   
  1132.     arg1 = valuePop(ctxt);
  1133.     if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
  1134.         if (arg1 != NULL)
  1135.     xmlXPathFreeObject(arg1);
  1136. xmlXPathFreeObject(arg2);
  1137. ERROR0(XPATH_INVALID_OPERAND);
  1138.     }
  1139.     if (arg1->type != XPATH_NUMBER) {
  1140. valuePush(ctxt, arg1);
  1141. xmlXPathNumberFunction(ctxt, 1);
  1142. arg1 = valuePop(ctxt);
  1143.     }
  1144.     if (arg1->type != XPATH_NUMBER) {
  1145. xmlXPathFreeObject(arg1);
  1146. xmlXPathFreeObject(arg2);
  1147. ERROR0(XPATH_INVALID_OPERAND);
  1148.     }
  1149.     if (arg2->type != XPATH_NUMBER) {
  1150. valuePush(ctxt, arg2);
  1151. xmlXPathNumberFunction(ctxt, 1);
  1152. arg2 = valuePop(ctxt);
  1153.     }
  1154.     if (arg2->type != XPATH_NUMBER) {
  1155. xmlXPathFreeObject(arg1);
  1156. xmlXPathFreeObject(arg2);
  1157. ERROR0(XPATH_INVALID_OPERAND);
  1158.     }
  1159.     /*
  1160.      * Add tests for infinity and nan
  1161.      * => feedback on 3.4 for Inf and NaN
  1162.      */
  1163.     if (inf && strict) 
  1164.         ret = (arg1->floatval < arg2->floatval);
  1165.     else if (inf && !strict)
  1166.         ret = (arg1->floatval <= arg2->floatval);
  1167.     else if (!inf && strict)
  1168.         ret = (arg1->floatval > arg2->floatval);
  1169.     else if (!inf && !strict)
  1170.         ret = (arg1->floatval >= arg2->floatval);
  1171.     xmlXPathFreeObject(arg1);
  1172.     xmlXPathFreeObject(arg2);
  1173.     return(ret);
  1174. }
  1175. /**
  1176.  * xmlXPathValueFlipSign:
  1177.  * @ctxt:  the XPath Parser context
  1178.  *
  1179.  * Implement the unary - operation on an XPath object
  1180.  * The numeric operators convert their operands to numbers as if
  1181.  * by calling the number function.
  1182.  */
  1183. void
  1184. xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
  1185.     xmlXPathObjectPtr arg;
  1186.     
  1187.     POP_FLOAT
  1188.     arg->floatval = -arg->floatval;
  1189.     valuePush(ctxt, arg);
  1190. }
  1191. /**
  1192.  * xmlXPathAddValues:
  1193.  * @ctxt:  the XPath Parser context
  1194.  *
  1195.  * Implement the add operation on XPath objects:
  1196.  * The numeric operators convert their operands to numbers as if
  1197.  * by calling the number function.
  1198.  */
  1199. void
  1200. xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
  1201.     xmlXPathObjectPtr arg;
  1202.     double val;
  1203.     POP_FLOAT
  1204.     val = arg->floatval;
  1205.     xmlXPathFreeObject(arg);
  1206.     POP_FLOAT
  1207.     arg->floatval += val;
  1208.     valuePush(ctxt, arg);
  1209. }
  1210. /**
  1211.  * xmlXPathSubValues:
  1212.  * @ctxt:  the XPath Parser context
  1213.  *
  1214.  * Implement the substraction operation on XPath objects:
  1215.  * The numeric operators convert their operands to numbers as if
  1216.  * by calling the number function.
  1217.  */
  1218. void
  1219. xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
  1220.     xmlXPathObjectPtr arg;
  1221.     double val;
  1222.     POP_FLOAT
  1223.     val = arg->floatval;
  1224.     xmlXPathFreeObject(arg);
  1225.     POP_FLOAT
  1226.     arg->floatval -= val;
  1227.     valuePush(ctxt, arg);
  1228. }
  1229. /**
  1230.  * xmlXPathMultValues:
  1231.  * @ctxt:  the XPath Parser context
  1232.  *
  1233.  * Implement the multiply operation on XPath objects:
  1234.  * The numeric operators convert their operands to numbers as if
  1235.  * by calling the number function.
  1236.  */
  1237. void
  1238. xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
  1239.     xmlXPathObjectPtr arg;
  1240.     double val;
  1241.     POP_FLOAT
  1242.     val = arg->floatval;
  1243.     xmlXPathFreeObject(arg);
  1244.     POP_FLOAT
  1245.     arg->floatval *= val;
  1246.     valuePush(ctxt, arg);
  1247. }
  1248. /**
  1249.  * xmlXPathDivValues:
  1250.  * @ctxt:  the XPath Parser context
  1251.  *
  1252.  * Implement the div operation on XPath objects:
  1253.  * The numeric operators convert their operands to numbers as if
  1254.  * by calling the number function.
  1255.  */
  1256. void
  1257. xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
  1258.     xmlXPathObjectPtr arg;
  1259.     double val;
  1260.     POP_FLOAT
  1261.     val = arg->floatval;
  1262.     xmlXPathFreeObject(arg);
  1263.     POP_FLOAT
  1264.     arg->floatval /= val;
  1265.     valuePush(ctxt, arg);
  1266. }
  1267. /**
  1268.  * xmlXPathModValues:
  1269.  * @ctxt:  the XPath Parser context
  1270.  *
  1271.  * Implement the div operation on XPath objects: @arg1 / @arg2
  1272.  * The numeric operators convert their operands to numbers as if
  1273.  * by calling the number function.
  1274.  */
  1275. void
  1276. xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
  1277.     xmlXPathObjectPtr arg;
  1278.     double val;
  1279.     POP_FLOAT
  1280.     val = arg->floatval;
  1281.     xmlXPathFreeObject(arg);
  1282.     POP_FLOAT
  1283.     arg->floatval /= val;
  1284.     valuePush(ctxt, arg);
  1285. }
  1286. /************************************************************************
  1287.  * *
  1288.  * The traversal functions *
  1289.  * *
  1290.  ************************************************************************/
  1291. #define AXIS_ANCESTOR 1
  1292. #define AXIS_ANCESTOR_OR_SELF 2
  1293. #define AXIS_ATTRIBUTE 3
  1294. #define AXIS_CHILD 4
  1295. #define AXIS_DESCENDANT 5
  1296. #define AXIS_DESCENDANT_OR_SELF 6
  1297. #define AXIS_FOLLOWING 7
  1298. #define AXIS_FOLLOWING_SIBLING 8
  1299. #define AXIS_NAMESPACE 9
  1300. #define AXIS_PARENT 10
  1301. #define AXIS_PRECEDING 11
  1302. #define AXIS_PRECEDING_SIBLING 12
  1303. #define AXIS_SELF 13
  1304. /*
  1305.  * A traversal function enumerates nodes along an axis.
  1306.  * Initially it must be called with NULL, and it indicates
  1307.  * termination on the axis by returning NULL.
  1308.  */
  1309. typedef xmlNodePtr (*xmlXPathTraversalFunction)
  1310.                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
  1311. /**
  1312.  * mlXPathNextSelf:
  1313.  * @ctxt:  the XPath Parser context
  1314.  * @cur:  the current node in the traversal
  1315.  *
  1316.  * Traversal function for the "self" direction
  1317.  * he self axis contains just the context node itself
  1318.  *
  1319.  * Returns the next element following that axis
  1320.  */
  1321. xmlNodePtr
  1322. xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1323.     if (cur == NULL)
  1324.         return(ctxt->context->node);
  1325.     return(NULL);
  1326. }
  1327. /**
  1328.  * mlXPathNextChild:
  1329.  * @ctxt:  the XPath Parser context
  1330.  * @cur:  the current node in the traversal
  1331.  *
  1332.  * Traversal function for the "child" direction
  1333.  * The child axis contains the children of the context node in document order.
  1334.  *
  1335.  * Returns the next element following that axis
  1336.  */
  1337. xmlNodePtr
  1338. xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1339.     if (cur == NULL) {
  1340. if (ctxt->context->node == NULL) return(NULL);
  1341. switch (ctxt->context->node->type) {
  1342.             case XML_ELEMENT_NODE:
  1343.             case XML_TEXT_NODE:
  1344.             case XML_CDATA_SECTION_NODE:
  1345.             case XML_ENTITY_REF_NODE:
  1346.             case XML_ENTITY_NODE:
  1347.             case XML_PI_NODE:
  1348.             case XML_COMMENT_NODE:
  1349.             case XML_NOTATION_NODE:
  1350.             case XML_DTD_NODE:
  1351. return(ctxt->context->node->children);
  1352.             case XML_DOCUMENT_NODE:
  1353.             case XML_DOCUMENT_TYPE_NODE:
  1354.             case XML_DOCUMENT_FRAG_NODE:
  1355.             case XML_HTML_DOCUMENT_NODE:
  1356. return(((xmlDocPtr) ctxt->context->node)->children);
  1357.     case XML_ELEMENT_DECL:
  1358.     case XML_ATTRIBUTE_DECL:
  1359.     case XML_ENTITY_DECL:
  1360.             case XML_ATTRIBUTE_NODE:
  1361. return(NULL);
  1362. }
  1363. return(NULL);
  1364.     }
  1365.     if ((cur->type == XML_DOCUMENT_NODE) ||
  1366.         (cur->type == XML_HTML_DOCUMENT_NODE))
  1367. return(NULL);
  1368.     return(cur->next);
  1369. }
  1370. /**
  1371.  * mlXPathNextDescendant:
  1372.  * @ctxt:  the XPath Parser context
  1373.  * @cur:  the current node in the traversal
  1374.  *
  1375.  * Traversal function for the "descendant" direction
  1376.  * the descendant axis contains the descendants of the context node in document
  1377.  * order; a descendant is a child or a child of a child and so on.
  1378.  *
  1379.  * Returns the next element following that axis
  1380.  */
  1381. xmlNodePtr
  1382. xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1383.     if (cur == NULL) {
  1384. if (ctxt->context->node == NULL)
  1385.     return(NULL);
  1386. if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
  1387.     return(NULL);
  1388.         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  1389.     return(ctxt->context->doc->children);
  1390.         return(ctxt->context->node->children);
  1391.     }
  1392.     if (cur->children != NULL) return(cur->children);
  1393.     if (cur->next != NULL) return(cur->next);
  1394.     
  1395.     do {
  1396.         cur = cur->parent;
  1397. if (cur == NULL) return(NULL);
  1398. if (cur == ctxt->context->node) return(NULL);
  1399. if (cur->next != NULL) {
  1400.     cur = cur->next;
  1401.     return(cur);
  1402. }
  1403.     } while (cur != NULL);
  1404.     return(cur);
  1405. }
  1406. /**
  1407.  * mlXPathNextDescendantOrSelf:
  1408.  * @ctxt:  the XPath Parser context
  1409.  * @cur:  the current node in the traversal
  1410.  *
  1411.  * Traversal function for the "descendant-or-self" direction
  1412.  * the descendant-or-self axis contains the context node and the descendants
  1413.  * of the context node in document order; thus the context node is the first
  1414.  * node on the axis, and the first child of the context node is the second node
  1415.  * on the axis
  1416.  *
  1417.  * Returns the next element following that axis
  1418.  */
  1419. xmlNodePtr
  1420. xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1421.     if (cur == NULL) {
  1422. if (ctxt->context->node == NULL)
  1423.     return(NULL);
  1424. if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
  1425.     return(NULL);
  1426.         return(ctxt->context->node);
  1427.     }
  1428.     return(xmlXPathNextDescendant(ctxt, cur));
  1429. }
  1430. /**
  1431.  * xmlXPathNextParent:
  1432.  * @ctxt:  the XPath Parser context
  1433.  * @cur:  the current node in the traversal
  1434.  *
  1435.  * Traversal function for the "parent" direction
  1436.  * The parent axis contains the parent of the context node, if there is one.
  1437.  *
  1438.  * Returns the next element following that axis
  1439.  */
  1440. xmlNodePtr
  1441. xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1442.     /*
  1443.      * the parent of an attribute or namespace node is the element
  1444.      * to which the attribute or namespace node is attached
  1445.      * Namespace handling !!!
  1446.      */
  1447.     if (cur == NULL) {
  1448. if (ctxt->context->node == NULL) return(NULL);
  1449. switch (ctxt->context->node->type) {
  1450.             case XML_ELEMENT_NODE:
  1451.             case XML_TEXT_NODE:
  1452.             case XML_CDATA_SECTION_NODE:
  1453.             case XML_ENTITY_REF_NODE:
  1454.             case XML_ENTITY_NODE:
  1455.             case XML_PI_NODE:
  1456.             case XML_COMMENT_NODE:
  1457.             case XML_NOTATION_NODE:
  1458.             case XML_DTD_NODE:
  1459.     case XML_ELEMENT_DECL:
  1460.     case XML_ATTRIBUTE_DECL:
  1461.     case XML_ENTITY_DECL:
  1462. if (ctxt->context->node->parent == NULL)
  1463.     return((xmlNodePtr) ctxt->context->doc);
  1464. return(ctxt->context->node->parent);
  1465.             case XML_ATTRIBUTE_NODE: {
  1466. xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  1467. return(att->parent);
  1468.     }
  1469.             case XML_DOCUMENT_NODE:
  1470.             case XML_DOCUMENT_TYPE_NODE:
  1471.             case XML_DOCUMENT_FRAG_NODE:
  1472.             case XML_HTML_DOCUMENT_NODE:
  1473.                 return(NULL);
  1474. }
  1475.     }
  1476.     return(NULL);
  1477. }
  1478. /**
  1479.  * xmlXPathNextAncestor:
  1480.  * @ctxt:  the XPath Parser context
  1481.  * @cur:  the current node in the traversal
  1482.  *
  1483.  * Traversal function for the "ancestor" direction
  1484.  * the ancestor axis contains the ancestors of the context node; the ancestors
  1485.  * of the context node consist of the parent of context node and the parent's
  1486.  * parent and so on; the nodes are ordered in reverse document order; thus the
  1487.  * parent is the first node on the axis, and the parent's parent is the second
  1488.  * node on the axis
  1489.  *
  1490.  * Returns the next element following that axis
  1491.  */
  1492. xmlNodePtr
  1493. xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1494.     /*
  1495.      * the parent of an attribute or namespace node is the element
  1496.      * to which the attribute or namespace node is attached
  1497.      * !!!!!!!!!!!!!
  1498.      */
  1499.     if (cur == NULL) {
  1500. if (ctxt->context->node == NULL) return(NULL);
  1501. switch (ctxt->context->node->type) {
  1502.             case XML_ELEMENT_NODE:
  1503.             case XML_TEXT_NODE:
  1504.             case XML_CDATA_SECTION_NODE:
  1505.             case XML_ENTITY_REF_NODE:
  1506.             case XML_ENTITY_NODE:
  1507.             case XML_PI_NODE:
  1508.             case XML_COMMENT_NODE:
  1509.     case XML_DTD_NODE:
  1510.     case XML_ELEMENT_DECL:
  1511.     case XML_ATTRIBUTE_DECL:
  1512.     case XML_ENTITY_DECL:
  1513.             case XML_NOTATION_NODE:
  1514. if (ctxt->context->node->parent == NULL)
  1515.     return((xmlNodePtr) ctxt->context->doc);
  1516. return(ctxt->context->node->parent);
  1517.             case XML_ATTRIBUTE_NODE: {
  1518. xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
  1519. return(cur->parent);
  1520.     }
  1521.             case XML_DOCUMENT_NODE:
  1522.             case XML_DOCUMENT_TYPE_NODE:
  1523.             case XML_DOCUMENT_FRAG_NODE:
  1524.             case XML_HTML_DOCUMENT_NODE:
  1525.                 return(NULL);
  1526. }
  1527. return(NULL);
  1528.     }
  1529.     if (cur == ctxt->context->doc->children)
  1530. return((xmlNodePtr) ctxt->context->doc);
  1531.     if (cur == (xmlNodePtr) ctxt->context->doc)
  1532. return(NULL);
  1533.     switch (cur->type) {
  1534. case XML_ELEMENT_NODE:
  1535. case XML_TEXT_NODE:
  1536. case XML_CDATA_SECTION_NODE:
  1537. case XML_ENTITY_REF_NODE:
  1538. case XML_ENTITY_NODE:
  1539. case XML_PI_NODE:
  1540. case XML_COMMENT_NODE:
  1541. case XML_NOTATION_NODE:
  1542. case XML_DTD_NODE:
  1543.         case XML_ELEMENT_DECL:
  1544.         case XML_ATTRIBUTE_DECL:
  1545.         case XML_ENTITY_DECL:
  1546.     return(cur->parent);
  1547. case XML_ATTRIBUTE_NODE: {
  1548.     xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  1549.     return(att->parent);
  1550. }
  1551. case XML_DOCUMENT_NODE:
  1552. case XML_DOCUMENT_TYPE_NODE:
  1553. case XML_DOCUMENT_FRAG_NODE:
  1554. case XML_HTML_DOCUMENT_NODE:
  1555.     return(NULL);
  1556.     }
  1557.     return(NULL);
  1558. }
  1559. /**
  1560.  * xmlXPathNextAncestorOrSelf:
  1561.  * @ctxt:  the XPath Parser context
  1562.  * @cur:  the current node in the traversal
  1563.  *
  1564.  * Traversal function for the "ancestor-or-self" direction
  1565.  * he ancestor-or-self axis contains the context node and ancestors of
  1566.  * the context node in reverse document order; thus the context node is
  1567.  * the first node on the axis, and the context node's parent the second;
  1568.  * parent here is defined the same as with the parent axis.
  1569.  *
  1570.  * Returns the next element following that axis
  1571.  */
  1572. xmlNodePtr
  1573. xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1574.     if (cur == NULL)
  1575.         return(ctxt->context->node);
  1576.     return(xmlXPathNextAncestor(ctxt, cur));
  1577. }
  1578. /**
  1579.  * xmlXPathNextFollowingSibling:
  1580.  * @ctxt:  the XPath Parser context
  1581.  * @cur:  the current node in the traversal
  1582.  *
  1583.  * Traversal function for the "following-sibling" direction
  1584.  * The following-sibling axis contains the following siblings of the context
  1585.  * node in document order.
  1586.  *
  1587.  * Returns the next element following that axis
  1588.  */
  1589. xmlNodePtr
  1590. xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1591.     if (cur == (xmlNodePtr) ctxt->context->doc)
  1592.         return(NULL);
  1593.     if (cur == NULL)
  1594.         return(ctxt->context->node->next);
  1595.     return(cur->next);
  1596. }
  1597. /**
  1598.  * xmlXPathNextPrecedingSibling:
  1599.  * @ctxt:  the XPath Parser context
  1600.  * @cur:  the current node in the traversal
  1601.  *
  1602.  * Traversal function for the "preceding-sibling" direction
  1603.  * The preceding-sibling axis contains the preceding siblings of the context
  1604.  * node in reverse document order; the first preceding sibling is first on the
  1605.  * axis; the sibling preceding that node is the second on the axis and so on.
  1606.  *
  1607.  * Returns the next element following that axis
  1608.  */
  1609. xmlNodePtr
  1610. xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1611.     if (cur == (xmlNodePtr) ctxt->context->doc)
  1612.         return(NULL);
  1613.     if (cur == NULL)
  1614.         return(ctxt->context->node->prev);
  1615.     return(cur->prev);
  1616. }
  1617. /**
  1618.  * xmlXPathNextFollowing:
  1619.  * @ctxt:  the XPath Parser context
  1620.  * @cur:  the current node in the traversal
  1621.  *
  1622.  * Traversal function for the "following" direction
  1623.  * The following axis contains all nodes in the same document as the context
  1624.  * node that are after the context node in document order, excluding any
  1625.  * descendants and excluding attribute nodes and namespace nodes; the nodes
  1626.  * are ordered in document order
  1627.  *
  1628.  * Returns the next element following that axis
  1629.  */
  1630. xmlNodePtr
  1631. xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1632.     if (cur == (xmlNodePtr) ctxt->context->doc)
  1633.         return(NULL);
  1634.     if (cur == NULL)
  1635.         return(ctxt->context->node->next);; /* !!!!!!!!! */
  1636.     if (cur->children != NULL) return(cur->children);
  1637.     if (cur->next != NULL) return(cur->next);
  1638.     
  1639.     do {
  1640.         cur = cur->parent;
  1641. if (cur == NULL) return(NULL);
  1642. if (cur == ctxt->context->doc->children) return(NULL);
  1643. if (cur->next != NULL) {
  1644.     cur = cur->next;
  1645.     return(cur);
  1646. }
  1647.     } while (cur != NULL);
  1648.     return(cur);
  1649. }
  1650. /**
  1651.  * xmlXPathNextPreceding:
  1652.  * @ctxt:  the XPath Parser context
  1653.  * @cur:  the current node in the traversal
  1654.  *
  1655.  * Traversal function for the "preceding" direction
  1656.  * the preceding axis contains all nodes in the same document as the context
  1657.  * node that are before the context node in document order, excluding any
  1658.  * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  1659.  * ordered in reverse document order
  1660.  *
  1661.  * Returns the next element following that axis
  1662.  */
  1663. xmlNodePtr
  1664. xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  1665.     if (cur == (xmlNodePtr) ctxt->context->doc)
  1666.         return(NULL);
  1667.     if (cur == NULL)
  1668.         return(ctxt->context->node->prev); /* !!!!!!!!! */
  1669.     if (cur->last != NULL) return(cur->last);
  1670.     if (cur->prev != NULL) return(cur->prev);
  1671.     
  1672.     do {
  1673.         cur = cur->parent;
  1674. if (cur == NULL) return(NULL);
  1675. if (cur == ctxt->context->doc->children) return(NULL);
  1676. if (cur->prev != NULL) {
  1677.     cur = cur->prev;
  1678.     return(cur);
  1679. }
  1680.     } while (cur != NULL);
  1681.     return(cur);
  1682. }
  1683. /**
  1684.  * xmlXPathNextNamespace:
  1685.  * @ctxt:  the XPath Parser context
  1686.  * @cur:  the current attribute in the traversal
  1687.  *
  1688.  * Traversal function for the "namespace" direction
  1689.  * the namespace axis contains the namespace nodes of the context node;
  1690.  * the order of nodes on this axis is implementation-defined; the axis will
  1691.  * be empty unless the context node is an element
  1692.  *
  1693.  * Returns the next element following that axis
  1694.  */
  1695. xmlNsPtr
  1696. xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
  1697.     if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
  1698.         if (ctxt->context->namespaces != NULL)
  1699.     xmlFree(ctxt->context->namespaces);
  1700. ctxt->context->namespaces = 
  1701.     xmlGetNsList(ctxt->context->doc, ctxt->context->node);
  1702. if (ctxt->context->namespaces == NULL) return(NULL);
  1703. ctxt->context->nsNr = 0;
  1704.     }
  1705.     return(ctxt->context->namespaces[ctxt->context->nsNr++]);
  1706. }
  1707. /**
  1708.  * xmlXPathNextAttribute:
  1709.  * @ctxt:  the XPath Parser context
  1710.  * @cur:  the current attribute in the traversal
  1711.  *
  1712.  * Traversal function for the "attribute" direction
  1713.  * TODO: support DTD inherited default attributes
  1714.  *
  1715.  * Returns the next element following that axis
  1716.  */
  1717. xmlAttrPtr
  1718. xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
  1719.     if (cur == NULL) {
  1720.         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  1721.     return(NULL);
  1722.         return(ctxt->context->node->properties);
  1723.     }
  1724.     return(cur->next);
  1725. }
  1726. /************************************************************************
  1727.  * *
  1728.  * NodeTest Functions *
  1729.  * *
  1730.  ************************************************************************/
  1731. #define NODE_TEST_NONE 0
  1732. #define NODE_TEST_TYPE 1
  1733. #define NODE_TEST_PI 2
  1734. #define NODE_TEST_ALL 3
  1735. #define NODE_TEST_NS 4
  1736. #define NODE_TEST_NAME 5
  1737. #define NODE_TYPE_COMMENT 50
  1738. #define NODE_TYPE_TEXT 51
  1739. #define NODE_TYPE_PI 52
  1740. #define NODE_TYPE_NODE 53
  1741. #define IS_FUNCTION 200
  1742. /**
  1743.  * xmlXPathNodeCollectAndTest:
  1744.  * @ctxt:  the XPath Parser context
  1745.  * @cur:  the current node to test
  1746.  *
  1747.  * This is the function implementing a step: based on the current list
  1748.  * of nodes, it builds up a new list, looking at all nodes under that
  1749.  * axis and selecting them.
  1750.  *
  1751.  * Returns the new NodeSet resulting from the search.
  1752.  */
  1753. xmlNodeSetPtr
  1754. xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
  1755.                  int test, int type, const xmlChar *prefix, const xmlChar *name) {
  1756. #ifdef DEBUG_STEP
  1757.     int n = 0, t = 0;
  1758. #endif
  1759.     int i;
  1760.     xmlNodeSetPtr ret;
  1761.     xmlXPathTraversalFunction next = NULL;
  1762.     xmlNodePtr cur = NULL;
  1763.     if (ctxt->context->nodelist == NULL) {
  1764. if (ctxt->context->node == NULL) {
  1765.     fprintf(xmlXPathDebug,
  1766.      "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULLn",
  1767.             __FILE__, __LINE__);
  1768.     return(NULL);
  1769. }
  1770.         STRANGE
  1771.         return(NULL);
  1772.     }
  1773. #ifdef DEBUG_STEP
  1774.     fprintf(xmlXPathDebug, "new step : ");
  1775. #endif
  1776.     switch (axis) {
  1777.         case AXIS_ANCESTOR:
  1778. #ifdef DEBUG_STEP
  1779.     fprintf(xmlXPathDebug, "axis 'ancestors' ");
  1780. #endif
  1781.     next = xmlXPathNextAncestor; break;
  1782.         case AXIS_ANCESTOR_OR_SELF:
  1783. #ifdef DEBUG_STEP
  1784.     fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
  1785. #endif
  1786.     next = xmlXPathNextAncestorOrSelf; break;
  1787.         case AXIS_ATTRIBUTE:
  1788. #ifdef DEBUG_STEP
  1789.     fprintf(xmlXPathDebug, "axis 'attributes' ");
  1790. #endif
  1791.     next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
  1792.     break;
  1793.         case AXIS_CHILD:
  1794. #ifdef DEBUG_STEP
  1795.     fprintf(xmlXPathDebug, "axis 'child' ");
  1796. #endif
  1797.     next = xmlXPathNextChild; break;
  1798.         case AXIS_DESCENDANT:
  1799. #ifdef DEBUG_STEP
  1800.     fprintf(xmlXPathDebug, "axis 'descendant' ");
  1801. #endif
  1802.     next = xmlXPathNextDescendant; break;
  1803.         case AXIS_DESCENDANT_OR_SELF:
  1804. #ifdef DEBUG_STEP
  1805.     fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
  1806. #endif
  1807.     next = xmlXPathNextDescendantOrSelf; break;
  1808.         case AXIS_FOLLOWING:
  1809. #ifdef DEBUG_STEP
  1810.     fprintf(xmlXPathDebug, "axis 'following' ");
  1811. #endif
  1812.     next = xmlXPathNextFollowing; break;
  1813.         case AXIS_FOLLOWING_SIBLING:
  1814. #ifdef DEBUG_STEP
  1815.     fprintf(xmlXPathDebug, "axis 'following-siblings' ");
  1816. #endif
  1817.     next = xmlXPathNextFollowingSibling; break;
  1818.         case AXIS_NAMESPACE:
  1819. #ifdef DEBUG_STEP
  1820.     fprintf(xmlXPathDebug, "axis 'namespace' ");
  1821. #endif
  1822.     next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
  1823.     break;
  1824.         case AXIS_PARENT:
  1825. #ifdef DEBUG_STEP
  1826.     fprintf(xmlXPathDebug, "axis 'parent' ");
  1827. #endif
  1828.     next = xmlXPathNextParent; break;
  1829.         case AXIS_PRECEDING:
  1830. #ifdef DEBUG_STEP
  1831.     fprintf(xmlXPathDebug, "axis 'preceding' ");
  1832. #endif
  1833.     next = xmlXPathNextPreceding; break;
  1834.         case AXIS_PRECEDING_SIBLING:
  1835. #ifdef DEBUG_STEP
  1836.     fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
  1837. #endif
  1838.     next = xmlXPathNextPrecedingSibling; break;
  1839.         case AXIS_SELF:
  1840. #ifdef DEBUG_STEP
  1841.     fprintf(xmlXPathDebug, "axis 'self' ");
  1842. #endif
  1843.     next = xmlXPathNextSelf; break;
  1844.     }
  1845.     if (next == NULL) return(NULL);
  1846.     ret = xmlXPathNodeSetCreate(NULL);
  1847. #ifdef DEBUG_STEP
  1848.     fprintf(xmlXPathDebug, " context contains %d nodesn",
  1849.             ctxt->context->nodelist->nodeNr);
  1850.     switch (test) {
  1851. case NODE_TEST_NONE:
  1852.     fprintf(xmlXPathDebug, "           searching for none !!!n");
  1853.     break;
  1854. case NODE_TEST_TYPE:
  1855.     fprintf(xmlXPathDebug, "           searching for type %dn", type);
  1856.     break;
  1857. case NODE_TEST_PI:
  1858.     fprintf(xmlXPathDebug, "           searching for PI !!!n");
  1859.     break;
  1860. case NODE_TEST_ALL:
  1861.     fprintf(xmlXPathDebug, "           searching for *n");
  1862.     break;
  1863. case NODE_TEST_NS:
  1864.     fprintf(xmlXPathDebug, "           searching for namespace %sn",
  1865.             prefix);
  1866.     break;
  1867. case NODE_TEST_NAME:
  1868.     fprintf(xmlXPathDebug, "           searching for name %sn", name);
  1869.     if (prefix != NULL)
  1870. fprintf(xmlXPathDebug, "           with namespace %sn",
  1871.         prefix);
  1872.     break;
  1873.     }
  1874.     fprintf(xmlXPathDebug, "Testing : ");
  1875. #endif
  1876.     for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
  1877.         ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
  1878. cur = NULL;
  1879. do {
  1880.     cur = next(ctxt, cur);
  1881.     if (cur == NULL) break;
  1882. #ifdef DEBUG_STEP
  1883.             t++;
  1884.             fprintf(xmlXPathDebug, " %s", cur->name);
  1885. #endif
  1886.     switch (test) {
  1887.                 case NODE_TEST_NONE:
  1888.     STRANGE
  1889.     return(NULL);
  1890.                 case NODE_TEST_TYPE:
  1891.     if ((cur->type == type) ||
  1892.         ((type == XML_ELEMENT_NODE) && 
  1893.  ((cur->type == XML_DOCUMENT_NODE) ||
  1894.   (cur->type == XML_HTML_DOCUMENT_NODE)))) {
  1895. #ifdef DEBUG_STEP
  1896.                         n++;
  1897. #endif
  1898.         xmlXPathNodeSetAdd(ret, cur);
  1899.     }
  1900.     break;
  1901.                 case NODE_TEST_PI:
  1902.     if (cur->type == XML_PI_NODE) {
  1903.         if ((name != NULL) &&
  1904.     (xmlStrcmp(name, cur->name)))
  1905.     break;
  1906. #ifdef DEBUG_STEP
  1907. n++;
  1908. #endif
  1909. xmlXPathNodeSetAdd(ret, cur);
  1910.     }
  1911.     break;
  1912.                 case NODE_TEST_ALL:
  1913.     if ((cur->type == XML_ELEMENT_NODE) ||
  1914.         (cur->type == XML_ATTRIBUTE_NODE)) {
  1915. /* !!! || (cur->type == XML_TEXT_NODE)) { */
  1916. #ifdef DEBUG_STEP
  1917.                         n++;
  1918. #endif
  1919.         xmlXPathNodeSetAdd(ret, cur);
  1920.     }
  1921.     break;
  1922.                 case NODE_TEST_NS: {
  1923.     TODO /* namespace search */
  1924.     break;
  1925. }
  1926.                 case NODE_TEST_NAME:
  1927.     switch (cur->type) {
  1928.         case XML_ELEMENT_NODE:
  1929.     if (!xmlStrcmp(name, cur->name) && 
  1930. (((prefix == NULL) ||
  1931.   ((cur->ns != NULL) && 
  1932.    (!xmlStrcmp(prefix, cur->ns->href)))))) {
  1933. #ifdef DEBUG_STEP
  1934.     n++;
  1935. #endif
  1936. xmlXPathNodeSetAdd(ret, cur);
  1937.     }
  1938.     break;
  1939.         case XML_ATTRIBUTE_NODE: {
  1940.     xmlAttrPtr attr = (xmlAttrPtr) cur;
  1941.     if (!xmlStrcmp(name, attr->name)) {
  1942. #ifdef DEBUG_STEP
  1943.     n++;
  1944. #endif
  1945. xmlXPathNodeSetAdd(ret, cur);
  1946.     }
  1947.     break;
  1948. }
  1949. default:
  1950.     break;
  1951.     }
  1952.             break;
  1953.     
  1954.     }
  1955. } while (cur != NULL);
  1956.     }
  1957. #ifdef DEBUG_STEP
  1958.     fprintf(xmlXPathDebug,
  1959.             "nExamined %d nodes, found %d nodes at that stepn", t, n);
  1960. #endif
  1961.     return(ret);
  1962. }
  1963. /************************************************************************
  1964.  * *
  1965.  * Implicit tree core function library *
  1966.  * *
  1967.  ************************************************************************/
  1968. /**
  1969.  * xmlXPathRoot:
  1970.  * @ctxt:  the XPath Parser context
  1971.  *
  1972.  * Initialize the context to the root of the document
  1973.  */
  1974. void
  1975. xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
  1976.     if (ctxt->context->nodelist != NULL)
  1977.         xmlXPathFreeNodeSet(ctxt->context->nodelist);
  1978.     ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
  1979.     ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
  1980. }
  1981. /************************************************************************
  1982.  * *
  1983.  * The explicit core function library *
  1984.  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
  1985.  * *
  1986.  ************************************************************************/
  1987. /**
  1988.  * xmlXPathLastFunction:
  1989.  * @ctxt:  the XPath Parser context
  1990.  *
  1991.  * Implement the last() XPath function
  1992.  * The last function returns the number of nodes in the context node list.
  1993.  */
  1994. void
  1995. xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  1996.     CHECK_ARITY(0);
  1997.     if ((ctxt->context->nodelist == NULL) ||
  1998.         (ctxt->context->node == NULL) ||
  1999.         (ctxt->context->nodelist->nodeNr == 0)) {
  2000. valuePush(ctxt, xmlXPathNewFloat((double) 0));
  2001.     } else {
  2002. valuePush(ctxt, 
  2003.           xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
  2004.     }
  2005. }
  2006. /**
  2007.  * xmlXPathPositionFunction:
  2008.  * @ctxt:  the XPath Parser context
  2009.  *
  2010.  * Implement the position() XPath function
  2011.  * The position function returns the position of the context node in the
  2012.  * context node list. The first position is 1, and so the last positionr
  2013.  * will be equal to last().
  2014.  */
  2015. void
  2016. xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2017.     int i;
  2018.     CHECK_ARITY(0);
  2019.     if ((ctxt->context->nodelist == NULL) ||
  2020.         (ctxt->context->node == NULL) ||
  2021.         (ctxt->context->nodelist->nodeNr == 0)) {
  2022. valuePush(ctxt, xmlXPathNewFloat((double) 0));
  2023.     }
  2024.     for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
  2025.         if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
  2026.     valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
  2027.     return;
  2028. }
  2029.     }
  2030.     valuePush(ctxt, xmlXPathNewFloat((double) 0));
  2031. }
  2032. /**
  2033.  * xmlXPathCountFunction:
  2034.  * @ctxt:  the XPath Parser context
  2035.  *
  2036.  * Implement the count() XPath function
  2037.  */
  2038. void
  2039. xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2040.     xmlXPathObjectPtr cur;
  2041.     CHECK_ARITY(1);
  2042.     CHECK_TYPE(XPATH_NODESET);
  2043.     cur = valuePop(ctxt);
  2044.     valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
  2045.     xmlXPathFreeObject(cur);
  2046. }
  2047. /**
  2048.  * xmlXPathIdFunction:
  2049.  * @ctxt:  the XPath Parser context
  2050.  *
  2051.  * Implement the id() XPath function
  2052.  * The id function selects elements by their unique ID
  2053.  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
  2054.  * then the result is the union of the result of applying id to the
  2055.  * string value of each of the nodes in the argument node-set. When the
  2056.  * argument to id is of any other type, the argument is converted to a
  2057.  * string as if by a call to the string function; the string is split
  2058.  * into a whitespace-separated list of tokens (whitespace is any sequence
  2059.  * of characters matching the production S); the result is a node-set
  2060.  * containing the elements in the same document as the context node that
  2061.  * have a unique ID equal to any of the tokens in the list.
  2062.  */
  2063. void
  2064. xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2065.     const xmlChar *tokens;
  2066.     const xmlChar *cur;
  2067.     xmlChar *ID;
  2068.     xmlAttrPtr attr;
  2069.     xmlNodePtr elem = NULL;
  2070.     xmlXPathObjectPtr ret, obj;
  2071.     CHECK_ARITY(1);
  2072.     obj = valuePop(ctxt);
  2073.     if (obj == NULL) ERROR(XPATH_INVALID_OPERAND);
  2074.     if (obj->type == XPATH_NODESET) {
  2075.         TODO /* ID function in case of NodeSet */
  2076.     }
  2077.     if (obj->type != XPATH_STRING) {
  2078.         valuePush(ctxt, obj);
  2079. xmlXPathStringFunction(ctxt, 1);
  2080. obj = valuePop(ctxt);
  2081. if (obj->type != XPATH_STRING) {
  2082.     xmlXPathFreeObject(obj);
  2083.     return;
  2084. }
  2085.     }
  2086.     tokens = obj->stringval;
  2087.     ret = xmlXPathNewNodeSet(NULL);
  2088.     valuePush(ctxt, ret);
  2089.     if (tokens == NULL) {
  2090. xmlXPathFreeObject(obj);
  2091.         return;
  2092.     }
  2093.     cur = tokens;
  2094.     
  2095.     while (IS_BLANK(*cur)) cur++;
  2096.     while (*cur != 0) {
  2097. while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
  2098.        (*cur == '.') || (*cur == '-') ||
  2099.        (*cur == '_') || (*cur == ':') || 
  2100.        (IS_COMBINING(*cur)) ||
  2101.        (IS_EXTENDER(*cur)))
  2102.        cur++;
  2103. if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
  2104.         ID = xmlStrndup(tokens, cur - tokens);
  2105. attr = xmlGetID(ctxt->context->doc, ID);
  2106. if (attr != NULL) {
  2107.     elem = attr->parent;
  2108.             xmlXPathNodeSetAdd(ret->nodesetval, elem);
  2109.         }
  2110. if (ID != NULL)
  2111.     xmlFree(ID);
  2112. while (IS_BLANK(*cur)) cur++;
  2113. tokens = cur;
  2114.     }
  2115.     xmlXPathFreeObject(obj);
  2116.     return;
  2117. }
  2118. /**
  2119.  * xmlXPathLocalPartFunction:
  2120.  * @ctxt:  the XPath Parser context
  2121.  *
  2122.  * Implement the local-part() XPath function
  2123.  * The local-part function returns a string containing the local part
  2124.  * of the name of the node in the argument node-set that is first in
  2125.  * document order. If the node-set is empty or the first node has no
  2126.  * name, an empty string is returned. If the argument is omitted it
  2127.  * defaults to the context node.
  2128.  */
  2129. void
  2130. xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2131.     xmlXPathObjectPtr cur;
  2132.     CHECK_ARITY(1);
  2133.     CHECK_TYPE(XPATH_NODESET);
  2134.     cur = valuePop(ctxt);
  2135.     if (cur->nodesetval->nodeNr == 0) {
  2136. valuePush(ctxt, xmlXPathNewCString(""));
  2137.     } else {
  2138. int i = 0; /* Should be first in document order !!!!! */
  2139. valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
  2140.     }
  2141.     xmlXPathFreeObject(cur);
  2142. }
  2143. /**
  2144.  * xmlXPathNamespaceFunction:
  2145.  * @ctxt:  the XPath Parser context
  2146.  *
  2147.  * Implement the namespace() XPath function
  2148.  * The namespace function returns a string containing the namespace URI
  2149.  * of the expanded name of the node in the argument node-set that is
  2150.  * first in document order. If the node-set is empty, the first node has
  2151.  * no name, or the expanded name has no namespace URI, an empty string
  2152.  * is returned. If the argument is omitted it defaults to the context node.
  2153.  */
  2154. void
  2155. xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2156.     xmlXPathObjectPtr cur;
  2157.     if (nargs == 0) {
  2158.         valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
  2159. nargs = 1;
  2160.     }
  2161.     CHECK_ARITY(1);
  2162.     CHECK_TYPE(XPATH_NODESET);
  2163.     cur = valuePop(ctxt);
  2164.     if (cur->nodesetval->nodeNr == 0) {
  2165. valuePush(ctxt, xmlXPathNewCString(""));
  2166.     } else {
  2167. int i = 0; /* Should be first in document order !!!!! */
  2168. if (cur->nodesetval->nodeTab[i]->ns == NULL)
  2169.     valuePush(ctxt, xmlXPathNewCString(""));
  2170. else
  2171.     valuePush(ctxt, xmlXPathNewString(
  2172.       cur->nodesetval->nodeTab[i]->ns->href));
  2173.     }
  2174.     xmlXPathFreeObject(cur);
  2175. }
  2176. /**
  2177.  * xmlXPathNameFunction:
  2178.  * @ctxt:  the XPath Parser context
  2179.  *
  2180.  * Implement the name() XPath function
  2181.  * The name function returns a string containing a QName representing
  2182.  * the name of the node in the argument node-set that is first in documenti
  2183.  * order. The QName must represent the name with respect to the namespace
  2184.  * declarations in effect on the node whose name is being represented.
  2185.  * Typically, this will be the form in which the name occurred in the XML
  2186.  * source. This need not be the case if there are namespace declarations
  2187.  * in effect on the node that associate multiple prefixes with the same
  2188.  * namespace. However, an implementation may include information about
  2189.  * the original prefix in its representation of nodes; in this case, an
  2190.  * implementation can ensure that the returned string is always the same
  2191.  * as the QName used in the XML source. If the argument it omitted it
  2192.  * defaults to the context node.
  2193.  * Libxml keep the original prefix so the "real qualified name" used is
  2194.  * returned.
  2195.  */
  2196. void
  2197. xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2198.     xmlXPathObjectPtr cur;
  2199.     CHECK_ARITY(1);
  2200.     CHECK_TYPE(XPATH_NODESET);
  2201.     cur = valuePop(ctxt);
  2202.     if (cur->nodesetval->nodeNr == 0) {
  2203. valuePush(ctxt, xmlXPathNewCString(""));
  2204.     } else {
  2205. int i = 0; /* Should be first in document order !!!!! */
  2206. if (cur->nodesetval->nodeTab[i]->ns == NULL)
  2207.     valuePush(ctxt, xmlXPathNewString(
  2208.                 cur->nodesetval->nodeTab[i]->name));
  2209.     
  2210. else {
  2211.     char name[2000];
  2212.     sprintf(name, "%s:%s", 
  2213.             (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
  2214.             (char *) cur->nodesetval->nodeTab[i]->name);
  2215.     valuePush(ctxt, xmlXPathNewCString(name));
  2216.         }
  2217.     }
  2218.     xmlXPathFreeObject(cur);
  2219. }
  2220. /**
  2221.  * xmlXPathStringFunction:
  2222.  * @ctxt:  the XPath Parser context
  2223.  *
  2224.  * Implement the string() XPath function
  2225.  * he string function converts an object to a string as follows:
  2226.  *    - A node-set is converted to a string by returning the value of
  2227.  *      the node in the node-set that is first in document order.
  2228.  *      If the node-set is empty, an empty string is returned.
  2229.  *    - A number is converted to a string as follows
  2230.  *      + NaN is converted to the string NaN 
  2231.  *      + positive zero is converted to the string 0 
  2232.  *      + negative zero is converted to the string 0 
  2233.  *      + positive infinity is converted to the string Infinity 
  2234.  *      + negative infinity is converted to the string -Infinity 
  2235.  *      + if the number is an integer, the number is represented in
  2236.  *        decimal form as a Number with no decimal point and no leading
  2237.  *        zeros, preceded by a minus sign (-) if the number is negative
  2238.  *      + otherwise, the number is represented in decimal form as a
  2239.  *        Number including a decimal point with at least one digit
  2240.  *        before the decimal point and at least one digit after the
  2241.  *        decimal point, preceded by a minus sign (-) if the number
  2242.  *        is negative; there must be no leading zeros before the decimal
  2243.  *        point apart possibly from the one required digit immediatelyi
  2244.  *        before the decimal point; beyond the one required digit
  2245.  *        after the decimal point there must be as many, but only as
  2246.  *        many, more digits as are needed to uniquely distinguish the
  2247.  *        number from all other IEEE 754 numeric values.
  2248.  *    - The boolean false value is converted to the string false.
  2249.  *      The boolean true value is converted to the string true.
  2250.  */
  2251. void
  2252. xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2253.     xmlXPathObjectPtr cur;
  2254.     CHECK_ARITY(1);
  2255.     cur = valuePop(ctxt);
  2256.     if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
  2257.     switch (cur->type) {
  2258.         case XPATH_NODESET:
  2259.     if (cur->nodesetval->nodeNr == 0) {
  2260. valuePush(ctxt, xmlXPathNewCString(""));
  2261.     } else {
  2262. xmlChar *res;
  2263.         int i = 0; /* Should be first in document order !!!!! */
  2264. res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
  2265. valuePush(ctxt, xmlXPathNewString(res));
  2266. xmlFree(res);
  2267.     }
  2268.     xmlXPathFreeObject(cur);
  2269.     return;
  2270. case XPATH_STRING:
  2271.     valuePush(ctxt, cur);
  2272.     return;
  2273.         case XPATH_BOOLEAN:
  2274.     if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
  2275.     else valuePush(ctxt, xmlXPathNewCString("false"));
  2276.     xmlXPathFreeObject(cur);
  2277.     return;
  2278. case XPATH_NUMBER: {
  2279.     char buf[100];
  2280.     if (isnan(cur->floatval))
  2281.         sprintf(buf, "NaN");
  2282.     else if (isinf(cur->floatval) > 0)
  2283.         sprintf(buf, "+Infinity");
  2284.     else if (isinf(cur->floatval) < 0)
  2285.         sprintf(buf, "-Infinity");
  2286.     else
  2287. sprintf(buf, "%0g", cur->floatval);
  2288.     valuePush(ctxt, xmlXPathNewCString(buf));
  2289.     xmlXPathFreeObject(cur);
  2290.     return;
  2291. }
  2292.     }
  2293.     STRANGE
  2294. }
  2295. /**
  2296.  * xmlXPathStringLengthFunction:
  2297.  * @ctxt:  the XPath Parser context
  2298.  *
  2299.  * Implement the string-length() XPath function
  2300.  * The string-length returns the number of characters in the string
  2301.  * (see [3.6 Strings]). If the argument is omitted, it defaults to
  2302.  * the context node converted to a string, in other words the value
  2303.  * of the context node.
  2304.  */
  2305. void
  2306. xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2307.     xmlXPathObjectPtr cur;
  2308.     if (nargs == 0) {
  2309. if (ctxt->context->node == NULL) {
  2310.     valuePush(ctxt, xmlXPathNewFloat(0));
  2311. } else {
  2312.     xmlChar *content;
  2313.     content = xmlNodeGetContent(ctxt->context->node);
  2314.     valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
  2315.     xmlFree(content);
  2316. }
  2317. return;
  2318.     }
  2319.     CHECK_ARITY(1);
  2320.     CHECK_TYPE(XPATH_STRING);
  2321.     cur = valuePop(ctxt);
  2322.     valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
  2323.     xmlXPathFreeObject(cur);
  2324. }
  2325. /**
  2326.  * xmlXPathConcatFunction:
  2327.  * @ctxt:  the XPath Parser context
  2328.  *
  2329.  * Implement the concat() XPath function
  2330.  * The concat function returns the concatenation of its arguments.
  2331.  */
  2332. void
  2333. xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2334.     xmlXPathObjectPtr cur, new;
  2335.     xmlChar *tmp;
  2336.     if (nargs < 2) {
  2337. CHECK_ARITY(2);
  2338.     }
  2339.     cur = valuePop(ctxt);
  2340.     if ((cur == NULL) || (cur->type != XPATH_STRING)) {
  2341.         xmlXPathFreeObject(cur);
  2342. return;
  2343.     }
  2344.     nargs--;
  2345.     while (nargs > 0) {
  2346. new = valuePop(ctxt);
  2347. if ((new == NULL) || (new->type != XPATH_STRING)) {
  2348.     xmlXPathFreeObject(new);
  2349.     xmlXPathFreeObject(cur);
  2350.     ERROR(XPATH_INVALID_TYPE);
  2351. }
  2352. tmp = xmlStrcat(new->stringval, cur->stringval);
  2353. new->stringval = cur->stringval;
  2354. cur->stringval = tmp;
  2355. xmlXPathFreeObject(new);
  2356. nargs--;
  2357.     }
  2358.     valuePush(ctxt, cur);
  2359. }
  2360. /**
  2361.  * xmlXPathContainsFunction:
  2362.  * @ctxt:  the XPath Parser context
  2363.  *
  2364.  * Implement the contains() XPath function
  2365.  * The contains function returns true if the first argument string
  2366.  * contains the second argument string, and otherwise returns false.
  2367.  */
  2368. void
  2369. xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2370.     xmlXPathObjectPtr hay, needle;
  2371.     CHECK_ARITY(2);
  2372.     CHECK_TYPE(XPATH_STRING);
  2373.     needle = valuePop(ctxt);
  2374.     hay = valuePop(ctxt);
  2375.     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  2376.         xmlXPathFreeObject(hay);
  2377.         xmlXPathFreeObject(needle);
  2378. ERROR(XPATH_INVALID_TYPE);
  2379.     }
  2380.     if (xmlStrstr(hay->stringval, needle->stringval))
  2381.         valuePush(ctxt, xmlXPathNewBoolean(1));
  2382.     else
  2383.         valuePush(ctxt, xmlXPathNewBoolean(0));
  2384.     xmlXPathFreeObject(hay);
  2385.     xmlXPathFreeObject(needle);
  2386. }
  2387. /**
  2388.  * xmlXPathStartsWithFunction:
  2389.  * @ctxt:  the XPath Parser context
  2390.  *
  2391.  * Implement the starts-with() XPath function
  2392.  * The starts-with function returns true if the first argument string
  2393.  * starts with the second argument string, and otherwise returns false.
  2394.  */
  2395. void
  2396. xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2397.     xmlXPathObjectPtr hay, needle;
  2398.     int n;
  2399.     CHECK_ARITY(2);
  2400.     CHECK_TYPE(XPATH_STRING);
  2401.     needle = valuePop(ctxt);
  2402.     hay = valuePop(ctxt);
  2403.     if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  2404.         xmlXPathFreeObject(hay);
  2405.         xmlXPathFreeObject(needle);
  2406. ERROR(XPATH_INVALID_TYPE);
  2407.     }
  2408.     n = xmlStrlen(needle->stringval);
  2409.     if (xmlStrncmp(hay->stringval, needle->stringval, n))
  2410.         valuePush(ctxt, xmlXPathNewBoolean(0));
  2411.     else
  2412.         valuePush(ctxt, xmlXPathNewBoolean(1));
  2413.     xmlXPathFreeObject(hay);
  2414.     xmlXPathFreeObject(needle);
  2415. }
  2416. /**
  2417.  * xmlXPathSubstringFunction:
  2418.  * @ctxt:  the XPath Parser context
  2419.  *
  2420.  * Implement the substring() XPath function
  2421.  * The substring function returns the substring of the first argument
  2422.  * starting at the position specified in the second argument with
  2423.  * length specified in the third argument. For example,
  2424.  * substring("12345",2,3) returns "234". If the third argument is not
  2425.  * specified, it returns the substring starting at the position specified
  2426.  * in the second argument and continuing to the end of the string. For
  2427.  * example, substring("12345",2) returns "2345".  More precisely, each
  2428.  * character in the string (see [3.6 Strings]) is considered to have a
  2429.  * numeric position: the position of the first character is 1, the position
  2430.  * of the second character is 2 and so on. The returned substring contains
  2431.  * those characters for which the position of the character is greater than
  2432.  * or equal to the second argument and, if the third argument is specified,
  2433.  * less than the sum of the second and third arguments; the comparisons
  2434.  * and addition used for the above follow the standard IEEE 754 rules. Thus:
  2435.  *  - substring("12345", 1.5, 2.6) returns "234" 
  2436.  *  - substring("12345", 0, 3) returns "12" 
  2437.  *  - substring("12345", 0 div 0, 3) returns "" 
  2438.  *  - substring("12345", 1, 0 div 0) returns "" 
  2439.  *  - substring("12345", -42, 1 div 0) returns "12345" 
  2440.  *  - substring("12345", -1 div 0, 1 div 0) returns "" 
  2441.  */
  2442. void
  2443. xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2444.     xmlXPathObjectPtr str, start, len;
  2445.     double le, in;
  2446.     int i, l;
  2447.     xmlChar *ret;
  2448.     /* 
  2449.      * Conformance needs to be checked !!!!!
  2450.      */
  2451.     if (nargs < 2) {
  2452. CHECK_ARITY(2);
  2453.     }
  2454.     if (nargs > 3) {
  2455. CHECK_ARITY(3);
  2456.     }
  2457.     if (nargs == 3) {
  2458. CHECK_TYPE(XPATH_NUMBER);
  2459. len = valuePop(ctxt);
  2460. le = len->floatval;
  2461.         xmlXPathFreeObject(len);
  2462.     } else {
  2463. le = 2000000000;
  2464.     }
  2465.     CHECK_TYPE(XPATH_NUMBER);
  2466.     start = valuePop(ctxt);
  2467.     in = start->floatval;
  2468.     xmlXPathFreeObject(start);
  2469.     CHECK_TYPE(XPATH_STRING);
  2470.     str = valuePop(ctxt);
  2471.     le += in;
  2472.     /* integer index of the first char */
  2473.     i = in;
  2474.     if (((double)i) != in) i++;
  2475.     
  2476.     /* integer index of the last char */
  2477.     l = le;
  2478.     if (((double)l) != le) l++;
  2479.     /* back to a zero based len */
  2480.     i--;
  2481.     l--;
  2482.     /* check against the string len */
  2483.     if (l > 1024) {
  2484.         l = xmlStrlen(str->stringval);
  2485.     }
  2486.     if (i < 0) {
  2487.         i = 0;
  2488.     }
  2489.     /* number of chars to copy */
  2490.     l -= i;
  2491.     ret = xmlStrsub(str->stringval, i, l);
  2492.     if (ret == NULL)
  2493. valuePush(ctxt, xmlXPathNewCString(""));
  2494.     else {
  2495. valuePush(ctxt, xmlXPathNewString(ret));
  2496. xmlFree(ret);
  2497.     }
  2498.     xmlXPathFreeObject(str);
  2499. }
  2500. /**
  2501.  * xmlXPathSubstringBeforeFunction:
  2502.  * @ctxt:  the XPath Parser context
  2503.  *
  2504.  * Implement the substring-before() XPath function
  2505.  * The substring-before function returns the substring of the first
  2506.  * argument string that precedes the first occurrence of the second
  2507.  * argument string in the first argument string, or the empty string
  2508.  * if the first argument string does not contain the second argument
  2509.  * string. For example, substring-before("1999/04/01","/") returns 1999.
  2510.  */
  2511. void
  2512. xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2513.     CHECK_ARITY(2);
  2514.     TODO /* substring before */
  2515. }
  2516. /**
  2517.  * xmlXPathSubstringAfterFunction:
  2518.  * @ctxt:  the XPath Parser context
  2519.  *
  2520.  * Implement the substring-after() XPath function
  2521.  * The substring-after function returns the substring of the first
  2522.  * argument string that follows the first occurrence of the second
  2523.  * argument string in the first argument string, or the empty stringi
  2524.  * if the first argument string does not contain the second argument
  2525.  * string. For example, substring-after("1999/04/01","/") returns 04/01,
  2526.  * and substring-after("1999/04/01","19") returns 99/04/01.
  2527.  */
  2528. void
  2529. xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2530.     CHECK_ARITY(2);
  2531.     TODO /* substring after */
  2532. }
  2533. /**
  2534.  * xmlXPathNormalizeFunction:
  2535.  * @ctxt:  the XPath Parser context
  2536.  *
  2537.  * Implement the normalize() XPath function
  2538.  * The normalize function returns the argument string with white
  2539.  * space normalized by stripping leading and trailing whitespace
  2540.  * and replacing sequences of whitespace characters by a single
  2541.  * space. Whitespace characters are the same allowed by the S production
  2542.  * in XML. If the argument is omitted, it defaults to the context
  2543.  * node converted to a string, in other words the value of the context node.
  2544.  */
  2545. void
  2546. xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2547.     CHECK_ARITY(1);
  2548.     TODO /* normalize isn't as boring as translate, but pretty much */
  2549. }
  2550. /**
  2551.  * xmlXPathTranslateFunction:
  2552.  * @ctxt:  the XPath Parser context
  2553.  *
  2554.  * Implement the translate() XPath function
  2555.  * The translate function returns the first argument string with
  2556.  * occurrences of characters in the second argument string replaced
  2557.  * by the character at the corresponding position in the third argument
  2558.  * string. For example, translate("bar","abc","ABC") returns the string
  2559.  * BAr. If there is a character in the second argument string with no
  2560.  * character at a corresponding position in the third argument string
  2561.  * (because the second argument string is longer than the third argument
  2562.  * string), then occurrences of that character in the first argument
  2563.  * string are removed. For example, translate("--aaa--","abc-","ABC")
  2564.  * returns "AAA". If a character occurs more than once in second
  2565.  * argument string, then the first occurrence determines the replacement
  2566.  * character. If the third argument string is longer than the second
  2567.  * argument string, then excess characters are ignored.
  2568.  */
  2569. void
  2570. xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2571.     CHECK_ARITY(3);
  2572.     TODO /* translate is boring, waiting for UTF-8 representation too */
  2573. }
  2574. /**
  2575.  * xmlXPathBooleanFunction:
  2576.  * @ctxt:  the XPath Parser context
  2577.  *
  2578.  * Implement the boolean() XPath function
  2579.  * he boolean function converts its argument to a boolean as follows:
  2580.  *    - a number is true if and only if it is neither positive or
  2581.  *      negative zero nor NaN
  2582.  *    - a node-set is true if and only if it is non-empty
  2583.  *    - a string is true if and only if its length is non-zero
  2584.  */
  2585. void
  2586. xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2587.     xmlXPathObjectPtr cur;
  2588.     int res = 0;
  2589.     CHECK_ARITY(1);
  2590.     cur = valuePop(ctxt);
  2591.     if (cur == NULL) ERROR(XPATH_INVALID_OPERAND);
  2592.     switch (cur->type) {
  2593.         case XPATH_NODESET:
  2594.     if ((cur->nodesetval == NULL) ||
  2595.         (cur->nodesetval->nodeNr == 0)) res = 0;
  2596.     else 
  2597.         res = 1;
  2598.     break;
  2599. case XPATH_STRING:
  2600.     if ((cur->stringval == NULL) ||
  2601.         (cur->stringval[0] == 0)) res = 0;
  2602.     else 
  2603.         res = 1;
  2604.     break;
  2605.         case XPATH_BOOLEAN:
  2606.     valuePush(ctxt, cur);
  2607.     return;
  2608. case XPATH_NUMBER:
  2609.     if (cur->floatval) res = 1;
  2610.     break;
  2611. default:
  2612.     STRANGE
  2613.     }
  2614.     xmlXPathFreeObject(cur);
  2615.     valuePush(ctxt, xmlXPathNewBoolean(res));
  2616. }
  2617. /**
  2618.  * xmlXPathNotFunction:
  2619.  * @ctxt:  the XPath Parser context
  2620.  *
  2621.  * Implement the not() XPath function
  2622.  * The not function returns true if its argument is false,
  2623.  * and false otherwise.
  2624.  */
  2625. void
  2626. xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2627.     CHECK_ARITY(1);
  2628.     CHECK_TYPE(XPATH_BOOLEAN);
  2629.     ctxt->value->boolval = ! ctxt->value->boolval;
  2630. }
  2631. /**
  2632.  * xmlXPathTrueFunction:
  2633.  * @ctxt:  the XPath Parser context
  2634.  *
  2635.  * Implement the true() XPath function
  2636.  */
  2637. void
  2638. xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2639.     CHECK_ARITY(0);
  2640.     valuePush(ctxt, xmlXPathNewBoolean(1));
  2641. }
  2642. /**
  2643.  * xmlXPathFalseFunction:
  2644.  * @ctxt:  the XPath Parser context
  2645.  *
  2646.  * Implement the false() XPath function
  2647.  */
  2648. void
  2649. xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2650.     CHECK_ARITY(0);
  2651.     valuePush(ctxt, xmlXPathNewBoolean(0));
  2652. }
  2653. /**
  2654.  * xmlXPathLangFunction:
  2655.  * @ctxt:  the XPath Parser context
  2656.  *
  2657.  * Implement the lang() XPath function
  2658.  * The lang function returns true or false depending on whether the
  2659.  * language of the context node as specified by xml:lang attributes
  2660.  * is the same as or is a sublanguage of the language specified by
  2661.  * the argument string. The language of the context node is determined
  2662.  * by the value of the xml:lang attribute on the context node, or, if
  2663.  * the context node has no xml:lang attribute, by the value of the
  2664.  * xml:lang attribute on the nearest ancestor of the context node that
  2665.  * has an xml:lang attribute. If there is no such attribute, then lang
  2666.  * returns false. If there is such an attribute, then lang returns
  2667.  * true if the attribute value is equal to the argument ignoring case,
  2668.  * or if there is some suffix starting with - such that the attribute
  2669.  * value is equal to the argument ignoring that suffix of the attribute
  2670.  * value and ignoring case.
  2671.  */
  2672. void
  2673. xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2674.     xmlXPathObjectPtr val;
  2675.     const xmlChar *theLang;
  2676.     const xmlChar *lang;
  2677.     int ret = 0;
  2678.     int i;
  2679.     CHECK_ARITY(1);
  2680.     CHECK_TYPE(XPATH_STRING);
  2681.     val = valuePop(ctxt);
  2682.     lang = val->stringval;
  2683.     theLang = xmlNodeGetLang(ctxt->context->node);
  2684.     if ((theLang != NULL) && (lang != NULL)) {
  2685.         for (i = 0;lang[i] != 0;i++)
  2686.     if (toupper(lang[i]) != toupper(theLang[i]))
  2687.         goto not_equal;
  2688.         ret = 1;
  2689.     }
  2690. not_equal:
  2691.     xmlXPathFreeObject(val);
  2692.     valuePush(ctxt, xmlXPathNewBoolean(ret));
  2693. }
  2694. /**
  2695.  * xmlXPathNumberFunction:
  2696.  * @ctxt:  the XPath Parser context
  2697.  *
  2698.  * Implement the number() XPath function
  2699.  */
  2700. void
  2701. xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2702.     xmlXPathObjectPtr cur;
  2703.     double res;
  2704.     CHECK_ARITY(1);
  2705.     cur = valuePop(ctxt);
  2706.     switch (cur->type) {
  2707.         case XPATH_NODESET:
  2708.     valuePush(ctxt, cur);
  2709.     xmlXPathStringFunction(ctxt, 1);
  2710.     cur = valuePop(ctxt);
  2711. case XPATH_STRING:
  2712.     res = xmlXPathStringEvalNumber(cur->stringval);
  2713.     valuePush(ctxt, xmlXPathNewFloat(res));
  2714.     xmlXPathFreeObject(cur);
  2715.     return;
  2716.         case XPATH_BOOLEAN:
  2717.     if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
  2718.     else valuePush(ctxt, xmlXPathNewFloat(0.0));
  2719.     xmlXPathFreeObject(cur);
  2720.     return;
  2721. case XPATH_NUMBER:
  2722.     valuePush(ctxt, cur);
  2723.     return;
  2724.     }
  2725.     STRANGE
  2726. }
  2727. /**
  2728.  * xmlXPathSumFunction:
  2729.  * @ctxt:  the XPath Parser context
  2730.  *
  2731.  * Implement the sum() XPath function
  2732.  * The sum function returns the sum of the values of the nodes in
  2733.  * the argument node-set.
  2734.  */
  2735. void
  2736. xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2737.     CHECK_ARITY(1);
  2738.     TODO /* BUG Sum : don't understand the definition */
  2739. }
  2740. /**
  2741.  * xmlXPathFloorFunction:
  2742.  * @ctxt:  the XPath Parser context
  2743.  *
  2744.  * Implement the floor() XPath function
  2745.  * The floor function returns the largest (closest to positive infinity)
  2746.  * number that is not greater than the argument and that is an integer.
  2747.  */
  2748. void
  2749. xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2750.     CHECK_ARITY(1);
  2751.     CHECK_TYPE(XPATH_NUMBER);
  2752.     /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
  2753.     ctxt->value->floatval = (double)((int) ctxt->value->floatval);
  2754. }
  2755. /**
  2756.  * xmlXPathCeilingFunction:
  2757.  * @ctxt:  the XPath Parser context
  2758.  *
  2759.  * Implement the ceiling() XPath function
  2760.  * The ceiling function returns the smallest (closest to negative infinity)
  2761.  * number that is not less than the argument and that is an integer.
  2762.  */
  2763. void
  2764. xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2765.     double f;
  2766.     CHECK_ARITY(1);
  2767.     CHECK_TYPE(XPATH_NUMBER);
  2768.     f = (double)((int) ctxt->value->floatval);
  2769.     if (f != ctxt->value->floatval)
  2770. ctxt->value->floatval = f + 1;
  2771. }
  2772. /**
  2773.  * xmlXPathRoundFunction:
  2774.  * @ctxt:  the XPath Parser context
  2775.  *
  2776.  * Implement the round() XPath function
  2777.  * The round function returns the number that is closest to the
  2778.  * argument and that is an integer. If there are two such numbers,
  2779.  * then the one that is even is returned.
  2780.  */
  2781. void
  2782. xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  2783.     double f;
  2784.     CHECK_ARITY(1);
  2785.     CHECK_TYPE(XPATH_NUMBER);
  2786.     /* round(0.50000001) => 0  !!!!! */
  2787.     f = (double)((int) ctxt->value->floatval);
  2788.     if (ctxt->value->floatval < f + 0.5)
  2789.         ctxt->value->floatval = f;
  2790.     else if (ctxt->value->floatval == f + 0.5)
  2791.         ctxt->value->floatval = f; /* !!!! Not following the spec here */
  2792.     else 
  2793.         ctxt->value->floatval = f + 1;
  2794. }
  2795. /************************************************************************
  2796.  * *
  2797.  * The Parser *
  2798.  * *
  2799.  ************************************************************************/
  2800. /*
  2801.  * a couple of forward declarations since we use a recursive call based
  2802.  * implementation.
  2803.  */
  2804. void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
  2805. void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
  2806. void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
  2807. void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
  2808. /**
  2809.  * xmlXPathParseNCName:
  2810.  * @ctxt:  the XPath Parser context
  2811.  *
  2812.  * parse an XML namespace non qualified name.
  2813.  *
  2814.  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
  2815.  *
  2816.  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
  2817.  *                       CombiningChar | Extender
  2818.  *
  2819.  * Returns the namespace name or NULL
  2820.  */
  2821. xmlChar *
  2822. xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
  2823.     const xmlChar *q;
  2824.     xmlChar *ret = NULL;
  2825.     if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
  2826.     q = NEXT;
  2827.     while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
  2828.            (CUR == '.') || (CUR == '-') ||
  2829.    (CUR == '_') ||
  2830.    (IS_COMBINING(CUR)) ||
  2831.    (IS_EXTENDER(CUR)))
  2832. NEXT;
  2833.     
  2834.     ret = xmlStrndup(q, CUR_PTR - q);
  2835.     return(ret);
  2836. }
  2837. /**
  2838.  * xmlXPathParseQName:
  2839.  * @ctxt:  the XPath Parser context
  2840.  * @prefix:  a xmlChar ** 
  2841.  *
  2842.  * parse an XML qualified name
  2843.  *
  2844.  * [NS 5] QName ::= (Prefix ':')? LocalPart
  2845.  *
  2846.  * [NS 6] Prefix ::= NCName
  2847.  *
  2848.  * [NS 7] LocalPart ::= NCName
  2849.  *
  2850.  * Returns the function returns the local part, and prefix is updated
  2851.  *   to get the Prefix if any.
  2852.  */
  2853. xmlChar *
  2854. xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
  2855.     xmlChar *ret = NULL;
  2856.     *prefix = NULL;
  2857.     ret = xmlXPathParseNCName(ctxt);
  2858.     if (CUR == ':') {
  2859.         *prefix = ret;
  2860. NEXT;
  2861. ret = xmlXPathParseNCName(ctxt);
  2862.     }
  2863.     return(ret);
  2864. }
  2865. /**
  2866.  * xmlXPathStringEvalNumber:
  2867.  * @str:  A string to scan
  2868.  *
  2869.  *  [30]   Number ::=   Digits ('.' Digits)?
  2870.  *                    | '.' Digits 
  2871.  *  [31]   Digits ::=   [0-9]+
  2872.  *
  2873.  * Parse and evaluate a Number in the string
  2874.  *
  2875.  * BUG: "1.' is not valid ... James promised correction
  2876.  *       as Digits ('.' Digits?)?
  2877.  *
  2878.  * Returns the double value.
  2879.  */
  2880. double
  2881. xmlXPathStringEvalNumber(const xmlChar *str) {
  2882.     const xmlChar *cur = str;
  2883.     double ret = 0.0;
  2884.     double mult = 1;
  2885.     int ok = 0;
  2886.     while (*cur == ' ') cur++;
  2887.     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
  2888.         return(xmlXPathNAN);
  2889.     }
  2890.     while ((*cur >= '0') && (*cur <= '9')) {
  2891.         ret = ret * 10 + (*cur - '0');
  2892. ok = 1;
  2893. cur++;
  2894.     }
  2895.     if (*cur == '.') {
  2896.         cur++;
  2897. if (((*cur < '0') || (*cur > '9')) && (!ok)) {
  2898.     return(xmlXPathNAN);
  2899. }
  2900. while ((*cur >= '0') && (*cur <= '9')) {
  2901.     mult /= 10;
  2902.     ret = ret  + (*cur - '0') * mult;
  2903.     cur++;
  2904. }
  2905.     }
  2906.     while (*cur == ' ') cur++;
  2907.     if (*cur != 0) return(xmlXPathNAN);
  2908.     return(ret);
  2909. }
  2910. /**
  2911.  * xmlXPathEvalNumber:
  2912.  * @ctxt:  the XPath Parser context
  2913.  *
  2914.  *  [30]   Number ::=   Digits ('.' Digits)?
  2915.  *                    | '.' Digits 
  2916.  *  [31]   Digits ::=   [0-9]+
  2917.  *
  2918.  * Parse and evaluate a Number, then push it on the stack
  2919.  *
  2920.  * BUG: "1.' is not valid ... James promised correction
  2921.  *       as Digits ('.' Digits?)?
  2922.  */
  2923. void
  2924. xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
  2925.     double ret = 0.0;
  2926.     double mult = 1;
  2927.     int ok = 0;
  2928.     CHECK_ERROR;
  2929.     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
  2930.         ERROR(XPATH_NUMBER_ERROR);
  2931.     }
  2932.     while ((CUR >= '0') && (CUR <= '9')) {
  2933.         ret = ret * 10 + (CUR - '0');
  2934. ok = 1;
  2935. NEXT;
  2936.     }
  2937.     if (CUR == '.') {
  2938.         NEXT;
  2939. if (((CUR < '0') || (CUR > '9')) && (!ok)) {
  2940.      ERROR(XPATH_NUMBER_ERROR);
  2941. }
  2942. while ((CUR >= '0') && (CUR <= '9')) {
  2943.     mult /= 10;
  2944.     ret = ret  + (CUR - '0') * mult;
  2945.     NEXT;
  2946. }
  2947.     }
  2948.     valuePush(ctxt, xmlXPathNewFloat(ret));
  2949. }
  2950. /**
  2951.  * xmlXPathEvalLiteral:
  2952.  * @ctxt:  the XPath Parser context
  2953.  *
  2954.  * Parse a Literal and push it on the stack.
  2955.  *
  2956.  *  [29]   Literal ::=   '"' [^"]* '"'
  2957.  *                    | "'" [^']* "'"
  2958.  *
  2959.  * TODO: xmlXPathEvalLiteral memory allocation could be improved.
  2960.  */
  2961. void
  2962. xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
  2963.     const xmlChar *q;
  2964.     xmlChar *ret = NULL;
  2965.     if (CUR == '"') {
  2966.         NEXT;
  2967. q = CUR_PTR;
  2968. while ((IS_CHAR(CUR)) && (CUR != '"'))
  2969.     NEXT;
  2970. if (!IS_CHAR(CUR)) {
  2971.     ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  2972. } else {
  2973.     ret = xmlStrndup(q, CUR_PTR - q);
  2974.     NEXT;
  2975.         }
  2976.     } else if (CUR == ''') {
  2977.         NEXT;
  2978. q = CUR_PTR;
  2979. while ((IS_CHAR(CUR)) && (CUR != '''))
  2980.     NEXT;
  2981. if (!IS_CHAR(CUR)) {
  2982.     ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  2983. } else {
  2984.     ret = xmlStrndup(q, CUR_PTR - q);
  2985.     NEXT;
  2986.         }
  2987.     } else {
  2988. ERROR(XPATH_START_LITERAL_ERROR);
  2989.     }
  2990.     if (ret == NULL) return;
  2991.     valuePush(ctxt, xmlXPathNewString(ret));
  2992.     xmlFree(ret);
  2993. }
  2994. /**
  2995.  * xmlXPathEvalVariableReference:
  2996.  * @ctxt:  the XPath Parser context
  2997.  *
  2998.  * Parse a VariableReference, evaluate it and push it on the stack.
  2999.  *
  3000.  * The variable bindings consist of a mapping from variable names
  3001.  * to variable values. The value of a variable is an object, which
  3002.  * of any of the types that are possible for the value of an expression,
  3003.  * and may also be of additional types not specified here.
  3004.  *
  3005.  * Early evaluation is possible since:
  3006.  * The variable bindings [...] used to evaluate a subexpression are
  3007.  * always the same as those used to evaluate the containing expression. 
  3008.  *
  3009.  *  [36]   VariableReference ::=   '$' QName 
  3010.  */
  3011. void
  3012. xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
  3013.     xmlChar *name;
  3014.     xmlChar *prefix;
  3015.     xmlXPathObjectPtr value;
  3016.     if (CUR != '$') {
  3017. ERROR(XPATH_VARIABLE_REF_ERROR);
  3018.     }
  3019.     name = xmlXPathParseQName(ctxt, &prefix);
  3020.     if (name == NULL) {
  3021. ERROR(XPATH_VARIABLE_REF_ERROR);
  3022.     }
  3023.     value = xmlXPathVariablelookup(ctxt, prefix, name);
  3024.     if (value == NULL) {
  3025. ERROR(XPATH_UNDEF_VARIABLE_ERROR);
  3026.     }
  3027.     valuePush(ctxt, value);
  3028.     if (prefix != NULL) xmlFree(prefix);
  3029.     xmlFree(name);
  3030. }
  3031.  
  3032. /**
  3033.  * xmlXPathFunctionLookup:
  3034.  * @ctxt:  the XPath Parser context
  3035.  * @name:  a name string
  3036.  *
  3037.  * Search for a function of the given name
  3038.  *
  3039.  *  [35]   FunctionName ::=   QName - NodeType 
  3040.  *
  3041.  * TODO: for the moment the function list is hardcoded from the spec !!!!
  3042.  *
  3043.  * Returns the xmlXPathFunction if found, or NULL otherwise
  3044.  */
  3045. xmlXPathFunction
  3046. xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
  3047.     switch (name[0]) {
  3048.         case 'b':
  3049.     if (!xmlStrcmp(name, BAD_CAST "boolean"))
  3050.         return(xmlXPathBooleanFunction);
  3051.     break;
  3052.         case 'c':
  3053.     if (!xmlStrcmp(name, BAD_CAST "ceiling"))
  3054.         return(xmlXPathCeilingFunction);
  3055.     if (!xmlStrcmp(name, BAD_CAST "count"))
  3056.         return(xmlXPathCountFunction);
  3057.     if (!xmlStrcmp(name, BAD_CAST "concat"))
  3058.         return(xmlXPathConcatFunction);
  3059.     if (!xmlStrcmp(name, BAD_CAST "contains"))
  3060.         return(xmlXPathContainsFunction);
  3061.     break;
  3062.         case 'i':
  3063.     if (!xmlStrcmp(name, BAD_CAST "id"))
  3064.         return(xmlXPathIdFunction);
  3065.     break;
  3066.         case 'f':
  3067.     if (!xmlStrcmp(name, BAD_CAST "false"))
  3068.         return(xmlXPathFalseFunction);
  3069.     if (!xmlStrcmp(name, BAD_CAST "floor"))
  3070.         return(xmlXPathFloorFunction);
  3071.     break;
  3072.         case 'l':
  3073.     if (!xmlStrcmp(name, BAD_CAST "last"))
  3074.         return(xmlXPathLastFunction);
  3075.     if (!xmlStrcmp(name, BAD_CAST "lang"))
  3076.         return(xmlXPathLangFunction);
  3077.     if (!xmlStrcmp(name, BAD_CAST "local-part"))
  3078.         return(xmlXPathLocalPartFunction);
  3079.     break;
  3080.         case 'n':
  3081.     if (!xmlStrcmp(name, BAD_CAST "not"))
  3082.         return(xmlXPathNotFunction);
  3083.     if (!xmlStrcmp(name, BAD_CAST "name"))
  3084.         return(xmlXPathNameFunction);
  3085.     if (!xmlStrcmp(name, BAD_CAST "namespace"))
  3086.         return(xmlXPathNamespaceFunction);
  3087.     if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
  3088.         return(xmlXPathNormalizeFunction);
  3089.     if (!xmlStrcmp(name, BAD_CAST "normalize"))
  3090.         return(xmlXPathNormalizeFunction);
  3091.     if (!xmlStrcmp(name, BAD_CAST "number"))
  3092.         return(xmlXPathNumberFunction);
  3093.     break;
  3094.         case 'p':
  3095.     if (!xmlStrcmp(name, BAD_CAST "position"))
  3096.         return(xmlXPathPositionFunction);
  3097.     break;
  3098.         case 'r':
  3099.     if (!xmlStrcmp(name, BAD_CAST "round"))
  3100.         return(xmlXPathRoundFunction);
  3101.     break;
  3102.         case 's':
  3103.     if (!xmlStrcmp(name, BAD_CAST "string"))
  3104.         return(xmlXPathStringFunction);
  3105.     if (!xmlStrcmp(name, BAD_CAST "string-length"))
  3106.         return(xmlXPathStringLengthFunction);
  3107.     if (!xmlStrcmp(name, BAD_CAST "starts-with"))
  3108.         return(xmlXPathStartsWithFunction);
  3109.     if (!xmlStrcmp(name, BAD_CAST "substring"))
  3110.         return(xmlXPathSubstringFunction);
  3111.     if (!xmlStrcmp(name, BAD_CAST "substring-before"))
  3112.         return(xmlXPathSubstringBeforeFunction);
  3113.     if (!xmlStrcmp(name, BAD_CAST "substring-after"))
  3114.         return(xmlXPathSubstringAfterFunction);
  3115.     if (!xmlStrcmp(name, BAD_CAST "sum"))
  3116.         return(xmlXPathSumFunction);
  3117.     break;
  3118.         case 't':
  3119.     if (!xmlStrcmp(name, BAD_CAST "true"))
  3120.         return(xmlXPathTrueFunction);
  3121.     if (!xmlStrcmp(name, BAD_CAST "translate"))
  3122.         return(xmlXPathTranslateFunction);
  3123.     break;
  3124.     }
  3125.     return(NULL);
  3126. }
  3127. /**
  3128.  * xmlXPathEvalLocationPathName:
  3129.  * @ctxt:  the XPath Parser context
  3130.  * @name:  a name string
  3131.  *
  3132.  * Various names in the beginning of a LocationPath expression
  3133.  * indicate whether that's an Axis, a node type, 
  3134.  *
  3135.  *  [6]   AxisName ::=   'ancestor'
  3136.  *               | 'ancestor-or-self'
  3137.  *               | 'attribute'
  3138.  *               | 'child'
  3139.  *               | 'descendant'
  3140.  *               | 'descendant-or-self'
  3141.  *               | 'following'
  3142.  *               | 'following-sibling'
  3143.  *               | 'namespace'
  3144.  *               | 'parent'
  3145.  *               | 'preceding'
  3146.  *               | 'preceding-sibling'
  3147.  *               | 'self'
  3148.  *  [38]   NodeType ::=   'comment'
  3149.  *                    | 'text'
  3150.  *                    | 'processing-instruction'
  3151.  *                    | 'node'
  3152.  */
  3153. int
  3154. xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
  3155.     switch (name[0]) {
  3156.         case 'a':
  3157.     if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
  3158.     if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
  3159.         return(AXIS_ANCESTOR_OR_SELF);
  3160.             if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
  3161.     break;
  3162.         case 'c':
  3163.             if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
  3164.             if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
  3165.     break;
  3166.         case 'd':
  3167.             if (!xmlStrcmp(name, BAD_CAST "descendant"))
  3168.         return(AXIS_DESCENDANT);
  3169.             if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
  3170.         return(AXIS_DESCENDANT_OR_SELF);
  3171.     break;
  3172.         case 'f':
  3173.             if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
  3174.             if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
  3175.         return(AXIS_FOLLOWING_SIBLING);
  3176.     break;
  3177.         case 'n':
  3178.             if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
  3179.             if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
  3180.     break;
  3181.         case 'p':
  3182.             if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
  3183.             if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
  3184.             if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
  3185.         return(AXIS_PRECEDING_SIBLING);
  3186.             if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
  3187.         return(NODE_TYPE_PI);
  3188.     break;
  3189.         case 's':
  3190.             if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
  3191.     break;
  3192.         case 't':
  3193.             if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
  3194.     break;
  3195.     }
  3196.     if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
  3197.     return(0);
  3198. }
  3199.  
  3200. /**
  3201.  * xmlXPathEvalFunctionCall:
  3202.  * @ctxt:  the XPath Parser context
  3203.  *
  3204.  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
  3205.  *  [17]   Argument ::=   Expr 
  3206.  *
  3207.  * Parse and evaluate a function call, the evaluation of all arguments are
  3208.  * pushed on the stack
  3209.  */
  3210. void
  3211. xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
  3212.     xmlChar *name;
  3213.     xmlChar *prefix;
  3214.     xmlXPathFunction func;
  3215.     int nbargs = 0;
  3216.     name = xmlXPathParseQName(ctxt, &prefix);
  3217.     if (name == NULL) {
  3218. ERROR(XPATH_EXPR_ERROR);
  3219.     }
  3220.     SKIP_BLANKS;
  3221.     func = xmlXPathIsFunction(ctxt, name);
  3222.     if (func == NULL) {
  3223.         xmlFree(name);
  3224. ERROR(XPATH_UNKNOWN_FUNC_ERROR);
  3225.     }
  3226. #ifdef DEBUG_EXPR
  3227.     fprintf(xmlXPathDebug, "Calling function %sn", name);
  3228. #endif
  3229.     if (CUR != '(') {
  3230.         xmlFree(name);
  3231. ERROR(XPATH_EXPR_ERROR);
  3232.     }
  3233.     NEXT;
  3234.     SKIP_BLANKS;
  3235.     while (CUR != ')') {
  3236.         xmlXPathEvalExpr(ctxt);
  3237. nbargs++;
  3238. if (CUR == ')') break;
  3239. if (CUR != ',') {
  3240.     xmlFree(name);
  3241.     ERROR(XPATH_EXPR_ERROR);
  3242. }
  3243. NEXT;
  3244. SKIP_BLANKS;
  3245.     }
  3246.     NEXT;
  3247.     SKIP_BLANKS;
  3248.     xmlFree(name);
  3249.     func(ctxt, nbargs);
  3250. }
  3251. /**
  3252.  * xmlXPathEvalPrimaryExpr:
  3253.  * @ctxt:  the XPath Parser context
  3254.  *
  3255.  *  [15]   PrimaryExpr ::=   VariableReference 
  3256.  *                | '(' Expr ')'
  3257.  *                | Literal 
  3258.  *                | Number 
  3259.  *                | FunctionCall 
  3260.  *
  3261.  * Parse and evaluate a primary expression, then push the result on the stack
  3262.  */
  3263. void
  3264. xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
  3265.     SKIP_BLANKS;
  3266.     if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
  3267.     else if (CUR == '(') {
  3268.         NEXT;
  3269. SKIP_BLANKS;
  3270.         xmlXPathEvalExpr(ctxt);
  3271. if (CUR != ')') {
  3272.     ERROR(XPATH_EXPR_ERROR);
  3273. }
  3274. NEXT;
  3275. SKIP_BLANKS;
  3276.     } else if (IS_DIGIT(CUR)) {
  3277.         xmlXPathEvalNumber(ctxt);
  3278.     } else if ((CUR == ''') || (CUR == '"')) {
  3279.         xmlXPathEvalLiteral(ctxt);
  3280.     } else {
  3281.         xmlXPathEvalFunctionCall(ctxt);
  3282.     }
  3283. }
  3284. /**
  3285.  * xmlXPathEvalFilterExpr:
  3286.  * @ctxt:  the XPath Parser context
  3287.  *
  3288.  *  [20]   FilterExpr ::=   PrimaryExpr 
  3289.  *               | FilterExpr Predicate 
  3290.  *
  3291.  * Parse and evaluate a filter expression, then push the result on the stack
  3292.  * Square brackets are used to filter expressions in the same way that
  3293.  * they are used in location paths. It is an error if the expression to
  3294.  * be filtered does not evaluate to a node-set. The context node list
  3295.  * used for evaluating the expression in square brackets is the node-set
  3296.  * to be filtered listed in document order.
  3297.  */
  3298. void
  3299. xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
  3300.     /****
  3301.     xmlNodeSetPtr oldset = NULL;
  3302.     xmlXPathObjectPtr arg;
  3303.      ****/
  3304.     xmlXPathEvalPrimaryExpr(ctxt);
  3305.     CHECK_ERROR;
  3306.     SKIP_BLANKS;
  3307.     
  3308.     if (CUR != '[') return;
  3309.     CHECK_TYPE(XPATH_NODESET);
  3310.     while (CUR == '[') {
  3311. xmlXPathEvalPredicate(ctxt);
  3312. SKIP_BLANKS;
  3313.     }
  3314.     
  3315. }
  3316. /**
  3317.  * xmlXPathScanName:
  3318.  * @ctxt:  the XPath Parser context
  3319.  *
  3320.  * Trickery: parse an XML name but without consuming the input flow
  3321.  * Needed for rollback cases.
  3322.  *
  3323.  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  3324.  *                  CombiningChar | Extender
  3325.  *
  3326.  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  3327.  *
  3328.  * [6] Names ::= Name (S Name)*
  3329.  *
  3330.  * Returns the Name parsed or NULL
  3331.  */
  3332. xmlChar *
  3333. xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
  3334.     xmlChar buf[XML_MAX_NAMELEN];
  3335.     int len = 0;
  3336.     SKIP_BLANKS;
  3337.     if (!IS_LETTER(CUR) && (CUR != '_') &&
  3338.         (CUR != ':')) {
  3339. return(NULL);
  3340.     }
  3341.     while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
  3342.            (NXT(len) == '.') || (NXT(len) == '-') ||
  3343.    (NXT(len) == '_') || (NXT(len) == ':') || 
  3344.    (IS_COMBINING(NXT(len))) ||
  3345.    (IS_EXTENDER(NXT(len)))) {
  3346. buf[len] = NXT(len);
  3347. len++;
  3348. if (len >= XML_MAX_NAMELEN) {
  3349.     fprintf(stderr, 
  3350.        "xmlScanName: reached XML_MAX_NAMELEN limitn");
  3351.     while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
  3352.    (NXT(len) == '.') || (NXT(len) == '-') ||
  3353.    (NXT(len) == '_') || (NXT(len) == ':') || 
  3354.    (IS_COMBINING(NXT(len))) ||
  3355.    (IS_EXTENDER(NXT(len))))
  3356.  len++;
  3357.     break;
  3358. }
  3359.     }
  3360.     return(xmlStrndup(buf, len));
  3361. }
  3362. /**
  3363.  * xmlXPathEvalPathExpr:
  3364.  * @ctxt:  the XPath Parser context
  3365.  *
  3366.  *  [19]   PathExpr ::=   LocationPath 
  3367.  *               | FilterExpr 
  3368.  *               | FilterExpr '/' RelativeLocationPath 
  3369.  *               | FilterExpr '//' RelativeLocationPath 
  3370.  *
  3371.  * Parse and evaluate a path expression, then push the result on the stack
  3372.  * The / operator and // operators combine an arbitrary expression
  3373.  * and a relative location path. It is an error if the expression
  3374.  * does not evaluate to a node-set.
  3375.  * The / operator does composition in the same way as when / is
  3376.  * used in a location path. As in location paths, // is short for
  3377.  * /descendant-or-self::node()/.
  3378.  */
  3379. void
  3380. xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
  3381.     xmlNodeSetPtr newset = NULL;
  3382.     SKIP_BLANKS;
  3383.     if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
  3384.         (CUR == ''') || (CUR == '"')) {
  3385. xmlXPathEvalFilterExpr(ctxt);
  3386. CHECK_ERROR;
  3387. if ((CUR == '/') && (NXT(1) == '/')) {
  3388.     SKIP(2);
  3389.     SKIP_BLANKS;
  3390.     if (ctxt->context->nodelist == NULL) {
  3391. STRANGE
  3392. xmlXPathRoot(ctxt);
  3393.     }
  3394.     newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
  3395.      NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
  3396.     if (ctxt->context->nodelist != NULL)
  3397. xmlXPathFreeNodeSet(ctxt->context->nodelist);
  3398.     ctxt->context->nodelist = newset;
  3399.     ctxt->context->node = NULL;
  3400.     xmlXPathEvalRelativeLocationPath(ctxt);
  3401. } else if (CUR == '/') {
  3402.     xmlXPathEvalRelativeLocationPath(ctxt);
  3403. }
  3404.     } else {
  3405.         /******* !!!!!!!!!! @attname */
  3406.         xmlChar *name;
  3407. name = xmlXPathScanName(ctxt);
  3408. if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
  3409.     xmlXPathEvalLocationPath(ctxt);
  3410. else
  3411.     xmlXPathEvalFilterExpr(ctxt);
  3412. if (name != NULL)
  3413.     xmlFree(name);
  3414.     }
  3415.     if (ctxt->context->nodelist != NULL)
  3416. valuePush(ctxt, xmlXPathNewNodeSetList(ctxt->context->nodelist));
  3417. }
  3418. /**
  3419.  * xmlXPathEvalUnionExpr:
  3420.  * @ctxt:  the XPath Parser context
  3421.  *
  3422.  *  [18]   UnionExpr ::=   PathExpr 
  3423.  *               | UnionExpr '|' PathExpr 
  3424.  *
  3425.  * Parse and evaluate an union expression, then push the result on the stack
  3426.  */
  3427. void
  3428. xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
  3429.     xmlXPathEvalPathExpr(ctxt);
  3430.     CHECK_ERROR;
  3431.     SKIP_BLANKS;
  3432.     if (CUR == '|') {
  3433. xmlNodeSetPtr old = ctxt->context->nodelist;
  3434. NEXT;
  3435. SKIP_BLANKS;
  3436. xmlXPathEvalPathExpr(ctxt);
  3437. if (ctxt->context->nodelist == NULL)
  3438.     ctxt->context->nodelist = old;
  3439. else {
  3440.     ctxt->context->nodelist = 
  3441.         xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
  3442.     xmlXPathFreeNodeSet(old);
  3443. }
  3444.     }
  3445. }
  3446. /**
  3447.  * xmlXPathEvalUnaryExpr:
  3448.  * @ctxt:  the XPath Parser context
  3449.  *
  3450.  *  [27]   UnaryExpr ::=   UnionExpr 
  3451.  *                   | '-' UnaryExpr 
  3452.  *
  3453.  * Parse and evaluate an unary expression, then push the result on the stack
  3454.  */
  3455. void
  3456. xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
  3457.     int minus = 0;
  3458.     SKIP_BLANKS;
  3459.     if (CUR == '-') {
  3460.         minus = 1;
  3461. NEXT;
  3462. SKIP_BLANKS;
  3463.     }
  3464.     xmlXPathEvalUnionExpr(ctxt);
  3465.     CHECK_ERROR;
  3466.     if (minus) {
  3467.         xmlXPathValueFlipSign(ctxt);
  3468.     }
  3469. }
  3470. /**
  3471.  * xmlXPathEvalMultiplicativeExpr:
  3472.  * @ctxt:  the XPath Parser context
  3473.  *
  3474.  *  [26]   MultiplicativeExpr ::=   UnaryExpr 
  3475.  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr 
  3476.  *                   | MultiplicativeExpr 'div' UnaryExpr 
  3477.  *                   | MultiplicativeExpr 'mod' UnaryExpr 
  3478.  *  [34]   MultiplyOperator ::=   '*'
  3479.  *
  3480.  * Parse and evaluate an Additive expression, then push the result on the stack
  3481.  */
  3482. void
  3483. xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
  3484.     xmlXPathEvalUnaryExpr(ctxt);
  3485.     CHECK_ERROR;
  3486.     SKIP_BLANKS;
  3487.     while ((CUR == '*') || 
  3488.            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
  3489.            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
  3490. int op = -1;
  3491.         if (CUR == '*') {
  3492.     op = 0;
  3493.     NEXT;
  3494. } else if (CUR == 'd') {
  3495.     op = 1;
  3496.     SKIP(3);
  3497. } else if (CUR == 'm') {
  3498.     op = 2;
  3499.     SKIP(3);
  3500. }
  3501. SKIP_BLANKS;
  3502.         xmlXPathEvalUnaryExpr(ctxt);
  3503. CHECK_ERROR;
  3504. switch (op) {
  3505.     case 0:
  3506.         xmlXPathMultValues(ctxt);
  3507. break;
  3508.     case 1:
  3509.         xmlXPathDivValues(ctxt);
  3510. break;
  3511.     case 2:
  3512.         xmlXPathModValues(ctxt);
  3513. break;
  3514. }
  3515.     }
  3516. }
  3517. /**
  3518.  * xmlXPathEvalAdditiveExpr:
  3519.  * @ctxt:  the XPath Parser context
  3520.  *
  3521.  *  [25]   AdditiveExpr ::=   MultiplicativeExpr 
  3522.  *                   | AdditiveExpr '+' MultiplicativeExpr 
  3523.  *                   | AdditiveExpr '-' MultiplicativeExpr 
  3524.  *
  3525.  * Parse and evaluate an Additive expression, then push the result on the stack
  3526.  */
  3527. void
  3528. xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
  3529.     xmlXPathEvalMultiplicativeExpr(ctxt);
  3530.     CHECK_ERROR;
  3531.     SKIP_BLANKS;
  3532.     while ((CUR == '+') || (CUR == '-')) {
  3533. int plus;
  3534.         if (CUR == '+') plus = 1;
  3535. else plus = 0;
  3536. NEXT;
  3537. SKIP_BLANKS;
  3538.         xmlXPathEvalMultiplicativeExpr(ctxt);
  3539. CHECK_ERROR;
  3540. if (plus) xmlXPathAddValues(ctxt);
  3541. else xmlXPathSubValues(ctxt);
  3542.     }
  3543. }
  3544. /**
  3545.  * xmlXPathEvalRelationalExpr:
  3546.  * @ctxt:  the XPath Parser context
  3547.  *
  3548.  *  [24]   RelationalExpr ::=   AdditiveExpr 
  3549.  *                 | RelationalExpr '<' AdditiveExpr 
  3550.  *                 | RelationalExpr '>' AdditiveExpr 
  3551.  *                 | RelationalExpr '<=' AdditiveExpr 
  3552.  *                 | RelationalExpr '>=' AdditiveExpr 
  3553.  *
  3554.  *  A <= B > C is allowed ? Answer from James, yes with
  3555.  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
  3556.  *  which is basically what got implemented.
  3557.  *
  3558.  * Parse and evaluate a Relational expression, then push the result
  3559.  * on the stack
  3560.  */
  3561. void
  3562. xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
  3563.     xmlXPathEvalAdditiveExpr(ctxt);
  3564.     CHECK_ERROR;
  3565.     SKIP_BLANKS;
  3566.     while ((CUR == '<') ||
  3567.            (CUR == '>') ||
  3568.            ((CUR == '<') && (NXT(1) == '=')) ||
  3569.            ((CUR == '>') && (NXT(1) == '='))) {
  3570. int inf, strict, ret;
  3571.         if (CUR == '<') inf = 1;
  3572. else inf = 0;
  3573. if (NXT(1) == '=') strict = 0;
  3574. else strict = 1;
  3575. NEXT;
  3576. if (!strict) NEXT;
  3577. SKIP_BLANKS;
  3578.         xmlXPathEvalAdditiveExpr(ctxt);
  3579. CHECK_ERROR;
  3580. ret = xmlXPathCompareValues(ctxt, inf, strict);
  3581. valuePush(ctxt, xmlXPathNewBoolean(ret));
  3582.     }
  3583. }
  3584. /**
  3585.  * xmlXPathEvalEqualityExpr:
  3586.  * @ctxt:  the XPath Parser context
  3587.  *
  3588.  *  [23]   EqualityExpr ::=   RelationalExpr 
  3589.  *                 | EqualityExpr '=' RelationalExpr 
  3590.  *                 | EqualityExpr '!=' RelationalExpr 
  3591.  *
  3592.  *  A != B != C is allowed ? Answer from James, yes with
  3593.  *  (RelationalExpr = RelationalExpr) = RelationalExpr
  3594.  *  (RelationalExpr != RelationalExpr) != RelationalExpr
  3595.  *  which is basically what got implemented.
  3596.  *
  3597.  * Parse and evaluate an Equality expression, then push the result on the stack
  3598.  *
  3599.  */
  3600. void
  3601. xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
  3602.     xmlXPathEvalRelationalExpr(ctxt);
  3603.     CHECK_ERROR;
  3604.     SKIP_BLANKS;
  3605.     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
  3606. xmlXPathObjectPtr res;
  3607. int eq, equal;
  3608.         if (CUR == '=') eq = 1;
  3609. else eq = 0;
  3610. NEXT;
  3611. if (!eq) NEXT;
  3612. SKIP_BLANKS;
  3613.         xmlXPathEvalRelationalExpr(ctxt);
  3614. CHECK_ERROR;
  3615. equal = xmlXPathEqualValues(ctxt);
  3616. if (eq) res = xmlXPathNewBoolean(equal);
  3617. else res = xmlXPathNewBoolean(!equal);
  3618. valuePush(ctxt, res);
  3619.     }
  3620. }
  3621. /**
  3622.  * xmlXPathEvalAndExpr:
  3623.  * @ctxt:  the XPath Parser context
  3624.  *
  3625.  *  [22]   AndExpr ::=   EqualityExpr 
  3626.  *                 | AndExpr 'and' EqualityExpr 
  3627.  *
  3628.  * Parse and evaluate an AND expression, then push the result on the stack
  3629.  *
  3630.  */
  3631. void
  3632. xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
  3633.     xmlXPathEvalEqualityExpr(ctxt);
  3634.     CHECK_ERROR;
  3635.     SKIP_BLANKS;
  3636.     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'n')) {
  3637. xmlXPathObjectPtr arg1, arg2;
  3638.         SKIP(3);
  3639. SKIP_BLANKS;
  3640.         xmlXPathEvalEqualityExpr(ctxt);
  3641. CHECK_ERROR;
  3642. arg2 = valuePop(ctxt);
  3643. arg1 = valuePop(ctxt);
  3644. arg1->boolval &= arg2->boolval;
  3645. valuePush(ctxt, arg1);
  3646. xmlXPathFreeObject(arg2);
  3647.     }
  3648. }
  3649. /**
  3650.  * xmlXPathEvalExpr:
  3651.  * @ctxt:  the XPath Parser context
  3652.  *
  3653.  *  [14]   Expr ::=   OrExpr 
  3654.  *  [21]   OrExpr ::=   AndExpr 
  3655.  *                 | OrExpr 'or' AndExpr 
  3656.  *
  3657.  * Parse and evaluate an expression, then push the result on the stack
  3658.  *
  3659.  */
  3660. void
  3661. xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
  3662.     xmlXPathEvalAndExpr(ctxt);
  3663.     CHECK_ERROR;
  3664.     SKIP_BLANKS;
  3665.     while ((CUR == 'o') && (NXT(1) == 'r')) {
  3666. xmlXPathObjectPtr arg1, arg2;
  3667.         SKIP(2);
  3668. SKIP_BLANKS;
  3669.         xmlXPathEvalAndExpr(ctxt);
  3670. CHECK_ERROR;
  3671. arg2 = valuePop(ctxt);
  3672. arg1 = valuePop(ctxt);
  3673. arg1->boolval |= arg2->boolval;
  3674. valuePush(ctxt, arg1);
  3675. xmlXPathFreeObject(arg2);
  3676.     }
  3677. }
  3678. /**
  3679.  * xmlXPathEvaluatePredicateResult:
  3680.  * @ctxt:  the XPath Parser context
  3681.  * @res:  the Predicate Expression evaluation result
  3682.  * @index:  index of the current node in the current list
  3683.  *
  3684.  * Evaluate a predicate result for the current node.
  3685.  * A PredicateExpr is evaluated by evaluating the Expr and converting
  3686.  * the result to a boolean. If the result is a number, the result will
  3687.  * be converted to true if the number is equal to the position of the
  3688.  * context node in the context node list (as returned by the position
  3689.  * function) and will be converted to false otherwise; if the result
  3690.  * is not a number, then the result will be converted as if by a call
  3691.  * to the boolean function. 
  3692.  */
  3693. int
  3694. xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
  3695.                                 xmlXPathObjectPtr res, int index) {
  3696.     if (res == NULL) return(0);
  3697.     switch (res->type) {
  3698.         case XPATH_BOOLEAN:
  3699.     return(res->boolval);
  3700.         case XPATH_NUMBER:
  3701.     return(res->floatval == index);
  3702.         case XPATH_NODESET:
  3703.     return(res->nodesetval->nodeNr != 0);
  3704.         case XPATH_STRING:
  3705.     return((res->stringval != NULL) &&
  3706.            (xmlStrlen(res->stringval) != 0));
  3707.         default:
  3708.     STRANGE
  3709.     }
  3710.     return(0);
  3711. }
  3712. /**
  3713.  * xmlXPathEvalPredicate:
  3714.  * @ctxt:  the XPath Parser context
  3715.  *
  3716.  *  [8]   Predicate ::=   '[' PredicateExpr ']'
  3717.  *  [9]   PredicateExpr ::=   Expr 
  3718.  *
  3719.  * Parse and evaluate a predicate for all the elements of the
  3720.  * current node list. Then refine the list by removing all
  3721.  * nodes where the predicate is false.
  3722.  */
  3723. void
  3724. xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
  3725.     const xmlChar *cur;
  3726.     xmlXPathObjectPtr res;
  3727.     xmlNodeSetPtr newset = NULL;
  3728.     int i;
  3729.     SKIP_BLANKS;
  3730.     if (CUR != '[') {
  3731. ERROR(XPATH_INVALID_PREDICATE_ERROR);
  3732.     }
  3733.     NEXT;
  3734.     SKIP_BLANKS;
  3735.     if ((ctxt->context->nodelist == NULL) ||
  3736.         (ctxt->context->nodelist->nodeNr == 0)) {
  3737.         ctxt->context->node = NULL;
  3738. xmlXPathEvalExpr(ctxt);
  3739. CHECK_ERROR;
  3740. res = valuePop(ctxt);
  3741. if (res != NULL)
  3742.     xmlXPathFreeObject(res);
  3743.     } else {
  3744.         cur = ctxt->cur;
  3745. newset = xmlXPathNodeSetCreate(NULL);
  3746.         for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
  3747.     ctxt->cur = cur;
  3748.     ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
  3749.     xmlXPathEvalExpr(ctxt);
  3750.     CHECK_ERROR;
  3751.     res = valuePop(ctxt);
  3752.     if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
  3753.         xmlXPathNodeSetAdd(newset,
  3754.                    ctxt->context->nodelist->nodeTab[i]);
  3755.     if (res != NULL)
  3756.     xmlXPathFreeObject(res);
  3757. }
  3758. if (ctxt->context->nodelist != NULL)
  3759.     xmlXPathFreeNodeSet(ctxt->context->nodelist);
  3760. ctxt->context->nodelist = newset;
  3761. ctxt->context->node = NULL;
  3762.     }
  3763.     if (CUR != ']') {
  3764. ERROR(XPATH_INVALID_PREDICATE_ERROR);
  3765.     }
  3766.     NEXT;
  3767.     SKIP_BLANKS;
  3768. #ifdef DEBUG_STEP
  3769.     fprintf(xmlXPathDebug, "After predicate : ");
  3770.     xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
  3771. #endif
  3772. }
  3773. /**
  3774.  * xmlXPathEvalBasis:
  3775.  * @ctxt:  the XPath Parser context
  3776.  *
  3777.  *  [5]   Basis ::=   AxisName '::' NodeTest 
  3778.  *            | AbbreviatedBasis 
  3779.  *  [13]   AbbreviatedBasis ::=   NodeTest 
  3780.  *                           | '@' NodeTest 
  3781.  *  [7]   NodeTest ::=   WildcardName 
  3782.  *              | NodeType '(' ')'
  3783.  *              | 'processing-instruction' '(' Literal ')'
  3784.  *  [37]   WildcardName ::=   '*'
  3785.  *                    | NCName ':' '*'
  3786.  *                    | QName 
  3787.  *
  3788.  * Evaluate one step in a Location Path
  3789.  */
  3790. void
  3791. xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
  3792.     xmlChar *name = NULL;
  3793.     xmlChar *prefix = NULL;
  3794.     int type = 0;
  3795.     int axis = AXIS_CHILD; /* the default on abbreviated syntax */
  3796.     int nodetest = NODE_TEST_NONE;
  3797.     int nodetype = 0;
  3798.     xmlNodeSetPtr newset = NULL;
  3799.     if (CUR == '@') {
  3800.         NEXT;
  3801. axis = AXIS_ATTRIBUTE;
  3802. goto parse_NodeTest;
  3803.     } else if (CUR == '*') {
  3804.         NEXT;
  3805.         nodetest = NODE_TEST_ALL;
  3806.     } else {
  3807.         name = xmlXPathParseNCName(ctxt);
  3808. if (name == NULL) {
  3809.     ERROR(XPATH_EXPR_ERROR);
  3810. }
  3811. type = xmlXPathGetNameType(ctxt, name);
  3812. switch (type) {
  3813.     case IS_FUNCTION: {
  3814. xmlXPathFunction func;
  3815. int nbargs = 0;
  3816. xmlXPathObjectPtr top;
  3817.                 top = ctxt->value;
  3818. func = xmlXPathIsFunction(ctxt, name);
  3819. if (func == NULL) {
  3820.     xmlFree(name);
  3821.     ERROR(XPATH_UNKNOWN_FUNC_ERROR);
  3822. }
  3823. #ifdef DEBUG_EXPR
  3824. fprintf(xmlXPathDebug, "Calling function %sn", name);
  3825. #endif
  3826. if (CUR != '(') {
  3827.     xmlFree(name);
  3828.     ERROR(XPATH_EXPR_ERROR);
  3829. }
  3830. NEXT;
  3831. while (CUR != ')') {
  3832.     xmlXPathEvalExpr(ctxt);
  3833.     nbargs++;
  3834.     if (CUR == ')') break;
  3835.     if (CUR != ',') {
  3836. xmlFree(name);
  3837. ERROR(XPATH_EXPR_ERROR);
  3838.     }
  3839.     NEXT;
  3840. }
  3841. NEXT;
  3842. xmlFree(name);
  3843. func(ctxt, nbargs);
  3844. if ((ctxt->value != top) &&
  3845.     (ctxt->value != NULL) &&
  3846.     (ctxt->value->type == XPATH_NODESET)) {
  3847.     xmlXPathObjectPtr cur;
  3848.     cur = valuePop(ctxt);
  3849.     ctxt->context->nodelist = cur->nodesetval;
  3850.     ctxt->context->node = NULL;
  3851.     cur->nodesetval = NULL;
  3852.                     xmlXPathFreeObject(cur);
  3853. }
  3854.         return;
  3855.     }
  3856.     /*
  3857.      * Simple case: no axis seach all given node types.
  3858.      */
  3859.             case NODE_TYPE_COMMENT:
  3860.         if ((CUR != '(') || (NXT(1) != ')')) break;
  3861. SKIP(2);
  3862. nodetest = NODE_TEST_TYPE;
  3863. nodetype = XML_COMMENT_NODE;
  3864. goto search_nodes;
  3865.             case NODE_TYPE_TEXT:
  3866.         if ((CUR != '(') || (NXT(1) != ')')) break;
  3867. SKIP(2);
  3868. nodetest = NODE_TEST_TYPE;
  3869. nodetype = XML_TEXT_NODE;
  3870. goto search_nodes;
  3871.             case NODE_TYPE_NODE:
  3872.         if ((CUR != '(') || (NXT(1) != ')')) {
  3873.     nodetest = NODE_TEST_NAME;
  3874.     break;
  3875. }
  3876. SKIP(2);
  3877. nodetest = NODE_TEST_TYPE;
  3878. nodetype = XML_ELEMENT_NODE;
  3879. goto search_nodes;
  3880.             case NODE_TYPE_PI:
  3881.         if (CUR != '(') break;
  3882. if (name != NULL) xmlFree(name);
  3883. name = NULL;
  3884. if (NXT(1) != ')') {
  3885.     xmlXPathObjectPtr cur;
  3886.     /*
  3887.      * Specific case: search a PI by name.
  3888.      */
  3889.                     NEXT;
  3890.     nodetest = NODE_TEST_PI;
  3891.     xmlXPathEvalLiteral(ctxt);
  3892.     CHECK_ERROR;
  3893.     if (CUR != ')')
  3894. ERROR(XPATH_UNCLOSED_ERROR);
  3895.                     NEXT;
  3896.     xmlXPathStringFunction(ctxt, 1);
  3897.     CHECK_ERROR;
  3898.     cur = valuePop(ctxt);
  3899.     name = xmlStrdup(cur->stringval);
  3900.     xmlXPathFreeObject(cur);
  3901. } else
  3902.     SKIP(2);
  3903. nodetest = NODE_TEST_PI;
  3904. goto search_nodes;
  3905.     /*
  3906.      * Handling of the compund form: got the axis.
  3907.      */
  3908.             case AXIS_ANCESTOR:
  3909.             case AXIS_ANCESTOR_OR_SELF:
  3910.             case AXIS_ATTRIBUTE:
  3911.             case AXIS_CHILD:
  3912.             case AXIS_DESCENDANT:
  3913.             case AXIS_DESCENDANT_OR_SELF:
  3914.             case AXIS_FOLLOWING:
  3915.             case AXIS_FOLLOWING_SIBLING:
  3916.             case AXIS_NAMESPACE:
  3917.             case AXIS_PARENT:
  3918.             case AXIS_PRECEDING:
  3919.             case AXIS_PRECEDING_SIBLING:
  3920.             case AXIS_SELF:
  3921.         if ((CUR != ':') || (NXT(1) != ':')) {
  3922.     nodetest = NODE_TEST_NAME;
  3923.     break;
  3924. }
  3925. SKIP(2);
  3926. axis = type;
  3927. break;
  3928.     /*
  3929.      * Default: abbreviated syntax the axis is AXIS_CHILD
  3930.      */
  3931.     default:
  3932.         nodetest = NODE_TEST_NAME;
  3933. }
  3934. parse_NodeTest:
  3935. if (nodetest == NODE_TEST_NONE) {
  3936.     if (CUR == '*') {
  3937. NEXT;
  3938. nodetest = NODE_TEST_ALL;
  3939.     } else {
  3940. if (name != NULL) 
  3941.     xmlFree(name);
  3942. name = xmlXPathParseQName(ctxt, &prefix);
  3943. if (name == NULL) {
  3944.     ERROR(XPATH_EXPR_ERROR);
  3945. }
  3946. type = xmlXPathGetNameType(ctxt, name);
  3947. switch (type) {
  3948.     /*
  3949.      * Simple case: no axis seach all given node types.
  3950.      */
  3951.     case NODE_TYPE_COMMENT:
  3952. if ((CUR != '(') || (NXT(1) != ')')) break;
  3953. SKIP(2);
  3954. nodetest = NODE_TEST_TYPE;
  3955. nodetype = XML_COMMENT_NODE;
  3956. goto search_nodes;
  3957.     case NODE_TYPE_TEXT:
  3958. if ((CUR != '(') || (NXT(1) != ')')) break;
  3959. SKIP(2);
  3960. nodetest = NODE_TEST_TYPE;
  3961. nodetype = XML_TEXT_NODE;
  3962. goto search_nodes;
  3963.     case NODE_TYPE_NODE:
  3964. if ((CUR != '(') || (NXT(1) != ')')) {
  3965.     nodetest = NODE_TEST_NAME;
  3966.     break;
  3967. }
  3968. SKIP(2);
  3969. nodetest = NODE_TEST_TYPE;
  3970. nodetype = XML_ELEMENT_NODE;
  3971. goto search_nodes;
  3972.     case NODE_TYPE_PI:
  3973. if (CUR != '(') break;
  3974. if (name != NULL) xmlFree(name);
  3975. name = NULL;
  3976. if (NXT(1) != ')') {
  3977.     xmlXPathObjectPtr cur;
  3978.     /*
  3979.      * Specific case: search a PI by name.
  3980.      */
  3981.     NEXT;
  3982.     nodetest = NODE_TEST_PI;
  3983.     xmlXPathEvalLiteral(ctxt);
  3984.     CHECK_ERROR;
  3985.     if (CUR != ')')
  3986. ERROR(XPATH_UNCLOSED_ERROR);
  3987.     NEXT;
  3988.     xmlXPathStringFunction(ctxt, 1);
  3989.     CHECK_ERROR;
  3990.     cur = valuePop(ctxt);
  3991.     name = xmlStrdup(cur->stringval);
  3992.     xmlXPathFreeObject(cur);
  3993. } else
  3994.     SKIP(2);
  3995. nodetest = NODE_TEST_PI;
  3996. goto search_nodes;
  3997. }
  3998. nodetest = NODE_TEST_NAME;
  3999.     }
  4000. } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
  4001.     NEXT;
  4002.     prefix = name;
  4003.     if (CUR == '*') {
  4004.         NEXT;
  4005. nodetest = NODE_TEST_ALL;
  4006.     } else 
  4007. name = xmlXPathParseNCName(ctxt);
  4008. } else if (name == NULL)
  4009.     ERROR(XPATH_EXPR_ERROR);
  4010.     }
  4011. search_nodes:
  4012.         
  4013. #ifdef DEBUG_STEP
  4014.     fprintf(xmlXPathDebug, "Basis : computing new setn");
  4015. #endif
  4016.     newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
  4017.                                         prefix, name);
  4018.     if (ctxt->context->nodelist != NULL)
  4019. xmlXPathFreeNodeSet(ctxt->context->nodelist);
  4020.     ctxt->context->nodelist = newset;
  4021.     ctxt->context->node = NULL;
  4022. #ifdef DEBUG_STEP
  4023.     fprintf(xmlXPathDebug, "Basis : ");
  4024.     xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
  4025. #endif
  4026.     if (name != NULL) xmlFree(name);
  4027.     if (prefix != NULL) xmlFree(prefix);
  4028. }
  4029. /**
  4030.  * xmlXPathEvalStep:
  4031.  * @ctxt:  the XPath Parser context
  4032.  *
  4033.  *  [4]   Step ::=   Basis Predicate*
  4034.  *                     | AbbreviatedStep 
  4035.  *  [12]   AbbreviatedStep ::=   '.'
  4036.  *                           | '..'
  4037.  *
  4038.  * Evaluate one step in a Location Path
  4039.  * A location step of . is short for self::node(). This is
  4040.  * particularly useful in conjunction with //. For example, the
  4041.  * location path .//para is short for
  4042.  * self::node()/descendant-or-self::node()/child::para
  4043.  * and so will select all para descendant elements of the context
  4044.  * node.
  4045.  * Similarly, a location step of .. is short for parent::node().
  4046.  * For example, ../title is short for parent::node()/child::title
  4047.  * and so will select the title children of the parent of the context
  4048.  * node.
  4049.  */
  4050. void
  4051. xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
  4052.     xmlNodeSetPtr newset = NULL;
  4053.     SKIP_BLANKS;
  4054.     if ((CUR == '.') && (NXT(1) == '.')) {
  4055. SKIP(2);
  4056. SKIP_BLANKS;
  4057. if (ctxt->context->nodelist == NULL) {
  4058.     STRANGE
  4059.     xmlXPathRoot(ctxt);
  4060. }
  4061. newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
  4062.  NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
  4063. if (ctxt->context->nodelist != NULL)
  4064.     xmlXPathFreeNodeSet(ctxt->context->nodelist);
  4065. ctxt->context->nodelist = newset;
  4066. ctxt->context->node = NULL;
  4067.     } else if (CUR == '.') {
  4068. NEXT;
  4069. SKIP_BLANKS;
  4070.     } else {
  4071. xmlXPathEvalBasis(ctxt);
  4072. SKIP_BLANKS;
  4073. while (CUR == '[') {
  4074.     xmlXPathEvalPredicate(ctxt);
  4075. }
  4076.     }
  4077. #ifdef DEBUG_STEP
  4078.     fprintf(xmlXPathDebug, "Step : ");
  4079.     xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
  4080. #endif
  4081. }
  4082. /**
  4083.  * xmlXPathEvalRelativeLocationPath:
  4084.  * @ctxt:  the XPath Parser context
  4085.  *
  4086.  *  [3]   RelativeLocationPath ::=   Step 
  4087.  *                     | RelativeLocationPath '/' Step 
  4088.  *                     | AbbreviatedRelativeLocationPath 
  4089.  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step 
  4090.  *
  4091.  */
  4092. void
  4093. xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
  4094.     xmlNodeSetPtr newset = NULL;
  4095.     SKIP_BLANKS;
  4096.     xmlXPathEvalStep(ctxt);
  4097.     SKIP_BLANKS;
  4098.     while (CUR == '/') {
  4099. if ((CUR == '/') && (NXT(1) == '/')) {
  4100.     SKIP(2);
  4101.     SKIP_BLANKS;
  4102.     if (ctxt->context->nodelist == NULL) {
  4103. STRANGE
  4104. xmlXPathRoot(ctxt);
  4105.     }
  4106.     newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
  4107.      NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
  4108.     if (ctxt->context->nodelist != NULL)
  4109. xmlXPathFreeNodeSet(ctxt->context->nodelist);
  4110.     ctxt->context->nodelist = newset;
  4111.     ctxt->context->node = NULL;
  4112.     xmlXPathEvalStep(ctxt);
  4113. } else if (CUR == '/') {
  4114.     NEXT;
  4115.     SKIP_BLANKS;
  4116.     xmlXPathEvalStep(ctxt);
  4117. }
  4118. SKIP_BLANKS;
  4119.     }
  4120. }
  4121. /**
  4122.  * xmlXPathEvalLocationPath:
  4123.  * @ctxt:  the XPath Parser context
  4124.  *
  4125.  *  [1]   LocationPath ::=   RelativeLocationPath 
  4126.  *                     | AbsoluteLocationPath 
  4127.  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
  4128.  *                     | AbbreviatedAbsoluteLocationPath 
  4129.  *  [10]   AbbreviatedAbsoluteLocationPath ::=   
  4130.  *                           '//' RelativeLocationPath 
  4131.  *
  4132.  * // is short for /descendant-or-self::node()/. For example,
  4133.  * //para is short for /descendant-or-self::node()/child::para and
  4134.  * so will select any para element in the document (even a para element
  4135.  * that is a document element will be selected by //para since the
  4136.  * document element node is a child of the root node); div//para is
  4137.  * short for div/descendant-or-self::node()/child::para and so will
  4138.  * select all para descendants of div children.
  4139.  */
  4140. void
  4141. xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
  4142.     xmlNodeSetPtr newset = NULL;
  4143.     SKIP_BLANKS;
  4144.     if (CUR != '/') {
  4145.         xmlXPathEvalRelativeLocationPath(ctxt);
  4146.     } else {
  4147. while (CUR == '/') {
  4148.     if ((CUR == '/') && (NXT(1) == '/')) {
  4149. SKIP(2);
  4150. SKIP_BLANKS;
  4151. if (ctxt->context->nodelist == NULL)
  4152.     xmlXPathRoot(ctxt);
  4153. newset = xmlXPathNodeCollectAndTest(ctxt,
  4154.                  AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
  4155.  XML_ELEMENT_NODE, NULL, NULL);
  4156. if (ctxt->context->nodelist != NULL)
  4157.     xmlXPathFreeNodeSet(ctxt->context->nodelist);
  4158. ctxt->context->nodelist = newset;
  4159. ctxt->context->node = NULL;
  4160. xmlXPathEvalRelativeLocationPath(ctxt);
  4161.     } else if (CUR == '/') {
  4162. NEXT;
  4163. SKIP_BLANKS;
  4164. xmlXPathRoot(ctxt);
  4165. if (CUR != 0)
  4166.     xmlXPathEvalRelativeLocationPath(ctxt);
  4167.     } else {
  4168. xmlXPathEvalRelativeLocationPath(ctxt);
  4169.     }
  4170. }
  4171.     }
  4172. }
  4173. /**
  4174.  * xmlXPathEval:
  4175.  * @str:  the XPath expression
  4176.  * @ctxt:  the XPath context
  4177.  *
  4178.  * Evaluate the XPath Location Path in the given context.
  4179.  *
  4180.  * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
  4181.  *         the caller has to free the object.
  4182.  */
  4183. xmlXPathObjectPtr
  4184. xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
  4185.     xmlXPathParserContextPtr pctxt;
  4186.     xmlXPathObjectPtr res = NULL, tmp;
  4187.     int stack = 0;
  4188.     xmlXPathInit();
  4189.     CHECK_CONTEXT
  4190.     if (xmlXPathDebug == NULL)
  4191.         xmlXPathDebug = stderr;
  4192.     pctxt = xmlXPathNewParserContext(str, ctxt);
  4193.     if (str[0] == '/')
  4194.         xmlXPathRoot(pctxt);
  4195.     xmlXPathEvalLocationPath(pctxt);
  4196.     /* TODO: cleanup nodelist, res = valuePop(pctxt); */
  4197.     do {
  4198.         tmp = valuePop(pctxt);
  4199. if (tmp != NULL) {
  4200.     xmlXPathFreeObject(tmp);
  4201.     stack++;    
  4202.         }
  4203.     } while (tmp != NULL);
  4204.     if (stack != 0) {
  4205. fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stackn",
  4206.         stack);
  4207.     }
  4208.     if (pctxt->error == XPATH_EXPRESSION_OK)
  4209. res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
  4210.     else
  4211.         res = NULL;
  4212.     xmlXPathFreeParserContext(pctxt);
  4213.     return(res);
  4214. }
  4215. /**
  4216.  * xmlXPathEvalExpression:
  4217.  * @str:  the XPath expression
  4218.  * @ctxt:  the XPath context
  4219.  *
  4220.  * Evaluate the XPath expression in the given context.
  4221.  *
  4222.  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  4223.  *         the caller has to free the object.
  4224.  */
  4225. xmlXPathObjectPtr
  4226. xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
  4227.     xmlXPathParserContextPtr pctxt;
  4228.     xmlXPathObjectPtr res, tmp;
  4229.     int stack = 0;
  4230.     xmlXPathInit();
  4231.     CHECK_CONTEXT
  4232.     if (xmlXPathDebug == NULL)
  4233.         xmlXPathDebug = stderr;
  4234.     pctxt = xmlXPathNewParserContext(str, ctxt);
  4235.     xmlXPathEvalExpr(pctxt);
  4236.     res = valuePop(pctxt);
  4237.     do {
  4238.         tmp = valuePop(pctxt);
  4239. if (tmp != NULL) {
  4240.     xmlXPathFreeObject(tmp);
  4241.     stack++;
  4242. }
  4243.     } while (tmp != NULL);
  4244.     if (stack != 0) {
  4245. fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stackn",
  4246.         stack);
  4247.     }
  4248.     xmlXPathFreeParserContext(pctxt);
  4249.     return(res);
  4250. }
  4251. #endif /* LIBXML_XPATH_ENABLED */