2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
12 * The Original Code is the Sablotron XSLT Processor.
14 * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15 * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16 * Ginger Alliance Ltd. All Rights Reserved.
20 * Alternatively, the contents of this file may be used under the
21 * terms of the GNU General Public License Version 2 or later (the
22 * "GPL"), in which case the provisions of the GPL are applicable
23 * instead of those above. If you wish to allow use of your
24 * version of this file only under the terms of the GPL and not to
25 * allow others to use your version of this file under the MPL,
26 * indicate your decision by deleting the provisions above and
27 * replace them with the notice and other provisions required by
28 * the GPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under either the MPL or the
39 DecimalFormat::DecimalFormat(const EQName& name_)
41 decimalSeparator(".", TRUE, XSLA_DECIMAL_SEPARATOR),
42 groupingSeparator(",", TRUE, XSLA_GROUPING_SEPARATOR),
43 infinity("Infinity", FALSE, XSLA_INFINITY),
44 minusSign("-", TRUE, XSLA_MINUS_SIGN),
45 NaN("NaN", FALSE, XSLA_NAN),
46 percent("%", TRUE, XSLA_PERCENT),
47 perMille("\xe2\x80\x83", TRUE, XSLA_PER_MILLE), // U+2030
48 zeroDigit("0", TRUE, XSLA_ZERO_DIGIT),
49 digit("#", TRUE, XSLA_DIGIT),
50 patternSeparator(";", TRUE, XSLA_PATTERN_SEPARATOR)
54 DecimalFormat::~DecimalFormat()
58 eFlag DecimalFormat::setItem(Sit S, XSL_ATT itemId, const Str& value)
60 return NZ(findItem(itemId)) -> set(S, value);
63 const Str& DecimalFormat::getItem(XSL_ATT itemId)
65 return NZ(findItem(itemId)) -> get();
68 DefaultedStr* DecimalFormat::findItem(XSL_ATT itemId)
72 case XSLA_DECIMAL_SEPARATOR:
73 return &decimalSeparator;
74 case XSLA_GROUPING_SEPARATOR:
75 return &groupingSeparator;
90 case XSLA_PATTERN_SEPARATOR:
91 return &patternSeparator;
97 #define max(x,y) (x > y ? x : y)
99 eFlag DecimalFormat::format(Sit S, Number& num, const Str& fmt, Str& result)
103 result = getItem(XSLA_NAN);
113 E( parse(S, fmt, num < 0.0, prefix, suffix, factor, iDigitsMin, fDigits, fDigitsMin, gSize) );
115 // printf("pfx %s sfx %s factor %d imin %d fmax %d fmin %d gsize %d",
116 // (char*)prefix, (char*)suffix, factor, iDigitsMin, fDigits, fDigitsMin, gSize);
118 // start with the prefix (DO NOT we need to add it as the very last step)
119 //DStr tempResult = prefix;
124 tempResult += getItem(XSLA_INFINITY);
125 tempResult += suffix;
129 // we have a legitimate number
130 // convert number to string form
132 double theNumber = fabs((double) num * factor);
138 //auxFmt += iDigitsMin + fDigits + 1 /* + (num < 0.0 ? 1 : 0) */;
139 auxFmt += iDigitsMin + (fDigits ? fDigits + 1 : 0);
143 sprintf(buff, (char*) auxFmt, theNumber);
145 // buff now holds the number without sign, grouping marks and with possibly too many trailing zeroes
146 // scan the number for decimal point position and trailing zeroes count
147 //if #.00 was specified, we still have a leading zero (0.12 instead of .12)
149 if ( ! iDigitsMin ) //remove leading zeros
150 while ( *buff1 == '0' ) buff1++;
155 for (j = 0; buff1[j]; j++)
157 if (buff1[j] == '.' && decPt < 0)
170 // insert separators into integer part
171 int block = gSize ? decPt % gSize : decPt;
172 if (!block) block = gSize;
173 for (int i = 0; i < decPt; i += block, block = gSize)
175 for (int k = 0; k < block; k++)
177 if (buff1[i + k] != 0)
178 tempResult.nadd(buff1 + i + k, 1);
180 tempResult += getItem(XSLA_ZERO_DIGIT);
182 if (i + block < decPt)
183 tempResult += getItem(XSLA_GROUPING_SEPARATOR);
185 // add a decimal point if needed
186 if (fDigitsMin || !(trailingCount == fDigits))
187 tempResult += getItem(XSLA_DECIMAL_SEPARATOR);
189 // copy decimal part, omitting the extra trailing zeroes
190 tempResult.nadd(buff1 + decPt + 1, max(fDigits - trailingCount, fDigitsMin));
192 //replace the zero character (tell me why for god's sakes)
193 char zd = *((char*)zeroDigit.get());
196 char *aux = (char*)tempResult;
197 while ((aux = strchr(aux, '0')))
201 // add percent or per-mille sign
203 tempResult += getItem(XSLA_PERCENT);
205 tempResult += getItem(XSLA_PER_MILLE );
207 // add the prefix and suffix
208 DStr final = prefix + tempResult + suffix;
213 const EQName& DecimalFormat::getname()
218 #define readToken(STRG, PTR, LENGTH) STRG.nset(PTR, LENGTH)
220 XSL_ATT tokensList[] =
224 XSLA_GROUPING_SEPARATOR,
225 XSLA_DECIMAL_SEPARATOR,
226 XSLA_PATTERN_SEPARATOR,
232 XSL_ATT DecimalFormat::whichToken(const char* ptr, int len)
234 for (int i = 0; tokensList[i] != XSLA_NONE; i++)
235 if (!strncmp(ptr, getItem(tokensList[i]), len))
236 return tokensList[i];
240 eFlag DecimalFormat::parseSubpattern(Sit S, const char *&ptr, Bool negative,
241 Str& prefix, Str& suffix, int& factor,
242 int& iDigitsMin, int& fDigits, int& fDigitsMin, int& gSize)
246 Bool wasDigit = FALSE;
250 iDigitsMin = fDigits = fDigitsMin = 0;
253 for (; *ptr && state < 5; ptr += len)
257 // escaped special character; if non-special follows, throw error
260 len = utf8SingleCharLength(ptr);
261 if (whichToken(ptr, len) == XSLA_NONE)
262 Err(S, E_FORMAT_INVALID);
267 len = utf8SingleCharLength(ptr);
268 token = whichToken(ptr, len);
271 // check for the forbidden currency sign U+00a4
272 if ((unsigned char)*ptr == 0xc2 && (unsigned char)(ptr[1]) == 0xa4)
273 Err(S, E_FORMAT_INVALID);
280 if (token == XSLA_NONE)
282 //readToken(prefix, ptr, len);
284 readToken(foo, ptr, len);
285 prefix = prefix + foo;
291 // after the prefix has been retrieved
296 case XSLA_ZERO_DIGIT:
298 if (gSize >= 0) gSize++;
300 if (token == XSLA_DIGIT)
303 Err(S, E_FORMAT_INVALID);
308 case XSLA_GROUPING_SEPARATOR:
310 // forbid consecutive commas and comma at start
311 if (!gSize || !wasDigit)
312 Err(S, E_FORMAT_INVALID);
315 case XSLA_DECIMAL_SEPARATOR:
321 Err(S, E_FORMAT_INVALID);
322 factor = (token == XSLA_PERCENT) ? 100 : 1000;
327 readToken(suffix, ptr, len);
330 case XSLA_PATTERN_SEPARATOR:
333 Err(S, E_FORMAT_INVALID);
337 Err(S, E_FORMAT_INVALID);
341 // after the decimal point
345 case XSLA_ZERO_DIGIT:
347 if (fDigits > fDigitsMin)
348 Err(S, E_FORMAT_INVALID);
358 Err(S, E_FORMAT_INVALID);
359 factor = (token == XSLA_PERCENT) ? 100 : 1000;
364 readToken(suffix, ptr, len);
367 case XSLA_PATTERN_SEPARATOR:
370 Err(S, E_FORMAT_INVALID);
374 Err(S, E_FORMAT_INVALID);
378 // after the percent/per-mille sign was retrieved
384 readToken(suffix, ptr, len);
387 case XSLA_PATTERN_SEPARATOR:
390 Err(S, E_FORMAT_INVALID);
394 Err(S, E_FORMAT_INVALID);
398 // after the suffix was retrieved
400 if (token == XSLA_NONE) {
402 readToken(foo, ptr, len);
403 suffix = suffix + foo;
406 if (token != XSLA_PATTERN_SEPARATOR || negative)
407 Err(S, E_FORMAT_INVALID);
412 if ((negative && *ptr)) //|| !iDigitsMin)
413 Err(S, E_FORMAT_INVALID);
415 if (!negative && !*ptr && state == 5)
416 Err(S, E_FORMAT_INVALID);
422 eFlag DecimalFormat::parse(Sit S, const Str &src, Bool negative,
423 Str& prefix, Str& suffix, int& factor,
424 int& iDigitsMin, int& fDigits, int& fDigitsMin, int& gSize)
426 const char *p = (const char*) src;
427 E( parseSubpattern(S, p, FALSE, prefix, suffix, factor,
428 iDigitsMin, fDigits, fDigitsMin, gSize) );
433 int iDigitsMin_, fDigits_, fDigitsMin_, gSize_;
434 // determine prefix, suffix and factor, rest given by positive subpattern
435 E( parseSubpattern(S, p, TRUE, prefix, suffix, factor,
436 iDigitsMin_, fDigits_, fDigitsMin_, gSize_) );
441 prefix = DStr(getItem(XSLA_MINUS_SIGN)) + prefix;
442 // suffix and factor remain
448 void DecimalFormat::report(Sit S, MsgType type, MsgCode code,
449 const Str &arg1, const Str &arg2) const
451 S.message(type, code, arg1, arg2);
460 DefaultedStr::DefaultedStr(const char *defaultValue_, Bool singleChar_, XSL_ATT id_)
461 : defaultValue(defaultValue_), specified(FALSE), singleChar(singleChar_), id(id_)
465 DefaultedStr::~DefaultedStr()
469 eFlag DefaultedStr::set(Sit S, const Str& value)
471 if (specified && value != specifiedValue)
472 Err1(S, E1_FORMAT_DUPLICIT_OPTION, ownName());
473 if (singleChar && utf8StrLength(value) != 1)
474 Err1(S, E1_FORMAT_OPTION_CHAR, ownName());
475 specifiedValue = value;
480 const Str& DefaultedStr::get()
483 return specifiedValue;
488 char* DefaultedStr::ownName()
490 return (char*)xslAttNames[id];
493 void DefaultedStr::report(Sit S, MsgType type, MsgCode code,
494 const Str &arg1, const Str &arg2) const
496 S.message(type, code, arg1, arg2);
505 DecimalFormatList::DecimalFormatList()
510 void DecimalFormatList::initialize()
514 // append the default format
515 append(new DecimalFormat(emptyName));
518 DecimalFormatList::~DecimalFormatList()
523 eFlag DecimalFormatList::add(Sit S, const EQName& name, DecimalFormat*& result)
525 int ndx = findNdx(name);
527 result = (*this)[ndx];
529 append(result = new DecimalFormat(name));
533 eFlag DecimalFormatList::format(Sit S, const EQName& name, Number& num, const Str& fmt, Str& result)
535 int ndx = findNdx(name);
537 E( (*this)[ndx] -> format(S, num, fmt, result) )
541 name.getname(fullname);
542 Err1(S, E1_FORMAT_NOT_FOUND, fullname);
547 int DecimalFormatList::findNdx(const EQName& name)
550 for (i = 0; i < number(); i++)
551 if ((*this)[i] -> getname() == name)
556 void DecimalFormatList::report(Sit S, MsgType type, MsgCode code,
557 const Str &arg1, const Str &arg2) const
559 S.message(type, code, arg1, arg2);