UnicodeString& U_EXPORT2 ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) { UErrorCode status = U_ZERO_ERROR; // Get canonical country for the zone getCanonicalCountry(tzid, country); if (!country.isEmpty()) { UResourceBundle *supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status); UResourceBundle *zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status); UResourceBundle *multizone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status); if (U_SUCCESS(status)) { while (ures_hasNext(multizone)) { int32_t len; const UChar* multizoneCountry = ures_getNextString(multizone, &len, NULL, &status); if (country.compare(multizoneCountry, len) == 0) { // Included in the multizone country list country.remove(); break; } } } ures_close(multizone); ures_close(zoneFormatting); ures_close(supplementalDataBundle); } return country; }
void ChoiceFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& status) const { // find the best number (defined as the one with the longest parse) int32_t start = status.getIndex(); int32_t furthest = start; double bestNumber = uprv_getNaN(); double tempNumber = 0.0; for (int i = 0; i < fCount; ++i) { int32_t len = fChoiceFormats[i].length(); if (text.compare(start, len, fChoiceFormats[i]) == 0) { status.setIndex(start + len); tempNumber = fChoiceLimits[i]; if (status.getIndex() > furthest) { furthest = status.getIndex(); bestNumber = tempNumber; if (furthest == text.length()) break; } } } status.setIndex(furthest); if (status.getIndex() == start) { status.setErrorIndex(furthest); } result.setDouble(bestNumber); }
UnicodeString& U_EXPORT2 ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString ®ion, UnicodeString &result) { initializeMetaToOlson(); UBool isSet = FALSE; if (gMetaToOlson != NULL) { UErrorCode status = U_ZERO_ERROR; UChar mzidUChars[ZID_KEY_MAX]; mzid.extract(mzidUChars, ZID_KEY_MAX, status); if (U_SUCCESS(status) && status!=U_STRING_NOT_TERMINATED_WARNING) { UVector *mappings = (UVector*)uhash_get(gMetaToOlson, mzidUChars); if (mappings != NULL) { // Find a preferred time zone for the given region. for (int32_t i = 0; i < mappings->size(); i++) { MetaToOlsonMappingEntry *olsonmap = (MetaToOlsonMappingEntry*)mappings->elementAt(i); if (region.compare(olsonmap->territory, -1) == 0) { result.setTo(olsonmap->id); isSet = TRUE; break; } else if (u_strcmp(olsonmap->territory, gWorld) == 0) { result.setTo(olsonmap->id); isSet = TRUE; } } } } } if (!isSet) { result.remove(); } return result; }
//---------------------------------------------------------------------------------------- // // findSetFor given a UnicodeString, // - find the corresponding Unicode Set (uset node) // (create one if necessary) // - Set fLeftChild of the caller's node (should be a setRef node) // to the uset node // Maintain a hash table of uset nodes, so the same one is always used // for the same string. // If a "to adopt" set is provided and we haven't seen this key before, // add the provided set to the hash table. // If the string is one (32 bit) char in length, the set contains // just one element which is the char in question. // If the string is "any", return a set containing all chars. // //---------------------------------------------------------------------------------------- void RBBIRuleScanner::findSetFor(const UnicodeString &s, RBBINode *node, UnicodeSet *setToAdopt) { RBBISetTableEl *el; // First check whether we've already cached a set for this string. // If so, just use the cached set in the new node. // delete any set provided by the caller, since we own it. el = (RBBISetTableEl *)uhash_get(fSetTable, &s); if (el != NULL) { delete setToAdopt; node->fLeftChild = el->val; U_ASSERT(node->fLeftChild->fType == RBBINode::uset); return; } // Haven't seen this set before. // If the caller didn't provide us with a prebuilt set, // create a new UnicodeSet now. if (setToAdopt == NULL) { if (s.compare(kAny, -1) == 0) { setToAdopt = new UnicodeSet(0x000000, 0x10ffff); } else { UChar32 c; c = s.char32At(0); setToAdopt = new UnicodeSet(c, c); } } // // Make a new uset node to refer to this UnicodeSet // This new uset node becomes the child of the caller's setReference node. // RBBINode *usetNode = new RBBINode(RBBINode::uset); usetNode->fInputSet = setToAdopt; usetNode->fParent = node; node->fLeftChild = usetNode; usetNode->fText = s; // // Add the new uset node to the list of all uset nodes. // fRB->fUSetNodes->addElement(usetNode, *fRB->fStatus); // // Add the new set to the set hash table. // el = (RBBISetTableEl *)uprv_malloc(sizeof(RBBISetTableEl)); UnicodeString *tkey = new UnicodeString(s); if (tkey == NULL || el == NULL || setToAdopt == NULL) { error(U_MEMORY_ALLOCATION_ERROR); return; } el->key = tkey; el->val = usetNode; uhash_put(fSetTable, el->key, el, fRB->fStatus); return; }
int pelet::SkipToIdentifier(BufferClass *buffer, UnicodeString identifier) { bool end = false; // add semicolon to make checks easier identifier.append(';'); UChar c = *buffer->Current; while (!end) { /* * read one line at a time. If the line is the identifier we'll stop. If we reach the * end, then this heredoc in unterminated. * be careful; do NOT store buffer->Current since it may change at any after buffer->AppendToLexeme * is called */ UnicodeString line; while (c != 0 && c != '\n' && c != '\r') { line.append(c); // only fill buffer when we its close to being filled up; this will prevent // useless copying of the buffer to remove slack if ((buffer->Limit - buffer->Current) < 2) { buffer->AppendToLexeme(1); } c = *(++buffer->Current); } if (c == 0) { end = true; return T_ERROR_UNTERMINATED_STRING; } // since we are eating up a newline, otherwise line numbering in lint errors // will be wrong buffer->IncrementLine(); bool hasEndingSemicolon = true; if (!line.endsWith(UNICODE_STRING(";", 1))) { line.append(UNICODE_STRING(";", 1)); hasEndingSemicolon = false; } if (line.compare(identifier) == 0) { end = true; // semicolons and newlines are NOT part of the nowdoc; the parser will look for semicolons // semicolon is OPTIONAL for heredoc / nowdoc if (hasEndingSemicolon) { buffer->Current--; } } else { if ((buffer->Limit - buffer->Current) < 2) { buffer->AppendToLexeme(1); } c = *(++buffer->Current); } } return 0; }
/** * Register a source-target/variant in the specDAG. Variant may be * empty, but source and target must not be. */ void TransliteratorRegistry::registerSTV(const UnicodeString& source, const UnicodeString& target, const UnicodeString& variant) { // assert(source.length() > 0); // assert(target.length() > 0); UErrorCode status = U_ZERO_ERROR; Hashtable *targets = (Hashtable*) specDAG.get(source); if (targets == 0) { int32_t size = 3; if (source.compare(ANY,3) == 0) { size = ANY_TARGETS_INIT_SIZE; } else if (source.compare(LAT,3) == 0) { size = LAT_TARGETS_INIT_SIZE; } targets = new Hashtable(TRUE, size, status); if (U_FAILURE(status) || targets == NULL) { return; } specDAG.put(source, targets, status); } int32_t variantListIndex = variantList.indexOf((void*) &variant, 0); if (variantListIndex < 0) { if (variantList.size() >= VARIANT_LIST_MAX_SIZE) { // can't handle any more variants return; } UnicodeString *variantEntry = new UnicodeString(variant); if (variantEntry != NULL) { variantList.addElement(variantEntry, status); if (U_SUCCESS(status)) { variantListIndex = variantList.size() - 1; } } if (variantListIndex < 0) { return; } } uint32_t addMask = 1 << variantListIndex; uint32_t varMask = targets->geti(target); targets->puti(target, varMask | addMask, status); }
int32_t StandardPlural::indexOrNegativeFromString(const UnicodeString &keyword) { switch (keyword.length()) { case 3: if (keyword.compare(gOne, 3) == 0) { return ONE; } else if (keyword.compare(gTwo, 3) == 0) { return TWO; } else if (keyword.compare(gFew, 3) == 0) { return FEW; } break; case 4: if (keyword.compare(gMany, 4) == 0) { return MANY; } else if (keyword.compare(gZero, 4) == 0) { return ZERO; } break; case 5: if (keyword.compare(gOther, 5) == 0) { return OTHER; } break; default: break; } return -1; }
UBool PluralRules::isKeyword(const UnicodeString& keyword) const { if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) { return true; } else { if (mRules==NULL) { return false; } else { return mRules->isKeyword(keyword); } } }
UnicodeString t4p::RowToSqlInsertClass::CreateStatement(t4p::DatabaseTagClass::Drivers driver) const { UnicodeString query; UnicodeString columnDelim; switch (driver) { case t4p::DatabaseTagClass::MYSQL: columnDelim = '`'; break; case t4p::DatabaseTagClass::SQLITE: columnDelim = '"'; break; } bool doMultiLine = MULTI_LINE == LineMode; query = UNICODE_STRING_SIMPLE("INSERT INTO "); query += TableName; query += UNICODE_STRING_SIMPLE(" ("); for (size_t i = 0; i < CheckedColumns.size(); ++i) { if (doMultiLine && (i % 5) == 0) { query += UNICODE_STRING_SIMPLE("\n"); } query += columnDelim + CheckedColumns[i] + columnDelim; if (i < (CheckedColumns.size() - 1)) { query += UNICODE_STRING_SIMPLE(","); } } if (doMultiLine) { query += UNICODE_STRING_SIMPLE("\n"); } query += UNICODE_STRING_SIMPLE(" ) VALUES ("); for (size_t i = 0; i < CheckedValues.size(); ++i) { if (doMultiLine && (i % 5) == 0) { query += UNICODE_STRING_SIMPLE("\n"); } UnicodeString val = CheckedValues[i]; if (val.compare(UNICODE_STRING_SIMPLE("<NULL>")) == 0) { val = UNICODE_STRING_SIMPLE("NULL"); } else { val = UNICODE_STRING_SIMPLE("'") + val + UNICODE_STRING_SIMPLE("'"); } query += val; if (i < (CheckedValues.size() - 1)) { query += UNICODE_STRING_SIMPLE(", "); } } query += UNICODE_STRING_SIMPLE(");"); return query; }
void RBBIAPITest::doTest(UnicodeString& testString, int32_t start, int32_t gotoffset, int32_t expectedOffset, const char* expectedString){ UnicodeString selected; UnicodeString expected=CharsToUnicodeString(expectedString); if(gotoffset != expectedOffset) errln((UnicodeString)"ERROR:****returned #" + gotoffset + (UnicodeString)" instead of #" + expectedOffset); if(start <= gotoffset){ testString.extractBetween(start, gotoffset, selected); } else{ testString.extractBetween(gotoffset, start, selected); } if(selected.compare(expected) != 0) errln(prettify((UnicodeString)"ERROR:****selected \"" + selected + "\" instead of \"" + expected + "\"")); else logln(prettify("****selected \"" + selected + "\"")); }
// ------------------------------------- // Finds the string, s, in the string array, list. int32_t MessageFormat::findKeyword(const UnicodeString& s, const UChar * const *list) { if (s.length() == 0) return 0; // default UnicodeString buffer = s; // Trims the space characters and turns all characters // in s to lower case. buffer.trim().toLower(""); for (int32_t i = 0; list[i]; ++i) { if (!buffer.compare(list[i], u_strlen(list[i]))) { return i; } } return -1; }
//------------------------------------------------------------------------------------- // // RangeDescriptor::setDictionaryFlag // // Character Category Numbers that include characters from // the original Unicode Set named "dictionary" have bit 14 // set to 1. The RBBI runtime engine uses this to trigger // use of the word dictionary. // // This function looks through the Unicode Sets that it // (the range) includes, and sets the bit in fNum when // "dictionary" is among them. // // TODO: a faster way would be to find the set node for // "dictionary" just once, rather than looking it // up by name every time. // //------------------------------------------------------------------------------------- void RangeDescriptor::setDictionaryFlag() { int i; for (i=0; i<this->fIncludesSets->size(); i++) { RBBINode *usetNode = (RBBINode *)fIncludesSets->elementAt(i); UnicodeString setName; RBBINode *setRef = usetNode->fParent; if (setRef != NULL) { RBBINode *varRef = setRef->fParent; if (varRef != NULL && varRef->fType == RBBINode::varRef) { setName = varRef->fText; } } if (setName.compare(UNICODE_STRING("dictionary", 10)) == 0) { // TODO: no string literals. this->fNum |= 0x4000; break; } } }
void RuleParser::getKeyType(const UnicodeString& token, tokenType& keyType, UErrorCode &status) { if (U_FAILURE(status)) { return; } if ( keyType==tNumber) { } else if (0 == token.compare(PK_VAR_N, 1)) { keyType = tVariableN; } else if (0 == token.compare(PK_IS, 2)) { keyType = tIs; } else if (0 == token.compare(PK_AND, 3)) { keyType = tAnd; } else if (0 == token.compare(PK_IN, 2)) { keyType = tIn; } else if (0 == token.compare(PK_WITHIN, 6)) { keyType = tWithin; } else if (0 == token.compare(PK_NOT, 3)) { keyType = tNot; } else if (0 == token.compare(PK_MOD, 3)) { keyType = tMod; } else if (0 == token.compare(PK_OR, 2)) { keyType = tOr; } else if ( isValidKeyword(token) ) { keyType = tKeyword; } else { status = U_UNEXPECTED_TOKEN; } }
int32_t PluralRules::getKeywordIndex(const UnicodeString& keyword, UErrorCode& status) const { if (U_SUCCESS(status)) { int32_t n = 0; RuleChain* rc = mRules; while (rc != NULL) { if (rc->ruleHeader != NULL) { if (rc->keyword == keyword) { return n; } ++n; } rc = rc->next; } if (0 == keyword.compare(PLURAL_KEYWORD_OTHER, 5)) { return n; } } return -1; }
static int32_t findInStringArray(UResourceBundle* array, const UnicodeString& id, UErrorCode &status) { UnicodeString copy; const UChar *u; int32_t len; int32_t start = 0; int32_t limit = ures_getSize(array); int32_t mid; int32_t lastMid = INT32_MAX; if(U_FAILURE(status) || (limit < 1)) { return -1; } U_DEBUG_TZ_MSG(("fisa: Looking for %s, between %d and %d\n", U_DEBUG_TZ_STR(UnicodeString(id).getTerminatedBuffer()), start, limit)); for (;;) { mid = (int32_t)((start + limit) / 2); if (lastMid == mid) { /* Have we moved? */ break; /* We haven't moved, and it wasn't found. */ } lastMid = mid; u = ures_getStringByIndex(array, mid, &len, &status); if (U_FAILURE(status)) { break; } U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit)); copy.setTo(TRUE, u, len); int r = id.compare(copy); if(r==0) { U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid)); return mid; } else if(r<0) { limit = mid; } else { start = mid; } } U_DEBUG_TZ_MSG(("fisa: not found\n")); return -1; }
UnicodeString t4p::RowToPhpClass::CreatePhpArray() { UnicodeString code; UnicodeString endCode; if (SYNTAX_KEYWORD == ArraySyntax) { code += UNICODE_STRING_SIMPLE("array (\n"); endCode = UNICODE_STRING_SIMPLE(")\n"); } else { code += UNICODE_STRING_SIMPLE("[\n"); endCode = UNICODE_STRING_SIMPLE("]\n"); } for (size_t i = 0; i < CheckedColumns.size(); ++i) { code += UNICODE_STRING_SIMPLE(" "); code += UNICODE_STRING_SIMPLE("'"); code += CheckedColumns[i]; code += UNICODE_STRING_SIMPLE("'"); code += UNICODE_STRING_SIMPLE(" => "); UnicodeString val; if (VALUES_ROW == CopyValues && i < CheckedValues.size()) { val = CheckedValues[i]; if (val.compare(UNICODE_STRING_SIMPLE("<NULL>")) == 0) { code += UNICODE_STRING_SIMPLE("NULL"); } else { code += UNICODE_STRING_SIMPLE("'"); code += val; code += UNICODE_STRING_SIMPLE("'"); } } else { code += UNICODE_STRING_SIMPLE("''"); } if (i < (CheckedColumns.size() - 1)) { code += UNICODE_STRING_SIMPLE(","); } code += UNICODE_STRING_SIMPLE("\n"); } code += endCode; code += UNICODE_STRING_SIMPLE("\n"); return code; }
void RelativeDateFormat::parse( const UnicodeString& text, Calendar& cal, ParsePosition& pos) const { // Can the fDateFormat parse it? if(fDateFormat != NULL) { ParsePosition aPos(pos); fDateFormat->parse(text,cal,aPos); if((aPos.getIndex() != pos.getIndex()) && (aPos.getErrorIndex()==-1)) { pos=aPos; // copy the sub parse return; // parsed subfmt OK } } // Linear search the relative strings for(int n=0; n<fDatesLen; n++) { if(fDates[n].string != NULL && (0==text.compare(pos.getIndex(), fDates[n].len, fDates[n].string))) { UErrorCode status = U_ZERO_ERROR; // Set the calendar to now+offset cal.setTime(Calendar::getNow(),status); cal.add(UCAL_DATE,fDates[n].offset, status); if(U_FAILURE(status)) { // failure in setting calendar fields pos.setErrorIndex(pos.getIndex()+fDates[n].len); } else { pos.setIndex(pos.getIndex()+fDates[n].len); } return; } } // parse failed }
int32_t ChoiceFormat::matchStringUntilLimitPart( const MessagePattern &pattern, int32_t partIndex, int32_t limitPartIndex, const UnicodeString &source, int32_t sourceOffset) { int32_t matchingSourceLength = 0; const UnicodeString &msgString = pattern.getPatternString(); int32_t prevIndex = pattern.getPart(partIndex).getLimit(); for (;;) { const MessagePattern::Part &part = pattern.getPart(++partIndex); if (partIndex == limitPartIndex || part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) { int32_t index = part.getIndex(); int32_t length = index - prevIndex; if (length != 0 && 0 != source.compare(sourceOffset, length, msgString, prevIndex, length)) { return -1; // mismatch } matchingSourceLength += length; if (partIndex == limitPartIndex) { return matchingSourceLength; } prevIndex = part.getLimit(); // SKIP_SYNTAX } } }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, EStyles style, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= kStyleCount) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } #ifdef U_WINDOWS char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat if (count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case kNumberStyle: curr = FALSE; // fall-through case kCurrencyStyle: case kIsoCurrencyStyle: // do not support plural formatting here case kPluralCurrencyStyle: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } #endif NumberFormat* f = NULL; DecimalFormatSymbols* symbolsToAdopt = NULL; UnicodeString pattern; UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status); UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status); NumberingSystem *ns = NULL; UBool deleteSymbols = TRUE; UHashtable * cache = NULL; int32_t hashKey; UBool getCache = FALSE; UBool deleteNS = FALSE; if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. symbolsToAdopt = new DecimalFormatSymbols(status); // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // If not all the styled patterns exists for the NumberFormat in this locale, // sets the status code to failure and returns nil. if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0])) -2 ) { //minus 2: ISO and plural status = U_INVALID_FORMAT_ERROR; goto cleanup; } // Loads the decimal symbols of the desired locale. symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status); int32_t patLen = 0; /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE, * the pattern is the same as the pattern of CURRENCYSTYLE * but by replacing the single currency sign with * double currency sign or triple currency sign. */ int styleInNumberPattern = ((style == kIsoCurrencyStyle || style == kPluralCurrencyStyle) ? kCurrencyStyle : style); const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)styleInNumberPattern, &patLen, &status); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status) || symbolsToAdopt == NULL) { goto cleanup; } if(style==kCurrencyStyle || style == kIsoCurrencyStyle){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } // Use numbering system cache hashtable UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache); if (getCache) { umtx_lock(&nscacheMutex); cache = NumberingSystem_cache; umtx_unlock(&nscacheMutex); } // Check cache we got, create if non-existant status = U_ZERO_ERROR; if (cache == NULL) { cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); if (cache == NULL || U_FAILURE(status)) { // cache not created - out of memory cache = NULL; } else { // cache created uhash_setValueDeleter(cache, deleteNumberingSystem); // set final NumberingSystem_cache value UHashtable* h = NULL; UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache); if (getCache) { umtx_lock(&nscacheMutex); h = NumberingSystem_cache; umtx_unlock(&nscacheMutex); } if (h == NULL) { umtx_lock(&nscacheMutex); NumberingSystem_cache = h = cache; cache = NULL; ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); umtx_unlock(&nscacheMutex); } if(cache != NULL) { uhash_close(cache); } cache = h; } } // Get cached numbering system if (cache != NULL) { hashKey = desiredLocale.hashCode(); umtx_lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(cache, hashKey, (void*)ns, &status); } umtx_unlock(&nscacheMutex); } else { ns = NumberingSystem::createInstance(desiredLocale,status); deleteNS = TRUE; } // check results of getting a numbering system if ((ns == NULL) || (U_FAILURE(status))) { goto cleanup; } if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; UnicodeString nsRuleSetName; Locale nsLoc; URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; nsDesc.setTo(ns->getDescription()); int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { char nsLocID[ULOC_FULLNAME_CAPACITY]; nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { desiredRulesType = URBNF_SPELLOUT; } } else { nsLoc = desiredLocale; nsRuleSetName.setTo(nsDesc); } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); if (U_FAILURE(status) || r == NULL) { goto cleanup; } r->setDefaultRuleSet(nsRuleSetName,status); f = (NumberFormat *) r; } else { // replace single currency sign in the pattern with double currency sign // if the style is kIsoCurrencyStyle if (style == kIsoCurrencyStyle) { pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign); } f = new DecimalFormat(pattern, symbolsToAdopt, style, status); if (U_FAILURE(status) || f == NULL) { goto cleanup; } deleteSymbols = FALSE; } f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status), ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status)); cleanup: ures_close(numberPatterns); ures_close(resource); if (deleteNS && ns) { delete ns; } if (U_FAILURE(status)) { /* If f exists, then it will delete the symbols */ if (f==NULL) { delete symbolsToAdopt; } else { delete f; } return NULL; } if (f == NULL || symbolsToAdopt == NULL) { status = U_MEMORY_ALLOCATION_ERROR; f = NULL; } if (deleteSymbols && symbolsToAdopt != NULL) { delete symbolsToAdopt; } return f; }
int32_t PluralFormat::findSubMessage(const MessagePattern& pattern, int32_t partIndex, const PluralSelector& selector, void *context, double number, UErrorCode& ec) { if (U_FAILURE(ec)) { return 0; } int32_t count=pattern.countParts(); double offset; const MessagePattern::Part* part=&pattern.getPart(partIndex); if (MessagePattern::Part::hasNumericValue(part->getType())) { offset=pattern.getNumericValue(*part); ++partIndex; } else { offset=0; } // The keyword is empty until we need to match against a non-explicit, not-"other" value. // Then we get the keyword from the selector. // (In other words, we never call the selector if we match against an explicit value, // or if the only non-explicit keyword is "other".) UnicodeString keyword; UnicodeString other(FALSE, OTHER_STRING, 5); // When we find a match, we set msgStart>0 and also set this boolean to true // to avoid matching the keyword again (duplicates are allowed) // while we continue to look for an explicit-value match. UBool haveKeywordMatch=FALSE; // msgStart is 0 until we find any appropriate sub-message. // We remember the first "other" sub-message if we have not seen any // appropriate sub-message before. // We remember the first matching-keyword sub-message if we have not seen // one of those before. // (The parser allows [does not check for] duplicate keywords. // We just have to make sure to take the first one.) // We avoid matching the keyword twice by also setting haveKeywordMatch=true // at the first keyword match. // We keep going until we find an explicit-value match or reach the end of the plural style. int32_t msgStart=0; // Iterate over (ARG_SELECTOR [ARG_INT|ARG_DOUBLE] message) tuples // until ARG_LIMIT or end of plural-only pattern. do { part=&pattern.getPart(partIndex++); const UMessagePatternPartType type = part->getType(); if(type==UMSGPAT_PART_TYPE_ARG_LIMIT) { break; } U_ASSERT (type==UMSGPAT_PART_TYPE_ARG_SELECTOR); // part is an ARG_SELECTOR followed by an optional explicit value, and then a message if(MessagePattern::Part::hasNumericValue(pattern.getPartType(partIndex))) { // explicit value like "=2" part=&pattern.getPart(partIndex++); if(number==pattern.getNumericValue(*part)) { // matches explicit value return partIndex; } } else if(!haveKeywordMatch) { // plural keyword like "few" or "other" // Compare "other" first and call the selector if this is not "other". if(pattern.partSubstringMatches(*part, other)) { if(msgStart==0) { msgStart=partIndex; if(0 == keyword.compare(other)) { // This is the first "other" sub-message, // and the selected keyword is also "other". // Do not match "other" again. haveKeywordMatch=TRUE; } } } else { if(keyword.isEmpty()) { keyword=selector.select(context, number-offset, ec); if(msgStart!=0 && (0 == keyword.compare(other))) { // We have already seen an "other" sub-message. // Do not match "other" again. haveKeywordMatch=TRUE; // Skip keyword matching but do getLimitPartIndex(). } } if(!haveKeywordMatch && pattern.partSubstringMatches(*part, keyword)) { // keyword matches msgStart=partIndex; // Do not match this keyword again. haveKeywordMatch=TRUE; } } } partIndex=pattern.getLimitPartIndex(partIndex); } while(++partIndex<count); return msgStart; }
void ChoiceFormat::applyPattern(const UnicodeString& pattern, UParseError& parseError, UErrorCode& status) { if (U_FAILURE(status)) { return; } // Clear error struct parseError.offset = -1; parseError.preContext[0] = parseError.postContext[0] = (UChar)0; // Perform 2 passes. The first computes the number of limits in // this pattern (fCount), which is 1 more than the number of // literal VERTICAL_BAR characters. int32_t count = 1; int32_t i; for (i=0; i<pattern.length(); ++i) { UChar c = pattern[i]; if (c == SINGLE_QUOTE) { // Skip over the entire quote, including embedded // contiguous pairs of SINGLE_QUOTE. for (;;) { do { ++i; } while (i<pattern.length() && pattern[i] != SINGLE_QUOTE); if ((i+1)<pattern.length() && pattern[i+1] == SINGLE_QUOTE) { // SINGLE_QUOTE pair; skip over it ++i; } else { break; } } } else if (c == VERTICAL_BAR) { ++count; } } // Allocate the required storage. double *newLimits = (double*) uprv_malloc( sizeof(double) * count); /* test for NULL */ if (newLimits == 0) { status = U_MEMORY_ALLOCATION_ERROR; return; } UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count); /* test for NULL */ if (newClosures == 0) { status = U_MEMORY_ALLOCATION_ERROR; uprv_free(newLimits); return; } UnicodeString *newFormats = new UnicodeString[count]; /* test for NULL */ if (newFormats == 0) { status = U_MEMORY_ALLOCATION_ERROR; uprv_free(newLimits); uprv_free(newClosures); return; } // Perform the second pass int32_t k = 0; // index into newXxx[] arrays UnicodeString buf; // scratch buffer UBool inQuote = FALSE; UBool inNumber = TRUE; // TRUE before < or #, FALSE after for (i=0; i<pattern.length(); ++i) { UChar c = pattern[i]; if (c == SINGLE_QUOTE) { // Check for SINGLE_QUOTE pair indicating a literal quote if ((i+1) < pattern.length() && pattern[i+1] == SINGLE_QUOTE) { buf += SINGLE_QUOTE; ++i; } else { inQuote = !inQuote; } } else if (inQuote) { buf += c; } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) { if (!inNumber || buf.length() == 0) { goto error; } inNumber = FALSE; double limit; buf.trim(); if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) { limit = uprv_getInfinity(); } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) { limit = -uprv_getInfinity(); } else { limit = stod(buf); } if (k == count) { // This shouldn't happen. If it does, it means that // the count determined in the first pass did not // match the number of elements found in the second // pass. goto error; } newLimits[k] = limit; newClosures[k] = (c == LESS_THAN); if (k > 0 && limit <= newLimits[k-1]) { // Each limit must be strictly > than the previous // limit. One exception: Two subsequent limits may be // == if the first closure is FALSE and the second // closure is TRUE. This places the limit value in // the second interval. if (!(limit == newLimits[k-1] && !newClosures[k-1] && newClosures[k])) { goto error; } } buf.truncate(0); } else if (c == VERTICAL_BAR) { if (inNumber) { goto error; } inNumber = TRUE; newFormats[k] = buf; ++k; buf.truncate(0); } else { buf += c; } } if (k != (count-1) || inNumber || inQuote) { goto error; } newFormats[k] = buf; // Don't modify this object until the parse succeeds uprv_free(fChoiceLimits); uprv_free(fClosures); delete[] fChoiceFormats; fCount = count; fChoiceLimits = newLimits; fClosures = newClosures; fChoiceFormats = newFormats; return; error: status = U_ILLEGAL_ARGUMENT_ERROR; syntaxError(pattern,i,parseError); uprv_free(newLimits); uprv_free(newClosures); delete[] newFormats; return; }
void RelativeDateFormat::parse( const UnicodeString& text, Calendar& cal, ParsePosition& pos) const { int32_t startIndex = pos.getIndex(); if (fDatePattern.isEmpty()) { // no date pattern, try parsing as time fDateTimeFormatter->applyPattern(fTimePattern); fDateTimeFormatter->parse(text,cal,pos); } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) { // no time pattern or way to combine, try parsing as date // first check whether text matches a relativeDayString UBool matchedRelative = FALSE; for (int n=0; n < fDatesLen && !matchedRelative; n++) { if (fDates[n].string != NULL && text.compare(startIndex, fDates[n].len, fDates[n].string) == 0) { // it matched, handle the relative day string UErrorCode status = U_ZERO_ERROR; matchedRelative = TRUE; // Set the calendar to now+offset cal.setTime(Calendar::getNow(),status); cal.add(UCAL_DATE,fDates[n].offset, status); if(U_FAILURE(status)) { // failure in setting calendar field, set offset to beginning of rel day string pos.setErrorIndex(startIndex); } else { pos.setIndex(startIndex + fDates[n].len); } } } if (!matchedRelative) { // just parse as normal date fDateTimeFormatter->applyPattern(fDatePattern); fDateTimeFormatter->parse(text,cal,pos); } } else { // Here we replace any relativeDayString in text with the equivalent date // formatted per fDatePattern, then parse text normally using the combined pattern. UnicodeString modifiedText(text); FieldPosition fPos; int32_t dateStart = 0, origDateLen = 0, modDateLen = 0; UErrorCode status = U_ZERO_ERROR; for (int n=0; n < fDatesLen; n++) { int32_t relativeStringOffset; if (fDates[n].string != NULL && (relativeStringOffset = modifiedText.indexOf(fDates[n].string, fDates[n].len, startIndex)) >= startIndex) { // it matched, replace the relative date with a real one for parsing UnicodeString dateString; Calendar * tempCal = cal.clone(); // Set the calendar to now+offset tempCal->setTime(Calendar::getNow(),status); tempCal->add(UCAL_DATE,fDates[n].offset, status); if(U_FAILURE(status)) { pos.setErrorIndex(startIndex); delete tempCal; return; } fDateTimeFormatter->applyPattern(fDatePattern); fDateTimeFormatter->format(*tempCal, dateString, fPos); dateStart = relativeStringOffset; origDateLen = fDates[n].len; modDateLen = dateString.length(); modifiedText.replace(dateStart, origDateLen, dateString); delete tempCal; break; } } UnicodeString combinedPattern; fCombinedFormat->format(fTimePattern, fDatePattern, combinedPattern, status); fDateTimeFormatter->applyPattern(combinedPattern); fDateTimeFormatter->parse(modifiedText,cal,pos); // Adjust offsets UBool noError = (pos.getErrorIndex() < 0); int32_t offset = (noError)? pos.getIndex(): pos.getErrorIndex(); if (offset >= dateStart + modDateLen) { // offset at or after the end of the replaced text, // correct by the difference between original and replacement offset -= (modDateLen - origDateLen); } else if (offset >= dateStart) { // offset in the replaced text, set it to the beginning of that text // (i.e. the beginning of the relative day string) offset = dateStart; } if (noError) { pos.setIndex(offset); } else { pos.setErrorIndex(offset); } } }
void NewResourceBundleTest::TestNewTypes() { char action[256]; const char* testdatapath; UErrorCode status = U_ZERO_ERROR; uint8_t *binResult = NULL; int32_t len = 0; int32_t i = 0; int32_t intResult = 0; uint32_t uintResult = 0; UChar expected[] = { 'a','b','c','\0','d','e','f' }; const char* expect ="tab:\t cr:\r ff:\f newline:\n backslash:\\\\ quote=\\\' doubleQuote=\\\" singlequoutes=''"; UChar uExpect[200]; testdatapath=loadTestData(status); if(U_FAILURE(status)) { dataerrln("Could not load testdata.dat %s \n",u_errorName(status)); return; } ResourceBundle theBundle(testdatapath, "testtypes", status); ResourceBundle bundle(testdatapath, Locale("te_IN"),status); UnicodeString emptyStr = theBundle.getStringEx("emptystring", status); if(emptyStr.length() != 0) { logln("Empty string returned invalid value\n"); } CONFIRM_UErrorCode(status, U_ZERO_ERROR); /* This test reads the string "abc\u0000def" from the bundle */ /* if everything is working correctly, the size of this string */ /* should be 7. Everything else is a wrong answer, esp. 3 and 6*/ strcpy(action, "getting and testing of string with embeded zero"); ResourceBundle res = theBundle.get("zerotest", status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_STRING); UnicodeString zeroString=res.getString(status); len = zeroString.length(); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(len, 7); CONFIRM_NE(len, 3); } for(i=0;i<len;i++){ if(zeroString[i]!= expected[i]){ logln("Output didnot match Expected: \\u%4X Got: \\u%4X", expected[i], zeroString[i]); } } strcpy(action, "getting and testing of binary type"); res = theBundle.get("binarytest", status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_BINARY); binResult=(uint8_t*)res.getBinary(len, status); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(len, 15); for(i = 0; i<15; i++) { CONFIRM_EQ(binResult[i], i); } } strcpy(action, "getting and testing of imported binary type"); res = theBundle.get("importtest",status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_BINARY); binResult=(uint8_t*)res.getBinary(len, status); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(len, 15); for(i = 0; i<15; i++) { CONFIRM_EQ(binResult[i], i); } } strcpy(action, "getting and testing of integer types"); res = theBundle.get("one", status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_INT); intResult=res.getInt(status); uintResult = res.getUInt(status); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(uintResult, (uint32_t)intResult); CONFIRM_EQ(intResult, 1); } strcpy(action, "getting minusone"); res = theBundle.get((const char*)"minusone", status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_INT); intResult=res.getInt(status); uintResult = res.getUInt(status); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(uintResult, 0x0FFFFFFF); /* a 28 bit integer */ CONFIRM_EQ(intResult, -1); CONFIRM_NE(uintResult, (uint32_t)intResult); } strcpy(action, "getting plusone"); res = theBundle.get("plusone",status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_INT); intResult=res.getInt(status); uintResult = res.getUInt(status); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(uintResult, (uint32_t)intResult); CONFIRM_EQ(intResult, 1); } res = theBundle.get("onehundredtwentythree",status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(res.getType(), URES_INT); intResult=res.getInt(status); if(U_SUCCESS(status)){ CONFIRM_UErrorCode(status, U_ZERO_ERROR); CONFIRM_EQ(intResult, 123); } /* this tests if escapes are preserved or not */ { UnicodeString str = theBundle.getStringEx("testescape",status); CONFIRM_UErrorCode(status, U_ZERO_ERROR); if(U_SUCCESS(status)){ u_charsToUChars(expect,uExpect,(int32_t)uprv_strlen(expect)+1); if(str.compare(uExpect)!=0){ errln("Did not get the expected string for testescape expected. Expected : " +UnicodeString(uExpect )+ " Got: " + str); } } } /* test for jitterbug#1435 */ { UnicodeString str = theBundle.getStringEx("test_underscores",status); expect ="test message ...."; CONFIRM_UErrorCode(status, U_ZERO_ERROR); u_charsToUChars(expect,uExpect,(int32_t)uprv_strlen(expect)+1); if(str.compare(uExpect)!=0){ errln("Did not get the expected string for test_underscores.\n"); } } }
virtual void run() { fTraceInfo = 1; LocalPointer<NumberFormat> percentFormatter; UErrorCode status = U_ZERO_ERROR; #if 0 // debugging code, for (int i=0; i<4000; i++) { status = U_ZERO_ERROR; UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status); UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status); udata_close(data1); udata_close(data2); if (U_FAILURE(status)) { error("udata_openChoice failed.\n"); break; } } return; #endif #if 0 // debugging code, int m; for (m=0; m<4000; m++) { status = U_ZERO_ERROR; UResourceBundle *res = NULL; const char *localeName = NULL; Locale loc = Locale::getEnglish(); localeName = loc.getName(); // localeName = "en"; // ResourceBundle bund = ResourceBundle(0, loc, status); //umtx_lock(&gDebugMutex); res = ures_open(NULL, localeName, &status); //umtx_unlock(&gDebugMutex); //umtx_lock(&gDebugMutex); ures_close(res); //umtx_unlock(&gDebugMutex); if (U_FAILURE(status)) { error("Resource bundle construction failed.\n"); break; } } return; #endif // Keep this data here to avoid static initialization. FormatThreadTestData kNumberFormatTestData[] = { FormatThreadTestData((double)5.0, UnicodeString("5", "")), FormatThreadTestData( 6.0, UnicodeString("6", "")), FormatThreadTestData( 20.0, UnicodeString("20", "")), FormatThreadTestData( 8.0, UnicodeString("8", "")), FormatThreadTestData( 8.3, UnicodeString("8.3", "")), FormatThreadTestData( 12345, UnicodeString("12,345", "")), FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")), }; int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) / sizeof(kNumberFormatTestData[0])); // Keep this data here to avoid static initialization. FormatThreadTestData kPercentFormatTestData[] = { FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")), FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")), FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")), FormatThreadTestData( 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP FormatThreadTestData( 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")), }; int32_t kPercentFormatTestDataLength = (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0])); int32_t iteration; status = U_ZERO_ERROR; LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status)); if(U_FAILURE(status)) { error("Error on NumberFormat::createInstance()."); goto cleanupAndReturn; } percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status)); if(U_FAILURE(status)) { error("Error on NumberFormat::createPercentInstance()."); goto cleanupAndReturn; } for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++) { int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength; UnicodeString output; formatter->format(kNumberFormatTestData[whichLine].number, output); if(0 != output.compare(kNumberFormatTestData[whichLine].string)) { error("format().. expected " + kNumberFormatTestData[whichLine].string + " got " + output); goto cleanupAndReturn; } // Now check percent. output.remove(); whichLine = (iteration + fOffset)%kPercentFormatTestDataLength; percentFormatter->format(kPercentFormatTestData[whichLine].number, output); if(0 != output.compare(kPercentFormatTestData[whichLine].string)) { error("percent format().. \n" + showDifference(kPercentFormatTestData[whichLine].string,output)); goto cleanupAndReturn; } // Test message error const int kNumberOfMessageTests = 3; UErrorCode statusToCheck; UnicodeString patternToCheck; Locale messageLocale; Locale countryToCheck; double currencyToCheck; UnicodeString expected; // load the cases. switch((iteration+fOffset) % kNumberOfMessageTests) { default: case 0: statusToCheck= U_FILE_ACCESS_ERROR; patternToCheck= "0:Someone from {2} is receiving a #{0}" " error - {1}. Their telephone call is costing " "{3,number,currency}."; // number,currency messageLocale= Locale("en","US"); countryToCheck= Locale("","HR"); currencyToCheck= 8192.77; expected= "0:Someone from Croatia is receiving a #4 error - " "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77."; break; case 1: statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR; patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency messageLocale= Locale("de","DE@currency=DEM"); countryToCheck= Locale("","BF"); currencyToCheck= 2.32; expected= CharsToUnicodeString( "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM."); break; case 2: statusToCheck= U_MEMORY_ALLOCATION_ERROR; patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. " "They insist they just spent {3,number,currency} " "on memory."; // number,currency messageLocale= Locale("de","AT@currency=ATS"); // Austrian German countryToCheck= Locale("","US"); // hmm currencyToCheck= 40193.12; expected= CharsToUnicodeString( "2:user in Vereinigte Staaten is receiving a #7 error" " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent" " \\u00f6S\\u00A040.193,12 on memory."); break; } UnicodeString result; UErrorCode status = U_ZERO_ERROR; formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck, countryToCheck,currencyToCheck,result); if(U_FAILURE(status)) { UnicodeString tmp(u_errorName(status)); error("Failure on message format, pattern=" + patternToCheck + ", error = " + tmp); goto cleanupAndReturn; } if(result != expected) { error("PatternFormat: \n" + showDifference(expected,result)); goto cleanupAndReturn; } } /* end of for loop */ cleanupAndReturn: // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing fTraceInfo = 2; }
/* {{{ timezone_convert_to_datetimezone * Convert from TimeZone to DateTimeZone object */ U_CFUNC zval *timezone_convert_to_datetimezone(const TimeZone *timeZone, intl_error *outside_error, const char *func, zval *ret) { UnicodeString id; char *message = NULL; php_timezone_obj *tzobj; zval arg; timeZone->getID(id); if (id.isBogus()) { spprintf(&message, 0, "%s: could not obtain TimeZone id", func); intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1); goto error; } object_init_ex(ret, php_date_get_timezone_ce()); tzobj = Z_PHPTIMEZONE_P(ret); if (id.compare(0, 3, UnicodeString("GMT", sizeof("GMT")-1, US_INV)) == 0) { /* The DateTimeZone constructor doesn't support offset time zones, * so we must mess with DateTimeZone structure ourselves */ tzobj->initialized = 1; tzobj->type = TIMELIB_ZONETYPE_OFFSET; //convert offset from milliseconds to minutes tzobj->tzi.utc_offset = -1 * timeZone->getRawOffset() / (60 * 1000); } else { char *str; size_t str_len; /* Call the constructor! */ if (intl_charFromString(id, &str, &str_len, &INTL_ERROR_CODE(*outside_error)) == FAILURE) { spprintf(&message, 0, "%s: could not convert id to UTF-8", func); intl_errors_set(outside_error, INTL_ERROR_CODE(*outside_error), message, 1); goto error; } ZVAL_STRINGL(&arg, str, str_len); //??? efree(str); zend_call_method_with_1_params(ret, NULL, NULL, "__construct", NULL, &arg); if (EG(exception)) { spprintf(&message, 0, "%s: DateTimeZone constructor threw exception", func); intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, message, 1); zend_object_store_ctor_failed(Z_OBJ_P(ret)); zval_ptr_dtor(&arg); goto error; } zval_ptr_dtor(&arg); } if (0) { error: if (ret) { zval_ptr_dtor(ret); } ret = NULL; } if (message) { efree(message); } return ret; }
void DecimalFormatPatternParser::applyPatternWithoutExpandAffix( const UnicodeString& pattern, DecimalFormatPattern& out, UParseError& parseError, UErrorCode& status) { if (U_FAILURE(status)) { return; } out = DecimalFormatPattern(); // Clear error struct parseError.offset = -1; parseError.preContext[0] = parseError.postContext[0] = (UChar)0; // TODO: Travis Keep: This won't always work. UChar nineDigit = (UChar)(fZeroDigit + 9); int32_t digitLen = fDigit.length(); int32_t groupSepLen = fGroupingSeparator.length(); int32_t decimalSepLen = fDecimalSeparator.length(); int32_t pos = 0; int32_t patLen = pattern.length(); // Part 0 is the positive pattern. Part 1, if present, is the negative // pattern. for (int32_t part=0; part<2 && pos<patLen; ++part) { // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix, // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is // between the prefix and suffix, and consists of pattern // characters. In the prefix and suffix, percent, perMill, and // currency symbols are recognized and translated. int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0; // It's important that we don't change any fields of this object // prematurely. We set the following variables for the multiplier, // grouping, etc., and then only change the actual object fields if // everything parses correctly. This also lets us register // the data from part 0 and ignore the part 1, except for the // prefix and suffix. UnicodeString prefix; UnicodeString suffix; int32_t decimalPos = -1; int32_t multiplier = 1; int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0; int8_t groupingCount = -1; int8_t groupingCount2 = -1; int32_t padPos = -1; UChar32 padChar = 0; int32_t roundingPos = -1; DigitList roundingInc; int8_t expDigits = -1; UBool expSignAlways = FALSE; // The affix is either the prefix or the suffix. UnicodeString* affix = &prefix; int32_t start = pos; UBool isPartDone = FALSE; UChar32 ch; for (; !isPartDone && pos < patLen; ) { // Todo: account for surrogate pairs ch = pattern.char32At(pos); switch (subpart) { case 0: // Pattern proper subpart (between prefix & suffix) // Process the digits, decimal, and grouping characters. We // record five pieces of information. We expect the digits // to occur in the pattern ####00.00####, and we record the // number of left digits, zero (central) digits, and right // digits. The position of the last grouping character is // recorded (should be somewhere within the first two blocks // of characters), as is the position of the decimal point, // if any (should be in the zero digits). If there is no // decimal point, then there should be no right digits. if (pattern.compare(pos, digitLen, fDigit) == 0) { if (zeroDigitCount > 0 || sigDigitCount > 0) { ++digitRightCount; } else { ++digitLeftCount; } if (groupingCount >= 0 && decimalPos < 0) { ++groupingCount; } pos += digitLen; } else if ((ch >= fZeroDigit && ch <= nineDigit) || ch == fSigDigit) { if (digitRightCount > 0) { // Unexpected '0' debug("Unexpected '0'") status = U_UNEXPECTED_TOKEN; syntaxError(pattern,pos,parseError); return; } if (ch == fSigDigit) { ++sigDigitCount; } else { if (ch != fZeroDigit && roundingPos < 0) { roundingPos = digitLeftCount + zeroDigitCount; } if (roundingPos >= 0) { roundingInc.append((char)(ch - fZeroDigit + '0')); } ++zeroDigitCount; } if (groupingCount >= 0 && decimalPos < 0) { ++groupingCount; } pos += U16_LENGTH(ch); } else if (pattern.compare(pos, groupSepLen, fGroupingSeparator) == 0) { if (decimalPos >= 0) { // Grouping separator after decimal debug("Grouping separator after decimal") status = U_UNEXPECTED_TOKEN; syntaxError(pattern,pos,parseError); return; } groupingCount2 = groupingCount; groupingCount = 0; pos += groupSepLen; } else if (pattern.compare(pos, decimalSepLen, fDecimalSeparator) == 0) { if (decimalPos >= 0) { // Multiple decimal separators debug("Multiple decimal separators") status = U_MULTIPLE_DECIMAL_SEPARATORS; syntaxError(pattern,pos,parseError); return; } // Intentionally incorporate the digitRightCount, // even though it is illegal for this to be > 0 // at this point. We check pattern syntax below. decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; pos += decimalSepLen; } else { if (pattern.compare(pos, fExponent.length(), fExponent) == 0) { if (expDigits >= 0) { // Multiple exponential symbols debug("Multiple exponential symbols") status = U_MULTIPLE_EXPONENTIAL_SYMBOLS; syntaxError(pattern,pos,parseError); return; } if (groupingCount >= 0) { // Grouping separator in exponential pattern debug("Grouping separator in exponential pattern") status = U_MALFORMED_EXPONENTIAL_PATTERN; syntaxError(pattern,pos,parseError); return; } pos += fExponent.length(); // Check for positive prefix if (pos < patLen && pattern.compare(pos, fPlus.length(), fPlus) == 0) { expSignAlways = TRUE; pos += fPlus.length(); } // Use lookahead to parse out the exponential part of the // pattern, then jump into suffix subpart. expDigits = 0; while (pos < patLen && pattern.char32At(pos) == fZeroDigit) { ++expDigits; pos += U16_LENGTH(fZeroDigit); } // 1. Require at least one mantissa pattern digit // 2. Disallow "#+ @" in mantissa // 3. Require at least one exponent pattern digit if (((digitLeftCount + zeroDigitCount) < 1 && (sigDigitCount + digitRightCount) < 1) || (sigDigitCount > 0 && digitLeftCount > 0) || expDigits < 1) { // Malformed exponential pattern debug("Malformed exponential pattern") status = U_MALFORMED_EXPONENTIAL_PATTERN; syntaxError(pattern,pos,parseError); return; } } // Transition to suffix subpart subpart = 2; // suffix subpart affix = &suffix; sub0Limit = pos; continue; } break; case 1: // Prefix subpart case 2: // Suffix subpart // Process the prefix / suffix characters // Process unquoted characters seen in prefix or suffix // subpart. // Several syntax characters implicitly begins the // next subpart if we are in the prefix; otherwise // they are illegal if unquoted. if (!pattern.compare(pos, digitLen, fDigit) || !pattern.compare(pos, groupSepLen, fGroupingSeparator) || !pattern.compare(pos, decimalSepLen, fDecimalSeparator) || (ch >= fZeroDigit && ch <= nineDigit) || ch == fSigDigit) { if (subpart == 1) { // prefix subpart subpart = 0; // pattern proper subpart sub0Start = pos; // Reprocess this character continue; } else { status = U_UNQUOTED_SPECIAL; syntaxError(pattern,pos,parseError); return; } } else if (ch == kCurrencySign) { affix->append(kQuote); // Encode currency // Use lookahead to determine if the currency sign is // doubled or not. U_ASSERT(U16_LENGTH(kCurrencySign) == 1); if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) { affix->append(kCurrencySign); ++pos; // Skip over the doubled character if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) { affix->append(kCurrencySign); ++pos; // Skip over the doubled character out.fCurrencySignCount = fgCurrencySignCountInPluralFormat; } else { out.fCurrencySignCount = fgCurrencySignCountInISOFormat; } } else { out.fCurrencySignCount = fgCurrencySignCountInSymbolFormat; } // Fall through to append(ch) } else if (ch == kQuote) { // A quote outside quotes indicates either the opening // quote or two quotes, which is a quote literal. That is, // we have the first quote in 'do' or o''clock. U_ASSERT(U16_LENGTH(kQuote) == 1); ++pos; if (pos < pattern.length() && pattern[pos] == kQuote) { affix->append(kQuote); // Encode quote // Fall through to append(ch) } else { subpart += 2; // open quote continue; } } else if (pattern.compare(pos, fSeparator.length(), fSeparator) == 0) { // Don't allow separators in the prefix, and don't allow // separators in the second pattern (part == 1). if (subpart == 1 || part == 1) { // Unexpected separator debug("Unexpected separator") status = U_UNEXPECTED_TOKEN; syntaxError(pattern,pos,parseError); return; } sub2Limit = pos; isPartDone = TRUE; // Go to next part pos += fSeparator.length(); break; } else if (pattern.compare(pos, fPercent.length(), fPercent) == 0) { // Next handle characters which are appended directly. if (multiplier != 1) { // Too many percent/perMill characters debug("Too many percent characters") status = U_MULTIPLE_PERCENT_SYMBOLS; syntaxError(pattern,pos,parseError); return; } affix->append(kQuote); // Encode percent/perMill affix->append(kPatternPercent); // Use unlocalized pattern char multiplier = 100; pos += fPercent.length(); break; } else if (pattern.compare(pos, fPerMill.length(), fPerMill) == 0) { // Next handle characters which are appended directly. if (multiplier != 1) { // Too many percent/perMill characters debug("Too many perMill characters") status = U_MULTIPLE_PERMILL_SYMBOLS; syntaxError(pattern,pos,parseError); return; } affix->append(kQuote); // Encode percent/perMill affix->append(kPatternPerMill); // Use unlocalized pattern char multiplier = 1000; pos += fPerMill.length(); break; } else if (pattern.compare(pos, fPadEscape.length(), fPadEscape) == 0) { if (padPos >= 0 || // Multiple pad specifiers (pos+1) == pattern.length()) { // Nothing after padEscape debug("Multiple pad specifiers") status = U_MULTIPLE_PAD_SPECIFIERS; syntaxError(pattern,pos,parseError); return; } padPos = pos; pos += fPadEscape.length(); padChar = pattern.char32At(pos); pos += U16_LENGTH(padChar); break; } else if (pattern.compare(pos, fMinus.length(), fMinus) == 0) { affix->append(kQuote); // Encode minus affix->append(kPatternMinus); pos += fMinus.length(); break; } else if (pattern.compare(pos, fPlus.length(), fPlus) == 0) { affix->append(kQuote); // Encode plus affix->append(kPatternPlus); pos += fPlus.length(); break; } // Unquoted, non-special characters fall through to here, as // well as other code which needs to append something to the // affix. affix->append(ch); pos += U16_LENGTH(ch); break; case 3: // Prefix subpart, in quote case 4: // Suffix subpart, in quote // A quote within quotes indicates either the closing // quote or two quotes, which is a quote literal. That is, // we have the second quote in 'do' or 'don''t'. if (ch == kQuote) { ++pos; if (pos < pattern.length() && pattern[pos] == kQuote) { affix->append(kQuote); // Encode quote // Fall through to append(ch) } else { subpart -= 2; // close quote continue; } } affix->append(ch); pos += U16_LENGTH(ch); break; } } if (sub0Limit == 0) { sub0Limit = pattern.length(); } if (sub2Limit == 0) { sub2Limit = pattern.length(); } /* Handle patterns with no '0' pattern character. These patterns * are legal, but must be recodified to make sense. "##.###" -> * "#0.###". ".###" -> ".0##". * * We allow patterns of the form "####" to produce a zeroDigitCount * of zero (got that?); although this seems like it might make it * possible for format() to produce empty strings, format() checks * for this condition and outputs a zero digit in this situation. * Having a zeroDigitCount of zero yields a minimum integer digits * of zero, which allows proper round-trip patterns. We don't want * "#" to become "#0" when toPattern() is called (even though that's * what it really is, semantically). */ if (zeroDigitCount == 0 && sigDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { // Handle "###.###" and "###." and ".###" int n = decimalPos; if (n == 0) ++n; // Handle ".###" digitRightCount = digitLeftCount - n; digitLeftCount = n - 1; zeroDigitCount = 1; } // Do syntax checking on the digits, decimal points, and quotes. if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) || (decimalPos >= 0 && (sigDigitCount > 0 || decimalPos < digitLeftCount || decimalPos > (digitLeftCount + zeroDigitCount))) || groupingCount == 0 || groupingCount2 == 0 || (sigDigitCount > 0 && zeroDigitCount > 0) || subpart > 2) { // subpart > 2 == unmatched quote debug("Syntax error") status = U_PATTERN_SYNTAX_ERROR; syntaxError(pattern,pos,parseError); return; } // Make sure pad is at legal position before or after affix. if (padPos >= 0) { if (padPos == start) { padPos = DecimalFormatPattern::kPadBeforePrefix; } else if (padPos+2 == sub0Start) { padPos = DecimalFormatPattern::kPadAfterPrefix; } else if (padPos == sub0Limit) { padPos = DecimalFormatPattern::kPadBeforeSuffix; } else if (padPos+2 == sub2Limit) { padPos = DecimalFormatPattern::kPadAfterSuffix; } else { // Illegal pad position debug("Illegal pad position") status = U_ILLEGAL_PAD_POSITION; syntaxError(pattern,pos,parseError); return; } } if (part == 0) { out.fPosPatternsBogus = FALSE; out.fPosPrefixPattern = prefix; out.fPosSuffixPattern = suffix; out.fNegPatternsBogus = TRUE; out.fNegPrefixPattern.remove(); out.fNegSuffixPattern.remove(); out.fUseExponentialNotation = (expDigits >= 0); if (out.fUseExponentialNotation) { out.fMinExponentDigits = expDigits; } out.fExponentSignAlwaysShown = expSignAlways; int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; // The effectiveDecimalPos is the position the decimal is at or // would be at if there is no decimal. Note that if // decimalPos<0, then digitTotalCount == digitLeftCount + // zeroDigitCount. int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount; UBool isSigDig = (sigDigitCount > 0); out.fUseSignificantDigits = isSigDig; if (isSigDig) { out.fMinimumSignificantDigits = sigDigitCount; out.fMaximumSignificantDigits = sigDigitCount + digitRightCount; } else { int32_t minInt = effectiveDecimalPos - digitLeftCount; out.fMinimumIntegerDigits = minInt; out.fMaximumIntegerDigits = out.fUseExponentialNotation ? digitLeftCount + out.fMinimumIntegerDigits : gDefaultMaxIntegerDigits; out.fMaximumFractionDigits = decimalPos >= 0 ? (digitTotalCount - decimalPos) : 0; out.fMinimumFractionDigits = decimalPos >= 0 ? (digitLeftCount + zeroDigitCount - decimalPos) : 0; } out.fGroupingUsed = groupingCount > 0; out.fGroupingSize = (groupingCount > 0) ? groupingCount : 0; out.fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount) ? groupingCount2 : 0; out.fMultiplier = multiplier; out.fDecimalSeparatorAlwaysShown = decimalPos == 0 || decimalPos == digitTotalCount; if (padPos >= 0) { out.fPadPosition = (DecimalFormatPattern::EPadPosition) padPos; // To compute the format width, first set up sub0Limit - // sub0Start. Add in prefix/suffix length later. // fFormatWidth = prefix.length() + suffix.length() + // sub0Limit - sub0Start; out.fFormatWidth = sub0Limit - sub0Start; out.fPad = padChar; } else { out.fFormatWidth = 0; } if (roundingPos >= 0) { out.fRoundingIncrementUsed = TRUE; roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos); out.fRoundingIncrement = roundingInc; } else { out.fRoundingIncrementUsed = FALSE; } } else { out.fNegPatternsBogus = FALSE; out.fNegPrefixPattern = prefix; out.fNegSuffixPattern = suffix; } } if (pattern.length() == 0) { out.fNegPatternsBogus = TRUE; out.fNegPrefixPattern.remove(); out.fNegSuffixPattern.remove(); out.fPosPatternsBogus = FALSE; out.fPosPrefixPattern.remove(); out.fPosSuffixPattern.remove(); out.fMinimumIntegerDigits = 0; out.fMaximumIntegerDigits = kDoubleIntegerDigits; out.fMinimumFractionDigits = 0; out.fMaximumFractionDigits = kDoubleFractionDigits; out.fUseExponentialNotation = FALSE; out.fCurrencySignCount = fgCurrencySignCountZero; out.fGroupingUsed = FALSE; out.fGroupingSize = 0; out.fGroupingSize2 = 0; out.fMultiplier = 1; out.fDecimalSeparatorAlwaysShown = FALSE; out.fFormatWidth = 0; out.fRoundingIncrementUsed = FALSE; } // If there was no negative pattern, or if the negative pattern is // identical to the positive pattern, then prepend the minus sign to the // positive pattern to form the negative pattern. if (out.fNegPatternsBogus || (out.fNegPrefixPattern == out.fPosPrefixPattern && out.fNegSuffixPattern == out.fPosSuffixPattern)) { out.fNegPatternsBogus = FALSE; out.fNegSuffixPattern = out.fPosSuffixPattern; out.fNegPrefixPattern.remove(); out.fNegPrefixPattern.append(kQuote).append(kPatternMinus) .append(out.fPosPrefixPattern); } // TODO: Deprecate/Remove out.fNegSuffixPattern and 3 other fields. AffixPattern::parseAffixString( out.fNegSuffixPattern, out.fNegSuffixAffix, status); AffixPattern::parseAffixString( out.fPosSuffixPattern, out.fPosSuffixAffix, status); AffixPattern::parseAffixString( out.fNegPrefixPattern, out.fNegPrefixAffix, status); AffixPattern::parseAffixString( out.fPosPrefixPattern, out.fPosPrefixAffix, status); }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, UNumberFormatStyle style, UBool mustBeDecimalFormat, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // Some styles are not supported. This is a result of merging // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle. // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations: // this one and unum_open(). // The UNUM_PATTERN_ styles are not supported here // because this method does not take a pattern string. if (!isStyleSupported(style)) { status = U_UNSUPPORTED_ERROR; return NULL; } #if U_PLATFORM_USES_ONLY_WIN32_API if (!mustBeDecimalFormat) { char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat if (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case UNUM_DECIMAL: curr = FALSE; // fall-through case UNUM_CURRENCY: case UNUM_CURRENCY_ISO: // do not support plural formatting here case UNUM_CURRENCY_PLURAL: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } } #endif // Use numbering system cache hashtable umtx_initOnce(gNSCacheInitOnce, &nscacheInit); // Get cached numbering system LocalPointer<NumberingSystem> ownedNs; NumberingSystem *ns = NULL; if (NumberingSystem_cache != NULL) { // TODO: Bad hash key usage, see ticket #8504. int32_t hashKey = desiredLocale.hashCode(); Mutex lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status); } } else { ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); ns = ownedNs.getAlias(); } // check results of getting a numbering system if (U_FAILURE(status)) { return NULL; } if (mustBeDecimalFormat && ns->isAlgorithmic()) { status = U_UNSUPPORTED_ERROR; return NULL; } LocalPointer<DecimalFormatSymbols> symbolsToAdopt; UnicodeString pattern; LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status)); if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // Loads the decimal symbols of the desired locale. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } UResourceBundle *resource = ownedResource.orphan(); UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status); resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); ownedResource.adoptInstead(resource); int32_t patLen = 0; const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); // Didn't find a pattern specific to the numbering system, so fall back to "latn" if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) { status = U_ZERO_ERROR; resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); } ures_close(numElements); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status)) { return NULL; } if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } NumberFormat *f; if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; UnicodeString nsRuleSetName; Locale nsLoc; URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; nsDesc.setTo(ns->getDescription()); int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { CharString nsLocID; nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID.data()); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { desiredRulesType = URBNF_SPELLOUT; } } else { nsLoc = desiredLocale; nsRuleSetName.setTo(nsDesc); } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); if (r == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } r->setDefaultRuleSet(nsRuleSetName,status); f = r; } else { // replace single currency sign in the pattern with double currency sign // if the style is UNUM_CURRENCY_ISO if (style == UNUM_CURRENCY_ISO) { pattern.findAndReplace(UnicodeString(TRUE, gSingleCurrencySign, 1), UnicodeString(TRUE, gDoubleCurrencySign, 2)); } // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); f = new DecimalFormat(pattern, syms, style, status); if (f == NULL) { delete syms; status = U_MEMORY_ALLOCATION_ERROR; return NULL; } } f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); if (U_FAILURE(status)) { delete f; return NULL; } return f; }
seec::Maybe<IndexedString> IndexedString::from(UnicodeString const &String) { if (String.isBogus()) return seec::Maybe<IndexedString>(); UnicodeString const NeedleStart("@["); UnicodeString const NeedleEscape("@[["); UnicodeString const NeedleEnd("]"); UnicodeString CleanedString; // String with index indicators removed. std::multimap<UnicodeString, Needle> Needles; std::vector<std::pair<UnicodeString, int32_t>> IndexStack; int32_t SearchFrom = 0; // Current offset in String. int32_t FoundStart; // Position of matched index indicator. while ((FoundStart = String.indexOf(NeedleStart, SearchFrom)) != -1) { // Copy all the literal string data. CleanedString.append(String, SearchFrom, FoundStart - SearchFrom); // Check if this is an escape sequence. if (String.compare(FoundStart, NeedleEscape.length(), NeedleEscape) == 0) { CleanedString.append(NeedleStart); SearchFrom = FoundStart + NeedleEscape.length(); continue; } // Find the end of this sequence. int32_t FoundEnd = String.indexOf(NeedleEnd, SearchFrom); if (FoundEnd == -1) return seec::Maybe<IndexedString>(); if (FoundEnd == FoundStart + NeedleStart.length()) { // This is a closing sequence. if (IndexStack.size() == 0) return seec::Maybe<IndexedString>(); // Pop the starting details of the last-opened sequence. auto const Start = IndexStack.back(); IndexStack.pop_back(); // Store the needle for this sequence. Needles.insert(std::make_pair(Start.first, Needle(Start.second, CleanedString.countChar32()))); } else { // This is an opening sequence. int32_t const NameStart = FoundStart + NeedleStart.length(); int32_t const NameLength = FoundEnd - NameStart; IndexStack.emplace_back(UnicodeString(String, NameStart, NameLength), CleanedString.countChar32()); } SearchFrom = FoundEnd + NeedleEnd.length(); } // Copy all remaining literal data. CleanedString.append(String, SearchFrom, String.length() - SearchFrom); return IndexedString(std::move(CleanedString), std::move(Needles)); }
/** * See if the decomposition of cp2 is at segment starting at segmentPos * (with canonical rearrangment!) * If so, take the remainder, and return the equivalents */ Hashtable *CanonicalIterator::extract(Hashtable *fillinResult, UChar32 comp, const UChar *segment, int32_t segLen, int32_t segmentPos, UErrorCode &status) { //Hashtable *CanonicalIterator::extract(UChar32 comp, const UnicodeString &segment, int32_t segLen, int32_t segmentPos, UErrorCode &status) { //if (PROGRESS) printf(" extract: %s, ", UToS(Tr(UnicodeString(comp)))); //if (PROGRESS) printf("%s, %i\n", UToS(Tr(segment)), segmentPos); if (U_FAILURE(status)) { return NULL; } UnicodeString temp(comp); int32_t inputLen=temp.length(); UnicodeString decompString; nfd.normalize(temp, decompString, status); if (U_FAILURE(status)) { return NULL; } if (decompString.isBogus()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } const UChar *decomp=decompString.getBuffer(); int32_t decompLen=decompString.length(); // See if it matches the start of segment (at segmentPos) UBool ok = FALSE; UChar32 cp; int32_t decompPos = 0; UChar32 decompCp; U16_NEXT(decomp, decompPos, decompLen, decompCp); int32_t i = segmentPos; while(i < segLen) { U16_NEXT(segment, i, segLen, cp); if (cp == decompCp) { // if equal, eat another cp from decomp //if (PROGRESS) printf(" matches: %s\n", UToS(Tr(UnicodeString(cp)))); if (decompPos == decompLen) { // done, have all decomp characters! temp.append(segment+i, segLen-i); ok = TRUE; break; } U16_NEXT(decomp, decompPos, decompLen, decompCp); } else { //if (PROGRESS) printf(" buffer: %s\n", UToS(Tr(UnicodeString(cp)))); // brute force approach temp.append(cp); /* TODO: optimize // since we know that the classes are monotonically increasing, after zero // e.g. 0 5 7 9 0 3 // we can do an optimization // there are only a few cases that work: zero, less, same, greater // if both classes are the same, we fail // if the decomp class < the segment class, we fail segClass = getClass(cp); if (decompClass <= segClass) return null; */ } } if (!ok) return NULL; // we failed, characters left over //if (PROGRESS) printf("Matches\n"); if (inputLen == temp.length()) { fillinResult->put(UnicodeString(), new UnicodeString(), status); return fillinResult; // succeed, but no remainder } // brute force approach // check to make sure result is canonically equivalent UnicodeString trial; nfd.normalize(temp, trial, status); if(U_FAILURE(status) || trial.compare(segment+segmentPos, segLen - segmentPos) != 0) { return NULL; } return getEquivalents2(fillinResult, temp.getBuffer()+inputLen, temp.length()-inputLen, status); }
void IdnaConfTest::Test(void){ if (!ReadAndConvertFile())return; UnicodeString s; UnicodeString key; UnicodeString value; // skip everything before the first "=====" and "=====" itself do { if (!ReadOneLine(s)) { errln("End of file prematurely found"); break; } } while (s.compare(C_TAG, -1) != 0); //"=====" while(ReadOneLine(s)){ s.trim(); key.remove(); value.remove(); if (s.compare(C_TAG, -1) == 0){ //"=====" Call(); } else { // explain key:value int p = s.indexOf((UChar)0x3A); // : key.setTo(s,0,p).trim(); value.setTo(s,p+1).trim(); if (key.compare(C_TYPE, -1) == 0){ if (value.compare(C_TOASCII, -1) == 0) { type = 0; } else if (value.compare(C_TOUNICODE, -1) == 0){ type = 1; } } else if (key.compare(C_PASSFAIL, -1) == 0){ if (value.compare(C_PASS, -1) == 0){ passfail = 0; } else if (value.compare(C_FAIL, -1) == 0){ passfail = 1; } } else if (key.compare(C_DESC, -1) == 0){ if (value.indexOf(C_USESTD3ASCIIRULES, u_strlen(C_USESTD3ASCIIRULES), 0) == -1){ option = 1; // not found } else { option = 0; } id.setTo(value, 0, value.indexOf((UChar)0x20)); // space } else if (key.compare(C_NAMEZONE, -1) == 0){ ExplainCodePointTag(value); namezone.setTo(value); } else if (key.compare(C_NAMEBASE, -1) == 0){ ExplainCodePointTag(value); namebase.setTo(value); } // just skip other lines } } Call(); // for last record }