numbers.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364
  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. #define IN_LIBXSLT
  13. #include "libxslt.h"
  14. #include <math.h>
  15. #include <limits.h>
  16. #include <float.h>
  17. #include <string.h>
  18. #include <libxml/xmlmemory.h>
  19. #include <libxml/parserInternals.h>
  20. #include <libxml/xpath.h>
  21. #include <libxml/xpathInternals.h>
  22. #include <libxml/encoding.h>
  23. #include "xsltutils.h"
  24. #include "pattern.h"
  25. #include "templates.h"
  26. #include "transform.h"
  27. #include "numbersInternals.h"
  28. #ifndef FALSE
  29. # define FALSE (0 == 1)
  30. # define TRUE (1 == 1)
  31. #endif
  32. #define SYMBOL_QUOTE ((xmlChar)'\'')
  33. #define DEFAULT_TOKEN '0'
  34. #define DEFAULT_SEPARATOR "."
  35. #define MAX_TOKENS 1024
  36. typedef struct _xsltFormatToken xsltFormatToken;
  37. typedef xsltFormatToken *xsltFormatTokenPtr;
  38. struct _xsltFormatToken {
  39. xmlChar *separator;
  40. int token;
  41. int width;
  42. };
  43. typedef struct _xsltFormat xsltFormat;
  44. typedef xsltFormat *xsltFormatPtr;
  45. struct _xsltFormat {
  46. xmlChar *start;
  47. xsltFormatToken tokens[MAX_TOKENS];
  48. int nTokens;
  49. xmlChar *end;
  50. };
  51. static char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  52. static char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz";
  53. static xsltFormatToken default_token;
  54. /*
  55. * **** Start temp insert ****
  56. *
  57. * The following routine xsltUTF8Charcmp will be replaced with calls to
  58. * the corresponding libxml routine at a later date (when other
  59. * inter-library dependencies require it).
  60. */
  61. /**
  62. * xsltUTF8Charcmp
  63. * @utf1: pointer to first UTF8 char
  64. * @utf2: pointer to second UTF8 char
  65. *
  66. * returns result of comparing the two UCS4 values
  67. * as with xmlStrncmp
  68. */
  69. static int
  70. xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) {
  71. int len = xmlUTF8Strsize(utf1, 1);
  72. if (len < 1)
  73. return -1;
  74. if (utf1 == NULL ) {
  75. if (utf2 == NULL)
  76. return 0;
  77. return -1;
  78. }
  79. return xmlStrncmp(utf1, utf2, len);
  80. }
  81. /***** Stop temp insert *****/
  82. /************************************************************************
  83. * *
  84. * Utility functions *
  85. * *
  86. ************************************************************************/
  87. #define IS_SPECIAL(self,letter) \
  88. ((xsltUTF8Charcmp((letter), (self)->zeroDigit) == 0) || \
  89. (xsltUTF8Charcmp((letter), (self)->digit) == 0) || \
  90. (xsltUTF8Charcmp((letter), (self)->decimalPoint) == 0) || \
  91. (xsltUTF8Charcmp((letter), (self)->grouping) == 0) || \
  92. (xsltUTF8Charcmp((letter), (self)->patternSeparator) == 0))
  93. #define IS_DIGIT_ZERO(x) xsltIsDigitZero(x)
  94. #define IS_DIGIT_ONE(x) xsltIsDigitZero((x)-1)
  95. static int
  96. xsltIsDigitZero(unsigned int ch)
  97. {
  98. /*
  99. * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
  100. *
  101. * There a many more digit ranges in newer Unicode versions. These
  102. * are only the zeros that match Digit in XML 1.0 (IS_DIGIT macro).
  103. */
  104. switch (ch) {
  105. case 0x0030: case 0x0660: case 0x06F0: case 0x0966:
  106. case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66:
  107. case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50:
  108. case 0x0ED0: case 0x0F20:
  109. return TRUE;
  110. default:
  111. return FALSE;
  112. }
  113. }
  114. static void
  115. xsltNumberFormatDecimal(xmlBufferPtr buffer,
  116. double number,
  117. int digit_zero,
  118. int width,
  119. int digitsPerGroup,
  120. int groupingCharacter,
  121. int groupingCharacterLen)
  122. {
  123. /*
  124. * This used to be
  125. * xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 4];
  126. * which would be length 68 on x86 arch. It was changed to be a longer,
  127. * fixed length in order to try to cater for (reasonable) UTF8
  128. * separators and numeric characters. The max UTF8 char size will be
  129. * 6 or less, so the value used [500] should be *much* larger than needed
  130. */
  131. xmlChar temp_string[500];
  132. xmlChar *pointer;
  133. xmlChar temp_char[6];
  134. int i;
  135. int val;
  136. int len;
  137. /* Build buffer from back */
  138. pointer = &temp_string[sizeof(temp_string)] - 1; /* last char */
  139. *pointer = 0;
  140. i = 0;
  141. while (pointer > temp_string) {
  142. if ((i >= width) && (fabs(number) < 1.0))
  143. break; /* for */
  144. if ((i > 0) && (groupingCharacter != 0) &&
  145. (digitsPerGroup > 0) &&
  146. ((i % digitsPerGroup) == 0)) {
  147. if (pointer - groupingCharacterLen < temp_string) {
  148. i = -1; /* flag error */
  149. break;
  150. }
  151. pointer -= groupingCharacterLen;
  152. xmlCopyCharMultiByte(pointer, groupingCharacter);
  153. }
  154. val = digit_zero + (int)fmod(number, 10.0);
  155. if (val < 0x80) { /* shortcut if ASCII */
  156. if (pointer <= temp_string) { /* Check enough room */
  157. i = -1;
  158. break;
  159. }
  160. *(--pointer) = (xmlChar)val;
  161. }
  162. else {
  163. /*
  164. * Here we have a multibyte character. It's a little messy,
  165. * because until we generate the char we don't know how long
  166. * it is. So, we generate it into the buffer temp_char, then
  167. * copy from there into temp_string.
  168. */
  169. len = xmlCopyCharMultiByte(temp_char, val);
  170. if ( (pointer - len) < temp_string ) {
  171. i = -1;
  172. break;
  173. }
  174. pointer -= len;
  175. memcpy(pointer, temp_char, len);
  176. }
  177. number /= 10.0;
  178. ++i;
  179. }
  180. if (i < 0)
  181. xsltGenericError(xsltGenericErrorContext,
  182. "xsltNumberFormatDecimal: Internal buffer size exceeded\n");
  183. xmlBufferCat(buffer, pointer);
  184. }
  185. static void
  186. xsltNumberFormatAlpha(xsltNumberDataPtr data,
  187. xmlBufferPtr buffer,
  188. double number,
  189. int is_upper)
  190. {
  191. char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1];
  192. char *pointer;
  193. int i;
  194. char *alpha_list;
  195. double alpha_size = (double)(sizeof(alpha_upper_list) - 1);
  196. /*
  197. * XSLT 1.0 isn't clear on how to handle zero, but XSLT 2.0 says:
  198. *
  199. * For all format tokens other than the first kind above (one that
  200. * consists of decimal digits), there may be implementation-defined
  201. * lower and upper bounds on the range of numbers that can be
  202. * formatted using this format token; indeed, for some numbering
  203. * sequences there may be intrinsic limits. [...] Numbers that fall
  204. * outside this range must be formatted using the format token 1.
  205. *
  206. * The "a" token has an intrinsic lower limit of 1.
  207. */
  208. if (number < 1.0) {
  209. xsltNumberFormatDecimal(buffer, number, '0', 1,
  210. data->digitsPerGroup,
  211. data->groupingCharacter,
  212. data->groupingCharacterLen);
  213. return;
  214. }
  215. /* Build buffer from back */
  216. pointer = &temp_string[sizeof(temp_string)];
  217. *(--pointer) = 0;
  218. alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list;
  219. for (i = 1; i < (int)sizeof(temp_string); i++) {
  220. number--;
  221. *(--pointer) = alpha_list[((int)fmod(number, alpha_size))];
  222. number /= alpha_size;
  223. if (number < 1.0)
  224. break; /* for */
  225. }
  226. xmlBufferCCat(buffer, pointer);
  227. }
  228. static void
  229. xsltNumberFormatRoman(xsltNumberDataPtr data,
  230. xmlBufferPtr buffer,
  231. double number,
  232. int is_upper)
  233. {
  234. /*
  235. * See discussion in xsltNumberFormatAlpha. Also use a reasonable upper
  236. * bound to avoid denial of service.
  237. */
  238. if (number < 1.0 || number > 5000.0) {
  239. xsltNumberFormatDecimal(buffer, number, '0', 1,
  240. data->digitsPerGroup,
  241. data->groupingCharacter,
  242. data->groupingCharacterLen);
  243. return;
  244. }
  245. /*
  246. * Based on an example by Jim Walsh
  247. */
  248. while (number >= 1000.0) {
  249. xmlBufferCCat(buffer, (is_upper) ? "M" : "m");
  250. number -= 1000.0;
  251. }
  252. if (number >= 900.0) {
  253. xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm");
  254. number -= 900.0;
  255. }
  256. while (number >= 500.0) {
  257. xmlBufferCCat(buffer, (is_upper) ? "D" : "d");
  258. number -= 500.0;
  259. }
  260. if (number >= 400.0) {
  261. xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd");
  262. number -= 400.0;
  263. }
  264. while (number >= 100.0) {
  265. xmlBufferCCat(buffer, (is_upper) ? "C" : "c");
  266. number -= 100.0;
  267. }
  268. if (number >= 90.0) {
  269. xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc");
  270. number -= 90.0;
  271. }
  272. while (number >= 50.0) {
  273. xmlBufferCCat(buffer, (is_upper) ? "L" : "l");
  274. number -= 50.0;
  275. }
  276. if (number >= 40.0) {
  277. xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl");
  278. number -= 40.0;
  279. }
  280. while (number >= 10.0) {
  281. xmlBufferCCat(buffer, (is_upper) ? "X" : "x");
  282. number -= 10.0;
  283. }
  284. if (number >= 9.0) {
  285. xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix");
  286. number -= 9.0;
  287. }
  288. while (number >= 5.0) {
  289. xmlBufferCCat(buffer, (is_upper) ? "V" : "v");
  290. number -= 5.0;
  291. }
  292. if (number >= 4.0) {
  293. xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv");
  294. number -= 4.0;
  295. }
  296. while (number >= 1.0) {
  297. xmlBufferCCat(buffer, (is_upper) ? "I" : "i");
  298. number--;
  299. }
  300. }
  301. static void
  302. xsltNumberFormatTokenize(const xmlChar *format,
  303. xsltFormatPtr tokens)
  304. {
  305. int ix = 0;
  306. int j;
  307. int val;
  308. int len;
  309. default_token.token = DEFAULT_TOKEN;
  310. default_token.width = 1;
  311. default_token.separator = BAD_CAST(DEFAULT_SEPARATOR);
  312. tokens->start = NULL;
  313. tokens->tokens[0].separator = NULL;
  314. tokens->end = NULL;
  315. /*
  316. * Insert initial non-alphanumeric token.
  317. * There is always such a token in the list, even if NULL
  318. */
  319. while (! (IS_LETTER(val=xmlStringCurrentChar(NULL, format+ix, &len)) ||
  320. IS_DIGIT(val)) ) {
  321. if (format[ix] == 0) /* if end of format string */
  322. break; /* while */
  323. ix += len;
  324. }
  325. if (ix > 0)
  326. tokens->start = xmlStrndup(format, ix);
  327. for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS;
  328. tokens->nTokens++) {
  329. if (format[ix] == 0)
  330. break; /* for */
  331. /*
  332. * separator has already been parsed (except for the first
  333. * number) in tokens->end, recover it.
  334. */
  335. if (tokens->nTokens > 0) {
  336. tokens->tokens[tokens->nTokens].separator = tokens->end;
  337. tokens->end = NULL;
  338. }
  339. val = xmlStringCurrentChar(NULL, format+ix, &len);
  340. if (IS_DIGIT_ONE(val) ||
  341. IS_DIGIT_ZERO(val)) {
  342. tokens->tokens[tokens->nTokens].width = 1;
  343. while (IS_DIGIT_ZERO(val)) {
  344. tokens->tokens[tokens->nTokens].width++;
  345. ix += len;
  346. val = xmlStringCurrentChar(NULL, format+ix, &len);
  347. }
  348. if (IS_DIGIT_ONE(val)) {
  349. tokens->tokens[tokens->nTokens].token = val - 1;
  350. ix += len;
  351. val = xmlStringCurrentChar(NULL, format+ix, &len);
  352. } else {
  353. tokens->tokens[tokens->nTokens].token = '0';
  354. tokens->tokens[tokens->nTokens].width = 1;
  355. }
  356. } else if ( (val == 'A') ||
  357. (val == 'a') ||
  358. (val == 'I') ||
  359. (val == 'i') ) {
  360. tokens->tokens[tokens->nTokens].token = val;
  361. ix += len;
  362. val = xmlStringCurrentChar(NULL, format+ix, &len);
  363. } else {
  364. /* XSLT section 7.7
  365. * "Any other format token indicates a numbering sequence
  366. * that starts with that token. If an implementation does
  367. * not support a numbering sequence that starts with that
  368. * token, it must use a format token of 1."
  369. */
  370. tokens->tokens[tokens->nTokens].token = '0';
  371. tokens->tokens[tokens->nTokens].width = 1;
  372. }
  373. /*
  374. * Skip over remaining alphanumeric characters from the Nd
  375. * (Number, decimal digit), Nl (Number, letter), No (Number,
  376. * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt
  377. * (Letters, titlecase), Lm (Letters, modifiers), and Lo
  378. * (Letters, other (uncased)) Unicode categories. This happens
  379. * to correspond to the Letter and Digit classes from XML (and
  380. * one wonders why XSLT doesn't refer to these instead).
  381. */
  382. while (IS_LETTER(val) || IS_DIGIT(val)) {
  383. ix += len;
  384. val = xmlStringCurrentChar(NULL, format+ix, &len);
  385. }
  386. /*
  387. * Insert temporary non-alphanumeric final tooken.
  388. */
  389. j = ix;
  390. while (! (IS_LETTER(val) || IS_DIGIT(val))) {
  391. if (val == 0)
  392. break; /* while */
  393. ix += len;
  394. val = xmlStringCurrentChar(NULL, format+ix, &len);
  395. }
  396. if (ix > j)
  397. tokens->end = xmlStrndup(&format[j], ix - j);
  398. }
  399. }
  400. static void
  401. xsltNumberFormatInsertNumbers(xsltNumberDataPtr data,
  402. double *numbers,
  403. int numbers_max,
  404. xsltFormatPtr tokens,
  405. xmlBufferPtr buffer)
  406. {
  407. int i = 0;
  408. double number;
  409. xsltFormatTokenPtr token;
  410. /*
  411. * Handle initial non-alphanumeric token
  412. */
  413. if (tokens->start != NULL)
  414. xmlBufferCat(buffer, tokens->start);
  415. for (i = 0; i < numbers_max; i++) {
  416. /* Insert number */
  417. number = numbers[(numbers_max - 1) - i];
  418. /* Round to nearest like XSLT 2.0 */
  419. number = floor(number + 0.5);
  420. /*
  421. * XSLT 1.0 isn't clear on how to handle negative numbers, but XSLT
  422. * 2.0 says:
  423. *
  424. * It is a non-recoverable dynamic error if any undiscarded item
  425. * in the atomized sequence supplied as the value of the value
  426. * attribute of xsl:number cannot be converted to an integer, or
  427. * if the resulting integer is less than 0 (zero).
  428. */
  429. if (number < 0.0) {
  430. xsltTransformError(NULL, NULL, NULL,
  431. "xsl-number : negative value\n");
  432. /* Recover by treating negative values as zero. */
  433. number = 0.0;
  434. }
  435. if (i < tokens->nTokens) {
  436. /*
  437. * The "n"th format token will be used to format the "n"th
  438. * number in the list
  439. */
  440. token = &(tokens->tokens[i]);
  441. } else if (tokens->nTokens > 0) {
  442. /*
  443. * If there are more numbers than format tokens, then the
  444. * last format token will be used to format the remaining
  445. * numbers.
  446. */
  447. token = &(tokens->tokens[tokens->nTokens - 1]);
  448. } else {
  449. /*
  450. * If there are no format tokens, then a format token of
  451. * 1 is used to format all numbers.
  452. */
  453. token = &default_token;
  454. }
  455. /* Print separator, except for the first number */
  456. if (i > 0) {
  457. if (token->separator != NULL)
  458. xmlBufferCat(buffer, token->separator);
  459. else
  460. xmlBufferCCat(buffer, DEFAULT_SEPARATOR);
  461. }
  462. switch (xmlXPathIsInf(number)) {
  463. case -1:
  464. xmlBufferCCat(buffer, "-Infinity");
  465. break;
  466. case 1:
  467. xmlBufferCCat(buffer, "Infinity");
  468. break;
  469. default:
  470. if (xmlXPathIsNaN(number)) {
  471. xmlBufferCCat(buffer, "NaN");
  472. } else {
  473. switch (token->token) {
  474. case 'A':
  475. xsltNumberFormatAlpha(data, buffer, number, TRUE);
  476. break;
  477. case 'a':
  478. xsltNumberFormatAlpha(data, buffer, number, FALSE);
  479. break;
  480. case 'I':
  481. xsltNumberFormatRoman(data, buffer, number, TRUE);
  482. break;
  483. case 'i':
  484. xsltNumberFormatRoman(data, buffer, number, FALSE);
  485. break;
  486. default:
  487. if (IS_DIGIT_ZERO(token->token)) {
  488. xsltNumberFormatDecimal(buffer,
  489. number,
  490. token->token,
  491. token->width,
  492. data->digitsPerGroup,
  493. data->groupingCharacter,
  494. data->groupingCharacterLen);
  495. }
  496. break;
  497. }
  498. }
  499. }
  500. }
  501. /*
  502. * Handle final non-alphanumeric token
  503. */
  504. if (tokens->end != NULL)
  505. xmlBufferCat(buffer, tokens->end);
  506. }
  507. static int
  508. xsltTestCompMatchCount(xsltTransformContextPtr context,
  509. xmlNodePtr node,
  510. xsltCompMatchPtr countPat,
  511. xmlNodePtr cur)
  512. {
  513. if (countPat != NULL) {
  514. return xsltTestCompMatchList(context, node, countPat);
  515. }
  516. else {
  517. /*
  518. * 7.7 Numbering
  519. *
  520. * If count attribute is not specified, then it defaults to the
  521. * pattern that matches any node with the same node type as the
  522. * current node and, if the current node has an expanded-name, with
  523. * the same expanded-name as the current node.
  524. */
  525. if (node->type != cur->type)
  526. return 0;
  527. if (node->type == XML_NAMESPACE_DECL)
  528. /*
  529. * Namespace nodes have no preceding siblings and no parents
  530. * that are namespace nodes. This means that node == cur.
  531. */
  532. return 1;
  533. /* TODO: Skip node types without expanded names like text nodes. */
  534. if (!xmlStrEqual(node->name, cur->name))
  535. return 0;
  536. if (node->ns == cur->ns)
  537. return 1;
  538. if ((node->ns == NULL) || (cur->ns == NULL))
  539. return 0;
  540. return (xmlStrEqual(node->ns->href, cur->ns->href));
  541. }
  542. }
  543. static int
  544. xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context,
  545. xmlNodePtr node,
  546. xsltCompMatchPtr countPat,
  547. xsltCompMatchPtr fromPat,
  548. double *array)
  549. {
  550. int amount = 0;
  551. int cnt = 0;
  552. xmlNodePtr cur = node;
  553. while (cur != NULL) {
  554. /* process current node */
  555. if (xsltTestCompMatchCount(context, cur, countPat, node))
  556. cnt++;
  557. if ((fromPat != NULL) &&
  558. xsltTestCompMatchList(context, cur, fromPat)) {
  559. break; /* while */
  560. }
  561. /* Skip to next preceding or ancestor */
  562. if ((cur->type == XML_DOCUMENT_NODE) ||
  563. #ifdef LIBXML_DOCB_ENABLED
  564. (cur->type == XML_DOCB_DOCUMENT_NODE) ||
  565. #endif
  566. (cur->type == XML_HTML_DOCUMENT_NODE))
  567. break; /* while */
  568. if (cur->type == XML_NAMESPACE_DECL) {
  569. /*
  570. * The XPath module stores the parent of a namespace node in
  571. * the ns->next field.
  572. */
  573. cur = (xmlNodePtr) ((xmlNsPtr) cur)->next;
  574. } else if (cur->type == XML_ATTRIBUTE_NODE) {
  575. cur = cur->parent;
  576. } else {
  577. while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) ||
  578. (cur->prev->type == XML_XINCLUDE_START) ||
  579. (cur->prev->type == XML_XINCLUDE_END)))
  580. cur = cur->prev;
  581. if (cur->prev != NULL) {
  582. for (cur = cur->prev; cur->last != NULL; cur = cur->last);
  583. } else {
  584. cur = cur->parent;
  585. }
  586. }
  587. }
  588. array[amount++] = (double) cnt;
  589. return(amount);
  590. }
  591. static int
  592. xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context,
  593. xmlNodePtr node,
  594. xsltCompMatchPtr countPat,
  595. xsltCompMatchPtr fromPat,
  596. double *array,
  597. int max)
  598. {
  599. int amount = 0;
  600. int cnt;
  601. xmlNodePtr oldCtxtNode;
  602. xmlNodePtr ancestor;
  603. xmlNodePtr preceding;
  604. xmlXPathParserContextPtr parser;
  605. oldCtxtNode = context->xpathCtxt->node;
  606. parser = xmlXPathNewParserContext(NULL, context->xpathCtxt);
  607. if (parser) {
  608. /* ancestor-or-self::*[count] */
  609. ancestor = node;
  610. while ((ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE)) {
  611. if ((fromPat != NULL) &&
  612. xsltTestCompMatchList(context, ancestor, fromPat))
  613. break; /* for */
  614. /*
  615. * The xmlXPathNext* iterators require that the context node is
  616. * set to the start node. Calls to xsltTestCompMatch* may also
  617. * leave the context node in an undefined state, so make sure
  618. * that the context node is reset before each iterator invocation.
  619. */
  620. if (xsltTestCompMatchCount(context, ancestor, countPat, node)) {
  621. /* count(preceding-sibling::*) */
  622. cnt = 1;
  623. context->xpathCtxt->node = ancestor;
  624. preceding = xmlXPathNextPrecedingSibling(parser, ancestor);
  625. while (preceding != NULL) {
  626. if (xsltTestCompMatchCount(context, preceding, countPat,
  627. node))
  628. cnt++;
  629. context->xpathCtxt->node = ancestor;
  630. preceding =
  631. xmlXPathNextPrecedingSibling(parser, preceding);
  632. }
  633. array[amount++] = (double)cnt;
  634. if (amount >= max)
  635. break; /* for */
  636. }
  637. context->xpathCtxt->node = node;
  638. ancestor = xmlXPathNextAncestor(parser, ancestor);
  639. }
  640. xmlXPathFreeParserContext(parser);
  641. }
  642. context->xpathCtxt->node = oldCtxtNode;
  643. return amount;
  644. }
  645. static int
  646. xsltNumberFormatGetValue(xmlXPathContextPtr context,
  647. xmlNodePtr node,
  648. const xmlChar *value,
  649. double *number)
  650. {
  651. int amount = 0;
  652. xmlBufferPtr pattern;
  653. xmlXPathObjectPtr obj;
  654. pattern = xmlBufferCreate();
  655. if (pattern != NULL) {
  656. xmlBufferCCat(pattern, "number(");
  657. xmlBufferCat(pattern, value);
  658. xmlBufferCCat(pattern, ")");
  659. context->node = node;
  660. obj = xmlXPathEvalExpression(xmlBufferContent(pattern),
  661. context);
  662. if (obj != NULL) {
  663. *number = obj->floatval;
  664. amount++;
  665. xmlXPathFreeObject(obj);
  666. }
  667. xmlBufferFree(pattern);
  668. }
  669. return amount;
  670. }
  671. /**
  672. * xsltNumberFormat:
  673. * @ctxt: the XSLT transformation context
  674. * @data: the formatting information
  675. * @node: the data to format
  676. *
  677. * Convert one number.
  678. */
  679. void
  680. xsltNumberFormat(xsltTransformContextPtr ctxt,
  681. xsltNumberDataPtr data,
  682. xmlNodePtr node)
  683. {
  684. xmlBufferPtr output = NULL;
  685. int amount, i;
  686. double number;
  687. xsltFormat tokens;
  688. if (data->format != NULL) {
  689. xsltNumberFormatTokenize(data->format, &tokens);
  690. }
  691. else {
  692. xmlChar *format;
  693. /* The format needs to be recomputed each time */
  694. if (data->has_format == 0)
  695. return;
  696. format = xsltEvalAttrValueTemplate(ctxt, data->node,
  697. (const xmlChar *) "format",
  698. XSLT_NAMESPACE);
  699. if (format == NULL)
  700. return;
  701. xsltNumberFormatTokenize(format, &tokens);
  702. xmlFree(format);
  703. }
  704. output = xmlBufferCreate();
  705. if (output == NULL)
  706. goto XSLT_NUMBER_FORMAT_END;
  707. /*
  708. * Evaluate the XPath expression to find the value(s)
  709. */
  710. if (data->value) {
  711. amount = xsltNumberFormatGetValue(ctxt->xpathCtxt,
  712. node,
  713. data->value,
  714. &number);
  715. if (amount == 1) {
  716. xsltNumberFormatInsertNumbers(data,
  717. &number,
  718. 1,
  719. &tokens,
  720. output);
  721. }
  722. } else if (data->level) {
  723. if (xmlStrEqual(data->level, (const xmlChar *) "single")) {
  724. amount = xsltNumberFormatGetMultipleLevel(ctxt,
  725. node,
  726. data->countPat,
  727. data->fromPat,
  728. &number,
  729. 1);
  730. if (amount == 1) {
  731. xsltNumberFormatInsertNumbers(data,
  732. &number,
  733. 1,
  734. &tokens,
  735. output);
  736. }
  737. } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) {
  738. double numarray[1024];
  739. int max = sizeof(numarray)/sizeof(numarray[0]);
  740. amount = xsltNumberFormatGetMultipleLevel(ctxt,
  741. node,
  742. data->countPat,
  743. data->fromPat,
  744. numarray,
  745. max);
  746. if (amount > 0) {
  747. xsltNumberFormatInsertNumbers(data,
  748. numarray,
  749. amount,
  750. &tokens,
  751. output);
  752. }
  753. } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) {
  754. amount = xsltNumberFormatGetAnyLevel(ctxt,
  755. node,
  756. data->countPat,
  757. data->fromPat,
  758. &number);
  759. if (amount > 0) {
  760. xsltNumberFormatInsertNumbers(data,
  761. &number,
  762. 1,
  763. &tokens,
  764. output);
  765. }
  766. }
  767. /*
  768. * Unlike `match` patterns, `count` and `from` patterns can contain
  769. * variable references, so we have to clear the pattern match
  770. * cache if the "direct" matching algorithm was used.
  771. */
  772. if (data->countPat != NULL)
  773. xsltCompMatchClearCache(ctxt, data->countPat);
  774. if (data->fromPat != NULL)
  775. xsltCompMatchClearCache(ctxt, data->fromPat);
  776. }
  777. /* Insert number as text node */
  778. xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0);
  779. xmlBufferFree(output);
  780. XSLT_NUMBER_FORMAT_END:
  781. if (tokens.start != NULL)
  782. xmlFree(tokens.start);
  783. if (tokens.end != NULL)
  784. xmlFree(tokens.end);
  785. for (i = 0;i < tokens.nTokens;i++) {
  786. if (tokens.tokens[i].separator != NULL)
  787. xmlFree(tokens.tokens[i].separator);
  788. }
  789. }
  790. static int
  791. xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info)
  792. {
  793. /* will hold total length of prefix/suffix without quote characters */
  794. int count=0;
  795. int len;
  796. while (1) {
  797. /*
  798. * prefix / suffix ends at end of string or at
  799. * first 'special' character
  800. */
  801. if (**format == 0)
  802. return count;
  803. /* if next character 'escaped' just count it */
  804. if (**format == SYMBOL_QUOTE) {
  805. if (*++(*format) == 0)
  806. return -1;
  807. }
  808. else if (IS_SPECIAL(self, *format))
  809. return count;
  810. /*
  811. * else treat percent/per-mille as special cases,
  812. * depending on whether +ve or -ve
  813. */
  814. else {
  815. /*
  816. * for +ve prefix/suffix, allow only a
  817. * single occurence of either
  818. */
  819. if (xsltUTF8Charcmp(*format, self->percent) == 0) {
  820. if (info->is_multiplier_set)
  821. return -1;
  822. info->multiplier = 100;
  823. info->is_multiplier_set = TRUE;
  824. } else if (xsltUTF8Charcmp(*format, self->permille) == 0) {
  825. if (info->is_multiplier_set)
  826. return -1;
  827. info->multiplier = 1000;
  828. info->is_multiplier_set = TRUE;
  829. }
  830. }
  831. if ((len=xmlUTF8Strsize(*format, 1)) < 1)
  832. return -1;
  833. count += len;
  834. *format += len;
  835. }
  836. }
  837. /**
  838. * xsltFormatNumberConversion:
  839. * @self: the decimal format
  840. * @format: the format requested
  841. * @number: the value to format
  842. * @result: the place to output the result
  843. *
  844. * format-number() uses the JDK 1.1 DecimalFormat class:
  845. *
  846. * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html
  847. *
  848. * Structure:
  849. *
  850. * pattern := subpattern{;subpattern}
  851. * subpattern := {prefix}integer{.fraction}{suffix}
  852. * prefix := '\\u0000'..'\\uFFFD' - specialCharacters
  853. * suffix := '\\u0000'..'\\uFFFD' - specialCharacters
  854. * integer := '#'* '0'* '0'
  855. * fraction := '0'* '#'*
  856. *
  857. * Notation:
  858. * X* 0 or more instances of X
  859. * (X | Y) either X or Y.
  860. * X..Y any character from X up to Y, inclusive.
  861. * S - T characters in S, except those in T
  862. *
  863. * Special Characters:
  864. *
  865. * Symbol Meaning
  866. * 0 a digit
  867. * # a digit, zero shows as absent
  868. * . placeholder for decimal separator
  869. * , placeholder for grouping separator.
  870. * ; separates formats.
  871. * - default negative prefix.
  872. * % multiply by 100 and show as percentage
  873. * ? multiply by 1000 and show as per mille
  874. * X any other characters can be used in the prefix or suffix
  875. * ' used to quote special characters in a prefix or suffix.
  876. *
  877. * Returns a possible XPath error
  878. */
  879. xmlXPathError
  880. xsltFormatNumberConversion(xsltDecimalFormatPtr self,
  881. xmlChar *format,
  882. double number,
  883. xmlChar **result)
  884. {
  885. xmlXPathError status = XPATH_EXPRESSION_OK;
  886. xmlBufferPtr buffer;
  887. xmlChar *the_format, *prefix = NULL, *suffix = NULL;
  888. xmlChar *nprefix, *nsuffix = NULL;
  889. int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length;
  890. double scale;
  891. int j, len = 0;
  892. int self_grouping_len;
  893. xsltFormatNumberInfo format_info;
  894. /*
  895. * delayed_multiplier allows a 'trailing' percent or
  896. * permille to be treated as suffix
  897. */
  898. int delayed_multiplier = 0;
  899. /* flag to show no -ve format present for -ve number */
  900. char default_sign = 0;
  901. /* flag to show error found, should use default format */
  902. char found_error = 0;
  903. if (xmlStrlen(format) <= 0) {
  904. xsltTransformError(NULL, NULL, NULL,
  905. "xsltFormatNumberConversion : "
  906. "Invalid format (0-length)\n");
  907. }
  908. *result = NULL;
  909. switch (xmlXPathIsInf(number)) {
  910. case -1:
  911. if (self->minusSign == NULL)
  912. *result = xmlStrdup(BAD_CAST "-");
  913. else
  914. *result = xmlStrdup(self->minusSign);
  915. /* Intentional fall-through */
  916. case 1:
  917. if ((self == NULL) || (self->infinity == NULL))
  918. *result = xmlStrcat(*result, BAD_CAST "Infinity");
  919. else
  920. *result = xmlStrcat(*result, self->infinity);
  921. return(status);
  922. default:
  923. if (xmlXPathIsNaN(number)) {
  924. if ((self == NULL) || (self->noNumber == NULL))
  925. *result = xmlStrdup(BAD_CAST "NaN");
  926. else
  927. *result = xmlStrdup(self->noNumber);
  928. return(status);
  929. }
  930. }
  931. buffer = xmlBufferCreate();
  932. if (buffer == NULL) {
  933. return XPATH_MEMORY_ERROR;
  934. }
  935. format_info.integer_hash = 0;
  936. format_info.integer_digits = 0;
  937. format_info.frac_digits = 0;
  938. format_info.frac_hash = 0;
  939. format_info.group = -1;
  940. format_info.multiplier = 1;
  941. format_info.add_decimal = FALSE;
  942. format_info.is_multiplier_set = FALSE;
  943. format_info.is_negative_pattern = FALSE;
  944. the_format = format;
  945. /*
  946. * First we process the +ve pattern to get percent / permille,
  947. * as well as main format
  948. */
  949. prefix = the_format;
  950. prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
  951. if (prefix_length < 0) {
  952. found_error = 1;
  953. goto OUTPUT_NUMBER;
  954. }
  955. /*
  956. * Here we process the "number" part of the format. It gets
  957. * a little messy because of the percent/per-mille - if that
  958. * appears at the end, it may be part of the suffix instead
  959. * of part of the number, so the variable delayed_multiplier
  960. * is used to handle it
  961. */
  962. self_grouping_len = xmlStrlen(self->grouping);
  963. while ((*the_format != 0) &&
  964. (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) &&
  965. (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) {
  966. if (delayed_multiplier != 0) {
  967. format_info.multiplier = delayed_multiplier;
  968. format_info.is_multiplier_set = TRUE;
  969. delayed_multiplier = 0;
  970. }
  971. if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
  972. if (format_info.integer_digits > 0) {
  973. found_error = 1;
  974. goto OUTPUT_NUMBER;
  975. }
  976. format_info.integer_hash++;
  977. if (format_info.group >= 0)
  978. format_info.group++;
  979. } else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
  980. format_info.integer_digits++;
  981. if (format_info.group >= 0)
  982. format_info.group++;
  983. } else if ((self_grouping_len > 0) &&
  984. (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) {
  985. /* Reset group count */
  986. format_info.group = 0;
  987. the_format += self_grouping_len;
  988. continue;
  989. } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
  990. if (format_info.is_multiplier_set) {
  991. found_error = 1;
  992. goto OUTPUT_NUMBER;
  993. }
  994. delayed_multiplier = 100;
  995. } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
  996. if (format_info.is_multiplier_set) {
  997. found_error = 1;
  998. goto OUTPUT_NUMBER;
  999. }
  1000. delayed_multiplier = 1000;
  1001. } else
  1002. break; /* while */
  1003. if ((len=xmlUTF8Strsize(the_format, 1)) < 1) {
  1004. found_error = 1;
  1005. goto OUTPUT_NUMBER;
  1006. }
  1007. the_format += len;
  1008. }
  1009. /* We have finished the integer part, now work on fraction */
  1010. if ( (*the_format != 0) &&
  1011. (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) {
  1012. format_info.add_decimal = TRUE;
  1013. if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
  1014. found_error = 1;
  1015. goto OUTPUT_NUMBER;
  1016. }
  1017. the_format += len; /* Skip over the decimal */
  1018. }
  1019. while (*the_format != 0) {
  1020. if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) {
  1021. if (format_info.frac_hash != 0) {
  1022. found_error = 1;
  1023. goto OUTPUT_NUMBER;
  1024. }
  1025. format_info.frac_digits++;
  1026. } else if (xsltUTF8Charcmp(the_format, self->digit) == 0) {
  1027. format_info.frac_hash++;
  1028. } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) {
  1029. if (format_info.is_multiplier_set) {
  1030. found_error = 1;
  1031. goto OUTPUT_NUMBER;
  1032. }
  1033. delayed_multiplier = 100;
  1034. if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
  1035. found_error = 1;
  1036. goto OUTPUT_NUMBER;
  1037. }
  1038. the_format += len;
  1039. continue; /* while */
  1040. } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) {
  1041. if (format_info.is_multiplier_set) {
  1042. found_error = 1;
  1043. goto OUTPUT_NUMBER;
  1044. }
  1045. delayed_multiplier = 1000;
  1046. if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
  1047. found_error = 1;
  1048. goto OUTPUT_NUMBER;
  1049. }
  1050. the_format += len;
  1051. continue; /* while */
  1052. } else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) {
  1053. break; /* while */
  1054. }
  1055. if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
  1056. found_error = 1;
  1057. goto OUTPUT_NUMBER;
  1058. }
  1059. the_format += len;
  1060. if (delayed_multiplier != 0) {
  1061. format_info.multiplier = delayed_multiplier;
  1062. delayed_multiplier = 0;
  1063. format_info.is_multiplier_set = TRUE;
  1064. }
  1065. }
  1066. /*
  1067. * If delayed_multiplier is set after processing the
  1068. * "number" part, should be in suffix
  1069. */
  1070. if (delayed_multiplier != 0) {
  1071. the_format -= len;
  1072. delayed_multiplier = 0;
  1073. }
  1074. suffix = the_format;
  1075. suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info);
  1076. if ( (suffix_length < 0) ||
  1077. ((*the_format != 0) &&
  1078. (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) {
  1079. found_error = 1;
  1080. goto OUTPUT_NUMBER;
  1081. }
  1082. /*
  1083. * We have processed the +ve prefix, number part and +ve suffix.
  1084. * If the number is -ve, we must substitute the -ve prefix / suffix
  1085. */
  1086. if (number < 0) {
  1087. /*
  1088. * Note that j is the number of UTF8 chars before the separator,
  1089. * not the number of bytes! (bug 151975)
  1090. */
  1091. j = xmlUTF8Strloc(format, self->patternSeparator);
  1092. if (j < 0) {
  1093. /* No -ve pattern present, so use default signing */
  1094. default_sign = 1;
  1095. }
  1096. else {
  1097. /* Skip over pattern separator (accounting for UTF8) */
  1098. the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1);
  1099. /*
  1100. * Flag changes interpretation of percent/permille
  1101. * in -ve pattern
  1102. */
  1103. format_info.is_negative_pattern = TRUE;
  1104. format_info.is_multiplier_set = FALSE;
  1105. /* First do the -ve prefix */
  1106. nprefix = the_format;
  1107. nprefix_length = xsltFormatNumberPreSuffix(self,
  1108. &the_format, &format_info);
  1109. if (nprefix_length<0) {
  1110. found_error = 1;
  1111. goto OUTPUT_NUMBER;
  1112. }
  1113. while (*the_format != 0) {
  1114. if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) ||
  1115. (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) {
  1116. if (format_info.is_multiplier_set) {
  1117. found_error = 1;
  1118. goto OUTPUT_NUMBER;
  1119. }
  1120. format_info.is_multiplier_set = TRUE;
  1121. delayed_multiplier = 1;
  1122. }
  1123. else if (IS_SPECIAL(self, the_format))
  1124. delayed_multiplier = 0;
  1125. else
  1126. break; /* while */
  1127. if ((len = xmlUTF8Strsize(the_format, 1)) < 1) {
  1128. found_error = 1;
  1129. goto OUTPUT_NUMBER;
  1130. }
  1131. the_format += len;
  1132. }
  1133. if (delayed_multiplier != 0) {
  1134. format_info.is_multiplier_set = FALSE;
  1135. the_format -= len;
  1136. }
  1137. /* Finally do the -ve suffix */
  1138. if (*the_format != 0) {
  1139. nsuffix = the_format;
  1140. nsuffix_length = xsltFormatNumberPreSuffix(self,
  1141. &the_format, &format_info);
  1142. if (nsuffix_length < 0) {
  1143. found_error = 1;
  1144. goto OUTPUT_NUMBER;
  1145. }
  1146. }
  1147. else
  1148. nsuffix_length = 0;
  1149. if (*the_format != 0) {
  1150. found_error = 1;
  1151. goto OUTPUT_NUMBER;
  1152. }
  1153. /*
  1154. * Here's another Java peculiarity:
  1155. * if -ve prefix/suffix == +ve ones, discard & use default
  1156. */
  1157. if ((nprefix_length != prefix_length) ||
  1158. (nsuffix_length != suffix_length) ||
  1159. ((nprefix_length > 0) &&
  1160. (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) ||
  1161. ((nsuffix_length > 0) &&
  1162. (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) {
  1163. prefix = nprefix;
  1164. prefix_length = nprefix_length;
  1165. suffix = nsuffix;
  1166. suffix_length = nsuffix_length;
  1167. } /* else {
  1168. default_sign = 1;
  1169. }
  1170. */
  1171. }
  1172. }
  1173. OUTPUT_NUMBER:
  1174. if (found_error != 0) {
  1175. xsltTransformError(NULL, NULL, NULL,
  1176. "xsltFormatNumberConversion : "
  1177. "error in format string '%s', using default\n", format);
  1178. default_sign = (number < 0.0) ? 1 : 0;
  1179. prefix_length = suffix_length = 0;
  1180. format_info.integer_hash = 0;
  1181. format_info.integer_digits = 1;
  1182. format_info.frac_digits = 1;
  1183. format_info.frac_hash = 4;
  1184. format_info.group = -1;
  1185. format_info.multiplier = 1;
  1186. format_info.add_decimal = TRUE;
  1187. }
  1188. /* Ready to output our number. First see if "default sign" is required */
  1189. if (default_sign != 0)
  1190. xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1));
  1191. /* Put the prefix into the buffer */
  1192. for (j = 0; j < prefix_length; ) {
  1193. if (*prefix == SYMBOL_QUOTE)
  1194. prefix++;
  1195. len = xmlUTF8Strsize(prefix, 1);
  1196. xmlBufferAdd(buffer, prefix, len);
  1197. prefix += len;
  1198. j += len;
  1199. }
  1200. /* Next do the integer part of the number */
  1201. number = fabs(number) * (double)format_info.multiplier;
  1202. scale = pow(10.0, (double)(format_info.frac_digits + format_info.frac_hash));
  1203. number = floor((scale * number + 0.5)) / scale;
  1204. if ((self->grouping != NULL) &&
  1205. (self->grouping[0] != 0)) {
  1206. int gchar;
  1207. len = xmlStrlen(self->grouping);
  1208. gchar = xsltGetUTF8Char(self->grouping, &len);
  1209. xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
  1210. format_info.integer_digits,
  1211. format_info.group,
  1212. gchar, len);
  1213. } else
  1214. xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
  1215. format_info.integer_digits,
  1216. format_info.group,
  1217. ',', 1);
  1218. /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */
  1219. if ((format_info.integer_digits + format_info.integer_hash +
  1220. format_info.frac_digits == 0) && (format_info.frac_hash > 0)) {
  1221. ++format_info.frac_digits;
  1222. --format_info.frac_hash;
  1223. }
  1224. /* Add leading zero, if required */
  1225. if ((floor(number) == 0) &&
  1226. (format_info.integer_digits + format_info.frac_digits == 0)) {
  1227. xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1));
  1228. }
  1229. /* Next the fractional part, if required */
  1230. if (format_info.frac_digits + format_info.frac_hash == 0) {
  1231. if (format_info.add_decimal)
  1232. xmlBufferAdd(buffer, self->decimalPoint,
  1233. xmlUTF8Strsize(self->decimalPoint, 1));
  1234. }
  1235. else {
  1236. number -= floor(number);
  1237. if ((number != 0) || (format_info.frac_digits != 0)) {
  1238. xmlBufferAdd(buffer, self->decimalPoint,
  1239. xmlUTF8Strsize(self->decimalPoint, 1));
  1240. number = floor(scale * number + 0.5);
  1241. for (j = format_info.frac_hash; j > 0; j--) {
  1242. if (fmod(number, 10.0) >= 1.0)
  1243. break; /* for */
  1244. number /= 10.0;
  1245. }
  1246. xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0],
  1247. format_info.frac_digits + j,
  1248. 0, 0, 0);
  1249. }
  1250. }
  1251. /* Put the suffix into the buffer */
  1252. for (j = 0; j < suffix_length; ) {
  1253. if (*suffix == SYMBOL_QUOTE)
  1254. suffix++;
  1255. len = xmlUTF8Strsize(suffix, 1);
  1256. xmlBufferAdd(buffer, suffix, len);
  1257. suffix += len;
  1258. j += len;
  1259. }
  1260. *result = xmlStrdup(xmlBufferContent(buffer));
  1261. xmlBufferFree(buffer);
  1262. return status;
  1263. }