/* Generated automatically by jlpp - do not edit. */ #include static jakelib::lang::String* jakelib2_strings[] = {null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null}; // "multiplier already set " static jchar chars_jakelib2_str_0[] = {109,117,108,116,105,112,108,105,101,114,32,97,108,114,101,97,100,121,32,115,101,116,32}; // "- index: " static jchar chars_jakelib2_str_1[] = {45,32,105,110,100,101,120,58,32}; // "multiplier already set " static jchar chars_jakelib2_str_2[] = {109,117,108,116,105,112,108,105,101,114,32,97,108,114,101,97,100,121,32,115,101,116,32}; // "- index: " static jchar chars_jakelib2_str_3[] = {45,32,105,110,100,101,120,58,32}; // "digit mark following " static jchar chars_jakelib2_str_4[] = {100,105,103,105,116,32,109,97,114,107,32,102,111,108,108,111,119,105,110,103,32}; // "zero - index: " static jchar chars_jakelib2_str_5[] = {122,101,114,111,32,45,32,105,110,100,101,120,58,32}; // "zero mark " static jchar chars_jakelib2_str_6[] = {122,101,114,111,32,109,97,114,107,32}; // "following digit - index: " static jchar chars_jakelib2_str_7[] = {102,111,108,108,111,119,105,110,103,32,100,105,103,105,116,32,45,32,105,110,100,101,120,58,32}; // "unexpected special " static jchar chars_jakelib2_str_8[] = {117,110,101,120,112,101,99,116,101,100,32,115,112,101,99,105,97,108,32}; // "character - index: " static jchar chars_jakelib2_str_9[] = {99,104,97,114,97,99,116,101,114,32,45,32,105,110,100,101,120,58,32}; // "digit mark following zero " static jchar chars_jakelib2_str_10[] = {100,105,103,105,116,32,109,97,114,107,32,102,111,108,108,111,119,105,110,103,32,122,101,114,111,32}; // "in exponent - index: " static jchar chars_jakelib2_str_11[] = {105,110,32,101,120,112,111,110,101,110,116,32,45,32,105,110,100,101,120,58,32}; // "unexpected special " static jchar chars_jakelib2_str_12[] = {117,110,101,120,112,101,99,116,101,100,32,115,112,101,99,105,97,108,32}; // "character - index: " static jchar chars_jakelib2_str_13[] = {99,104,97,114,97,99,116,101,114,32,45,32,105,110,100,101,120,58,32}; // "" static jchar chars_jakelib2_str_14[] = {0}; // "" static jchar chars_jakelib2_str_15[] = {0}; // "" static jchar chars_jakelib2_str_16[] = {0}; // "" static jchar chars_jakelib2_str_17[] = {0}; // "separator character " static jchar chars_jakelib2_str_18[] = {115,101,112,97,114,97,116,111,114,32,99,104,97,114,97,99,116,101,114,32}; // "expected - index: " static jchar chars_jakelib2_str_19[] = {101,120,112,101,99,116,101,100,32,45,32,105,110,100,101,120,58,32}; // "end of pattern expected " static jchar chars_jakelib2_str_20[] = {101,110,100,32,111,102,32,112,97,116,116,101,114,110,32,101,120,112,101,99,116,101,100,32}; // "- index: " static jchar chars_jakelib2_str_21[] = {45,32,105,110,100,101,120,58,32}; // "jakelib.text.DecimalFormat" static jchar chars_jakelib2_str_22[] = {106,97,107,101,108,105,98,46,116,101,120,116,46,68,101,99,105,109,97,108,70,111,114,109,97,116}; #line 1 "text/DecimalFormat.jlc" // -*- c++ -*- /* * Jakelib2 - General purpose C++ library * Copyright (C) 2001 Florian Wolff (florian@donuz.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: DecimalFormat.jlc,v 1.15 2003/09/27 08:10:28 florian Exp $ */ #include "jakelib2.h" #include "jakelib2/text/DecimalFormat.h" #include "jakelib2/lang/Math.h" #include "jakelib2/lang/Double.h" #include "jakelib2/lang/Long.h" #include "jakelib2/lang/System.h" using namespace jakelib::lang; using namespace jakelib::text; using namespace jakelib::util; JAKELIB_IMPLEMENT_CLASS("jakelib.text.DecimalFormat", DecimalFormat, NumberFormat); JAKELIB_IMPLEMENT_ARRAY(DecimalFormat); DecimalFormatSyms *DecimalFormat::nonLocalizedSymbols = null; /*****************************************************************************\ * DecimalFormat | *****************************************************************************/ DecimalFormat::DecimalFormat() { // FIXME: Doesn't compile on gcc //DecimalFormat("#,##0.###"); } DecimalFormat::DecimalFormat(String * pattern) { this->symbols = new DecimalFormatSyms(); applyPattern(pattern); } DecimalFormat::DecimalFormat(String * pattern, DecimalFormatSyms * symbols) { this->symbols = symbols; applyPattern(pattern); } /*****************************************************************************\ * scanFix | *****************************************************************************/ jint DecimalFormat::scanFix(String * pattern, jint index, StringBuffer * buf, String * patChars, DecimalFormatSyms * syms, jboolean is_suffix) { jint len = pattern->length(); buf->setLength(0); jboolean multiplierSet = false; while (index < len) { jchar c = pattern->charAt(index); if (c == '\'' && index + 1 < len && pattern->charAt(index + 1) == '\'') { buf->append(c); ++index; } else if (c == '\'' && index + 2 < len && pattern->charAt(index + 2) == '\'') { buf->append(pattern->charAt(index + 1)); index += 2; } else if (c == 0x00a4 /*'\u00a4' */ ) { if ((index + 1 < len) && (pattern->charAt(index + 1) == 0x00a4 /*'\u00a4' */ )) { buf->append(syms->getInternationalCurrencySymbol()); ++index; } else buf->append(syms->getCurrencySymbol()); } else if (is_suffix && c == syms->getPercent()) { if (multiplierSet) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[0], new jakelib::lang::String(chars_jakelib2_str_0, 0, 23))->plus(JAKELIB_ONDEMAND(jakelib2_strings[1], new jakelib::lang::String(chars_jakelib2_str_1, 0, 9)))->plus( index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFix"))); multiplierSet = true; multiplier = 100; buf->append(c); } else if (is_suffix && c == syms->getPerMill()) { if (multiplierSet) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[2], new jakelib::lang::String(chars_jakelib2_str_2, 0, 23))->plus( JAKELIB_ONDEMAND(jakelib2_strings[3], new jakelib::lang::String(chars_jakelib2_str_3, 0, 9)) )->plus( index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFix"))); multiplierSet = true; multiplier = 1000; buf->append(c); } else if (patChars->indexOf(c) != -1) { // This is a pattern character. break; } else buf->append(c); ++index; } return index; } /*****************************************************************************\ * scanFormat | *****************************************************************************/ jint DecimalFormat::scanFormat(String *pattern, jint index, String *patChars, DecimalFormatSyms *syms, jboolean is_positive) { jint max = pattern->length(); jint countSinceGroup = 0; jint zeroCount = 0; jboolean saw_group = false; // // Scan integer part. // while (index < max) { jchar c = pattern->charAt(index); if (c == syms->getDigit()) { if (zeroCount > 0) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[4], new jakelib::lang::String(chars_jakelib2_str_4, 0, 21))->plus( JAKELIB_ONDEMAND(jakelib2_strings[5], new jakelib::lang::String(chars_jakelib2_str_5, 0, 14)))->plus(index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFormat"))); ++countSinceGroup; } else if (c == syms->getZeroDigit()) { ++zeroCount; ++countSinceGroup; } else if (c == syms->getGroupingSeparator()) { countSinceGroup = 0; saw_group = true; } else break; ++index; } // We can only side-effect when parsing the positive format. if (is_positive) { groupingUsed = saw_group; groupingSize = (jbyte) countSinceGroup; minimumIntegerDigits = zeroCount; } // Early termination. if (index == max || pattern->charAt(index) == syms->getGroupingSeparator()) { if (is_positive) decimalSeparatorAlwaysShown = false; return index; } if (pattern->charAt(index) == syms->getDecimalSeparator()) { ++index; // // Scan fractional part. // jint hashCount = 0; zeroCount = 0; while (index < max) { jchar c = pattern->charAt(index); if (c == syms->getZeroDigit()) { if (hashCount > 0) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[6], new jakelib::lang::String(chars_jakelib2_str_6, 0, 10))->plus( JAKELIB_ONDEMAND(jakelib2_strings[7], new jakelib::lang::String(chars_jakelib2_str_7, 0, 25)))->plus( index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFormat"))); ++zeroCount; } else if (c == syms->getDigit()) { ++hashCount; } else if (c != syms->getExponential() && c != syms->getPatternSeparator() && patChars->indexOf(c) != -1) { throw IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[8], new jakelib::lang::String(chars_jakelib2_str_8, 0, 19))->plus( JAKELIB_ONDEMAND(jakelib2_strings[9], new jakelib::lang::String(chars_jakelib2_str_9, 0, 19)))->plus(index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFormat"))); } else { break; } ++index; } if (is_positive) { maximumFractionDigits = hashCount + zeroCount; minimumFractionDigits = zeroCount; } if (index == max) return index; } if (pattern->charAt(index) == syms->getExponential()) { // // Scan exponential format. // zeroCount = 0; ++index; while (index < max) { jchar c = pattern->charAt(index); if (c == syms->getZeroDigit()) ++zeroCount; else if (c == syms->getDigit()) { if (zeroCount > 0) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[10], new jakelib::lang::String(chars_jakelib2_str_10, 0, 26))->plus( JAKELIB_ONDEMAND(jakelib2_strings[11], new jakelib::lang::String(chars_jakelib2_str_11, 0, 21)))->plus(index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFormat"))); } else if (patChars->indexOf(c) != -1) { throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[12], new jakelib::lang::String(chars_jakelib2_str_12, 0, 19))->plus( JAKELIB_ONDEMAND(jakelib2_strings[13], new jakelib::lang::String(chars_jakelib2_str_13, 0, 19)))->plus(index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.scanFormat"))); } else { break; } ++index; } if (is_positive) { useExponentialNotation = true; minExponentDigits = (jbyte) zeroCount; } } return index; } /*****************************************************************************\ * patternChars | *****************************************************************************/ String *DecimalFormat::patternChars(DecimalFormatSyms * syms) { StringBuffer buf; buf.append(syms->getDecimalSeparator()); buf.append(syms->getDigit()); buf.append(syms->getExponential()); buf.append(syms->getGroupingSeparator()); // Adding this one causes pattern application to fail. // Of course, omitting is causes toPattern to fail. // ... but we already have bugs there. FIXME. // buf.append(syms->getMinusSign()); buf.append(syms->getPatternSeparator()); buf.append(syms->getPercent()); buf.append(syms->getPerMill()); buf.append(syms->getZeroDigit()); buf.append(0x00a4 /*'\u00a4' */ ); return buf.toString(); } /*****************************************************************************\ * applyPatternWithSymbols | *****************************************************************************/ void DecimalFormat::applyPatternWithSymbols(String * pattern, DecimalFormatSyms * syms) { // Initialize to the state the parser expects. negativePrefix = JAKELIB_ONDEMAND(jakelib2_strings[14], new jakelib::lang::String(chars_jakelib2_str_14, 0, 0)); negativeSuffix = JAKELIB_ONDEMAND(jakelib2_strings[15], new jakelib::lang::String(chars_jakelib2_str_15, 0, 0)); positivePrefix = JAKELIB_ONDEMAND(jakelib2_strings[16], new jakelib::lang::String(chars_jakelib2_str_16, 0, 0)); positiveSuffix = JAKELIB_ONDEMAND(jakelib2_strings[17], new jakelib::lang::String(chars_jakelib2_str_17, 0, 0)); decimalSeparatorAlwaysShown = false; groupingSize = 0; minExponentDigits = 0; multiplier = 1; useExponentialNotation = false; groupingUsed = false; maximumFractionDigits = 0; maximumIntegerDigits = 309; minimumFractionDigits = 0; minimumIntegerDigits = 1; StringBuffer *buf = new StringBuffer(); String *patChars = patternChars(syms); jint max = pattern->length(); jint index = scanFix(pattern, 0, buf, patChars, syms, false); positivePrefix = buf->toString(); index = scanFormat(pattern, index, patChars, syms, true); index = scanFix(pattern, index, buf, patChars, syms, true); positiveSuffix = buf->toString(); if (index == pattern->length()) { // No negative info. negativePrefix = null; negativeSuffix = null; } else { if (pattern->charAt(index) != syms->getPatternSeparator()) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[18], new jakelib::lang::String(chars_jakelib2_str_18, 0, 20))->plus( JAKELIB_ONDEMAND(jakelib2_strings[19], new jakelib::lang::String(chars_jakelib2_str_19, 0, 18)))->plus(index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.applyPatternWithSymbols"))); index = scanFix(pattern, index + 1, buf, patChars, syms, false); negativePrefix = buf->toString(); // We parse the negative format for errors but we don't let // it side-effect this object. index = scanFormat(pattern, index, patChars, syms, false); index = scanFix(pattern, index, buf, patChars, syms, true); negativeSuffix = buf->toString(); if (index != pattern->length()) throw new IllegalArgumentException(JAKELIB_ONDEMAND(jakelib2_strings[20], new jakelib::lang::String(chars_jakelib2_str_20, 0, 24))->plus( JAKELIB_ONDEMAND(jakelib2_strings[21], new jakelib::lang::String(chars_jakelib2_str_21, 0, 9)))->plus(index )->plus( JAKELIB_AT2("jakelib.text.DecimalFormat.applyPatternWithSymbols"))); } } /*****************************************************************************\ * applyLocalizedPattern | *****************************************************************************/ void DecimalFormat::applyLocalizedPattern(jakelib::lang::String * pattern) { // JCL p. 638 claims this throws a ParseException but p. 629 // contradicts this. Empirical tests with patterns of "0,###.0" // and "#.#.#" corroborate the p. 629 statement that an // IllegalArgumentException is thrown. applyPatternWithSymbols(pattern, symbols); } /*****************************************************************************\ * applyPattern | *****************************************************************************/ void DecimalFormat::applyPattern(String * pattern) { // JCL p. 638 claims this throws a ParseException but p. 629 // contradicts this. Empirical tests with patterns of "0,###.0" // and "#.#.#" corroborate the p. 629 statement that an // IllegalArgumentException is thrown. applyPatternWithSymbols(pattern, nonLocalizedSymbols); } /*****************************************************************************\ * equals | *****************************************************************************/ jboolean DecimalFormat::equals(jakelib::lang::Object * obj) { if (!(obj->instanceOf(JAKELIB_ONDEMAND(jakelib2_strings[22], new jakelib::lang::String(chars_jakelib2_str_22, 0, 26))))) return false; DecimalFormat *dup = (DecimalFormat *) obj; return (decimalSeparatorAlwaysShown == dup->decimalSeparatorAlwaysShown && groupingSize == dup->groupingSize && minExponentDigits == dup->minExponentDigits && multiplier == dup->multiplier && equals(negativePrefix, dup->negativePrefix) && equals(negativeSuffix, dup->negativeSuffix) && equals(positivePrefix, dup->positivePrefix) && equals(positiveSuffix, dup->positiveSuffix) && symbols->equals(dup->symbols) && useExponentialNotation == dup->useExponentialNotation); } jboolean DecimalFormat::equals(String * s1, String * s2) { if (s1 == null || s2 == null) return s1 == s2; return s1->equals(s2); } /*****************************************************************************\ * format | *****************************************************************************/ StringBuffer *DecimalFormat::format(jdouble number, StringBuffer * dest, FieldPosition * fieldPos) { // A very special case. if (Double::isNaN(number)) { dest->append(symbols->getNaN()); if (fieldPos != null && fieldPos->getField() == INTEGER_FIELD) { jint index = dest->length(); fieldPos->setBeginIndex(index - symbols->getNaN()->length()); fieldPos->setEndIndex(index); } return dest; } jboolean is_neg = number < 0; if (is_neg) { if (negativePrefix != null) dest->append(negativePrefix); else { dest->append(symbols->getMinusSign()); dest->append(positivePrefix); } number = -number; } else dest->append(positivePrefix); jint integerBeginIndex = dest->length(); jint integerEndIndex = 0; if (Double::isInfinite(number)) { dest->append(symbols->getInfinity()); integerEndIndex = dest->length(); } else { number *= multiplier; // Compute exponent. jlong exponent = 0; jdouble baseNumber; if (useExponentialNotation) { exponent = (jlong) Math::floor(Math::log(number) / Math::log(10)); if (minimumIntegerDigits > 0) exponent -= minimumIntegerDigits - 1; baseNumber = number / Math::pow(10.0, (jdouble) exponent); } else baseNumber = number; // Round to the correct number of digits. baseNumber += 5 * Math::pow(10.0, -maximumFractionDigits - 1); jint index = dest->length(); jdouble intPart = Math::floor(baseNumber); jint count = 0; while (count < maximumIntegerDigits && (intPart > 0 || count < minimumIntegerDigits)) { jlong dig = (jlong) ((jlong) intPart % 10); intPart = Math::floor(intPart / 10); // Append group separator if required. if (groupingUsed && count > 0 && count % groupingSize == 0) dest->insert(index, symbols->getGroupingSeparator()); dest->insert(index, (jchar) (symbols->getZeroDigit() + dig)); ++count; } integerEndIndex = dest->length(); jint decimal_index = integerEndIndex; jint consecutive_zeros = 0; jint total_digits = 0; // Strip integer part from NUMBER. jdouble fracPart = baseNumber - Math::floor(baseNumber); for (count = 0; count < maximumFractionDigits && (fracPart != 0 || count < minimumFractionDigits); ++count) { ++total_digits; fracPart *= 10; jlong dig = (jlong) fracPart; if (dig == 0) ++consecutive_zeros; else consecutive_zeros = 0; dest->append((jchar) (symbols->getZeroDigit() + dig)); // Strip integer part from FRACPART. fracPart = fracPart - Math::floor(fracPart); } // Strip extraneous trailing `0's. We can't always detect // these in the loop. jint extra_zeros = Math::min(consecutive_zeros, total_digits - minimumFractionDigits); if (extra_zeros > 0) { dest->setLength(dest->length() - extra_zeros); total_digits -= extra_zeros; } // If required, add the decimal symbol. if (decimalSeparatorAlwaysShown || total_digits > 0) { dest->insert(decimal_index, symbols->getDecimalSeparator()); if (fieldPos != null && fieldPos->getField() == FRACTION_FIELD) { fieldPos->setBeginIndex(decimal_index + 1); fieldPos->setEndIndex(dest->length()); } } // Finally, print the exponent. if (useExponentialNotation) { dest->append(symbols->getExponential()); if (exponent < 0) { dest->append(symbols->getMinusSign()); exponent = -exponent; } index = dest->length(); for (count = 0; exponent > 0 || count < minExponentDigits; ++count) { jlong dig = exponent % 10; exponent /= 10; dest->insert(index, (jchar) (symbols->getZeroDigit() + dig)); } } } if (fieldPos != null && fieldPos->getField() == INTEGER_FIELD) { fieldPos->setBeginIndex(integerBeginIndex); fieldPos->setEndIndex(integerEndIndex); } dest->append((is_neg && negativeSuffix != null) ? negativeSuffix : positiveSuffix); return dest; } jakelib::lang::StringBuffer * DecimalFormat::format(jlong number, StringBuffer * dest, FieldPosition * fieldPos) { // If using exponential notation, we just format as a jdouble. if (useExponentialNotation) return format((jdouble) number, dest, fieldPos); jboolean is_neg = number < 0; if (is_neg) { if (negativePrefix != null) dest->append(negativePrefix); else { dest->append(symbols->getMinusSign()); dest->append(positivePrefix); } number = -number; } else { dest->append(positivePrefix); } jint integerBeginIndex = dest->length(); jint index = dest->length(); jint count = 0; while (count < maximumIntegerDigits && (number > 0 || count < minimumIntegerDigits)) { jlong dig = number % 10; number /= 10; // NUMBER and DIG will be less than 0 if the original number // was the most negative jlong. if (dig < 0) { dig = -dig; number = -number; } // Append group separator if required. if (groupingUsed && count > 0 && count % groupingSize == 0) { dest->insert(index, (jchar) symbols->getGroupingSeparator()); } dest->insert(index, (jchar) (symbols->getZeroDigit() + dig)); ++count; } if (fieldPos != null && fieldPos->getField() == INTEGER_FIELD) { fieldPos->setBeginIndex(integerBeginIndex); fieldPos->setEndIndex(dest->length()); } if (decimalSeparatorAlwaysShown || minimumFractionDigits > 0) { dest->append(symbols->getDecimalSeparator()); if (fieldPos != null && fieldPos->getField() == FRACTION_FIELD) { fieldPos->setBeginIndex(dest->length()); fieldPos->setEndIndex(dest->length() + minimumFractionDigits); } } for (count = 0; count < minimumFractionDigits; ++count) dest->append(symbols->getZeroDigit()); dest->append((is_neg && negativeSuffix != null) ? negativeSuffix : positiveSuffix); return dest; } /*****************************************************************************\ * getDecimalFormatSymbols | *****************************************************************************/ jakelib::text::DecimalFormatSyms * DecimalFormat::getDecimalFormatSymbols() { return symbols; } /*****************************************************************************\ * getGroupingSize | *****************************************************************************/ jint DecimalFormat::getGroupingSize() { return groupingSize; } /*****************************************************************************\ * getMultiplier | *****************************************************************************/ jint DecimalFormat::getMultiplier() { return multiplier; } /*****************************************************************************\ * getNegativePrefix | *****************************************************************************/ jakelib::lang::String * DecimalFormat::getNegativePrefix() { return negativePrefix; } /*****************************************************************************\ * getNegativeSuffix | *****************************************************************************/ jakelib::lang::String * DecimalFormat::getNegativeSuffix() { return negativeSuffix; } /*****************************************************************************\ * getPositivePrefix | *****************************************************************************/ jakelib::lang::String * DecimalFormat::getPositivePrefix() { return positivePrefix; } /*****************************************************************************\ * getPositivePrefix | *****************************************************************************/ jakelib::lang::String * DecimalFormat::getPositiveSuffix() { return positiveSuffix; } /*****************************************************************************\ * getPositivePrefix | *****************************************************************************/ jint DecimalFormat::hashCode() { jint hash = (negativeSuffix->hashCode() ^ negativePrefix->hashCode() ^ positivePrefix->hashCode() ^ positiveSuffix->hashCode()); // FIXME. return hash; } /*****************************************************************************\ * getPositivePrefix | *****************************************************************************/ jboolean DecimalFormat::isDecimalSeparatorAlwaysShown() { return decimalSeparatorAlwaysShown; } /*****************************************************************************\ * getPositivePrefix | *****************************************************************************/ jakelib::lang::Number * DecimalFormat::parse(String * str, ParsePosition * pos) { // Our strategy is simple: copy the text into a buffer, // translating or omitting locale-specific information. Then // let Double or Long convert the number for us. jboolean is_neg = false; jint index = pos->getIndex(); StringBuffer *buf = new StringBuffer(); // We have to check both prefixes, because one might be empty. // We want to pick the longest prefix that matches. jboolean got_pos = str->startsWith(positivePrefix, index); String *np = (negativePrefix != null ? negativePrefix : positivePrefix + symbols->getMinusSign()); jboolean got_neg = str->startsWith(np, index); if (got_pos && got_neg) { // By checking this way, we preserve ambiguity in the case // where the negative format differs only in suffix. We // check this again later. if (np->length() > positivePrefix->length()) { is_neg = true; index += np->length(); } else { index += positivePrefix->length(); } } else if (got_neg) { is_neg = true; index += np->length(); } else if (got_pos) index += positivePrefix->length(); else { pos->setErrorIndex(index); return null; } // FIXME: handle Inf and NaN. // FIXME: do we have to respect minimum/maxmimum digit stuff? // What about leading zeros? What about multiplier? jint start_index = index; jint max = str->length(); jchar zero = symbols->getZeroDigit(); jint last_group = -1; jboolean int_part = true; jboolean exp_part = false; for (; index < max; ++index) { jchar c = str->charAt(index); // FIXME: what about grouping size? if (groupingUsed && c == symbols->getGroupingSeparator()) { if (last_group != -1 && (index - last_group) % groupingSize != 0) { pos->setErrorIndex(index); return null; } last_group = index; } else if (c >= zero && c <= zero + 9) { buf->append((jchar) (c - zero + '0')); exp_part = false; } else if (parseIntegerOnly) { break; } else if (c == symbols->getDecimalSeparator()) { if (last_group != -1 && (index - last_group) % groupingSize != 0) { pos->setErrorIndex(index); return null; } buf->append('.'); int_part = false; } else if (c == symbols->getExponential()) { buf->append('E'); int_part = false; exp_part = true; } else if (exp_part && (c == '+' || c == '-' || c == symbols->getMinusSign())) { // For exponential notation. buf->append(c); } else { break; } } if (index == start_index) { // Didn't see any digits. pos->setErrorIndex(index); return null; } // Check the suffix. We must do this before converting the // buffer to a number to handle the case of a number which is // the most negative Long. jboolean got_pos_suf = str->startsWith(positiveSuffix, index); String *ns = (negativePrefix == null ? positiveSuffix : negativeSuffix); jboolean got_neg_suf = str->startsWith(ns, index); if (is_neg) { if (!got_neg_suf) { pos->setErrorIndex(index); return null; } } else if (got_pos && got_neg && got_neg_suf) { is_neg = true; } else if (got_pos != got_pos_suf && got_neg != got_neg_suf) { pos->setErrorIndex(index); return null; } String *suffix = is_neg ? ns : positiveSuffix; if (is_neg) { buf->insert(0, '-'); } String *t = buf->toString(); Number *result = null; try { result = new Long(t); } catch(NumberFormatException &) { try { result = new Double(t); } catch(NumberFormatException &) {} } if (result == null) { pos->setErrorIndex(index); return null; } pos->setIndex(index + suffix->length()); return result; } /*****************************************************************************\ * setDecimalFormatSymbols | *****************************************************************************/ void DecimalFormat::setDecimalFormatSymbols(jakelib::text::DecimalFormatSyms * newSymbols) { symbols = newSymbols; } /*****************************************************************************\ * setDecimalSeparatorAlwaysShown | *****************************************************************************/ void DecimalFormat::setDecimalSeparatorAlwaysShown(jboolean newValue) { decimalSeparatorAlwaysShown = newValue; } /*****************************************************************************\ * setGroupingSize | *****************************************************************************/ void DecimalFormat::setGroupingSize(jint groupSize) { groupingSize = (jbyte) groupSize; } /*****************************************************************************\ * setMaximumFractionDigits | *****************************************************************************/ void DecimalFormat::setMaximumFractionDigits(jint newValue) { maximumFractionDigits = Math::min(newValue, 340); } /*****************************************************************************\ * setMaximumIntegerDigits | *****************************************************************************/ void DecimalFormat::setMaximumIntegerDigits(jint newValue) { maximumIntegerDigits = Math::min(newValue, 309); } /*****************************************************************************\ * setMinimumFractionDigits | *****************************************************************************/ void DecimalFormat::setMinimumFractionDigits(jint newValue) { minimumFractionDigits = Math::min(newValue, 340); } /*****************************************************************************\ * setMinimumIntegerDigits | *****************************************************************************/ void DecimalFormat::setMinimumIntegerDigits(jint newValue) { minimumIntegerDigits = Math::min(newValue, 309); } /*****************************************************************************\ * setMultiplier | *****************************************************************************/ void DecimalFormat::setMultiplier(jint newValue) { multiplier = newValue; } /*****************************************************************************\ * setNegativePrefix | *****************************************************************************/ void DecimalFormat::setNegativePrefix(jakelib::lang::String * newValue) { negativePrefix = newValue; } /*****************************************************************************\ * setNegativeSuffix | *****************************************************************************/ void DecimalFormat::setNegativeSuffix(jakelib::lang::String * newValue) { negativeSuffix = newValue; } /*****************************************************************************\ * setPositivePrefix | *****************************************************************************/ void DecimalFormat::setPositivePrefix(jakelib::lang::String * newValue) { positivePrefix = newValue; } /*****************************************************************************\ * setPositiveSuffix | *****************************************************************************/ void DecimalFormat::setPositiveSuffix(jakelib::lang::String * newValue) { positiveSuffix = newValue; } /*****************************************************************************\ * quoteFix | *****************************************************************************/ void DecimalFormat::quoteFix(StringBuffer * buf, String * text, String * patChars) { jint len = text->length(); for (jint index = 0; index < len; ++index) { jchar c = text->charAt(index); if (patChars->indexOf(c) != -1) { buf->append('\''); buf->append(c); buf->append('\''); } else { buf->append(c); } } } /*****************************************************************************\ * computePattern | *****************************************************************************/ jakelib::lang::String * DecimalFormat::computePattern(DecimalFormatSyms * syms) { StringBuffer *mainPattern = new StringBuffer(); jint i = 0; // We have to at least emit a zero for the minimum number of // digits. Past that we need hash marks up to the grouping // separator (and one beyond). jint total_digits = Math::max(minimumIntegerDigits, groupingUsed ? groupingSize + 1 : 0); for (i = 0; i < total_digits - minimumIntegerDigits; ++i) mainPattern->append(syms->getDigit()); for (i = total_digits - minimumIntegerDigits; i < total_digits; ++i) mainPattern->append(syms->getZeroDigit()); // Inserting the gropuing operator afterwards is easier. if (groupingUsed) mainPattern->insert(mainPattern->length() - groupingSize, syms->getGroupingSeparator()); // See if we need decimal info. if (minimumFractionDigits > 0 || maximumFractionDigits > 0 || decimalSeparatorAlwaysShown) mainPattern->append(syms->getDecimalSeparator()); for (i = 0; i < minimumFractionDigits; ++i) mainPattern->append(syms->getZeroDigit()); for (i = minimumFractionDigits; i < maximumFractionDigits; ++i) mainPattern->append(syms->getDigit()); if (useExponentialNotation) { mainPattern->append(syms->getExponential()); for (i = 0; i < minExponentDigits; ++i) mainPattern->append(syms->getZeroDigit()); if (minExponentDigits == 0) mainPattern->append(syms->getDigit()); } String *main = mainPattern->toString(); String *patChars = patternChars(syms); mainPattern->setLength(0); quoteFix(mainPattern, positivePrefix, patChars); mainPattern->append(main); quoteFix(mainPattern, positiveSuffix, patChars); if (negativePrefix != null) { quoteFix(mainPattern, negativePrefix, patChars); mainPattern->append(main); quoteFix(mainPattern, negativeSuffix, patChars); } return mainPattern->toString(); } /*****************************************************************************\ * toLocalizedPattern | *****************************************************************************/ jakelib::lang::String * DecimalFormat::toLocalizedPattern() { return computePattern(symbols); } /*****************************************************************************\ * toPattern | *****************************************************************************/ jakelib::lang::String * DecimalFormat::toPattern() { return computePattern(nonLocalizedSymbols); } /*****************************************************************************\ * initDecimalFormatClass | *****************************************************************************/ void DecimalFormat::initDecimalFormatClass() { nonLocalizedSymbols = new DecimalFormatSyms(Locale::US); }