2 * numbers.c: Implementation of the XSLT number functions
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
10 * Bjorn Reese <breese@users.sourceforge.net>
20 #include <libxml/xmlmemory.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/xpath.h>
23 #include <libxml/xpathInternals.h>
24 #include "xsltutils.h"
26 #include "templates.h"
27 #include "numbersInternals.h"
30 # define FALSE (0 == 1)
31 # define TRUE (1 == 1)
34 #define SYMBOL_QUOTE ((xmlChar)'\'')
36 #define DEFAULT_TOKEN (xmlChar)'0'
37 #define DEFAULT_SEPARATOR "."
39 #define MAX_TOKENS 1024
41 typedef struct _xsltFormatToken xsltFormatToken;
42 typedef xsltFormatToken *xsltFormatTokenPtr;
43 struct _xsltFormatToken {
49 typedef struct _xsltFormat xsltFormat;
50 typedef xsltFormat *xsltFormatPtr;
53 xsltFormatToken tokens[MAX_TOKENS];
58 static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
59 static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
60 static xsltFormatToken default_token;
63 /************************************************************************
67 ************************************************************************/
69 #define IS_SPECIAL(self,letter) \
70 (((letter) == (self)->zeroDigit[0]) || \
71 ((letter) == (self)->digit[0]) || \
72 ((letter) == (self)->decimalPoint[0]) || \
73 ((letter) == (self)->grouping[0]) || \
74 ((letter) == (self)->patternSeparator[0]))
76 #define IS_DIGIT_ZERO(x) xsltIsDigitZero(x)
77 #define IS_DIGIT_ONE(x) xsltIsDigitZero((xmlChar)(x)-1)
80 xsltIsDigitZero(xmlChar ch)
83 * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
86 case 0x0030: case 0x0660: case 0x06F0: case 0x0966:
87 case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66:
88 case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50:
89 case 0x0E60: case 0x0F20: case 0x1040: case 0x17E0:
90 case 0x1810: case 0xFF10:
98 xsltNumberFormatDecimal(xmlBufferPtr buffer,
103 xmlChar groupingCharacter)
105 xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
109 /* Build buffer from back */
110 pointer = &temp_string[sizeof(temp_string)];
112 for (i = 1; i < (int)sizeof(temp_string); i++) {
113 *(--pointer) = digit_zero + (int)fmod(number, 10.0);
115 if ((i >= width) && (fabs(number) < 1.0))
117 if ((groupingCharacter != 0) &&
118 (digitsPerGroup > 0) &&
119 ((i % digitsPerGroup) == 0)) {
120 *(--pointer) = groupingCharacter;
123 xmlBufferCat(buffer, pointer);
127 xsltNumberFormatAlpha(xmlBufferPtr buffer,
131 char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
135 double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
137 /* Build buffer from back */
138 pointer = &temp_string[sizeof(temp_string)];
140 alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list;
142 for (i = 1; i < (int)sizeof(temp_string); i++) {
144 *(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
145 number /= alpha_size;
146 if (fabs(number) < 1.0)
149 xmlBufferCCat(buffer, pointer);
153 xsltNumberFormatRoman(xmlBufferPtr buffer,
158 * Based on an example by Jim Walsh
160 while (number >= 1000.0) {
161 xmlBufferCCat(buffer, (is_upper) ? "M" : "m");
164 if (number >= 900.0) {
165 xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm");
168 while (number >= 500.0) {
169 xmlBufferCCat(buffer, (is_upper) ? "D" : "d");
172 if (number >= 400.0) {
173 xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd");
176 while (number >= 100.0) {
177 xmlBufferCCat(buffer, (is_upper) ? "C" : "c");
180 if (number >= 90.0) {
181 xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc");
184 while (number >= 50.0) {
185 xmlBufferCCat(buffer, (is_upper) ? "L" : "l");
188 if (number >= 40.0) {
189 xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl");
192 while (number >= 10.0) {
193 xmlBufferCCat(buffer, (is_upper) ? "X" : "x");
197 xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix");
200 while (number >= 5.0) {
201 xmlBufferCCat(buffer, (is_upper) ? "V" : "v");
205 xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv");
208 while (number >= 1.0) {
209 xmlBufferCCat(buffer, (is_upper) ? "I" : "i");
215 xsltNumberFormatTokenize(xmlChar *format,
216 xsltFormatPtr tokens)
221 default_token.token = DEFAULT_TOKEN;
222 default_token.width = 1;
223 default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
226 tokens->start = NULL;
227 tokens->tokens[0].separator = NULL;
231 * Insert initial non-alphanumeric token.
232 * There is always such a token in the list, even if NULL
234 while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
235 if (format[index] == 0)
240 tokens->start = xmlStrndup(format, index);
243 for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
245 if (format[index] == 0)
249 * separator has already been parsed (except for the first
250 * number) in tokens->end, recover it.
252 if (tokens->nTokens > 0) {
253 tokens->tokens[tokens->nTokens].separator = tokens->end;
257 if (IS_DIGIT_ONE(format[index]) ||
258 IS_DIGIT_ZERO(format[index])) {
259 tokens->tokens[tokens->nTokens].width = 1;
260 while (IS_DIGIT_ZERO(format[index])) {
261 tokens->tokens[tokens->nTokens].width++;
264 if (IS_DIGIT_ONE(format[index])) {
265 tokens->tokens[tokens->nTokens].token = format[index] - 1;
268 } else if (format[index] == (xmlChar)'A') {
269 tokens->tokens[tokens->nTokens].token = format[index];
271 } else if (format[index] == (xmlChar)'a') {
272 tokens->tokens[tokens->nTokens].token = format[index];
274 } else if (format[index] == (xmlChar)'I') {
275 tokens->tokens[tokens->nTokens].token = format[index];
277 } else if (format[index] == (xmlChar)'i') {
278 tokens->tokens[tokens->nTokens].token = format[index];
282 * "Any other format token indicates a numbering sequence
283 * that starts with that token. If an implementation does
284 * not support a numbering sequence that starts with that
285 * token, it must use a format token of 1."
287 tokens->tokens[tokens->nTokens].token = (xmlChar)'0';
288 tokens->tokens[tokens->nTokens].width = 1;
291 * Skip over remaining alphanumeric characters from the Nd
292 * (Number, decimal digit), Nl (Number, letter), No (Number,
293 * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt
294 * (Letters, titlecase), Lm (Letters, modifiers), and Lo
295 * (Letters, other (uncased)) Unicode categories. This happens
296 * to correspond to the Letter and Digit classes from XML (and
297 * one wonders why XSLT doesn't refer to these instead).
299 while (IS_LETTER(format[index]) || IS_DIGIT(format[index]))
303 * Insert temporary non-alphanumeric final tooken.
306 while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
307 if (format[index] == 0)
312 tokens->end = xmlStrndup(&format[j], index - j);
317 xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
320 xsltFormatPtr tokens,
325 xsltFormatTokenPtr token;
328 * Handle initial non-alphanumeric token
330 if (tokens->start != NULL)
331 xmlBufferCat(buffer, tokens->start);
333 for (i = 0; i < numbers_max; i++) {
335 number = numbers[(numbers_max - 1) - i];
336 if (i < tokens->nTokens) {
337 /* The "n"th format token will be used to format the "n"th
338 * number in the list */
339 token = &(tokens->tokens[i]);
340 } else if (tokens->nTokens > 0) {
341 /* If there are more numbers than format tokens, then the
342 * last format token will be used to format the remaining
344 token = &(tokens->tokens[tokens->nTokens - 1]);
346 /* If there are no format tokens, then a format token of
347 * 1 is used to format all numbers. */
348 token = &default_token;
351 /* Print separator, except for the first number */
353 if (token->separator != NULL)
354 xmlBufferCat(buffer, token->separator);
356 xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
359 switch (xmlXPathIsInf(number)) {
361 xmlBufferCCat(buffer, "-Infinity");
364 xmlBufferCCat(buffer, "Infinity");
367 if (xmlXPathIsNaN(number)) {
368 xmlBufferCCat(buffer, "NaN");
371 switch (token->token) {
373 xsltNumberFormatAlpha(buffer,
379 xsltNumberFormatAlpha(buffer,
385 xsltNumberFormatRoman(buffer,
391 xsltNumberFormatRoman(buffer,
397 if (IS_DIGIT_ZERO(token->token)) {
398 xsltNumberFormatDecimal(buffer,
402 data->digitsPerGroup,
403 data->groupingCharacter);
413 * Handle final non-alphanumeric token
415 if (tokens->end != NULL)
416 xmlBufferCat(buffer, tokens->end);
421 xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
432 xsltCompMatchPtr countPat = NULL;
433 xsltCompMatchPtr fromPat = NULL;
436 countPat = xsltCompilePattern(count, doc, elem, NULL, context);
438 fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
440 /* select the starting node */
441 switch (node->type) {
442 case XML_ELEMENT_NODE:
445 case XML_ATTRIBUTE_NODE:
446 cur = ((xmlAttrPtr) node)->parent;
450 case XML_COMMENT_NODE:
458 while (cur != NULL) {
459 /* process current node */
461 if ((node->type == cur->type) &&
462 /* FIXME: must use expanded-name instead of local name */
463 xmlStrEqual(node->name, cur->name))
466 if (xsltTestCompMatchList(context, cur, countPat))
469 if ((from != NULL) &&
470 xsltTestCompMatchList(context, cur, fromPat)) {
474 /* Skip to next preceding or ancestor */
475 if ((cur->type == XML_DOCUMENT_NODE) ||
476 #ifdef LIBXML_DOCB_ENABLED
477 (cur->type == XML_DOCB_DOCUMENT_NODE) ||
479 (cur->type == XML_HTML_DOCUMENT_NODE))
482 while ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
484 if (cur->prev != NULL) {
485 for (cur = cur->prev; cur->last != NULL; cur = cur->last);
492 array[amount++] = (double) cnt;
494 if (countPat != NULL)
495 xsltFreeCompMatchList(countPat);
497 xsltFreeCompMatchList(fromPat);
502 xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
514 xmlNodePtr preceding;
515 xmlXPathParserContextPtr parser;
516 xsltCompMatchPtr countPat;
517 xsltCompMatchPtr fromPat;
520 countPat = xsltCompilePattern(count, doc, elem, NULL, context);
524 fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
527 context->xpathCtxt->node = node;
528 parser = xmlXPathNewParserContext(NULL, context->xpathCtxt);
530 /* ancestor-or-self::*[count] */
531 for (ancestor = node;
532 (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE);
533 ancestor = xmlXPathNextAncestor(parser, ancestor)) {
535 if ((from != NULL) &&
536 xsltTestCompMatchList(context, ancestor, fromPat))
539 if ((count == NULL) ||
540 xsltTestCompMatchList(context, ancestor, countPat)) {
541 /* count(preceding-sibling::*) */
543 for (preceding = ancestor;
546 xmlXPathNextPrecedingSibling(parser, preceding)) {
548 if ((preceding->type == ancestor->type) &&
550 xmlStrEqual(preceding->name, ancestor->name))
553 if (xsltTestCompMatchList(context, preceding,
558 array[amount++] = (double)cnt;
563 xmlXPathFreeParserContext(parser);
565 xsltFreeCompMatchList(countPat);
566 xsltFreeCompMatchList(fromPat);
571 xsltNumberFormatGetValue(xmlXPathContextPtr context,
577 xmlBufferPtr pattern;
578 xmlXPathObjectPtr obj;
580 pattern = xmlBufferCreate();
581 if (pattern != NULL) {
582 xmlBufferCCat(pattern, "number(");
583 xmlBufferCat(pattern, value);
584 xmlBufferCCat(pattern, ")");
585 context->node = node;
586 obj = xmlXPathEvalExpression(xmlBufferContent(pattern),
589 *number = obj->floatval;
591 xmlXPathFreeObject(obj);
593 xmlBufferFree(pattern);
600 * @ctxt: the XSLT transformation context
601 * @data: the formatting informations
602 * @node: the data to format
604 * Convert one number.
607 xsltNumberFormat(xsltTransformContextPtr ctxt,
608 xsltNumberDataPtr data,
611 xmlBufferPtr output = NULL;
612 xmlNodePtr copy = NULL;
618 if ((data->format == NULL) && (data->has_format != 0)) {
619 data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
620 (const xmlChar *) "format",
624 if (data->format == NULL) {
628 output = xmlBufferCreate();
630 goto XSLT_NUMBER_FORMAT_END;
632 xsltNumberFormatTokenize(data->format, &tokens);
635 * Evaluate the XPath expression to find the value(s)
638 amount = xsltNumberFormatGetValue(ctxt->xpathCtxt,
643 xsltNumberFormatInsertNumbers(data,
650 } else if (data->level) {
652 if (xmlStrEqual(data->level, (const xmlChar *) "single")) {
653 amount = xsltNumberFormatGetMultipleLevel(ctxt,
662 xsltNumberFormatInsertNumbers(data,
668 } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
669 double numarray[1024];
670 int max = sizeof(numarray)/sizeof(numarray[0]);
671 amount = xsltNumberFormatGetMultipleLevel(ctxt,
680 xsltNumberFormatInsertNumbers(data,
686 } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
687 amount = xsltNumberFormatGetAnyLevel(ctxt,
695 xsltNumberFormatInsertNumbers(data,
703 /* Insert number as text node */
704 copy = xmlNewText(xmlBufferContent(output));
706 xmlAddChild(ctxt->insert, copy);
709 if (tokens.start != NULL)
710 xmlFree(tokens.start);
711 if (tokens.end != NULL)
713 for (i = 0;i < tokens.nTokens;i++) {
714 if (tokens.tokens[i].separator != NULL)
715 xmlFree(tokens.tokens[i].separator);
718 XSLT_NUMBER_FORMAT_END:
719 if (tempformat == 1) {
720 /* The format need to be recomputed each time */
721 xmlFree(data->format);
725 xmlBufferFree(output);
729 xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info)
731 int count=0; /* will hold total length of prefix/suffix */
734 /* prefix / suffix ends at end of string or at first 'special' character */
737 /* if next character 'escaped' just count it */
738 if (**format == SYMBOL_QUOTE) {
739 if (*++(*format) == 0)
741 if (*++(*format) != SYMBOL_QUOTE)
744 else if (IS_SPECIAL(self, **format))
746 /* else treat percent/per-mille as special cases, depending on whether +ve or -ve */
747 else if (!info->is_negative_pattern) {
748 /* for +ve prefix/suffix, allow only a single occurence of either */
749 if (**format == self->percent[0]) {
750 if (info->is_multiplier_set)
752 info->multiplier = 100;
753 info->is_multiplier_set = TRUE;
754 } else if (**format == self->permille[0]) {
755 if (info->is_multiplier_set)
757 info->multiplier = 1000;
758 info->is_multiplier_set = TRUE;
761 /* for -ve prefix/suffix, allow only single occurence & insist it's previously defined */
762 if (**format == self->percent[0]) {
763 if (info->is_multiplier_set)
765 if (info->multiplier != 100)
767 info->is_multiplier_set = TRUE;
768 } else if (**format == self->permille[0]) {
769 if (info->is_multiplier_set)
771 if (info->multiplier != 1000)
773 info->is_multiplier_set = TRUE;
783 * xsltFormatNumberConversion:
784 * @self: the decimal format
785 * @format: the format requested
786 * @number: the value to format
787 * @result: the place to ouput the result
789 * format-number() uses the JDK 1.1 DecimalFormat class:
791 * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html
795 * pattern := subpattern{;subpattern}
796 * subpattern := {prefix}integer{.fraction}{suffix}
797 * prefix := '\\u0000'..'\\uFFFD' - specialCharacters
798 * suffix := '\\u0000'..'\\uFFFD' - specialCharacters
799 * integer := '#'* '0'* '0'
800 * fraction := '0'* '#'*
803 * X* 0 or more instances of X
804 * (X | Y) either X or Y.
805 * X..Y any character from X up to Y, inclusive.
806 * S - T characters in S, except those in T
808 * Special Characters:
812 * # a digit, zero shows as absent
813 * . placeholder for decimal separator
814 * , placeholder for grouping separator.
815 * ; separates formats.
816 * - default negative prefix.
817 * % multiply by 100 and show as percentage
818 * ? multiply by 1000 and show as per mille
819 * X any other characters can be used in the prefix or suffix
820 * ' used to quote special characters in a prefix or suffix.
823 xsltFormatNumberConversion(xsltDecimalFormatPtr self,
828 xmlXPathError status = XPATH_EXPRESSION_OK;
830 xmlChar *the_format, *prefix = NULL, *suffix = NULL;
831 xmlChar *nprefix, *nsuffix = NULL;
833 int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
836 xsltFormatNumberInfo format_info;
837 /* delayed_multiplier allows a 'trailing' percent or permille to be treated as suffix */
838 int delayed_multiplier = 0;
839 /* flag to show no -ve format present for -ve number */
840 char default_sign = 0;
841 /* flag to show error found, should use default format */
842 char found_error = 0;
845 switch (xmlXPathIsInf(number)) {
847 if (self->minusSign == NULL)
848 *result = xmlStrdup(BAD_CAST "-");
850 *result = xmlStrdup(self->minusSign);
851 /* no-break on purpose */
853 if ((self == NULL) || (self->infinity == NULL))
854 *result = xmlStrcat(*result, BAD_CAST "Infinity");
856 *result = xmlStrcat(*result, self->infinity);
859 if (xmlXPathIsNaN(number)) {
860 if ((self == NULL) || (self->noNumber == NULL))
861 *result = xmlStrdup(BAD_CAST "NaN");
863 *result = xmlStrdup(self->noNumber);
868 buffer = xmlBufferCreate();
869 if (buffer == NULL) {
870 return XPATH_MEMORY_ERROR;
873 format_info.integer_digits = 0;
874 format_info.frac_digits = 0;
875 format_info.frac_hash = 0;
876 format_info.group = -1;
877 format_info.multiplier = 1;
878 format_info.is_multiplier_set = FALSE;
879 format_info.is_negative_pattern = FALSE;
883 /* First we process the +ve pattern to get percent / permille, as well as main format */
885 prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
886 if (prefix_length < 0) {
891 /* Here we process the "number" part of the format. It gets a little messy because of */
892 /* the percent/per-mille - if that appears at the end, it may be part of the suffix */
893 /* instead of part of the number, so the variable delayed_multiplier is used to handle it */
894 while ((*the_format != 0) &&
895 (*the_format != self->decimalPoint[0]) &&
896 (*the_format != self->patternSeparator[0])) {
898 if (delayed_multiplier != 0) {
899 format_info.multiplier = delayed_multiplier;
900 format_info.is_multiplier_set = TRUE;
901 delayed_multiplier = 0;
903 if (*the_format == self->digit[0]) {
904 if (format_info.integer_digits > 0) {
908 if (format_info.group >= 0)
910 } else if (*the_format == self->zeroDigit[0]) {
911 format_info.integer_digits++;
912 if (format_info.group >= 0)
914 } else if (*the_format == self->grouping[0]) {
915 /* Reset group count */
916 format_info.group = 0;
917 } else if (*the_format == self->percent[0]) {
918 if (format_info.is_multiplier_set) {
922 delayed_multiplier = 100;
923 } else if (*the_format == self->permille[0]) {
924 if (format_info.is_multiplier_set) {
928 delayed_multiplier = 1000;
935 /* We have finished the integer part, now work on fraction */
936 if (*the_format == self->decimalPoint[0])
937 the_format++; /* Skip over the decimal */
939 while (*the_format != 0) {
941 if (*the_format == self->zeroDigit[0]) {
942 if (format_info.frac_hash != 0) {
946 format_info.frac_digits++;
947 } else if (*the_format == self->digit[0]) {
948 format_info.frac_hash++;
949 } else if (*the_format == self->percent[0]) {
950 if (format_info.is_multiplier_set) {
954 delayed_multiplier = 100;
956 continue; /* while */
957 } else if (*the_format == self->permille[0]) {
958 if (format_info.is_multiplier_set) {
962 delayed_multiplier = 1000;
964 continue; /* while */
965 } else if (*the_format != self->grouping[0]) {
969 if (delayed_multiplier != 0) {
970 format_info.multiplier = delayed_multiplier;
971 delayed_multiplier = 0;
972 format_info.is_multiplier_set = TRUE;
976 /* If delayed_multiplier is set after processing the "number" part, should be in suffix */
977 if (delayed_multiplier != 0) {
979 delayed_multiplier = 0;
983 suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
984 if ( (suffix_length < 0) ||
985 ((*the_format != 0) && (*the_format != self->patternSeparator[0])) ) {
990 /* We have processed the +ve prefix, number part and +ve suffix. */
991 /* If the number is -ve, we must substitute the -ve prefix / suffix */
993 the_format = (xmlChar *)xmlStrchr(format, self->patternSeparator[0]);
994 if (the_format == NULL) { /* No -ve pattern present, so use default signing */
998 /* Flag changes interpretation of percent/permille in -ve pattern */
999 the_format++; /* Skip over pattern separator */
1000 format_info.is_negative_pattern = TRUE;
1001 format_info.is_multiplier_set = FALSE;
1003 /* First do the -ve prefix */
1004 nprefix = the_format;
1005 nprefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
1006 if (nprefix_length<0) {
1011 /* Next skip over the -ve number info */
1012 the_format += prefix_length;
1013 while (*the_format != 0) {
1014 if ( (*the_format == (self)->percent[0]) ||
1015 (*the_format == (self)->permille[0]) ) {
1016 if (format_info.is_multiplier_set) {
1020 format_info.is_multiplier_set = TRUE;
1021 delayed_multiplier = 1;
1023 else if (IS_SPECIAL(self, *the_format))
1024 delayed_multiplier = 0;
1029 if (delayed_multiplier != 0) {
1030 format_info.is_multiplier_set = FALSE;
1034 /* Finally do the -ve suffix */
1035 if (*the_format != 0) {
1036 nsuffix = the_format;
1037 nsuffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
1038 if (nsuffix_length < 0) {
1045 if (*the_format != 0) {
1049 /* Here's another Java peculiarity:
1050 * if -ve prefix/suffix == +ve ones, discard & use default
1052 if ((nprefix_length != prefix_length) || (nsuffix_length != suffix_length) ||
1053 ((nprefix_length > 0) && (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) ||
1054 ((nsuffix_length > 0) && (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) {
1056 prefix_length = nprefix_length;
1058 suffix_length = nsuffix_length;
1066 if (found_error != 0) {
1067 xsltPrintErrorContext(NULL, NULL, NULL);
1068 xsltGenericError(xsltGenericErrorContext,
1069 "xsltFormatNumberConversion : error in format string, using default\n");
1070 default_sign = (number < 0.0) ? 1 : 0;
1071 prefix_length = suffix_length = 0;
1072 format_info.integer_digits = 1;
1073 format_info.frac_digits = 1;
1074 format_info.frac_hash = 4;
1075 format_info.group = -1;
1076 format_info.multiplier = 1;
1079 /* Ready to output our number. First see if "default sign" is required */
1080 if (default_sign != 0)
1081 xmlBufferAdd(buffer, self->minusSign, 1);
1083 /* Put the prefix into the buffer */
1084 for (j = 0; j < prefix_length; j++) {
1085 if ((pchar = *prefix++) == SYMBOL_QUOTE) {
1089 xmlBufferAdd(buffer, &pchar, 1);
1092 /* Next do the integer part of the number */
1093 number = fabs(number) * (double)format_info.multiplier;
1094 scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
1095 number = floor((scale * number + 0.5)) / scale;
1096 if ((self->grouping != NULL) && (self->grouping[0] != 0))
1097 xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1098 format_info.integer_digits,
1100 (xmlChar) self->grouping[0]);
1102 xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1103 format_info.integer_digits,
1107 /* Next the fractional part, if required */
1108 if (format_info.frac_digits + format_info.frac_hash > 0) {
1109 number -= floor(number);
1110 if ((number != 0) || (format_info.frac_digits != 0)) {
1111 xmlBufferAdd(buffer, self->decimalPoint, 1);
1112 number = floor(scale * number + 0.5);
1113 for (j = format_info.frac_hash; j > 0; j--) {
1114 if (fmod(number, 10.0) >= 1.0)
1118 xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1119 format_info.frac_digits + j,
1123 /* Put the suffix into the buffer */
1124 for (j = 0; j < suffix_length; j++) {
1125 if ((pchar = *suffix++) == SYMBOL_QUOTE) {
1129 xmlBufferAdd(buffer, &pchar, 1);
1132 *result = xmlStrdup(xmlBufferContent(buffer));
1133 xmlBufferFree(buffer);