Home | History | Annotate | Download | only in libexslt
      1 #define IN_LIBEXSLT
      2 #include "libexslt/libexslt.h"
      3 
      4 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
      5 #include <win32config.h>
      6 #else
      7 #include "config.h"
      8 #endif
      9 
     10 #include <libxml/tree.h>
     11 #include <libxml/xpath.h>
     12 #include <libxml/xpathInternals.h>
     13 
     14 #include <libxslt/xsltconfig.h>
     15 #include <libxslt/xsltutils.h>
     16 #include <libxslt/xsltInternals.h>
     17 #include <libxslt/extensions.h>
     18 
     19 #ifdef HAVE_MATH_H
     20 #include <math.h>
     21 #endif
     22 
     23 #ifdef HAVE_STDLIB_H
     24 #include <stdlib.h>
     25 #endif
     26 
     27 #include "exslt.h"
     28 
     29 /**
     30  * exsltMathMin:
     31  * @ns:  a node-set
     32  *
     33  * Implements the EXSLT - Math min() function:
     34  *    number math:min (node-set)
     35  *
     36  * Returns the minimum value of the nodes passed as the argument, or
     37  *         xmlXPathNAN if @ns is NULL or empty or if one of the nodes
     38  *         turns into NaN.
     39  */
     40 static double
     41 exsltMathMin (xmlNodeSetPtr ns) {
     42     double ret, cur;
     43     int i;
     44 
     45     if ((ns == NULL) || (ns->nodeNr == 0))
     46 	return(xmlXPathNAN);
     47     ret = xmlXPathCastNodeToNumber(ns->nodeTab[0]);
     48     if (xmlXPathIsNaN(ret))
     49 	return(xmlXPathNAN);
     50     for (i = 1; i < ns->nodeNr; i++) {
     51 	cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]);
     52 	if (xmlXPathIsNaN(cur))
     53 	    return(xmlXPathNAN);
     54 	if (cur < ret)
     55 	    ret = cur;
     56     }
     57     return(ret);
     58 }
     59 
     60 /**
     61  * exsltMathMinFunction:
     62  * @ctxt:  an XPath parser context
     63  * @nargs:  the number of arguments
     64  *
     65  * Wraps #exsltMathMin for use by the XPath processor.
     66  */
     67 static void
     68 exsltMathMinFunction (xmlXPathParserContextPtr ctxt, int nargs) {
     69     xmlNodeSetPtr ns;
     70     double ret;
     71     void *user = NULL;
     72 
     73     if (nargs != 1) {
     74 	xsltGenericError(xsltGenericErrorContext,
     75 			 "math:min: invalid number of arguments\n");
     76 	ctxt->error = XPATH_INVALID_ARITY;
     77 	return;
     78     }
     79     /* We need to delay the freeing of value->user */
     80     if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) {
     81         user = ctxt->value->user;
     82 	ctxt->value->boolval = 0;
     83 	ctxt->value->user = NULL;
     84     }
     85     ns = xmlXPathPopNodeSet(ctxt);
     86     if (xmlXPathCheckError(ctxt))
     87 	return;
     88 
     89     ret = exsltMathMin(ns);
     90 
     91     xmlXPathFreeNodeSet(ns);
     92     if (user != NULL)
     93         xmlFreeNodeList((xmlNodePtr)user);
     94 
     95     xmlXPathReturnNumber(ctxt, ret);
     96 }
     97 
     98 /**
     99  * exsltMathMax:
    100  * @ns:  a node-set
    101  *
    102  * Implements the EXSLT - Math max() function:
    103  *    number math:max (node-set)
    104  *
    105  * Returns the maximum value of the nodes passed as arguments, or
    106  *         xmlXPathNAN if @ns is NULL or empty or if one of the nodes
    107  *         turns into NaN.
    108  */
    109 static double
    110 exsltMathMax (xmlNodeSetPtr ns) {
    111     double ret, cur;
    112     int i;
    113 
    114     if ((ns == NULL) || (ns->nodeNr == 0))
    115 	return(xmlXPathNAN);
    116     ret = xmlXPathCastNodeToNumber(ns->nodeTab[0]);
    117     if (xmlXPathIsNaN(ret))
    118 	return(xmlXPathNAN);
    119     for (i = 1; i < ns->nodeNr; i++) {
    120 	cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]);
    121 	if (xmlXPathIsNaN(cur))
    122 	    return(xmlXPathNAN);
    123 	if (cur > ret)
    124 	    ret = cur;
    125     }
    126     return(ret);
    127 }
    128 
    129 /**
    130  * exsltMathMaxFunction:
    131  * @ctxt:  an XPath parser context
    132  * @nargs:  the number of arguments
    133  *
    134  * Wraps #exsltMathMax for use by the XPath processor.
    135  */
    136 static void
    137 exsltMathMaxFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    138     xmlNodeSetPtr ns;
    139     double ret;
    140     void *user = NULL;
    141 
    142     if (nargs != 1) {
    143 	xmlXPathSetArityError(ctxt);
    144 	return;
    145     }
    146 
    147     /* We need to delay the freeing of value->user */
    148     if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) {
    149 	user = ctxt->value->user;
    150 	ctxt->value->boolval = 0;
    151 	ctxt->value->user = 0;
    152     }
    153     ns = xmlXPathPopNodeSet(ctxt);
    154     if (xmlXPathCheckError(ctxt))
    155 	return;
    156 
    157     ret = exsltMathMax(ns);
    158 
    159     xmlXPathFreeNodeSet(ns);
    160 
    161     if (user != NULL)
    162         xmlFreeNodeList((xmlNodePtr)user);
    163     xmlXPathReturnNumber(ctxt, ret);
    164 }
    165 
    166 /**
    167  * exsltMathHighest:
    168  * @ns:  a node-set
    169  *
    170  * Implements the EXSLT - Math highest() function:
    171  *    node-set math:highest (node-set)
    172  *
    173  * Returns the nodes in the node-set whose value is the maximum value
    174  *         for the node-set.
    175  */
    176 static xmlNodeSetPtr
    177 exsltMathHighest (xmlNodeSetPtr ns) {
    178     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
    179     double max, cur;
    180     int i;
    181 
    182     if ((ns == NULL) || (ns->nodeNr == 0))
    183 	return(ret);
    184 
    185     max = xmlXPathCastNodeToNumber(ns->nodeTab[0]);
    186     if (xmlXPathIsNaN(max))
    187 	return(ret);
    188     else
    189 	xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]);
    190 
    191     for (i = 1; i < ns->nodeNr; i++) {
    192 	cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]);
    193 	if (xmlXPathIsNaN(cur)) {
    194 	    xmlXPathEmptyNodeSet(ret);
    195 	    return(ret);
    196 	}
    197 	if (cur < max)
    198 	    continue;
    199 	if (cur > max) {
    200 	    max = cur;
    201 	    xmlXPathEmptyNodeSet(ret);
    202 	    xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]);
    203 	    continue;
    204 	}
    205 	xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]);
    206     }
    207     return(ret);
    208 }
    209 
    210 /**
    211  * exsltMathHighestFunction:
    212  * @ctxt:  an XPath parser context
    213  * @nargs:  the number of arguments
    214  *
    215  * Wraps #exsltMathHighest for use by the XPath processor
    216  */
    217 static void
    218 exsltMathHighestFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    219     xmlNodeSetPtr ns, ret;
    220     void *user = NULL;
    221 
    222     if (nargs != 1) {
    223 	xmlXPathSetArityError(ctxt);
    224 	return;
    225     }
    226 
    227     /* We need to delay the freeing of value->user */
    228     if ((ctxt->value != NULL) && ctxt->value->boolval != 0) {
    229         user = ctxt->value->user;
    230 	ctxt->value->boolval = 0;
    231 	ctxt->value->user = NULL;
    232     }
    233     ns = xmlXPathPopNodeSet(ctxt);
    234     if (xmlXPathCheckError(ctxt))
    235 	return;
    236 
    237     ret = exsltMathHighest(ns);
    238 
    239     xmlXPathFreeNodeSet(ns);
    240     if (user != NULL)
    241         xmlFreeNodeList((xmlNodePtr)user);
    242 
    243     xmlXPathReturnNodeSet(ctxt, ret);
    244 }
    245 
    246 /**
    247  * exsltMathLowest:
    248  * @ns:  a node-set
    249  *
    250  * Implements the EXSLT - Math lowest() function
    251  *    node-set math:lowest (node-set)
    252  *
    253  * Returns the nodes in the node-set whose value is the minimum value
    254  *         for the node-set.
    255  */
    256 static xmlNodeSetPtr
    257 exsltMathLowest (xmlNodeSetPtr ns) {
    258     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
    259     double min, cur;
    260     int i;
    261 
    262     if ((ns == NULL) || (ns->nodeNr == 0))
    263 	return(ret);
    264 
    265     min = xmlXPathCastNodeToNumber(ns->nodeTab[0]);
    266     if (xmlXPathIsNaN(min))
    267 	return(ret);
    268     else
    269 	xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]);
    270 
    271     for (i = 1; i < ns->nodeNr; i++) {
    272 	cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]);
    273 	if (xmlXPathIsNaN(cur)) {
    274 	    xmlXPathEmptyNodeSet(ret);
    275 	    return(ret);
    276 	}
    277         if (cur > min)
    278 	    continue;
    279 	if (cur < min) {
    280 	    min = cur;
    281 	    xmlXPathEmptyNodeSet(ret);
    282 	    xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]);
    283             continue;
    284 	}
    285 	xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]);
    286     }
    287     return(ret);
    288 }
    289 
    290 /**
    291  * exsltMathLowestFunction:
    292  * @ctxt:  an XPath parser context
    293  * @nargs:  the number of arguments
    294  *
    295  * Wraps #exsltMathLowest for use by the XPath processor
    296  */
    297 static void
    298 exsltMathLowestFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    299     xmlNodeSetPtr ns, ret;
    300     void *user = NULL;
    301 
    302 
    303     if (nargs != 1) {
    304 	xmlXPathSetArityError(ctxt);
    305 	return;
    306     }
    307 
    308     /* We need to delay the freeing of value->user */
    309     if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) {
    310         user = ctxt->value->user;
    311 	ctxt->value->boolval = 0;
    312 	ctxt->value->user = NULL;
    313     }
    314     ns = xmlXPathPopNodeSet(ctxt);
    315     if (xmlXPathCheckError(ctxt))
    316 	return;
    317 
    318     ret = exsltMathLowest(ns);
    319 
    320     xmlXPathFreeNodeSet(ns);
    321     if (user != NULL)
    322         xmlFreeNodeList((xmlNodePtr)user);
    323 
    324     xmlXPathReturnNodeSet(ctxt, ret);
    325 }
    326 
    327 /* math other functions */
    328 
    329 /* constant values */
    330 #define EXSLT_PI        (const xmlChar *) \
    331 			"3.1415926535897932384626433832795028841971693993751"
    332 #define EXSLT_E         (const xmlChar *) \
    333 			"2.71828182845904523536028747135266249775724709369996"
    334 #define EXSLT_SQRRT2    (const xmlChar *) \
    335 			"1.41421356237309504880168872420969807856967187537694"
    336 #define EXSLT_LN2       (const xmlChar *) \
    337 			"0.69314718055994530941723212145817656807550013436025"
    338 #define EXSLT_LN10      (const xmlChar *) \
    339 			"2.30258509299404568402"
    340 #define EXSLT_LOG2E     (const xmlChar *) \
    341 			"1.4426950408889634074"
    342 #define EXSLT_SQRT1_2   (const xmlChar *) \
    343 			"0.70710678118654752440"
    344 
    345 /**
    346  * exsltMathConstant
    347  * @name: string
    348  * @precision:  number
    349  *
    350  * Implements the EXSLT - Math constant function:
    351  *     number math:constant(string, number)
    352  *
    353  * Returns a number value of the given constant with the given precision or
    354  * xmlXPathNAN if name is unknown.
    355  * The constants are PI, E, SQRRT2, LN2, LN10, LOG2E, and SQRT1_2
    356  */
    357 static double
    358 exsltMathConstant (xmlChar *name, double precision) {
    359     xmlChar *str;
    360     double ret;
    361 
    362     if ((name == NULL) || (xmlXPathIsNaN(precision)) || (precision < 1.0)) {
    363         return xmlXPathNAN;
    364     }
    365 
    366     if (xmlStrEqual(name, BAD_CAST "PI")) {
    367         int len = xmlStrlen(EXSLT_PI);
    368 
    369         if (precision <= len)
    370             len = (int)precision;
    371 
    372         str = xmlStrsub(EXSLT_PI, 0, len);
    373 
    374     } else if (xmlStrEqual(name, BAD_CAST "E")) {
    375         int len = xmlStrlen(EXSLT_E);
    376 
    377         if (precision <= len)
    378             len = (int)precision;
    379 
    380         str = xmlStrsub(EXSLT_E, 0, len);
    381 
    382     } else if (xmlStrEqual(name, BAD_CAST "SQRRT2")) {
    383         int len = xmlStrlen(EXSLT_SQRRT2);
    384 
    385         if (precision <= len)
    386             len = (int)precision;
    387 
    388         str = xmlStrsub(EXSLT_SQRRT2, 0, len);
    389 
    390     } else if (xmlStrEqual(name, BAD_CAST "LN2")) {
    391         int len = xmlStrlen(EXSLT_LN2);
    392 
    393         if (precision <= len)
    394             len = (int)precision;
    395 
    396         str = xmlStrsub(EXSLT_LN2, 0, len);
    397 
    398     } else if (xmlStrEqual(name, BAD_CAST "LN10")) {
    399         int len = xmlStrlen(EXSLT_LN10);
    400 
    401         if (precision <= len)
    402             len = (int)precision;
    403 
    404         str = xmlStrsub(EXSLT_LN10, 0, len);
    405 
    406     } else if (xmlStrEqual(name, BAD_CAST "LOG2E")) {
    407         int len = xmlStrlen(EXSLT_LOG2E);
    408 
    409         if (precision <= len)
    410             len = (int)precision;
    411 
    412         str = xmlStrsub(EXSLT_LOG2E, 0, len);
    413 
    414     } else if (xmlStrEqual(name, BAD_CAST "SQRT1_2")) {
    415         int len = xmlStrlen(EXSLT_SQRT1_2);
    416 
    417         if (precision <= len)
    418             len = (int)precision;
    419 
    420         str = xmlStrsub(EXSLT_SQRT1_2, 0, len);
    421 
    422     } else {
    423 	str = NULL;
    424     }
    425     if (str == NULL)
    426         return xmlXPathNAN;
    427     ret = xmlXPathCastStringToNumber(str);
    428     xmlFree(str);
    429     return ret;
    430 }
    431 
    432 /**
    433  * exsltMathConstantFunction:
    434  * @ctxt:  an XPath parser context
    435  * @nargs:  the number of arguments
    436  *
    437  * Wraps #exsltMathConstant for use by the XPath processor.
    438  */
    439 static void
    440 exsltMathConstantFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    441     double   ret;
    442     xmlChar *name;
    443 
    444     if (nargs != 2) {
    445 	xmlXPathSetArityError(ctxt);
    446 	return;
    447     }
    448     ret = xmlXPathPopNumber(ctxt);
    449     if (xmlXPathCheckError(ctxt))
    450 	return;
    451 
    452     name = xmlXPathPopString(ctxt);
    453     if (xmlXPathCheckError(ctxt))
    454 	return;
    455 
    456     ret = exsltMathConstant(name, ret);
    457     if (name != NULL)
    458 	xmlFree(name);
    459 
    460     xmlXPathReturnNumber(ctxt, ret);
    461 }
    462 
    463 #if defined(HAVE_STDLIB_H) && defined(RAND_MAX)
    464 
    465 /**
    466  * exsltMathRandom:
    467  *
    468  * Implements the EXSLT - Math random() function:
    469  *    number math:random ()
    470  *
    471  * Returns a random number between 0 and 1 inclusive.
    472  */
    473 static double
    474 exsltMathRandom (void) {
    475     double ret;
    476     int num;
    477 
    478     num = rand();
    479     ret = (double)num / (double)RAND_MAX;
    480     return(ret);
    481 }
    482 
    483 /**
    484  * exsltMathRandomFunction:
    485  * @ctxt:  an XPath parser context
    486  * @nargs:  the number of arguments
    487  *
    488  * Wraps #exsltMathRandom for use by the XPath processor.
    489  */
    490 static void
    491 exsltMathRandomFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    492     double ret;
    493 
    494     if (nargs != 0) {
    495 	xmlXPathSetArityError(ctxt);
    496 	return;
    497     }
    498 
    499     ret = exsltMathRandom();
    500 
    501     xmlXPathReturnNumber(ctxt, ret);
    502 }
    503 
    504 #endif /* defined(HAVE_STDLIB_H) && defined(RAND_MAX) */
    505 
    506 #if HAVE_MATH_H
    507 
    508 /**
    509  * exsltMathAbs:
    510  * @num:  a double
    511  *
    512  * Implements the EXSLT - Math abs() function:
    513  *    number math:abs (number)
    514  *
    515  * Returns the absolute value of the argument, or xmlXPathNAN if @num is Nan.
    516  */
    517 static double
    518 exsltMathAbs (double num) {
    519     double ret;
    520 
    521     if (xmlXPathIsNaN(num))
    522 	return(xmlXPathNAN);
    523     ret = fabs(num);
    524     return(ret);
    525 }
    526 
    527 /**
    528  * exsltMathAbsFunction:
    529  * @ctxt:  an XPath parser context
    530  * @nargs:  the number of arguments
    531  *
    532  * Wraps #exsltMathAbs for use by the XPath processor.
    533  */
    534 static void
    535 exsltMathAbsFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    536     double ret;
    537 
    538     if (nargs != 1) {
    539 	xmlXPathSetArityError(ctxt);
    540 	return;
    541     }
    542     ret = xmlXPathPopNumber(ctxt);
    543     if (xmlXPathCheckError(ctxt))
    544 	return;
    545 
    546     ret = exsltMathAbs(ret);
    547 
    548     xmlXPathReturnNumber(ctxt, ret);
    549 }
    550 
    551 /**
    552  * exsltMathSqrt:
    553  * @num:  a double
    554  *
    555  * Implements the EXSLT - Math sqrt() function:
    556  *    number math:sqrt (number)
    557  *
    558  * Returns the square root of the argument, or xmlXPathNAN if @num is Nan.
    559  */
    560 static double
    561 exsltMathSqrt (double num) {
    562     double ret;
    563 
    564     if (xmlXPathIsNaN(num))
    565 	return(xmlXPathNAN);
    566     ret = sqrt(num);
    567     return(ret);
    568 }
    569 
    570 /**
    571  * exsltMathSqrtFunction:
    572  * @ctxt:  an XPath parser context
    573  * @nargs:  the number of arguments
    574  *
    575  * Wraps #exsltMathSqrt for use by the XPath processor.
    576  */
    577 static void
    578 exsltMathSqrtFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    579     double ret;
    580 
    581     if (nargs != 1) {
    582 	xmlXPathSetArityError(ctxt);
    583 	return;
    584     }
    585     ret = xmlXPathPopNumber(ctxt);
    586     if (xmlXPathCheckError(ctxt))
    587 	return;
    588 
    589     ret = exsltMathSqrt(ret);
    590 
    591     xmlXPathReturnNumber(ctxt, ret);
    592 }
    593 
    594 /**
    595  * exsltMathPower:
    596  * @base:  a double
    597  * @power:  a double
    598  *
    599  * Implements the EXSLT - Math power() function:
    600  *    number math:power (number, number)
    601  *
    602  * Returns the power base and power arguments, or xmlXPathNAN
    603  * if either @base or @power is Nan.
    604  */
    605 static double
    606 exsltMathPower (double base, double power) {
    607     double ret;
    608 
    609     if ((xmlXPathIsNaN(base) || xmlXPathIsNaN(power)))
    610 	return(xmlXPathNAN);
    611     ret = pow(base, power);
    612     return(ret);
    613 }
    614 
    615 /**
    616  * exsltMathPower:
    617  * @ctxt:  an XPath parser context
    618  * @nargs:  the number of arguments
    619  *
    620  * Wraps #exsltMathPower for use by the XPath processor.
    621  */
    622 static void
    623 exsltMathPowerFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    624     double ret, base;
    625 
    626     if (nargs != 2) {
    627 	xmlXPathSetArityError(ctxt);
    628 	return;
    629     }
    630     ret = xmlXPathPopNumber(ctxt);
    631     if (xmlXPathCheckError(ctxt))
    632 	return;
    633 
    634     /* power */
    635     base = xmlXPathPopNumber(ctxt);
    636     if (xmlXPathCheckError(ctxt))
    637 	return;
    638 
    639     ret = exsltMathPower(base, ret);
    640 
    641     xmlXPathReturnNumber(ctxt, ret);
    642 }
    643 
    644 /**
    645  * exsltMathLog:
    646  * @num:  a double
    647  *
    648  * Implements the EXSLT - Math log() function:
    649  *    number math:log (number)
    650  *
    651  * Returns the natural log of the argument, or xmlXPathNAN if @num is Nan.
    652  */
    653 static double
    654 exsltMathLog (double num) {
    655     double ret;
    656 
    657     if (xmlXPathIsNaN(num))
    658 	return(xmlXPathNAN);
    659     ret = log(num);
    660     return(ret);
    661 }
    662 
    663 /**
    664  * exsltMathLogFunction:
    665  * @ctxt:  an XPath parser context
    666  * @nargs:  the number of arguments
    667  *
    668  * Wraps #exsltMathLog for use by the XPath processor.
    669  */
    670 static void
    671 exsltMathLogFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    672     double ret;
    673 
    674     if (nargs != 1) {
    675 	xmlXPathSetArityError(ctxt);
    676 	return;
    677     }
    678     ret = xmlXPathPopNumber(ctxt);
    679     if (xmlXPathCheckError(ctxt))
    680 	return;
    681 
    682     ret = exsltMathLog(ret);
    683 
    684     xmlXPathReturnNumber(ctxt, ret);
    685 }
    686 
    687 /**
    688  * exsltMathSin:
    689  * @num:  a double
    690  *
    691  * Implements the EXSLT - Math sin() function:
    692  *    number math:sin (number)
    693  *
    694  * Returns the sine of the argument, or xmlXPathNAN if @num is Nan.
    695  */
    696 static double
    697 exsltMathSin (double num) {
    698     double ret;
    699 
    700     if (xmlXPathIsNaN(num))
    701 	return(xmlXPathNAN);
    702     ret = sin(num);
    703     return(ret);
    704 }
    705 
    706 /**
    707  * exsltMathSinFunction:
    708  * @ctxt:  an XPath parser context
    709  * @nargs:  the number of arguments
    710  *
    711  * Wraps #exsltMathSin for use by the XPath processor.
    712  */
    713 static void
    714 exsltMathSinFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    715     double ret;
    716 
    717     if (nargs != 1) {
    718 	xmlXPathSetArityError(ctxt);
    719 	return;
    720     }
    721     ret = xmlXPathPopNumber(ctxt);
    722     if (xmlXPathCheckError(ctxt))
    723 	return;
    724 
    725     ret = exsltMathSin(ret);
    726 
    727     xmlXPathReturnNumber(ctxt, ret);
    728 }
    729 
    730 /**
    731  * exsltMathCos:
    732  * @num:  a double
    733  *
    734  * Implements the EXSLT - Math cos() function:
    735  *    number math:cos (number)
    736  *
    737  * Returns the cosine of the argument, or xmlXPathNAN if @num is Nan.
    738  */
    739 static double
    740 exsltMathCos (double num) {
    741     double ret;
    742 
    743     if (xmlXPathIsNaN(num))
    744 	return(xmlXPathNAN);
    745     ret = cos(num);
    746     return(ret);
    747 }
    748 
    749 /**
    750  * exsltMathCosFunction:
    751  * @ctxt:  an XPath parser context
    752  * @nargs:  the number of arguments
    753  *
    754  * Wraps #exsltMathCos for use by the XPath processor.
    755  */
    756 static void
    757 exsltMathCosFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    758     double ret;
    759 
    760     if (nargs != 1) {
    761 	xmlXPathSetArityError(ctxt);
    762 	return;
    763     }
    764     ret = xmlXPathPopNumber(ctxt);
    765     if (xmlXPathCheckError(ctxt))
    766 	return;
    767 
    768     ret = exsltMathCos(ret);
    769 
    770     xmlXPathReturnNumber(ctxt, ret);
    771 }
    772 
    773 /**
    774  * exsltMathTan:
    775  * @num:  a double
    776  *
    777  * Implements the EXSLT - Math tan() function:
    778  *    number math:tan (number)
    779  *
    780  * Returns the tangent of the argument, or xmlXPathNAN if @num is Nan.
    781  */
    782 static double
    783 exsltMathTan (double num) {
    784     double ret;
    785 
    786     if (xmlXPathIsNaN(num))
    787 	return(xmlXPathNAN);
    788     ret = tan(num);
    789     return(ret);
    790 }
    791 
    792 /**
    793  * exsltMathTanFunction:
    794  * @ctxt:  an XPath parser context
    795  * @nargs:  the number of arguments
    796  *
    797  * Wraps #exsltMathTan for use by the XPath processor.
    798  */
    799 static void
    800 exsltMathTanFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    801     double ret;
    802 
    803     if (nargs != 1) {
    804 	xmlXPathSetArityError(ctxt);
    805 	return;
    806     }
    807     ret = xmlXPathPopNumber(ctxt);
    808     if (xmlXPathCheckError(ctxt))
    809 	return;
    810 
    811     ret = exsltMathTan(ret);
    812 
    813     xmlXPathReturnNumber(ctxt, ret);
    814 }
    815 
    816 /**
    817  * exsltMathAsin:
    818  * @num:  a double
    819  *
    820  * Implements the EXSLT - Math asin() function:
    821  *    number math:asin (number)
    822  *
    823  * Returns the arc sine of the argument, or xmlXPathNAN if @num is Nan.
    824  */
    825 static double
    826 exsltMathAsin (double num) {
    827     double ret;
    828 
    829     if (xmlXPathIsNaN(num))
    830 	return(xmlXPathNAN);
    831     ret = asin(num);
    832     return(ret);
    833 }
    834 
    835 /**
    836  * exsltMathAsinFunction:
    837  * @ctxt:  an XPath parser context
    838  * @nargs:  the number of arguments
    839  *
    840  * Wraps #exsltMathAsin for use by the XPath processor.
    841  */
    842 static void
    843 exsltMathAsinFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    844     double ret;
    845 
    846     if (nargs != 1) {
    847 	xmlXPathSetArityError(ctxt);
    848 	return;
    849     }
    850     ret = xmlXPathPopNumber(ctxt);
    851     if (xmlXPathCheckError(ctxt))
    852 	return;
    853 
    854     ret = exsltMathAsin(ret);
    855 
    856     xmlXPathReturnNumber(ctxt, ret);
    857 }
    858 
    859 /**
    860  * exsltMathAcos:
    861  * @num:  a double
    862  *
    863  * Implements the EXSLT - Math acos() function:
    864  *    number math:acos (number)
    865  *
    866  * Returns the arc cosine of the argument, or xmlXPathNAN if @num is Nan.
    867  */
    868 static double
    869 exsltMathAcos (double num) {
    870     double ret;
    871 
    872     if (xmlXPathIsNaN(num))
    873 	return(xmlXPathNAN);
    874     ret = acos(num);
    875     return(ret);
    876 }
    877 
    878 /**
    879  * exsltMathAcosFunction:
    880  * @ctxt:  an XPath parser context
    881  * @nargs:  the number of arguments
    882  *
    883  * Wraps #exsltMathAcos for use by the XPath processor.
    884  */
    885 static void
    886 exsltMathAcosFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    887     double ret;
    888 
    889     if (nargs != 1) {
    890 	xmlXPathSetArityError(ctxt);
    891 	return;
    892     }
    893     ret = xmlXPathPopNumber(ctxt);
    894     if (xmlXPathCheckError(ctxt))
    895 	return;
    896 
    897     ret = exsltMathAcos(ret);
    898 
    899     xmlXPathReturnNumber(ctxt, ret);
    900 }
    901 
    902 /**
    903  * exsltMathAtan:
    904  * @num:  a double
    905  *
    906  * Implements the EXSLT - Math atan() function:
    907  *    number math:atan (number)
    908  *
    909  * Returns the arc tangent of the argument, or xmlXPathNAN if @num is Nan.
    910  */
    911 static double
    912 exsltMathAtan (double num) {
    913     double ret;
    914 
    915     if (xmlXPathIsNaN(num))
    916 	return(xmlXPathNAN);
    917     ret = atan(num);
    918     return(ret);
    919 }
    920 
    921 /**
    922  * exsltMathAtanFunction:
    923  * @ctxt:  an XPath parser context
    924  * @nargs:  the number of arguments
    925  *
    926  * Wraps #exsltMathAtan for use by the XPath processor.
    927  */
    928 static void
    929 exsltMathAtanFunction (xmlXPathParserContextPtr ctxt, int nargs) {
    930     double ret;
    931 
    932     if (nargs != 1) {
    933 	xmlXPathSetArityError(ctxt);
    934 	return;
    935     }
    936     ret = xmlXPathPopNumber(ctxt);
    937     if (xmlXPathCheckError(ctxt))
    938 	return;
    939 
    940     ret = exsltMathAtan(ret);
    941 
    942     xmlXPathReturnNumber(ctxt, ret);
    943 }
    944 
    945 /**
    946  * exsltMathAtan2:
    947  * @y:  a double
    948  * @x:  a double
    949  *
    950  * Implements the EXSLT - Math atan2() function:
    951  *    number math:atan2 (number, number)
    952  *
    953  * Returns the arc tangent function of the y/x arguments, or xmlXPathNAN
    954  * if either @y or @x is Nan.
    955  */
    956 static double
    957 exsltMathAtan2 (double y, double x) {
    958     double ret;
    959 
    960     if ((xmlXPathIsNaN(y) || xmlXPathIsNaN(x)))
    961 	return(xmlXPathNAN);
    962     ret = atan2(y, x);
    963     return(ret);
    964 }
    965 
    966 /**
    967  * exsltMathAtan2Function:
    968  * @ctxt:  an XPath parser context
    969  * @nargs:  the number of arguments
    970  *
    971  * Wraps #exsltMathAtan2 for use by the XPath processor.
    972  */
    973 static void
    974 exsltMathAtan2Function (xmlXPathParserContextPtr ctxt, int nargs) {
    975     double ret, x;
    976 
    977     if (nargs != 2) {
    978 	xmlXPathSetArityError(ctxt);
    979 	return;
    980     }
    981     x = xmlXPathPopNumber(ctxt);
    982     if (xmlXPathCheckError(ctxt))
    983 	return;
    984 
    985     /* y */
    986     ret = xmlXPathPopNumber(ctxt);
    987     if (xmlXPathCheckError(ctxt))
    988 	return;
    989 
    990     ret = exsltMathAtan2(ret, x);
    991 
    992     xmlXPathReturnNumber(ctxt, ret);
    993 }
    994 
    995 /**
    996  * exsltMathExp:
    997  * @num:  a double
    998  *
    999  * Implements the EXSLT - Math exp() function:
   1000  *    number math:exp (number)
   1001  *
   1002  * Returns the exponential function of the argument, or xmlXPathNAN if
   1003  * @num is Nan.
   1004  */
   1005 static double
   1006 exsltMathExp (double num) {
   1007     double ret;
   1008 
   1009     if (xmlXPathIsNaN(num))
   1010 	return(xmlXPathNAN);
   1011     ret = exp(num);
   1012     return(ret);
   1013 }
   1014 
   1015 /**
   1016  * exsltMathExpFunction:
   1017  * @ctxt:  an XPath parser context
   1018  * @nargs:  the number of arguments
   1019  *
   1020  * Wraps #exsltMathExp for use by the XPath processor.
   1021  */
   1022 static void
   1023 exsltMathExpFunction (xmlXPathParserContextPtr ctxt, int nargs) {
   1024     double ret;
   1025 
   1026     if (nargs != 1) {
   1027 	xmlXPathSetArityError(ctxt);
   1028 	return;
   1029     }
   1030     ret = xmlXPathPopNumber(ctxt);
   1031     if (xmlXPathCheckError(ctxt))
   1032 	return;
   1033 
   1034     ret = exsltMathExp(ret);
   1035 
   1036     xmlXPathReturnNumber(ctxt, ret);
   1037 }
   1038 
   1039 #endif /* HAVE_MATH_H */
   1040 
   1041 /**
   1042  * exsltMathRegister:
   1043  *
   1044  * Registers the EXSLT - Math module
   1045  */
   1046 
   1047 void
   1048 exsltMathRegister (void) {
   1049     xsltRegisterExtModuleFunction ((const xmlChar *) "min",
   1050 				   EXSLT_MATH_NAMESPACE,
   1051 				   exsltMathMinFunction);
   1052     xsltRegisterExtModuleFunction ((const xmlChar *) "max",
   1053 				   EXSLT_MATH_NAMESPACE,
   1054 				   exsltMathMaxFunction);
   1055     xsltRegisterExtModuleFunction ((const xmlChar *) "highest",
   1056 				   EXSLT_MATH_NAMESPACE,
   1057 				   exsltMathHighestFunction);
   1058     xsltRegisterExtModuleFunction ((const xmlChar *) "lowest",
   1059 				   EXSLT_MATH_NAMESPACE,
   1060 				   exsltMathLowestFunction);
   1061     /* register other math functions */
   1062     xsltRegisterExtModuleFunction ((const xmlChar *) "constant",
   1063 				   EXSLT_MATH_NAMESPACE,
   1064 				   exsltMathConstantFunction);
   1065 #ifdef HAVE_STDLIB_H
   1066     xsltRegisterExtModuleFunction ((const xmlChar *) "random",
   1067 				   EXSLT_MATH_NAMESPACE,
   1068 				   exsltMathRandomFunction);
   1069 #endif
   1070 #if HAVE_MATH_H
   1071     xsltRegisterExtModuleFunction ((const xmlChar *) "abs",
   1072 				   EXSLT_MATH_NAMESPACE,
   1073 				   exsltMathAbsFunction);
   1074     xsltRegisterExtModuleFunction ((const xmlChar *) "sqrt",
   1075 				   EXSLT_MATH_NAMESPACE,
   1076 				   exsltMathSqrtFunction);
   1077     xsltRegisterExtModuleFunction ((const xmlChar *) "power",
   1078 				   EXSLT_MATH_NAMESPACE,
   1079 				   exsltMathPowerFunction);
   1080     xsltRegisterExtModuleFunction ((const xmlChar *) "log",
   1081 				   EXSLT_MATH_NAMESPACE,
   1082 				   exsltMathLogFunction);
   1083     xsltRegisterExtModuleFunction ((const xmlChar *) "sin",
   1084 				   EXSLT_MATH_NAMESPACE,
   1085 				   exsltMathSinFunction);
   1086     xsltRegisterExtModuleFunction ((const xmlChar *) "cos",
   1087 				   EXSLT_MATH_NAMESPACE,
   1088 				   exsltMathCosFunction);
   1089     xsltRegisterExtModuleFunction ((const xmlChar *) "tan",
   1090 				   EXSLT_MATH_NAMESPACE,
   1091 				   exsltMathTanFunction);
   1092     xsltRegisterExtModuleFunction ((const xmlChar *) "asin",
   1093 				   EXSLT_MATH_NAMESPACE,
   1094 				   exsltMathAsinFunction);
   1095     xsltRegisterExtModuleFunction ((const xmlChar *) "acos",
   1096 				   EXSLT_MATH_NAMESPACE,
   1097 				   exsltMathAcosFunction);
   1098     xsltRegisterExtModuleFunction ((const xmlChar *) "atan",
   1099 				   EXSLT_MATH_NAMESPACE,
   1100 				   exsltMathAtanFunction);
   1101     xsltRegisterExtModuleFunction ((const xmlChar *) "atan2",
   1102 				   EXSLT_MATH_NAMESPACE,
   1103 				   exsltMathAtan2Function);
   1104     xsltRegisterExtModuleFunction ((const xmlChar *) "exp",
   1105 				   EXSLT_MATH_NAMESPACE,
   1106 				   exsltMathExpFunction);
   1107 #endif
   1108 }
   1109 
   1110 /**
   1111  * exsltMathXpathCtxtRegister:
   1112  *
   1113  * Registers the EXSLT - Math module for use outside XSLT
   1114  */
   1115 int
   1116 exsltMathXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix)
   1117 {
   1118     if (ctxt
   1119         && prefix
   1120         && !xmlXPathRegisterNs(ctxt,
   1121                                prefix,
   1122                                (const xmlChar *) EXSLT_MATH_NAMESPACE)
   1123         && !xmlXPathRegisterFuncNS(ctxt,
   1124                                    (const xmlChar *) "min",
   1125                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1126                                    exsltMathMinFunction)
   1127         && !xmlXPathRegisterFuncNS(ctxt,
   1128                                    (const xmlChar *) "max",
   1129                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1130                                    exsltMathMaxFunction)
   1131         && !xmlXPathRegisterFuncNS(ctxt,
   1132                                    (const xmlChar *) "highest",
   1133                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1134                                    exsltMathHighestFunction)
   1135         && !xmlXPathRegisterFuncNS(ctxt,
   1136                                    (const xmlChar *) "lowest",
   1137                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1138                                    exsltMathLowestFunction)
   1139 #ifdef HAVE_STDLIB_H
   1140         && !xmlXPathRegisterFuncNS(ctxt,
   1141                                    (const xmlChar *) "random",
   1142                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1143                                    exsltMathRandomFunction)
   1144 #endif
   1145 #if HAVE_MATH_H
   1146         && !xmlXPathRegisterFuncNS(ctxt,
   1147                                    (const xmlChar *) "abs",
   1148                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1149                                    exsltMathAbsFunction)
   1150         && !xmlXPathRegisterFuncNS(ctxt,
   1151                                    (const xmlChar *) "sqrt",
   1152                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1153                                    exsltMathSqrtFunction)
   1154         && !xmlXPathRegisterFuncNS(ctxt,
   1155                                    (const xmlChar *) "power",
   1156                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1157                                    exsltMathPowerFunction)
   1158         && !xmlXPathRegisterFuncNS(ctxt,
   1159                                    (const xmlChar *) "log",
   1160                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1161                                    exsltMathLogFunction)
   1162         && !xmlXPathRegisterFuncNS(ctxt,
   1163                                    (const xmlChar *) "sin",
   1164                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1165                                    exsltMathSinFunction)
   1166         && !xmlXPathRegisterFuncNS(ctxt,
   1167                                    (const xmlChar *) "cos",
   1168                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1169                                    exsltMathCosFunction)
   1170         && !xmlXPathRegisterFuncNS(ctxt,
   1171                                    (const xmlChar *) "tan",
   1172                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1173                                    exsltMathTanFunction)
   1174         && !xmlXPathRegisterFuncNS(ctxt,
   1175                                    (const xmlChar *) "asin",
   1176                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1177                                    exsltMathAsinFunction)
   1178         && !xmlXPathRegisterFuncNS(ctxt,
   1179                                    (const xmlChar *) "acos",
   1180                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1181                                    exsltMathAcosFunction)
   1182         && !xmlXPathRegisterFuncNS(ctxt,
   1183                                    (const xmlChar *) "atan",
   1184                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1185                                    exsltMathAtanFunction)
   1186         && !xmlXPathRegisterFuncNS(ctxt,
   1187                                    (const xmlChar *) "atan2",
   1188                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1189                                    exsltMathAtan2Function)
   1190         && !xmlXPathRegisterFuncNS(ctxt,
   1191                                    (const xmlChar *) "exp",
   1192                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1193                                    exsltMathExpFunction)
   1194 #endif
   1195         && !xmlXPathRegisterFuncNS(ctxt,
   1196                                    (const xmlChar *) "constant",
   1197                                    (const xmlChar *) EXSLT_MATH_NAMESPACE,
   1198                                    exsltMathConstantFunction)) {
   1199         return 0;
   1200     }
   1201     return -1;
   1202 }
   1203