preparing 1.0.14 updated rebuilt implemented the IN_LIBXSLT and
[platform/upstream/libxslt.git] / libxslt / numbers.c
1 /*
2  * numbers.c: Implementation of the XSLT number functions
3  *
4  * Reference:
5  *   http://www.w3.org/TR/1999/REC-xslt-19991116
6  *
7  * See Copyright for the status of this software.
8  *
9  * daniel@veillard.com
10  * Bjorn Reese <breese@users.sourceforge.net>
11  */
12
13 #define IN_LIBXSLT
14 #include "libxslt.h"
15
16 #include <math.h>
17 #include <limits.h>
18 #include <float.h>
19
20 #include <libxml/xmlmemory.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/xpath.h>
23 #include <libxml/xpathInternals.h>
24 #include "xsltutils.h"
25 #include "pattern.h"
26 #include "templates.h"
27 #include "numbersInternals.h"
28
29 #ifndef FALSE
30 # define FALSE (0 == 1)
31 # define TRUE (1 == 1)
32 #endif
33
34 #define SYMBOL_QUOTE            ((xmlChar)'\'')
35
36 #define DEFAULT_TOKEN           (xmlChar)'0'
37 #define DEFAULT_SEPARATOR       "."
38
39 #define MAX_TOKENS              1024
40
41 typedef struct _xsltFormatToken xsltFormatToken;
42 typedef xsltFormatToken *xsltFormatTokenPtr;
43 struct _xsltFormatToken {
44     xmlChar     *separator;
45     xmlChar      token;
46     int          width;
47 };
48
49 typedef struct _xsltFormat xsltFormat;
50 typedef xsltFormat *xsltFormatPtr;
51 struct _xsltFormat {
52     xmlChar             *start;
53     xsltFormatToken      tokens[MAX_TOKENS];
54     int                  nTokens;
55     xmlChar             *end;
56 };
57
58 static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
59 static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
60 static xsltFormatToken default_token;
61
62
63 /************************************************************************
64  *                                                                      *
65  *                      Utility functions                               *
66  *                                                                      *
67  ************************************************************************/
68
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]))
75
76 #define IS_DIGIT_ZERO(x) xsltIsDigitZero(x)
77 #define IS_DIGIT_ONE(x) xsltIsDigitZero((xmlChar)(x)-1)
78
79 static int
80 xsltIsDigitZero(xmlChar ch)
81 {
82     /*
83      * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
84      */
85     switch (ch) {
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:
91         return TRUE;
92     default:
93         return FALSE;
94     }
95 }
96
97 static void
98 xsltNumberFormatDecimal(xmlBufferPtr buffer,
99                         double number,
100                         xmlChar digit_zero,
101                         int width,
102                         int digitsPerGroup,
103                         xmlChar groupingCharacter)
104 {
105     xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
106     xmlChar *pointer;
107     int i;
108
109     /* Build buffer from back */
110     pointer = &temp_string[sizeof(temp_string)];
111     *(--pointer) = 0;
112     for (i = 1; i < (int)sizeof(temp_string); i++) {
113         *(--pointer) = digit_zero + (int)fmod(number, 10.0);
114         number /= 10.0;
115         if ((i >= width) && (fabs(number) < 1.0))
116             break; /* for */
117         if ((groupingCharacter != 0) &&
118             (digitsPerGroup > 0) &&
119             ((i % digitsPerGroup) == 0)) {
120             *(--pointer) = groupingCharacter;
121         }
122     }
123     xmlBufferCat(buffer, pointer);
124 }
125
126 static void
127 xsltNumberFormatAlpha(xmlBufferPtr buffer,
128                       double number,
129                       int is_upper)
130 {
131     char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
132     char *pointer;
133     int i;
134     char *alpha_list;
135     double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
136
137     /* Build buffer from back */
138     pointer = &temp_string[sizeof(temp_string)];
139     *(--pointer) = 0;
140     alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list;
141     
142     for (i = 1; i < (int)sizeof(temp_string); i++) {
143         number--;
144         *(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
145         number /= alpha_size;
146         if (fabs(number) < 1.0)
147             break; /* for */
148     }
149     xmlBufferCCat(buffer, pointer);
150 }
151
152 static void
153 xsltNumberFormatRoman(xmlBufferPtr buffer,
154                       double number,
155                       int is_upper)
156 {
157     /*
158      * Based on an example by Jim Walsh
159      */
160     while (number >= 1000.0) {
161         xmlBufferCCat(buffer, (is_upper) ? "M" : "m");
162         number -= 1000.0;
163     }
164     if (number >= 900.0) {
165         xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm");
166         number -= 900.0;
167     }
168     while (number >= 500.0) {
169         xmlBufferCCat(buffer, (is_upper) ? "D" : "d");
170         number -= 500.0;
171     }
172     if (number >= 400.0) {
173         xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd");
174         number -= 400.0;
175     }
176     while (number >= 100.0) {
177         xmlBufferCCat(buffer, (is_upper) ? "C" : "c");
178         number -= 100.0;
179     }
180     if (number >= 90.0) {
181         xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc");
182         number -= 90.0;
183     }
184     while (number >= 50.0) {
185         xmlBufferCCat(buffer, (is_upper) ? "L" : "l");
186         number -= 50.0;
187     }
188     if (number >= 40.0) {
189         xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl");
190         number -= 40.0;
191     }
192     while (number >= 10.0) {
193         xmlBufferCCat(buffer, (is_upper) ? "X" : "x");
194         number -= 10.0;
195     }
196     if (number >= 9.0) {
197         xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix");
198         number -= 9.0;
199     }
200     while (number >= 5.0) {
201         xmlBufferCCat(buffer, (is_upper) ? "V" : "v");
202         number -= 5.0;
203     }
204     if (number >= 4.0) {
205         xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv");
206         number -= 4.0;
207     }
208     while (number >= 1.0) {
209         xmlBufferCCat(buffer, (is_upper) ? "I" : "i");
210         number--;
211     }
212 }
213
214 static void
215 xsltNumberFormatTokenize(xmlChar *format,
216                          xsltFormatPtr tokens)
217 {
218     int index = 0;
219     int j;
220
221     default_token.token = DEFAULT_TOKEN;
222     default_token.width = 1;
223     default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
224
225
226     tokens->start = NULL;
227     tokens->tokens[0].separator = NULL;
228     tokens->end = NULL;
229
230     /*
231      * Insert initial non-alphanumeric token.
232      * There is always such a token in the list, even if NULL
233      */
234     while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
235         if (format[index] == 0)
236             break; /* while */
237         index++;
238     }
239     if (index > 0)
240         tokens->start = xmlStrndup(format, index);
241
242
243     for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
244          tokens->nTokens++) {
245         if (format[index] == 0)
246             break; /* for */
247
248         /*
249          * separator has already been parsed (except for the first
250          * number) in tokens->end, recover it.
251          */
252         if (tokens->nTokens > 0) {
253             tokens->tokens[tokens->nTokens].separator = tokens->end;
254             tokens->end = NULL;
255         }
256
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++;
262                 index++;
263             }
264             if (IS_DIGIT_ONE(format[index])) {
265                 tokens->tokens[tokens->nTokens].token = format[index] - 1;
266                 index++;
267             }
268         } else if (format[index] == (xmlChar)'A') {
269             tokens->tokens[tokens->nTokens].token = format[index];
270             index++;
271         } else if (format[index] == (xmlChar)'a') {
272             tokens->tokens[tokens->nTokens].token = format[index];
273             index++;
274         } else if (format[index] == (xmlChar)'I') {
275             tokens->tokens[tokens->nTokens].token = format[index];
276             index++;
277         } else if (format[index] == (xmlChar)'i') {
278             tokens->tokens[tokens->nTokens].token = format[index];
279             index++;
280         } else {
281             /* XSLT section 7.7
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."
286              */
287             tokens->tokens[tokens->nTokens].token = (xmlChar)'0';
288             tokens->tokens[tokens->nTokens].width = 1;
289         }
290         /*
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).
298          */
299         while (IS_LETTER(format[index]) || IS_DIGIT(format[index]))
300             index++;
301
302         /*
303          * Insert temporary non-alphanumeric final tooken.
304          */
305         j = index;
306         while (! (IS_LETTER(format[index]) || IS_DIGIT(format[index]))) {
307             if (format[index] == 0)
308                 break; /* while */
309             index++;
310         }
311         if (index > j)
312             tokens->end = xmlStrndup(&format[j], index - j);
313     }
314 }
315
316 static void
317 xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
318                               double *numbers,
319                               int numbers_max,
320                               xsltFormatPtr tokens,
321                               xmlBufferPtr buffer)
322 {
323     int i = 0;
324     double number;
325     xsltFormatTokenPtr token;
326
327     /*
328      * Handle initial non-alphanumeric token
329      */
330     if (tokens->start != NULL)
331          xmlBufferCat(buffer, tokens->start);
332
333     for (i = 0; i < numbers_max; i++) {
334         /* Insert number */
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
343            * numbers. */
344           token = &(tokens->tokens[tokens->nTokens - 1]);
345         } else {
346           /* If there are no format tokens, then a format token of
347            * 1 is used to format all numbers. */
348           token = &default_token;
349         }
350
351         /* Print separator, except for the first number */
352         if (i > 0) {
353             if (token->separator != NULL)
354                 xmlBufferCat(buffer, token->separator);
355             else
356                 xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
357         }
358
359         switch (xmlXPathIsInf(number)) {
360         case -1:
361             xmlBufferCCat(buffer, "-Infinity");
362             break;
363         case 1:
364             xmlBufferCCat(buffer, "Infinity");
365             break;
366         default:
367             if (xmlXPathIsNaN(number)) {
368                 xmlBufferCCat(buffer, "NaN");
369             } else {
370
371                 switch (token->token) {
372                 case 'A':
373                     xsltNumberFormatAlpha(buffer,
374                                           number,
375                                           TRUE);
376
377                     break;
378                 case 'a':
379                     xsltNumberFormatAlpha(buffer,
380                                           number,
381                                           FALSE);
382
383                     break;
384                 case 'I':
385                     xsltNumberFormatRoman(buffer,
386                                           number,
387                                           TRUE);
388
389                     break;
390                 case 'i':
391                     xsltNumberFormatRoman(buffer,
392                                           number,
393                                           FALSE);
394
395                     break;
396                 default:
397                     if (IS_DIGIT_ZERO(token->token)) {
398                         xsltNumberFormatDecimal(buffer,
399                                                 number,
400                                                 token->token,
401                                                 token->width,
402                                                 data->digitsPerGroup,
403                                                 data->groupingCharacter);
404                     }
405                     break;
406                 }
407             }
408
409         }
410     }
411
412     /*
413      * Handle final non-alphanumeric token
414      */
415     if (tokens->end != NULL)
416          xmlBufferCat(buffer, tokens->end);
417
418 }
419
420 static int
421 xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
422                             xmlNodePtr node,
423                             xmlChar *count,
424                             xmlChar *from,
425                             double *array,
426                             xmlDocPtr doc,
427                             xmlNodePtr elem)
428 {
429     int amount = 0;
430     int cnt = 0;
431     xmlNodePtr cur;
432     xsltCompMatchPtr countPat = NULL;
433     xsltCompMatchPtr fromPat = NULL;
434
435     if (count != NULL)
436         countPat = xsltCompilePattern(count, doc, elem, NULL, context);
437     if (from != NULL)
438         fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
439         
440     /* select the starting node */
441     switch (node->type) {
442         case XML_ELEMENT_NODE:
443             cur = node;
444             break;
445         case XML_ATTRIBUTE_NODE:
446             cur = ((xmlAttrPtr) node)->parent;
447             break;
448         case XML_TEXT_NODE:
449         case XML_PI_NODE:
450         case XML_COMMENT_NODE:
451             cur = node->parent;
452             break;
453         default:
454             cur = NULL;
455             break;
456     }
457
458     while (cur != NULL) {
459         /* process current node */
460         if (count == NULL) {
461             if ((node->type == cur->type) &&
462                 /* FIXME: must use expanded-name instead of local name */
463                 xmlStrEqual(node->name, cur->name))
464                 cnt++;
465         } else {
466             if (xsltTestCompMatchList(context, cur, countPat))
467                 cnt++;
468         }
469         if ((from != NULL) &&
470             xsltTestCompMatchList(context, cur, fromPat)) {
471             break; /* while */
472         }
473
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) ||
478 #endif
479             (cur->type == XML_HTML_DOCUMENT_NODE))
480             break; /* while */
481
482         while ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
483             cur = cur->prev;
484         if (cur->prev != NULL) {
485             for (cur = cur->prev; cur->last != NULL; cur = cur->last);
486         } else {
487             cur = cur->parent;
488         }
489
490     }
491
492     array[amount++] = (double) cnt;
493
494     if (countPat != NULL)
495         xsltFreeCompMatchList(countPat);
496     if (fromPat != NULL)
497         xsltFreeCompMatchList(fromPat);
498     return(amount);
499 }
500
501 static int
502 xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
503                                  xmlNodePtr node,
504                                  xmlChar *count,
505                                  xmlChar *from,
506                                  double *array,
507                                  int max,
508                                  xmlDocPtr doc,
509                                  xmlNodePtr elem)
510 {
511     int amount = 0;
512     int cnt;
513     xmlNodePtr ancestor;
514     xmlNodePtr preceding;
515     xmlXPathParserContextPtr parser;
516     xsltCompMatchPtr countPat;
517     xsltCompMatchPtr fromPat;
518
519     if (count != NULL)
520         countPat = xsltCompilePattern(count, doc, elem, NULL, context);
521     else
522         countPat = NULL;
523     if (from != NULL)
524         fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
525     else
526         fromPat = NULL;
527     context->xpathCtxt->node = node;
528     parser = xmlXPathNewParserContext(NULL, context->xpathCtxt);
529     if (parser) {
530         /* ancestor-or-self::*[count] */
531         for (ancestor = node;
532              (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE);
533              ancestor = xmlXPathNextAncestor(parser, ancestor)) {
534             
535             if ((from != NULL) &&
536                 xsltTestCompMatchList(context, ancestor, fromPat))
537                 break; /* for */
538             
539             if ((count == NULL) ||
540                 xsltTestCompMatchList(context, ancestor, countPat)) {
541                 /* count(preceding-sibling::*) */
542                 cnt = 0;
543                 for (preceding = ancestor;
544                      preceding != NULL;
545                      preceding = 
546                         xmlXPathNextPrecedingSibling(parser, preceding)) {
547                     if (count == NULL) {
548                         if ((preceding->type == ancestor->type) &&
549                             /* FIXME */
550                             xmlStrEqual(preceding->name, ancestor->name))
551                             cnt++;
552                     } else {
553                         if (xsltTestCompMatchList(context, preceding,
554                                                   countPat))
555                             cnt++;
556                     }
557                 }
558                 array[amount++] = (double)cnt;
559                 if (amount >= max)
560                     break; /* for */
561             }
562         }
563         xmlXPathFreeParserContext(parser);
564     }
565     xsltFreeCompMatchList(countPat);
566     xsltFreeCompMatchList(fromPat);
567     return amount;
568 }
569
570 static int
571 xsltNumberFormatGetValue(xmlXPathContextPtr context,
572                          xmlNodePtr node,
573                          xmlChar *value,
574                          double *number)
575 {
576     int amount = 0;
577     xmlBufferPtr pattern;
578     xmlXPathObjectPtr obj;
579     
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),
587                                      context);
588         if (obj != NULL) {
589             *number = obj->floatval;
590             amount++;
591             xmlXPathFreeObject(obj);
592         }
593         xmlBufferFree(pattern);
594     }
595     return amount;
596 }
597
598 /**
599  * xsltNumberFormat:
600  * @ctxt: the XSLT transformation context
601  * @data: the formatting informations
602  * @node: the data to format
603  *
604  * Convert one number.
605  */
606 void
607 xsltNumberFormat(xsltTransformContextPtr ctxt,
608                  xsltNumberDataPtr data,
609                  xmlNodePtr node)
610 {
611     xmlBufferPtr output = NULL;
612     xmlNodePtr copy = NULL;
613     int amount, i;
614     double number;
615     xsltFormat tokens;
616     int tempformat = 0;
617
618     if ((data->format == NULL) && (data->has_format != 0)) {
619         data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
620                                              (const xmlChar *) "format",
621                                              XSLT_NAMESPACE);
622         tempformat = 1;
623     }
624     if (data->format == NULL) {
625         return;
626     }
627
628     output = xmlBufferCreate();
629     if (output == NULL)
630         goto XSLT_NUMBER_FORMAT_END;
631
632     xsltNumberFormatTokenize(data->format, &tokens);
633
634     /*
635      * Evaluate the XPath expression to find the value(s)
636      */
637     if (data->value) {
638         amount = xsltNumberFormatGetValue(ctxt->xpathCtxt,
639                                           node,
640                                           data->value,
641                                           &number);
642         if (amount == 1) {
643             xsltNumberFormatInsertNumbers(data,
644                                           &number,
645                                           1,
646                                           &tokens,
647                                           output);
648         }
649         
650     } else if (data->level) {
651         
652         if (xmlStrEqual(data->level, (const xmlChar *) "single")) {
653             amount = xsltNumberFormatGetMultipleLevel(ctxt,
654                                                       node,
655                                                       data->count,
656                                                       data->from,
657                                                       &number,
658                                                       1,
659                                                       data->doc,
660                                                       data->node);
661             if (amount == 1) {
662                 xsltNumberFormatInsertNumbers(data,
663                                               &number,
664                                               1,
665                                               &tokens,
666                                               output);
667             }
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,
672                                                       node,
673                                                       data->count,
674                                                       data->from,
675                                                       numarray,
676                                                       max,
677                                                       data->doc,
678                                                       data->node);
679             if (amount > 0) {
680                 xsltNumberFormatInsertNumbers(data,
681                                               numarray,
682                                               amount,
683                                               &tokens,
684                                               output);
685             }
686         } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
687             amount = xsltNumberFormatGetAnyLevel(ctxt,
688                                                  node,
689                                                  data->count,
690                                                  data->from,
691                                                  &number, 
692                                                  data->doc,
693                                                  data->node);
694             if (amount > 0) {
695                 xsltNumberFormatInsertNumbers(data,
696                                               &number,
697                                               1,
698                                               &tokens,
699                                               output);
700             }
701         }
702     }
703     /* Insert number as text node */
704     copy = xmlNewText(xmlBufferContent(output));
705     if (copy != NULL) {
706         xmlAddChild(ctxt->insert, copy);
707     }
708
709     if (tokens.start != NULL)
710         xmlFree(tokens.start);
711     if (tokens.end != NULL)
712         xmlFree(tokens.end);
713     for (i = 0;i < tokens.nTokens;i++) {
714         if (tokens.tokens[i].separator != NULL)
715             xmlFree(tokens.tokens[i].separator);
716     }
717     
718 XSLT_NUMBER_FORMAT_END:
719     if (tempformat == 1) {
720         /* The format need to be recomputed each time */
721         xmlFree(data->format);
722         data->format = NULL;
723     }
724     if (output != NULL)
725         xmlBufferFree(output);
726 }
727
728 static int
729 xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info)
730 {
731     int count=0;        /* will hold total length of prefix/suffix */
732
733     while (1) {
734         /* prefix / suffix ends at end of string or at first 'special' character */
735         if (**format == 0)
736             return count;
737         /* if next character 'escaped' just count it */
738         if (**format == SYMBOL_QUOTE) {
739             if (*++(*format) == 0)
740                 return -1;
741             if (*++(*format) != SYMBOL_QUOTE)
742                 return -1;
743         }
744         else if (IS_SPECIAL(self, **format))
745             return count;
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)
751                     return -1;
752                 info->multiplier = 100;
753                 info->is_multiplier_set = TRUE;
754             } else if (**format == self->permille[0]) {
755                 if (info->is_multiplier_set)
756                     return -1;
757                 info->multiplier = 1000;
758                 info->is_multiplier_set = TRUE;
759             }
760         } else {
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)
764                     return -1;
765                 if (info->multiplier != 100)
766                     return -1;
767                 info->is_multiplier_set = TRUE;
768             } else if (**format == self->permille[0]) {
769                 if (info->is_multiplier_set)
770                     return -1;
771                 if (info->multiplier != 1000)
772                     return -1;
773                 info->is_multiplier_set = TRUE;
774             }
775         }
776         
777         count++;
778         (*format)++;
779     }
780 }
781             
782 /**
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
788  *
789  * format-number() uses the JDK 1.1 DecimalFormat class:
790  *
791  * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html
792  *
793  * Structure:
794  *
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'* '#'*
801  *
802  *   Notation:
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
807  *
808  * Special Characters:
809  *
810  *   Symbol Meaning
811  *   0      a digit
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.
821  */
822 xmlXPathError
823 xsltFormatNumberConversion(xsltDecimalFormatPtr self,
824                            xmlChar *format,
825                            double number,
826                            xmlChar **result)
827 {
828     xmlXPathError status = XPATH_EXPRESSION_OK;
829     xmlBufferPtr buffer;
830     xmlChar *the_format, *prefix = NULL, *suffix = NULL;
831     xmlChar *nprefix, *nsuffix = NULL;
832     xmlChar pchar;
833     int     prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
834     double  scale;
835     int     j;
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;
843
844     *result = NULL;
845     switch (xmlXPathIsInf(number)) {
846         case -1:
847             if (self->minusSign == NULL)
848                 *result = xmlStrdup(BAD_CAST "-");
849             else
850                 *result = xmlStrdup(self->minusSign);
851             /* no-break on purpose */
852         case 1:
853             if ((self == NULL) || (self->infinity == NULL))
854                 *result = xmlStrcat(*result, BAD_CAST "Infinity");
855             else
856                 *result = xmlStrcat(*result, self->infinity);
857             return(status);
858         default:
859             if (xmlXPathIsNaN(number)) {
860                 if ((self == NULL) || (self->noNumber == NULL))
861                     *result = xmlStrdup(BAD_CAST "NaN");
862                 else
863                     *result = xmlStrdup(self->noNumber);
864                 return(status);
865             }
866     }
867
868     buffer = xmlBufferCreate();
869     if (buffer == NULL) {
870         return XPATH_MEMORY_ERROR;
871     }
872
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;
880
881     the_format = format;
882
883     /* First we process the +ve pattern to get percent / permille, as well as main format */
884     prefix = the_format;
885     prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
886     if (prefix_length < 0) {
887         found_error = 1;
888         goto OUTPUT_NUMBER;
889     }
890
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])) {
897         
898         if (delayed_multiplier != 0) {
899             format_info.multiplier = delayed_multiplier;
900             format_info.is_multiplier_set = TRUE;
901             delayed_multiplier = 0;
902         }
903         if (*the_format == self->digit[0]) {
904             if (format_info.integer_digits > 0) {
905                 found_error = 1;
906                 goto OUTPUT_NUMBER;
907             }
908             if (format_info.group >= 0)
909                 format_info.group++;
910         } else if (*the_format == self->zeroDigit[0]) {
911             format_info.integer_digits++;
912             if (format_info.group >= 0)
913                 format_info.group++;
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) {
919                 found_error = 1;
920                 goto OUTPUT_NUMBER;
921             }
922             delayed_multiplier = 100;
923         } else  if (*the_format == self->permille[0]) {
924             if (format_info.is_multiplier_set) {
925                 found_error = 1;
926                 goto OUTPUT_NUMBER;
927             }
928             delayed_multiplier = 1000;
929         } else
930             break; /* while */
931         
932         the_format++;
933     }
934
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 */
938     
939     while (*the_format != 0) {
940         
941         if (*the_format == self->zeroDigit[0]) {
942             if (format_info.frac_hash != 0) {
943                 found_error = 1;
944                 goto OUTPUT_NUMBER;
945             }
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) {
951                 found_error = 1;
952                 goto OUTPUT_NUMBER;
953             }
954             delayed_multiplier = 100;
955             the_format++;
956             continue; /* while */
957         } else if (*the_format == self->permille[0]) {
958             if (format_info.is_multiplier_set) {
959                 found_error = 1;
960                 goto OUTPUT_NUMBER;
961             }
962             delayed_multiplier = 1000;
963             the_format++;
964             continue; /* while */
965         } else if (*the_format != self->grouping[0]) {
966             break; /* while */
967         }
968         the_format++;
969         if (delayed_multiplier != 0) {
970             format_info.multiplier = delayed_multiplier;
971             delayed_multiplier = 0;
972             format_info.is_multiplier_set = TRUE;
973         }
974     }
975
976     /* If delayed_multiplier is set after processing the "number" part, should be in suffix */
977     if (delayed_multiplier != 0) {
978         the_format--;
979         delayed_multiplier = 0;
980     }
981
982     suffix = the_format;
983     suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
984     if ( (suffix_length < 0) ||
985          ((*the_format != 0) && (*the_format != self->patternSeparator[0])) ) {
986         found_error = 1;
987         goto OUTPUT_NUMBER;
988     }
989
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 */
992     if (number < 0) {
993         the_format = (xmlChar *)xmlStrchr(format, self->patternSeparator[0]);
994         if (the_format == NULL) {       /* No -ve pattern present, so use default signing */
995             default_sign = 1;
996         }
997         else {
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;
1002
1003             /* First do the -ve prefix */
1004             nprefix = the_format;
1005             nprefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
1006             if (nprefix_length<0) {
1007                 found_error = 1;
1008                 goto OUTPUT_NUMBER;
1009             }
1010
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) {
1017                         found_error = 1;
1018                         goto OUTPUT_NUMBER;
1019                     }
1020                     format_info.is_multiplier_set = TRUE;
1021                     delayed_multiplier = 1;
1022                 }
1023                 else if (IS_SPECIAL(self, *the_format))
1024                     delayed_multiplier = 0;
1025                 else
1026                     break; /* while */
1027                 the_format++;
1028             }
1029             if (delayed_multiplier != 0) {
1030                 format_info.is_multiplier_set = FALSE;
1031                 the_format--;
1032             }
1033
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) {
1039                 found_error = 1;
1040                 goto OUTPUT_NUMBER;
1041                 }
1042             }
1043             else
1044                 nsuffix_length = 0;
1045             if (*the_format != 0) {
1046                 found_error = 1;
1047                 goto OUTPUT_NUMBER;
1048             }
1049             /* Here's another Java peculiarity:
1050              * if -ve prefix/suffix == +ve ones, discard & use default
1051              */
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 ))) {
1055                 prefix = nprefix;
1056                 prefix_length = nprefix_length;
1057                 suffix = nsuffix;
1058                 suffix_length = nsuffix_length;
1059             } else {
1060                 default_sign = 1;
1061             }
1062         }
1063     }
1064
1065 OUTPUT_NUMBER:
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;
1077     }
1078
1079     /* Ready to output our number.  First see if "default sign" is required */
1080     if (default_sign != 0)
1081         xmlBufferAdd(buffer, self->minusSign, 1);
1082
1083     /* Put the prefix into the buffer */
1084     for (j = 0; j < prefix_length; j++) {
1085         if ((pchar = *prefix++) == SYMBOL_QUOTE) {
1086             pchar = *prefix++;
1087             prefix++;
1088         }
1089         xmlBufferAdd(buffer, &pchar, 1);
1090     }
1091
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,
1099                                 format_info.group,
1100                                 (xmlChar) self->grouping[0]);
1101     else
1102         xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1103                                 format_info.integer_digits,
1104                                 format_info.group,
1105                                 (xmlChar) ',');
1106
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)
1115                     break; /* for */
1116                 number /= 10.0;
1117             }
1118             xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
1119                                 format_info.frac_digits + j,
1120                                 0, (xmlChar)0);
1121         }
1122     }
1123     /* Put the suffix into the buffer */
1124     for (j = 0; j < suffix_length; j++) {
1125         if ((pchar = *suffix++) == SYMBOL_QUOTE) {
1126             pchar = *suffix++;
1127             suffix++;
1128         }
1129         xmlBufferAdd(buffer, &pchar, 1);
1130     }
1131
1132     *result = xmlStrdup(xmlBufferContent(buffer));
1133     xmlBufferFree(buffer);
1134     return status;
1135 }