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
361    if ((name == NULL) || (xmlXPathIsNaN(precision)) || (precision < 1.0)) {
362        return xmlXPathNAN;
363    }
364
365    if (xmlStrEqual(name, BAD_CAST "PI")) {
366        int len = xmlStrlen(EXSLT_PI);
367
368        if (precision <= len)
369            len = (int)precision;
370
371        str = xmlStrsub(EXSLT_PI, 0, len);
372        if (str == NULL)
373            return xmlXPathNAN;
374
375        return xmlXPathCastStringToNumber(str);
376
377    } else if (xmlStrEqual(name, BAD_CAST "E")) {
378        int len = xmlStrlen(EXSLT_E);
379
380        if (precision <= len)
381            len = (int)precision;
382
383        str = xmlStrsub(EXSLT_E, 0, len);
384        if (str == NULL)
385            return xmlXPathNAN;
386
387        return xmlXPathCastStringToNumber(str);
388
389    } else if (xmlStrEqual(name, BAD_CAST "SQRRT2")) {
390        int len = xmlStrlen(EXSLT_SQRRT2);
391
392        if (precision <= len)
393            len = (int)precision;
394
395        str = xmlStrsub(EXSLT_SQRRT2, 0, len);
396        if (str == NULL)
397            return xmlXPathNAN;
398
399        return xmlXPathCastStringToNumber(str);
400
401    } else if (xmlStrEqual(name, BAD_CAST "LN2")) {
402        int len = xmlStrlen(EXSLT_LN2);
403
404        if (precision <= len)
405            len = (int)precision;
406
407        str = xmlStrsub(EXSLT_LN2, 0, len);
408        if (str == NULL)
409            return xmlXPathNAN;
410
411        return xmlXPathCastStringToNumber(str);
412
413    } else if (xmlStrEqual(name, BAD_CAST "LN10")) {
414        int len = xmlStrlen(EXSLT_LN10);
415
416        if (precision <= len)
417            len = (int)precision;
418
419        str = xmlStrsub(EXSLT_LN10, 0, len);
420        if (str == NULL)
421            return xmlXPathNAN;
422
423        return xmlXPathCastStringToNumber(str);
424
425    } else if (xmlStrEqual(name, BAD_CAST "LOG2E")) {
426        int len = xmlStrlen(EXSLT_LOG2E);
427
428        if (precision <= len)
429            len = (int)precision;
430
431        str = xmlStrsub(EXSLT_LOG2E, 0, len);
432        if (str == NULL)
433            return xmlXPathNAN;
434
435        return xmlXPathCastStringToNumber(str);
436
437    } else if (xmlStrEqual(name, BAD_CAST "SQRT1_2")) {
438        int len = xmlStrlen(EXSLT_SQRT1_2);
439
440        if (precision <= len)
441            len = (int)precision;
442
443        str = xmlStrsub(EXSLT_SQRT1_2, 0, len);
444        if (str == NULL)
445            return xmlXPathNAN;
446
447        return xmlXPathCastStringToNumber(str);
448
449    } else {
450        return xmlXPathNAN;
451    }
452}
453
454/**
455 * exsltMathConstantFunction:
456 * @ctxt:  an XPath parser context
457 * @nargs:  the number of arguments
458 *
459 * Wraps #exsltMathConstant for use by the XPath processor.
460 */
461static void
462exsltMathConstantFunction (xmlXPathParserContextPtr ctxt, int nargs) {
463    double   ret;
464    xmlChar *name;
465
466    if (nargs != 2) {
467	xmlXPathSetArityError(ctxt);
468	return;
469    }
470    ret = xmlXPathPopNumber(ctxt);
471    if (xmlXPathCheckError(ctxt))
472	return;
473
474    name = xmlXPathPopString(ctxt);
475    if (xmlXPathCheckError(ctxt))
476	return;
477
478    ret = exsltMathConstant(name, ret);
479
480    xmlXPathReturnNumber(ctxt, ret);
481}
482
483#if defined(HAVE_STDLIB_H) && defined(RAND_MAX)
484
485/**
486 * exsltMathRandom:
487 *
488 * Implements the EXSLT - Math random() function:
489 *    number math:random ()
490 *
491 * Returns a random number between 0 and 1 inclusive.
492 */
493static double
494exsltMathRandom (void) {
495    double ret;
496    int num;
497
498    num = rand();
499    ret = (double)num / (double)RAND_MAX;
500    return(ret);
501}
502
503/**
504 * exsltMathRandomFunction:
505 * @ctxt:  an XPath parser context
506 * @nargs:  the number of arguments
507 *
508 * Wraps #exsltMathRandom for use by the XPath processor.
509 */
510static void
511exsltMathRandomFunction (xmlXPathParserContextPtr ctxt, int nargs) {
512    double ret;
513
514    if (nargs != 0) {
515	xmlXPathSetArityError(ctxt);
516	return;
517    }
518
519    ret = exsltMathRandom();
520
521    xmlXPathReturnNumber(ctxt, ret);
522}
523
524#endif /* defined(HAVE_STDLIB_H) && defined(RAND_MAX) */
525
526#if HAVE_MATH_H
527
528/**
529 * exsltMathAbs:
530 * @num:  a double
531 *
532 * Implements the EXSLT - Math abs() function:
533 *    number math:abs (number)
534 *
535 * Returns the absolute value of the argument, or xmlXPathNAN if @num is Nan.
536 */
537static double
538exsltMathAbs (double num) {
539    double ret;
540
541    if (xmlXPathIsNaN(num))
542	return(xmlXPathNAN);
543    ret = fabs(num);
544    return(ret);
545}
546
547/**
548 * exsltMathAbsFunction:
549 * @ctxt:  an XPath parser context
550 * @nargs:  the number of arguments
551 *
552 * Wraps #exsltMathAbs for use by the XPath processor.
553 */
554static void
555exsltMathAbsFunction (xmlXPathParserContextPtr ctxt, int nargs) {
556    double ret;
557
558    if (nargs != 1) {
559	xmlXPathSetArityError(ctxt);
560	return;
561    }
562    ret = xmlXPathPopNumber(ctxt);
563    if (xmlXPathCheckError(ctxt))
564	return;
565
566    ret = exsltMathAbs(ret);
567
568    xmlXPathReturnNumber(ctxt, ret);
569}
570
571/**
572 * exsltMathSqrt:
573 * @num:  a double
574 *
575 * Implements the EXSLT - Math sqrt() function:
576 *    number math:sqrt (number)
577 *
578 * Returns the square root of the argument, or xmlXPathNAN if @num is Nan.
579 */
580static double
581exsltMathSqrt (double num) {
582    double ret;
583
584    if (xmlXPathIsNaN(num))
585	return(xmlXPathNAN);
586    ret = sqrt(num);
587    return(ret);
588}
589
590/**
591 * exsltMathSqrtFunction:
592 * @ctxt:  an XPath parser context
593 * @nargs:  the number of arguments
594 *
595 * Wraps #exsltMathSqrt for use by the XPath processor.
596 */
597static void
598exsltMathSqrtFunction (xmlXPathParserContextPtr ctxt, int nargs) {
599    double ret;
600
601    if (nargs != 1) {
602	xmlXPathSetArityError(ctxt);
603	return;
604    }
605    ret = xmlXPathPopNumber(ctxt);
606    if (xmlXPathCheckError(ctxt))
607	return;
608
609    ret = exsltMathSqrt(ret);
610
611    xmlXPathReturnNumber(ctxt, ret);
612}
613
614/**
615 * exsltMathPower:
616 * @base:  a double
617 * @power:  a double
618 *
619 * Implements the EXSLT - Math power() function:
620 *    number math:power (number, number)
621 *
622 * Returns the power base and power arguments, or xmlXPathNAN
623 * if either @base or @power is Nan.
624 */
625static double
626exsltMathPower (double base, double power) {
627    double ret;
628
629    if ((xmlXPathIsNaN(base) || xmlXPathIsNaN(power)))
630	return(xmlXPathNAN);
631    ret = pow(base, power);
632    return(ret);
633}
634
635/**
636 * exsltMathPower:
637 * @ctxt:  an XPath parser context
638 * @nargs:  the number of arguments
639 *
640 * Wraps #exsltMathPower for use by the XPath processor.
641 */
642static void
643exsltMathPowerFunction (xmlXPathParserContextPtr ctxt, int nargs) {
644    double ret, base;
645
646    if (nargs != 2) {
647	xmlXPathSetArityError(ctxt);
648	return;
649    }
650    ret = xmlXPathPopNumber(ctxt);
651    if (xmlXPathCheckError(ctxt))
652	return;
653
654    /* power */
655    base = xmlXPathPopNumber(ctxt);
656    if (xmlXPathCheckError(ctxt))
657	return;
658
659    ret = exsltMathPower(base, ret);
660
661    xmlXPathReturnNumber(ctxt, ret);
662}
663
664/**
665 * exsltMathLog:
666 * @num:  a double
667 *
668 * Implements the EXSLT - Math log() function:
669 *    number math:log (number)
670 *
671 * Returns the natural log of the argument, or xmlXPathNAN if @num is Nan.
672 */
673static double
674exsltMathLog (double num) {
675    double ret;
676
677    if (xmlXPathIsNaN(num))
678	return(xmlXPathNAN);
679    ret = log(num);
680    return(ret);
681}
682
683/**
684 * exsltMathLogFunction:
685 * @ctxt:  an XPath parser context
686 * @nargs:  the number of arguments
687 *
688 * Wraps #exsltMathLog for use by the XPath processor.
689 */
690static void
691exsltMathLogFunction (xmlXPathParserContextPtr ctxt, int nargs) {
692    double ret;
693
694    if (nargs != 1) {
695	xmlXPathSetArityError(ctxt);
696	return;
697    }
698    ret = xmlXPathPopNumber(ctxt);
699    if (xmlXPathCheckError(ctxt))
700	return;
701
702    ret = exsltMathLog(ret);
703
704    xmlXPathReturnNumber(ctxt, ret);
705}
706
707/**
708 * exsltMathSin:
709 * @num:  a double
710 *
711 * Implements the EXSLT - Math sin() function:
712 *    number math:sin (number)
713 *
714 * Returns the sine of the argument, or xmlXPathNAN if @num is Nan.
715 */
716static double
717exsltMathSin (double num) {
718    double ret;
719
720    if (xmlXPathIsNaN(num))
721	return(xmlXPathNAN);
722    ret = sin(num);
723    return(ret);
724}
725
726/**
727 * exsltMathSinFunction:
728 * @ctxt:  an XPath parser context
729 * @nargs:  the number of arguments
730 *
731 * Wraps #exsltMathSin for use by the XPath processor.
732 */
733static void
734exsltMathSinFunction (xmlXPathParserContextPtr ctxt, int nargs) {
735    double ret;
736
737    if (nargs != 1) {
738	xmlXPathSetArityError(ctxt);
739	return;
740    }
741    ret = xmlXPathPopNumber(ctxt);
742    if (xmlXPathCheckError(ctxt))
743	return;
744
745    ret = exsltMathSin(ret);
746
747    xmlXPathReturnNumber(ctxt, ret);
748}
749
750/**
751 * exsltMathCos:
752 * @num:  a double
753 *
754 * Implements the EXSLT - Math cos() function:
755 *    number math:cos (number)
756 *
757 * Returns the cosine of the argument, or xmlXPathNAN if @num is Nan.
758 */
759static double
760exsltMathCos (double num) {
761    double ret;
762
763    if (xmlXPathIsNaN(num))
764	return(xmlXPathNAN);
765    ret = cos(num);
766    return(ret);
767}
768
769/**
770 * exsltMathCosFunction:
771 * @ctxt:  an XPath parser context
772 * @nargs:  the number of arguments
773 *
774 * Wraps #exsltMathCos for use by the XPath processor.
775 */
776static void
777exsltMathCosFunction (xmlXPathParserContextPtr ctxt, int nargs) {
778    double ret;
779
780    if (nargs != 1) {
781	xmlXPathSetArityError(ctxt);
782	return;
783    }
784    ret = xmlXPathPopNumber(ctxt);
785    if (xmlXPathCheckError(ctxt))
786	return;
787
788    ret = exsltMathCos(ret);
789
790    xmlXPathReturnNumber(ctxt, ret);
791}
792
793/**
794 * exsltMathTan:
795 * @num:  a double
796 *
797 * Implements the EXSLT - Math tan() function:
798 *    number math:tan (number)
799 *
800 * Returns the tangent of the argument, or xmlXPathNAN if @num is Nan.
801 */
802static double
803exsltMathTan (double num) {
804    double ret;
805
806    if (xmlXPathIsNaN(num))
807	return(xmlXPathNAN);
808    ret = tan(num);
809    return(ret);
810}
811
812/**
813 * exsltMathTanFunction:
814 * @ctxt:  an XPath parser context
815 * @nargs:  the number of arguments
816 *
817 * Wraps #exsltMathTan for use by the XPath processor.
818 */
819static void
820exsltMathTanFunction (xmlXPathParserContextPtr ctxt, int nargs) {
821    double ret;
822
823    if (nargs != 1) {
824	xmlXPathSetArityError(ctxt);
825	return;
826    }
827    ret = xmlXPathPopNumber(ctxt);
828    if (xmlXPathCheckError(ctxt))
829	return;
830
831    ret = exsltMathTan(ret);
832
833    xmlXPathReturnNumber(ctxt, ret);
834}
835
836/**
837 * exsltMathAsin:
838 * @num:  a double
839 *
840 * Implements the EXSLT - Math asin() function:
841 *    number math:asin (number)
842 *
843 * Returns the arc sine of the argument, or xmlXPathNAN if @num is Nan.
844 */
845static double
846exsltMathAsin (double num) {
847    double ret;
848
849    if (xmlXPathIsNaN(num))
850	return(xmlXPathNAN);
851    ret = asin(num);
852    return(ret);
853}
854
855/**
856 * exsltMathAsinFunction:
857 * @ctxt:  an XPath parser context
858 * @nargs:  the number of arguments
859 *
860 * Wraps #exsltMathAsin for use by the XPath processor.
861 */
862static void
863exsltMathAsinFunction (xmlXPathParserContextPtr ctxt, int nargs) {
864    double ret;
865
866    if (nargs != 1) {
867	xmlXPathSetArityError(ctxt);
868	return;
869    }
870    ret = xmlXPathPopNumber(ctxt);
871    if (xmlXPathCheckError(ctxt))
872	return;
873
874    ret = exsltMathAsin(ret);
875
876    xmlXPathReturnNumber(ctxt, ret);
877}
878
879/**
880 * exsltMathAcos:
881 * @num:  a double
882 *
883 * Implements the EXSLT - Math acos() function:
884 *    number math:acos (number)
885 *
886 * Returns the arc cosine of the argument, or xmlXPathNAN if @num is Nan.
887 */
888static double
889exsltMathAcos (double num) {
890    double ret;
891
892    if (xmlXPathIsNaN(num))
893	return(xmlXPathNAN);
894    ret = acos(num);
895    return(ret);
896}
897
898/**
899 * exsltMathAcosFunction:
900 * @ctxt:  an XPath parser context
901 * @nargs:  the number of arguments
902 *
903 * Wraps #exsltMathAcos for use by the XPath processor.
904 */
905static void
906exsltMathAcosFunction (xmlXPathParserContextPtr ctxt, int nargs) {
907    double ret;
908
909    if (nargs != 1) {
910	xmlXPathSetArityError(ctxt);
911	return;
912    }
913    ret = xmlXPathPopNumber(ctxt);
914    if (xmlXPathCheckError(ctxt))
915	return;
916
917    ret = exsltMathAcos(ret);
918
919    xmlXPathReturnNumber(ctxt, ret);
920}
921
922/**
923 * exsltMathAtan:
924 * @num:  a double
925 *
926 * Implements the EXSLT - Math atan() function:
927 *    number math:atan (number)
928 *
929 * Returns the arc tangent of the argument, or xmlXPathNAN if @num is Nan.
930 */
931static double
932exsltMathAtan (double num) {
933    double ret;
934
935    if (xmlXPathIsNaN(num))
936	return(xmlXPathNAN);
937    ret = atan(num);
938    return(ret);
939}
940
941/**
942 * exsltMathAtanFunction:
943 * @ctxt:  an XPath parser context
944 * @nargs:  the number of arguments
945 *
946 * Wraps #exsltMathAtan for use by the XPath processor.
947 */
948static void
949exsltMathAtanFunction (xmlXPathParserContextPtr ctxt, int nargs) {
950    double ret;
951
952    if (nargs != 1) {
953	xmlXPathSetArityError(ctxt);
954	return;
955    }
956    ret = xmlXPathPopNumber(ctxt);
957    if (xmlXPathCheckError(ctxt))
958	return;
959
960    ret = exsltMathAtan(ret);
961
962    xmlXPathReturnNumber(ctxt, ret);
963}
964
965/**
966 * exsltMathAtan2:
967 * @y:  a double
968 * @x:  a double
969 *
970 * Implements the EXSLT - Math atan2() function:
971 *    number math:atan2 (number, number)
972 *
973 * Returns the arc tangent function of the y/x arguments, or xmlXPathNAN
974 * if either @y or @x is Nan.
975 */
976static double
977exsltMathAtan2 (double y, double x) {
978    double ret;
979
980    if ((xmlXPathIsNaN(y) || xmlXPathIsNaN(x)))
981	return(xmlXPathNAN);
982    ret = atan2(y, x);
983    return(ret);
984}
985
986/**
987 * exsltMathAtan2Function:
988 * @ctxt:  an XPath parser context
989 * @nargs:  the number of arguments
990 *
991 * Wraps #exsltMathAtan2 for use by the XPath processor.
992 */
993static void
994exsltMathAtan2Function (xmlXPathParserContextPtr ctxt, int nargs) {
995    double ret, y;
996
997    if (nargs != 2) {
998	xmlXPathSetArityError(ctxt);
999	return;
1000    }
1001    y = xmlXPathPopNumber(ctxt);
1002    if (xmlXPathCheckError(ctxt))
1003	return;
1004
1005    /* x */
1006    ret = xmlXPathPopNumber(ctxt);
1007    if (xmlXPathCheckError(ctxt))
1008	return;
1009
1010    ret = exsltMathAtan2(y, ret);
1011
1012    xmlXPathReturnNumber(ctxt, ret);
1013}
1014
1015/**
1016 * exsltMathExp:
1017 * @num:  a double
1018 *
1019 * Implements the EXSLT - Math exp() function:
1020 *    number math:exp (number)
1021 *
1022 * Returns the exponential function of the argument, or xmlXPathNAN if
1023 * @num is Nan.
1024 */
1025static double
1026exsltMathExp (double num) {
1027    double ret;
1028
1029    if (xmlXPathIsNaN(num))
1030	return(xmlXPathNAN);
1031    ret = exp(num);
1032    return(ret);
1033}
1034
1035/**
1036 * exsltMathExpFunction:
1037 * @ctxt:  an XPath parser context
1038 * @nargs:  the number of arguments
1039 *
1040 * Wraps #exsltMathExp for use by the XPath processor.
1041 */
1042static void
1043exsltMathExpFunction (xmlXPathParserContextPtr ctxt, int nargs) {
1044    double ret;
1045
1046    if (nargs != 1) {
1047	xmlXPathSetArityError(ctxt);
1048	return;
1049    }
1050    ret = xmlXPathPopNumber(ctxt);
1051    if (xmlXPathCheckError(ctxt))
1052	return;
1053
1054    ret = exsltMathExp(ret);
1055
1056    xmlXPathReturnNumber(ctxt, ret);
1057}
1058
1059#endif /* HAVE_MATH_H */
1060
1061/**
1062 * exsltMathRegister:
1063 *
1064 * Registers the EXSLT - Math module
1065 */
1066
1067void
1068exsltMathRegister (void) {
1069    xsltRegisterExtModuleFunction ((const xmlChar *) "min",
1070				   EXSLT_MATH_NAMESPACE,
1071				   exsltMathMinFunction);
1072    xsltRegisterExtModuleFunction ((const xmlChar *) "max",
1073				   EXSLT_MATH_NAMESPACE,
1074				   exsltMathMaxFunction);
1075    xsltRegisterExtModuleFunction ((const xmlChar *) "highest",
1076				   EXSLT_MATH_NAMESPACE,
1077				   exsltMathHighestFunction);
1078    xsltRegisterExtModuleFunction ((const xmlChar *) "lowest",
1079				   EXSLT_MATH_NAMESPACE,
1080				   exsltMathLowestFunction);
1081    /* register other math functions */
1082    xsltRegisterExtModuleFunction ((const xmlChar *) "constant",
1083				   EXSLT_MATH_NAMESPACE,
1084				   exsltMathConstantFunction);
1085#ifdef HAVE_STDLIB_H
1086    xsltRegisterExtModuleFunction ((const xmlChar *) "random",
1087				   EXSLT_MATH_NAMESPACE,
1088				   exsltMathRandomFunction);
1089#endif
1090#if HAVE_MATH_H
1091    xsltRegisterExtModuleFunction ((const xmlChar *) "abs",
1092				   EXSLT_MATH_NAMESPACE,
1093				   exsltMathAbsFunction);
1094    xsltRegisterExtModuleFunction ((const xmlChar *) "sqrt",
1095				   EXSLT_MATH_NAMESPACE,
1096				   exsltMathSqrtFunction);
1097    xsltRegisterExtModuleFunction ((const xmlChar *) "power",
1098				   EXSLT_MATH_NAMESPACE,
1099				   exsltMathPowerFunction);
1100    xsltRegisterExtModuleFunction ((const xmlChar *) "log",
1101				   EXSLT_MATH_NAMESPACE,
1102				   exsltMathLogFunction);
1103    xsltRegisterExtModuleFunction ((const xmlChar *) "sin",
1104				   EXSLT_MATH_NAMESPACE,
1105				   exsltMathSinFunction);
1106    xsltRegisterExtModuleFunction ((const xmlChar *) "cos",
1107				   EXSLT_MATH_NAMESPACE,
1108				   exsltMathCosFunction);
1109    xsltRegisterExtModuleFunction ((const xmlChar *) "tan",
1110				   EXSLT_MATH_NAMESPACE,
1111				   exsltMathTanFunction);
1112    xsltRegisterExtModuleFunction ((const xmlChar *) "asin",
1113				   EXSLT_MATH_NAMESPACE,
1114				   exsltMathAsinFunction);
1115    xsltRegisterExtModuleFunction ((const xmlChar *) "acos",
1116				   EXSLT_MATH_NAMESPACE,
1117				   exsltMathAcosFunction);
1118    xsltRegisterExtModuleFunction ((const xmlChar *) "atan",
1119				   EXSLT_MATH_NAMESPACE,
1120				   exsltMathAtanFunction);
1121    xsltRegisterExtModuleFunction ((const xmlChar *) "atan2",
1122				   EXSLT_MATH_NAMESPACE,
1123				   exsltMathAtan2Function);
1124    xsltRegisterExtModuleFunction ((const xmlChar *) "exp",
1125				   EXSLT_MATH_NAMESPACE,
1126				   exsltMathExpFunction);
1127#endif
1128}
1129