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 */
40static double
41exsltMathMin (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 */
67static void
68exsltMathMinFunction (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 */
109static double
110exsltMathMax (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 */
136static void
137exsltMathMaxFunction (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 */
176static xmlNodeSetPtr
177exsltMathHighest (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 */
217static void
218exsltMathHighestFunction (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 */
256static xmlNodeSetPtr
257exsltMathLowest (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 */
297static void
298exsltMathLowestFunction (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 */
357static double
358exsltMathConstant (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 */
439static void
440exsltMathConstantFunction (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 */
473static double
474exsltMathRandom (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 */
490static void
491exsltMathRandomFunction (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 */
517static double
518exsltMathAbs (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 */
534static void
535exsltMathAbsFunction (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 */
560static double
561exsltMathSqrt (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 */
577static void
578exsltMathSqrtFunction (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 */
605static double
606exsltMathPower (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 */
622static void
623exsltMathPowerFunction (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 */
653static double
654exsltMathLog (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 */
670static void
671exsltMathLogFunction (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 */
696static double
697exsltMathSin (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 */
713static void
714exsltMathSinFunction (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 */
739static double
740exsltMathCos (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 */
756static void
757exsltMathCosFunction (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 */
782static double
783exsltMathTan (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 */
799static void
800exsltMathTanFunction (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 */
825static double
826exsltMathAsin (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 */
842static void
843exsltMathAsinFunction (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 */
868static double
869exsltMathAcos (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 */
885static void
886exsltMathAcosFunction (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 */
911static double
912exsltMathAtan (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 */
928static void
929exsltMathAtanFunction (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 */
956static double
957exsltMathAtan2 (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 */
973static void
974exsltMathAtan2Function (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 */
1005static double
1006exsltMathExp (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 */
1022static void
1023exsltMathExpFunction (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
1047void
1048exsltMathRegister (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 */
1115int
1116exsltMathXpathCtxtRegister (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