• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
exsltMathMin(xmlNodeSetPtr ns)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
exsltMathMinFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathMax(xmlNodeSetPtr ns)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
exsltMathMaxFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathHighest(xmlNodeSetPtr ns)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
exsltMathHighestFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathLowest(xmlNodeSetPtr ns)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
exsltMathLowestFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathConstant(xmlChar * name,double precision)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
exsltMathConstantFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathRandom(void)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
exsltMathRandomFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathAbs(double num)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
exsltMathAbsFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathSqrt(double num)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
exsltMathSqrtFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathPower(double base,double power)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
exsltMathPowerFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathLog(double num)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
exsltMathLogFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathSin(double num)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
exsltMathSinFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathCos(double num)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
exsltMathCosFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathTan(double num)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
exsltMathTanFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathAsin(double num)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
exsltMathAsinFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathAcos(double num)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
exsltMathAcosFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathAtan(double num)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
exsltMathAtanFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathAtan2(double y,double x)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
exsltMathAtan2Function(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathExp(double num)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
exsltMathExpFunction(xmlXPathParserContextPtr ctxt,int nargs)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
exsltMathRegister(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
exsltMathXpathCtxtRegister(xmlXPathContextPtr ctxt,const xmlChar * prefix)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