ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

numbers.c
Go to the documentation of this file.
00001 /*
00002  * numbers.c: Implementation of the XSLT number functions
00003  *
00004  * Reference:
00005  *   http://www.w3.org/TR/1999/REC-xslt-19991116
00006  *
00007  * See Copyright for the status of this software.
00008  *
00009  * daniel@veillard.com
00010  * Bjorn Reese <breese@users.sourceforge.net>
00011  */
00012 
00013 #define IN_LIBXSLT
00014 #include "libxslt.h"
00015 
00016 #include <math.h>
00017 #include <limits.h>
00018 #include <float.h>
00019 #include <string.h>
00020 
00021 #include <libxml/xmlmemory.h>
00022 #include <libxml/parserInternals.h>
00023 #include <libxml/xpath.h>
00024 #include <libxml/xpathInternals.h>
00025 #include <libxml/encoding.h>
00026 #include "xsltutils.h"
00027 #include "pattern.h"
00028 #include "templates.h"
00029 #include "transform.h"
00030 #include "numbersInternals.h"
00031 
00032 #ifndef FALSE
00033 # define FALSE (0 == 1)
00034 # define TRUE (1 == 1)
00035 #endif
00036 
00037 #define SYMBOL_QUOTE        ((xmlChar)'\'')
00038 
00039 #define DEFAULT_TOKEN       (xmlChar)'0'
00040 #define DEFAULT_SEPARATOR   "."
00041 
00042 #define MAX_TOKENS      1024
00043 
00044 typedef struct _xsltFormatToken xsltFormatToken;
00045 typedef xsltFormatToken *xsltFormatTokenPtr;
00046 struct _xsltFormatToken {
00047     xmlChar *separator;
00048     xmlChar  token;
00049     int      width;
00050 };
00051 
00052 typedef struct _xsltFormat xsltFormat;
00053 typedef xsltFormat *xsltFormatPtr;
00054 struct _xsltFormat {
00055     xmlChar     *start;
00056     xsltFormatToken  tokens[MAX_TOKENS];
00057     int          nTokens;
00058     xmlChar     *end;
00059 };
00060 
00061 static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
00062 static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
00063 static xsltFormatToken default_token;
00064 
00065 /*
00066  * **** Start temp insert ****
00067  *
00068  * The following two routines (xsltUTF8Size and xsltUTF8Charcmp)
00069  * will be replaced with calls to the corresponding libxml routines
00070  * at a later date (when other inter-library dependencies require it)
00071  */
00072 
00079 static int
00080 xsltUTF8Size(xmlChar *utf) {
00081     xmlChar mask;
00082     int len;
00083 
00084     if (utf == NULL)
00085         return -1;
00086     if (*utf < 0x80)
00087         return 1;
00088     /* check valid UTF8 character */
00089     if (!(*utf & 0x40))
00090         return -1;
00091     /* determine number of bytes in char */
00092     len = 2;
00093     for (mask=0x20; mask != 0; mask>>=1) {
00094         if (!(*utf & mask))
00095             return len;
00096         len++;
00097     }
00098     return -1;
00099 }
00100 
00109 static int
00110 xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) {
00111 
00112     if (utf1 == NULL ) {
00113         if (utf2 == NULL)
00114             return 0;
00115         return -1;
00116     }
00117     return xmlStrncmp(utf1, utf2, xsltUTF8Size(utf1));
00118 }
00119 
00120 /***** Stop temp insert *****/
00121 /************************************************************************
00122  *                                  *
00123  *          Utility functions               *
00124  *                                  *
00125  ************************************************************************/
00126 
00127 #define IS_SPECIAL(self,letter)         \
00128     ((xsltUTF8Charcmp((letter), (self)->zeroDigit) == 0)        ||  \
00129      (xsltUTF8Charcmp((letter), (self)->digit) == 0)        ||  \
00130      (xsltUTF8Charcmp((letter), (self)->decimalPoint) == 0)  || \
00131      (xsltUTF8Charcmp((letter), (self)->grouping) == 0)     ||  \
00132      (xsltUTF8Charcmp((letter), (self)->patternSeparator) == 0))
00133 
00134 #define IS_DIGIT_ZERO(x) xsltIsDigitZero(x)
00135 #define IS_DIGIT_ONE(x) xsltIsDigitZero((xmlChar)(x)-1)
00136 
00137 static int
00138 xsltIsDigitZero(unsigned int ch)
00139 {
00140     /*
00141      * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
00142      */
00143     switch (ch) {
00144     case 0x0030: case 0x0660: case 0x06F0: case 0x0966:
00145     case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66:
00146     case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50:
00147     case 0x0E60: case 0x0F20: case 0x1040: case 0x17E0:
00148     case 0x1810: case 0xFF10:
00149     return TRUE;
00150     default:
00151     return FALSE;
00152     }
00153 }
00154 
00155 static void
00156 xsltNumberFormatDecimal(xmlBufferPtr buffer,
00157             double number,
00158             int digit_zero,
00159             int width,
00160             int digitsPerGroup,
00161             int groupingCharacter,
00162             int groupingCharacterLen)
00163 {
00164     /*
00165      * This used to be
00166      *  xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 4];
00167      * which would be length 68 on x86 arch.  It was changed to be a longer,
00168      * fixed length in order to try to cater for (reasonable) UTF8
00169      * separators and numeric characters.  The max UTF8 char size will be
00170      * 6 or less, so the value used [500] should be *much* larger than needed
00171      */
00172     xmlChar temp_string[500];
00173     xmlChar *pointer;
00174     xmlChar temp_char[6];
00175     int i;
00176     int val;
00177     int len;
00178 
00179     /* Build buffer from back */
00180     pointer = &temp_string[sizeof(temp_string)] - 1;    /* last char */
00181     *pointer = 0;
00182     i = 0;
00183     while (pointer > temp_string) {
00184     if ((i >= width) && (fabs(number) < 1.0))
00185         break; /* for */
00186     if ((i > 0) && (groupingCharacter != 0) &&
00187         (digitsPerGroup > 0) &&
00188         ((i % digitsPerGroup) == 0)) {
00189         if (pointer - groupingCharacterLen < temp_string) {
00190             i = -1;     /* flag error */
00191         break;
00192         }
00193         pointer -= groupingCharacterLen;
00194         xmlCopyCharMultiByte(pointer, groupingCharacter);
00195     }
00196     
00197     val = digit_zero + (int)fmod(number, 10.0);
00198     if (val < 0x80) {           /* shortcut if ASCII */
00199         if (pointer <= temp_string) {   /* Check enough room */
00200             i = -1;
00201         break;
00202         }
00203         *(--pointer) = val;
00204     }
00205     else {
00206     /* 
00207      * Here we have a multibyte character.  It's a little messy,
00208      * because until we generate the char we don't know how long
00209      * it is.  So, we generate it into the buffer temp_char, then
00210      * copy from there into temp_string.
00211      */
00212         len = xmlCopyCharMultiByte(temp_char, val);
00213         if ( (pointer - len) < temp_string ) {
00214             i = -1;
00215         break;
00216         }
00217         pointer -= len;
00218         memcpy(pointer, temp_char, len);
00219     }
00220     number /= 10.0;
00221     ++i;
00222     }
00223     if (i < 0)
00224         xsltGenericError(xsltGenericErrorContext,
00225         "xsltNumberFormatDecimal: Internal buffer size exceeded");
00226     xmlBufferCat(buffer, pointer);
00227 }
00228 
00229 static void
00230 xsltNumberFormatAlpha(xmlBufferPtr buffer,
00231               double number,
00232               int is_upper)
00233 {
00234     char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
00235     char *pointer;
00236     int i;
00237     char *alpha_list;
00238     double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
00239 
00240     /* Build buffer from back */
00241     pointer = &temp_string[sizeof(temp_string)];
00242     *(--pointer) = 0;
00243     alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list;
00244     
00245     for (i = 1; i < (int)sizeof(temp_string); i++) {
00246     number--;
00247     *(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
00248     number /= alpha_size;
00249     if (fabs(number) < 1.0)
00250         break; /* for */
00251     }
00252     xmlBufferCCat(buffer, pointer);
00253 }
00254 
00255 static void
00256 xsltNumberFormatRoman(xmlBufferPtr buffer,
00257               double number,
00258               int is_upper)
00259 {
00260     /*
00261      * Based on an example by Jim Walsh
00262      */
00263     while (number >= 1000.0) {
00264     xmlBufferCCat(buffer, (is_upper) ? "M" : "m");
00265     number -= 1000.0;
00266     }
00267     if (number >= 900.0) {
00268     xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm");
00269     number -= 900.0;
00270     }
00271     while (number >= 500.0) {
00272     xmlBufferCCat(buffer, (is_upper) ? "D" : "d");
00273     number -= 500.0;
00274     }
00275     if (number >= 400.0) {
00276     xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd");
00277     number -= 400.0;
00278     }
00279     while (number >= 100.0) {
00280     xmlBufferCCat(buffer, (is_upper) ? "C" : "c");
00281     number -= 100.0;
00282     }
00283     if (number >= 90.0) {
00284     xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc");
00285     number -= 90.0;
00286     }
00287     while (number >= 50.0) {
00288     xmlBufferCCat(buffer, (is_upper) ? "L" : "l");
00289     number -= 50.0;
00290     }
00291     if (number >= 40.0) {
00292     xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl");
00293     number -= 40.0;
00294     }
00295     while (number >= 10.0) {
00296     xmlBufferCCat(buffer, (is_upper) ? "X" : "x");
00297     number -= 10.0;
00298     }
00299     if (number >= 9.0) {
00300     xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix");
00301     number -= 9.0;
00302     }
00303     while (number >= 5.0) {
00304     xmlBufferCCat(buffer, (is_upper) ? "V" : "v");
00305     number -= 5.0;
00306     }
00307     if (number >= 4.0) {
00308     xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv");
00309     number -= 4.0;
00310     }
00311     while (number >= 1.0) {
00312     xmlBufferCCat(buffer, (is_upper) ? "I" : "i");
00313     number--;
00314     }
00315 }
00316 
00317 static void
00318 xsltNumberFormatTokenize(const xmlChar *format,
00319              xsltFormatPtr tokens)
00320 {
00321     int ix = 0;
00322     int j;
00323     int val;
00324     int len;
00325 
00326     default_token.token = DEFAULT_TOKEN;
00327     default_token.width = 1;
00328     default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
00329 
00330 
00331     tokens->start = NULL;
00332     tokens->tokens[0].separator = NULL;
00333     tokens->end = NULL;
00334 
00335     /*
00336      * Insert initial non-alphanumeric token.
00337      * There is always such a token in the list, even if NULL
00338      */
00339     while (! (IS_LETTER(val=xmlStringCurrentChar(NULL, format+ix, &len)) ||
00340               IS_DIGIT(val)) ) {
00341     if (format[ix] == 0)        /* if end of format string */
00342         break; /* while */
00343     ix += len;
00344     }
00345     if (ix > 0)
00346     tokens->start = xmlStrndup(format, ix);
00347 
00348 
00349     for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
00350      tokens->nTokens++) {
00351     if (format[ix] == 0)
00352         break; /* for */
00353 
00354     /*
00355      * separator has already been parsed (except for the first
00356      * number) in tokens->end, recover it.
00357      */
00358     if (tokens->nTokens > 0) {
00359         tokens->tokens[tokens->nTokens].separator = tokens->end;
00360         tokens->end = NULL;
00361     }
00362 
00363     val = xmlStringCurrentChar(NULL, format+ix, &len);
00364     if (IS_DIGIT_ONE(val) ||
00365          IS_DIGIT_ZERO(val)) {
00366         tokens->tokens[tokens->nTokens].width = 1;
00367         while (IS_DIGIT_ZERO(val)) {
00368         tokens->tokens[tokens->nTokens].width++;
00369         ix += len;
00370         val = xmlStringCurrentChar(NULL, format+ix, &len);
00371         }
00372         if (IS_DIGIT_ONE(val)) {
00373         tokens->tokens[tokens->nTokens].token = val - 1;
00374         ix += len;
00375         val = xmlStringCurrentChar(NULL, format+ix, &len);
00376         }
00377     } else if ( (val == (xmlChar)'A') ||
00378             (val == (xmlChar)'a') ||
00379             (val == (xmlChar)'I') ||
00380             (val == (xmlChar)'i') ) {
00381         tokens->tokens[tokens->nTokens].token = val;
00382         ix += len;
00383         val = xmlStringCurrentChar(NULL, format+ix, &len);
00384     } else {
00385         /* XSLT section 7.7
00386          * "Any other format token indicates a numbering sequence
00387          *  that starts with that token. If an implementation does
00388          *  not support a numbering sequence that starts with that
00389          *  token, it must use a format token of 1."
00390          */
00391         tokens->tokens[tokens->nTokens].token = (xmlChar)'0';
00392         tokens->tokens[tokens->nTokens].width = 1;
00393     }
00394     /*
00395      * Skip over remaining alphanumeric characters from the Nd
00396      * (Number, decimal digit), Nl (Number, letter), No (Number,
00397      * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt
00398      * (Letters, titlecase), Lm (Letters, modifiers), and Lo
00399      * (Letters, other (uncased)) Unicode categories. This happens
00400      * to correspond to the Letter and Digit classes from XML (and
00401      * one wonders why XSLT doesn't refer to these instead).
00402      */
00403     while (IS_LETTER(val) || IS_DIGIT(val)) {
00404         ix += len;
00405         val = xmlStringCurrentChar(NULL, format+ix, &len);
00406     }
00407 
00408     /*
00409      * Insert temporary non-alphanumeric final tooken.
00410      */
00411     j = ix;
00412     while (! (IS_LETTER(val) || IS_DIGIT(val))) {
00413         if (val == 0)
00414         break; /* while */
00415         ix += len;
00416         val = xmlStringCurrentChar(NULL, format+ix, &len);
00417     }
00418     if (ix > j)
00419         tokens->end = xmlStrndup(&format[j], ix - j);
00420     }
00421 }
00422 
00423 static void
00424 xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
00425                   double *numbers,
00426                   int numbers_max,
00427                   xsltFormatPtr tokens,
00428                   xmlBufferPtr buffer)
00429 {
00430     int i = 0;
00431     double number;
00432     xsltFormatTokenPtr token;
00433 
00434     /*
00435      * Handle initial non-alphanumeric token
00436      */
00437     if (tokens->start != NULL)
00438      xmlBufferCat(buffer, tokens->start);
00439 
00440     for (i = 0; i < numbers_max; i++) {
00441     /* Insert number */
00442     number = numbers[(numbers_max - 1) - i];
00443     if (i < tokens->nTokens) {
00444       /*
00445        * The "n"th format token will be used to format the "n"th
00446        * number in the list
00447        */
00448       token = &(tokens->tokens[i]);
00449     } else if (tokens->nTokens > 0) {
00450       /*
00451        * If there are more numbers than format tokens, then the
00452        * last format token will be used to format the remaining
00453        * numbers.
00454        */
00455       token = &(tokens->tokens[tokens->nTokens - 1]);
00456     } else {
00457       /*
00458        * If there are no format tokens, then a format token of
00459        * 1 is used to format all numbers.
00460        */
00461       token = &default_token;
00462     }
00463 
00464     /* Print separator, except for the first number */
00465     if (i > 0) {
00466         if (token->separator != NULL)
00467         xmlBufferCat(buffer, token->separator);
00468         else
00469         xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
00470     }
00471 
00472     switch (xmlXPathIsInf(number)) {
00473     case -1:
00474         xmlBufferCCat(buffer, "-Infinity");
00475         break;
00476     case 1:
00477         xmlBufferCCat(buffer, "Infinity");
00478         break;
00479     default:
00480         if (xmlXPathIsNaN(number)) {
00481         xmlBufferCCat(buffer, "NaN");
00482         } else {
00483 
00484         switch (token->token) {
00485         case 'A':
00486             xsltNumberFormatAlpha(buffer,
00487                       number,
00488                       TRUE);
00489 
00490             break;
00491         case 'a':
00492             xsltNumberFormatAlpha(buffer,
00493                       number,
00494                       FALSE);
00495 
00496             break;
00497         case 'I':
00498             xsltNumberFormatRoman(buffer,
00499                       number,
00500                       TRUE);
00501 
00502             break;
00503         case 'i':
00504             xsltNumberFormatRoman(buffer,
00505                       number,
00506                       FALSE);
00507 
00508             break;
00509         default:
00510             if (IS_DIGIT_ZERO(token->token)) {
00511             xsltNumberFormatDecimal(buffer,
00512                         number,
00513                         token->token,
00514                         token->width,
00515                         data->digitsPerGroup,
00516                         data->groupingCharacter,
00517                         data->groupingCharacterLen);
00518             }
00519             break;
00520         }
00521         }
00522 
00523     }
00524     }
00525 
00526     /*
00527      * Handle final non-alphanumeric token
00528      */
00529     if (tokens->end != NULL)
00530      xmlBufferCat(buffer, tokens->end);
00531 
00532 }
00533 
00534 static int
00535 xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
00536                 xmlNodePtr node,
00537                 const xmlChar *count,
00538                 const xmlChar *from,
00539                 double *array,
00540                 xmlDocPtr doc,
00541                 xmlNodePtr elem)
00542 {
00543     int amount = 0;
00544     int cnt = 0;
00545     xmlNodePtr cur;
00546     xsltCompMatchPtr countPat = NULL;
00547     xsltCompMatchPtr fromPat = NULL;
00548 
00549     if (count != NULL)
00550     countPat = xsltCompilePattern(count, doc, elem, NULL, context);
00551     if (from != NULL)
00552     fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
00553     
00554     /* select the starting node */
00555     switch (node->type) {
00556     case XML_ELEMENT_NODE:
00557         cur = node;
00558         break;
00559     case XML_ATTRIBUTE_NODE:
00560         cur = ((xmlAttrPtr) node)->parent;
00561         break;
00562     case XML_TEXT_NODE:
00563     case XML_PI_NODE:
00564     case XML_COMMENT_NODE:
00565         cur = node->parent;
00566         break;
00567     default:
00568         cur = NULL;
00569         break;
00570     }
00571 
00572     while (cur != NULL) {
00573     /* process current node */
00574     if (count == NULL) {
00575         if ((node->type == cur->type) &&
00576         /* FIXME: must use expanded-name instead of local name */
00577         xmlStrEqual(node->name, cur->name)) {
00578             if ((node->ns == cur->ns) ||
00579                 ((node->ns != NULL) &&
00580              (cur->ns != NULL) &&
00581                  (xmlStrEqual(node->ns->href,
00582                      cur->ns->href) )))
00583                 cnt++;
00584         }
00585     } else {
00586         if (xsltTestCompMatchList(context, cur, countPat))
00587         cnt++;
00588     }
00589     if ((from != NULL) &&
00590         xsltTestCompMatchList(context, cur, fromPat)) {
00591         break; /* while */
00592     }
00593 
00594     /* Skip to next preceding or ancestor */
00595     if ((cur->type == XML_DOCUMENT_NODE) ||
00596 #ifdef LIBXML_DOCB_ENABLED
00597             (cur->type == XML_DOCB_DOCUMENT_NODE) ||
00598 #endif
00599             (cur->type == XML_HTML_DOCUMENT_NODE))
00600         break; /* while */
00601 
00602     while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) ||
00603            (cur->prev->type == XML_XINCLUDE_START) ||
00604            (cur->prev->type == XML_XINCLUDE_END)))
00605         cur = cur->prev;
00606     if (cur->prev != NULL) {
00607         for (cur = cur->prev; cur->last != NULL; cur = cur->last);
00608     } else {
00609         cur = cur->parent;
00610     }
00611 
00612     }
00613 
00614     array[amount++] = (double) cnt;
00615 
00616     if (countPat != NULL)
00617     xsltFreeCompMatchList(countPat);
00618     if (fromPat != NULL)
00619     xsltFreeCompMatchList(fromPat);
00620     return(amount);
00621 }
00622 
00623 static int
00624 xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
00625                  xmlNodePtr node,
00626                  const xmlChar *count,
00627                  const xmlChar *from,
00628                  double *array,
00629                  int max,
00630                  xmlDocPtr doc,
00631                  xmlNodePtr elem)
00632 {
00633     int amount = 0;
00634     int cnt;
00635     xmlNodePtr ancestor;
00636     xmlNodePtr preceding;
00637     xmlXPathParserContextPtr parser;
00638     xsltCompMatchPtr countPat;
00639     xsltCompMatchPtr fromPat;
00640 
00641     if (count != NULL)
00642     countPat = xsltCompilePattern(count, doc, elem, NULL, context);
00643     else
00644     countPat = NULL;
00645     if (from != NULL)
00646     fromPat = xsltCompilePattern(from, doc, elem, NULL, context);
00647     else
00648     fromPat = NULL;
00649     context->xpathCtxt->node = node;
00650     parser = xmlXPathNewParserContext(NULL, context->xpathCtxt);
00651     if (parser) {
00652     /* ancestor-or-self::*[count] */
00653     for (ancestor = node;
00654          (ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE);
00655          ancestor = xmlXPathNextAncestor(parser, ancestor)) {
00656         
00657         if ((from != NULL) &&
00658         xsltTestCompMatchList(context, ancestor, fromPat))
00659         break; /* for */
00660         
00661         if ((count == NULL && node->type == ancestor->type && 
00662         xmlStrEqual(node->name, ancestor->name)) ||
00663         xsltTestCompMatchList(context, ancestor, countPat)) {
00664         /* count(preceding-sibling::*) */
00665         cnt = 0;
00666         for (preceding = ancestor;
00667              preceding != NULL;
00668              preceding = 
00669                 xmlXPathNextPrecedingSibling(parser, preceding)) {
00670             if (count == NULL) {
00671             if ((preceding->type == ancestor->type) &&
00672                 xmlStrEqual(preceding->name, ancestor->name)){
00673                 if ((preceding->ns == ancestor->ns) ||
00674                     ((preceding->ns != NULL) &&
00675                  (ancestor->ns != NULL) &&
00676                      (xmlStrEqual(preceding->ns->href,
00677                          ancestor->ns->href) )))
00678                     cnt++;
00679             }
00680             } else {
00681             if (xsltTestCompMatchList(context, preceding,
00682                                   countPat))
00683                 cnt++;
00684             }
00685         }
00686         array[amount++] = (double)cnt;
00687         if (amount >= max)
00688             break; /* for */
00689         }
00690     }
00691     xmlXPathFreeParserContext(parser);
00692     }
00693     xsltFreeCompMatchList(countPat);
00694     xsltFreeCompMatchList(fromPat);
00695     return amount;
00696 }
00697 
00698 static int
00699 xsltNumberFormatGetValue(xmlXPathContextPtr context,
00700              xmlNodePtr node,
00701              const xmlChar *value,
00702              double *number)
00703 {
00704     int amount = 0;
00705     xmlBufferPtr pattern;
00706     xmlXPathObjectPtr obj;
00707     
00708     pattern = xmlBufferCreate();
00709     if (pattern != NULL) {
00710     xmlBufferCCat(pattern, "number(");
00711     xmlBufferCat(pattern, value);
00712     xmlBufferCCat(pattern, ")");
00713     context->node = node;
00714     obj = xmlXPathEvalExpression(xmlBufferContent(pattern),
00715                      context);
00716     if (obj != NULL) {
00717         *number = obj->floatval;
00718         amount++;
00719         xmlXPathFreeObject(obj);
00720     }
00721     xmlBufferFree(pattern);
00722     }
00723     return amount;
00724 }
00725 
00734 void
00735 xsltNumberFormat(xsltTransformContextPtr ctxt,
00736          xsltNumberDataPtr data,
00737          xmlNodePtr node)
00738 {
00739     xmlBufferPtr output = NULL;
00740     int amount, i;
00741     double number;
00742     xsltFormat tokens;
00743     int tempformat = 0;
00744 
00745     if ((data->format == NULL) && (data->has_format != 0)) {
00746     data->format = xsltEvalAttrValueTemplate(ctxt, data->node,
00747                          (const xmlChar *) "format",
00748                          XSLT_NAMESPACE);
00749     tempformat = 1;
00750     }
00751     if (data->format == NULL) {
00752     return;
00753     }
00754 
00755     output = xmlBufferCreate();
00756     if (output == NULL)
00757     goto XSLT_NUMBER_FORMAT_END;
00758 
00759     xsltNumberFormatTokenize(data->format, &tokens);
00760 
00761     /*
00762      * Evaluate the XPath expression to find the value(s)
00763      */
00764     if (data->value) {
00765     amount = xsltNumberFormatGetValue(ctxt->xpathCtxt,
00766                       node,
00767                       data->value,
00768                       &number);
00769     if (amount == 1) {
00770         xsltNumberFormatInsertNumbers(data,
00771                       &number,
00772                       1,
00773                       &tokens,
00774                       output);
00775     }
00776     
00777     } else if (data->level) {
00778     
00779     if (xmlStrEqual(data->level, (const xmlChar *) "single")) {
00780         amount = xsltNumberFormatGetMultipleLevel(ctxt,
00781                               node,
00782                               data->count,
00783                               data->from,
00784                               &number,
00785                               1,
00786                               data->doc,
00787                               data->node);
00788         if (amount == 1) {
00789         xsltNumberFormatInsertNumbers(data,
00790                           &number,
00791                           1,
00792                           &tokens,
00793                           output);
00794         }
00795     } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
00796         double numarray[1024];
00797         int max = sizeof(numarray)/sizeof(numarray[0]);
00798         amount = xsltNumberFormatGetMultipleLevel(ctxt,
00799                               node,
00800                               data->count,
00801                               data->from,
00802                               numarray,
00803                               max,
00804                               data->doc,
00805                               data->node);
00806         if (amount > 0) {
00807         xsltNumberFormatInsertNumbers(data,
00808                           numarray,
00809                           amount,
00810                           &tokens,
00811                           output);
00812         }
00813     } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
00814         amount = xsltNumberFormatGetAnyLevel(ctxt,
00815                          node,
00816                          data->count,
00817                          data->from,
00818                          &number, 
00819                          data->doc,
00820                          data->node);
00821         if (amount > 0) {
00822         xsltNumberFormatInsertNumbers(data,
00823                           &number,
00824                           1,
00825                           &tokens,
00826                           output);
00827         }
00828     }
00829     }
00830     /* Insert number as text node */
00831     xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0);
00832 
00833     if (tokens.start != NULL)
00834     xmlFree(tokens.start);
00835     if (tokens.end != NULL)
00836     xmlFree(tokens.end);
00837     for (i = 0;i < tokens.nTokens;i++) {
00838     if (tokens.tokens[i].separator != NULL)
00839         xmlFree(tokens.tokens[i].separator);
00840     }
00841     
00842 XSLT_NUMBER_FORMAT_END:
00843     if (tempformat == 1) {
00844     /* The format need to be recomputed each time */
00845     data->format = NULL;
00846     }
00847     if (output != NULL)
00848     xmlBufferFree(output);
00849 }
00850 
00851 static int
00852 xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info)
00853 {
00854     int count=0;    /* will hold total length of prefix/suffix */
00855     int len;
00856 
00857     while (1) {
00858     /* 
00859      * prefix / suffix ends at end of string or at 
00860      * first 'special' character 
00861      */
00862     if (**format == 0)
00863         return count;
00864     /* if next character 'escaped' just count it */
00865     if (**format == SYMBOL_QUOTE) {
00866         if (*++(*format) == 0)
00867         return -1;
00868     }
00869     else if (IS_SPECIAL(self, *format))
00870         return count;
00871     /*
00872      * else treat percent/per-mille as special cases,
00873      * depending on whether +ve or -ve 
00874      */
00875     else {
00876         /*
00877          * for +ve prefix/suffix, allow only a 
00878          * single occurence of either 
00879          */
00880         if (xsltUTF8Charcmp(*format, self->percent) == 0) {
00881         if (info->is_multiplier_set)
00882             return -1;
00883         info->multiplier = 100;
00884         info->is_multiplier_set = TRUE;
00885         } else if (xsltUTF8Charcmp(*format, self->permille) == 0) {
00886         if (info->is_multiplier_set)
00887             return -1;
00888         info->multiplier = 1000;
00889         info->is_multiplier_set = TRUE;
00890         }
00891     }
00892     
00893     if ((len=xsltUTF8Size(*format)) < 1)
00894         return -1;
00895     count += len;
00896     *format += len;
00897     }
00898 }
00899         
00942 xmlXPathError
00943 xsltFormatNumberConversion(xsltDecimalFormatPtr self,
00944                xmlChar *format,
00945                double number,
00946                xmlChar **result)
00947 {
00948     xmlXPathError status = XPATH_EXPRESSION_OK;
00949     xmlBufferPtr buffer;
00950     xmlChar *the_format, *prefix = NULL, *suffix = NULL;
00951     xmlChar *nprefix, *nsuffix = NULL;
00952     xmlChar pchar;
00953     int     prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
00954     double  scale;
00955     int     j, len;
00956     int     self_grouping_len;
00957     xsltFormatNumberInfo format_info;
00958     /* 
00959      * delayed_multiplier allows a 'trailing' percent or
00960      * permille to be treated as suffix 
00961      */
00962     int     delayed_multiplier = 0;
00963     /* flag to show no -ve format present for -ve number */
00964     char    default_sign = 0;
00965     /* flag to show error found, should use default format */
00966     char    found_error = 0;
00967 
00968     if (xmlStrlen(format) <= 0) {
00969     xsltTransformError(NULL, NULL, NULL,
00970                 "xsltFormatNumberConversion : "
00971         "Invalid format (0-length)\n");
00972     }
00973     *result = NULL;
00974     switch (xmlXPathIsInf(number)) {
00975     case -1:
00976         if (self->minusSign == NULL)
00977         *result = xmlStrdup(BAD_CAST "-");
00978         else
00979         *result = xmlStrdup(self->minusSign);
00980         /* no-break on purpose */
00981     case 1:
00982         if ((self == NULL) || (self->infinity == NULL))
00983         *result = xmlStrcat(*result, BAD_CAST "Infinity");
00984         else
00985         *result = xmlStrcat(*result, self->infinity);
00986         return(status);
00987     default:
00988         if (xmlXPathIsNaN(number)) {
00989         if ((self == NULL) || (self->noNumber == NULL))
00990             *result = xmlStrdup(BAD_CAST "NaN");
00991         else
00992             *result = xmlStrdup(self->noNumber);
00993         return(status);
00994         }
00995     }
00996 
00997     buffer = xmlBufferCreate();
00998     if (buffer == NULL) {
00999     return XPATH_MEMORY_ERROR;
01000     }
01001 
01002     format_info.integer_hash = 0;
01003     format_info.integer_digits = 0;
01004     format_info.frac_digits = 0;
01005     format_info.frac_hash = 0;
01006     format_info.group = -1;
01007     format_info.multiplier = 1;
01008     format_info.add_decimal = FALSE;
01009     format_info.is_multiplier_set = FALSE;
01010     format_info.is_negative_pattern = FALSE;
01011 
01012     the_format = format;
01013 
01014     /*
01015      * First we process the +ve pattern to get percent / permille,
01016      * as well as main format 
01017      */
01018     prefix = the_format;
01019     prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
01020     if (prefix_length < 0) {
01021     found_error = 1;
01022     goto OUTPUT_NUMBER;
01023     }
01024 
01025     /* 
01026      * Here we process the "number" part of the format.  It gets 
01027      * a little messy because of the percent/per-mille - if that
01028      * appears at the end, it may be part of the suffix instead 
01029      * of part of the number, so the variable delayed_multiplier 
01030      * is used to handle it 
01031      */
01032     self_grouping_len = xmlStrlen(self->grouping);
01033     while ((*the_format != 0) &&
01034        (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) &&
01035        (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) {
01036     
01037     if (delayed_multiplier != 0) {
01038         format_info.multiplier = delayed_multiplier;
01039         format_info.is_multiplier_set = TRUE;
01040         delayed_multiplier = 0;
01041     }
01042     if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
01043         if (format_info.integer_digits > 0) {
01044         found_error = 1;
01045         goto OUTPUT_NUMBER;
01046         }
01047         format_info.integer_hash++;
01048         if (format_info.group >= 0)
01049         format_info.group++;
01050     } else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
01051         format_info.integer_digits++;
01052         if (format_info.group >= 0)
01053         format_info.group++;
01054     } else if ((self_grouping_len > 0) &&
01055         (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) {
01056         /* Reset group count */
01057         format_info.group = 0;
01058         the_format += self_grouping_len;
01059         continue;
01060     } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
01061         if (format_info.is_multiplier_set) {
01062         found_error = 1;
01063         goto OUTPUT_NUMBER;
01064         }
01065         delayed_multiplier = 100;
01066     } else  if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
01067         if (format_info.is_multiplier_set) {
01068         found_error = 1;
01069         goto OUTPUT_NUMBER;
01070         }
01071         delayed_multiplier = 1000;
01072     } else
01073         break; /* while */
01074     
01075     if ((len=xsltUTF8Size(the_format)) < 1) {
01076         found_error = 1;
01077         goto OUTPUT_NUMBER;
01078     }
01079     the_format += len;
01080 
01081     }
01082 
01083     /* We have finished the integer part, now work on fraction */
01084     if (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) {
01085         format_info.add_decimal = TRUE;
01086     the_format += xsltUTF8Size(the_format); /* Skip over the decimal */
01087     }
01088     
01089     while (*the_format != 0) {
01090     
01091     if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
01092         if (format_info.frac_hash != 0) {
01093         found_error = 1;
01094         goto OUTPUT_NUMBER;
01095         }
01096         format_info.frac_digits++;
01097     } else if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
01098         format_info.frac_hash++;
01099     } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
01100         if (format_info.is_multiplier_set) {
01101         found_error = 1;
01102         goto OUTPUT_NUMBER;
01103         }
01104         delayed_multiplier = 100;
01105         if ((len = xsltUTF8Size(the_format)) < 1) {
01106             found_error = 1;
01107         goto OUTPUT_NUMBER;
01108         }
01109         the_format += len;
01110         continue; /* while */
01111     } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
01112         if (format_info.is_multiplier_set) {
01113         found_error = 1;
01114         goto OUTPUT_NUMBER;
01115         }
01116         delayed_multiplier = 1000;
01117         if  ((len = xsltUTF8Size(the_format)) < 1) {
01118             found_error = 1;
01119         goto OUTPUT_NUMBER;
01120         }
01121         the_format += len;
01122         continue; /* while */
01123     } else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
01124         break; /* while */
01125     }
01126     if ((len = xsltUTF8Size(the_format)) < 1) {
01127         found_error = 1;
01128         goto OUTPUT_NUMBER;
01129     }
01130     the_format += len;
01131     if (delayed_multiplier != 0) {
01132         format_info.multiplier = delayed_multiplier;
01133         delayed_multiplier = 0;
01134         format_info.is_multiplier_set = TRUE;
01135     }
01136     }
01137 
01138     /* 
01139      * If delayed_multiplier is set after processing the 
01140      * "number" part, should be in suffix 
01141      */
01142     if (delayed_multiplier != 0) {
01143     the_format -= len;
01144     delayed_multiplier = 0;
01145     }
01146 
01147     suffix = the_format;
01148     suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
01149     if ( (suffix_length < 0) ||
01150      ((*the_format != 0) && 
01151       (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) {
01152     found_error = 1;
01153     goto OUTPUT_NUMBER;
01154     }
01155 
01156     /*
01157      * We have processed the +ve prefix, number part and +ve suffix.
01158      * If the number is -ve, we must substitute the -ve prefix / suffix
01159      */
01160     if (number < 0) {
01161         /*
01162      * Note that j is the number of UTF8 chars before the separator,
01163      * not the number of bytes! (bug 151975)
01164      */
01165         j =  xmlUTF8Strloc(format, self->patternSeparator);
01166     if (j < 0) {
01167     /* No -ve pattern present, so use default signing */
01168         default_sign = 1;
01169     }
01170     else {
01171         /* Skip over pattern separator (accounting for UTF8) */
01172         the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1);
01173         /* 
01174          * Flag changes interpretation of percent/permille 
01175          * in -ve pattern 
01176          */
01177         format_info.is_negative_pattern = TRUE;
01178         format_info.is_multiplier_set = FALSE;
01179 
01180         /* First do the -ve prefix */
01181         nprefix = the_format;
01182         nprefix_length = xsltFormatNumberPreSuffix(self, 
01183                         &the_format, &format_info);
01184         if (nprefix_length<0) {
01185         found_error = 1;
01186         goto OUTPUT_NUMBER;
01187         }
01188 
01189         while (*the_format != 0) {
01190         if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) ||
01191              (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) {
01192             if (format_info.is_multiplier_set) {
01193             found_error = 1;
01194             goto OUTPUT_NUMBER;
01195             }
01196             format_info.is_multiplier_set = TRUE;
01197             delayed_multiplier = 1;
01198         }
01199         else if (IS_SPECIAL(self, the_format))
01200             delayed_multiplier = 0;
01201         else
01202             break; /* while */
01203         if ((len = xsltUTF8Size(the_format)) < 1) {
01204             found_error = 1;
01205             goto OUTPUT_NUMBER;
01206         }
01207         the_format += len;
01208         }
01209         if (delayed_multiplier != 0) {
01210         format_info.is_multiplier_set = FALSE;
01211         the_format -= len;
01212         }
01213 
01214         /* Finally do the -ve suffix */
01215         if (*the_format != 0) {
01216         nsuffix = the_format;
01217         nsuffix_length = xsltFormatNumberPreSuffix(self, 
01218                     &the_format, &format_info);
01219         if (nsuffix_length < 0) {
01220             found_error = 1;
01221             goto OUTPUT_NUMBER;
01222         }
01223         }
01224         else
01225         nsuffix_length = 0;
01226         if (*the_format != 0) {
01227         found_error = 1;
01228         goto OUTPUT_NUMBER;
01229         }
01230         /*
01231          * Here's another Java peculiarity:
01232          * if -ve prefix/suffix == +ve ones, discard & use default
01233          */
01234         if ((nprefix_length != prefix_length) ||
01235             (nsuffix_length != suffix_length) ||
01236         ((nprefix_length > 0) && 
01237          (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) ||
01238         ((nsuffix_length > 0) && 
01239          (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) {
01240         prefix = nprefix;
01241         prefix_length = nprefix_length;
01242         suffix = nsuffix;
01243         suffix_length = nsuffix_length;
01244         } /* else {
01245         default_sign = 1;
01246         }
01247         */
01248     }
01249     }
01250 
01251 OUTPUT_NUMBER:
01252     if (found_error != 0) {
01253     xsltTransformError(NULL, NULL, NULL,
01254                 "xsltFormatNumberConversion : "
01255         "error in format string '%s', using default\n", format);
01256     default_sign = (number < 0.0) ? 1 : 0;
01257     prefix_length = suffix_length = 0;
01258     format_info.integer_hash = 0;
01259     format_info.integer_digits = 1;
01260     format_info.frac_digits = 1;
01261     format_info.frac_hash = 4;
01262     format_info.group = -1;
01263     format_info.multiplier = 1;
01264     format_info.add_decimal = TRUE;
01265     }
01266 
01267     /* Ready to output our number.  First see if "default sign" is required */
01268     if (default_sign != 0)
01269     xmlBufferAdd(buffer, self->minusSign, xsltUTF8Size(self->minusSign));
01270 
01271     /* Put the prefix into the buffer */
01272     for (j = 0; j < prefix_length; j++) {
01273     if ((pchar = *prefix++) == SYMBOL_QUOTE) {
01274         len = xsltUTF8Size(prefix);
01275         xmlBufferAdd(buffer, prefix, len);
01276         prefix += len;
01277         j += len - 1;   /* length of symbol less length of quote */
01278     } else
01279         xmlBufferAdd(buffer, &pchar, 1);
01280     }
01281 
01282     /* Next do the integer part of the number */
01283     number = fabs(number) * (double)format_info.multiplier;
01284     scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
01285     number = floor((scale * number + 0.5)) / scale;
01286     if ((self->grouping != NULL) && 
01287         (self->grouping[0] != 0)) {
01288     
01289     len = xmlStrlen(self->grouping);
01290     pchar = xsltGetUTF8Char(self->grouping, &len);
01291     xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
01292                 format_info.integer_digits,
01293                 format_info.group,
01294                 pchar, len);
01295     } else
01296     xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
01297                 format_info.integer_digits,
01298                 format_info.group,
01299                 ',', 1);
01300 
01301     /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */
01302     if ((format_info.integer_digits + format_info.integer_hash +
01303      format_info.frac_digits == 0) && (format_info.frac_hash > 0)) {
01304         ++format_info.frac_digits;
01305     --format_info.frac_hash;
01306     }
01307 
01308     /* Add leading zero, if required */
01309     if ((floor(number) == 0) &&
01310     (format_info.integer_digits + format_info.frac_digits == 0)) {
01311         xmlBufferAdd(buffer, self->zeroDigit, xsltUTF8Size(self->zeroDigit));
01312     }
01313 
01314     /* Next the fractional part, if required */
01315     if (format_info.frac_digits + format_info.frac_hash == 0) {
01316         if (format_info.add_decimal)
01317         xmlBufferAdd(buffer, self->decimalPoint, 
01318                  xsltUTF8Size(self->decimalPoint));
01319     }
01320     else {
01321       number -= floor(number);
01322     if ((number != 0) || (format_info.frac_digits != 0)) {
01323         xmlBufferAdd(buffer, self->decimalPoint,
01324                  xsltUTF8Size(self->decimalPoint));
01325         number = floor(scale * number + 0.5);
01326         for (j = format_info.frac_hash; j > 0; j--) {
01327         if (fmod(number, 10.0) >= 1.0)
01328             break; /* for */
01329         number /= 10.0;
01330         }
01331         xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
01332                 format_info.frac_digits + j,
01333                 0, 0, 0);
01334     }
01335     }
01336     /* Put the suffix into the buffer */
01337     for (j = 0; j < suffix_length; j++) {
01338     if ((pchar = *suffix++) == SYMBOL_QUOTE) {
01339             len = xsltUTF8Size(suffix);
01340         xmlBufferAdd(buffer, suffix, len);
01341         suffix += len;
01342         j += len - 1;   /* length of symbol less length of escape */
01343     } else
01344         xmlBufferAdd(buffer, &pchar, 1);
01345     }
01346 
01347     *result = xmlStrdup(xmlBufferContent(buffer));
01348     xmlBufferFree(buffer);
01349     return status;
01350 }
01351 

Generated on Sun May 27 2012 04:19:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.