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