ICU-22520 Standardize return on error for all locale functions.

· No function should do anything if an error has already occurred.
· On error, a value of 0, nullptr, {}, etc., should be returned.
· Values shouldn't have overloaded meanings (eg. index or found).
· Values that are never used should not be returned at all.
This commit is contained in:
Fredrik Roubert 2024-02-12 21:47:25 +01:00 committed by Fredrik Roubert
parent 35353f2d7f
commit 929cd9bb4f
17 changed files with 361 additions and 359 deletions

View file

@ -203,6 +203,7 @@ _copyExtensions(const Locale& from, icu::StringEnumeration *keywords,
void
_clearUAttributesAndKeyType(Locale& locale, UErrorCode& errorCode)
{
if (U_FAILURE(errorCode)) { return; }
// Clear Unicode attributes
locale.setKeywordValue(kAttributeKey, "", errorCode);
@ -218,6 +219,7 @@ _clearUAttributesAndKeyType(Locale& locale, UErrorCode& errorCode)
void
_setUnicodeExtensions(Locale& locale, const CharString& value, UErrorCode& errorCode)
{
if (U_FAILURE(errorCode)) { return; }
// Add the unicode extensions to extensions_
CharString locale_str("und-u-", errorCode);
locale_str.append(value, errorCode);

View file

@ -4,6 +4,8 @@
// localematcher.cpp
// created: 2019may08 Markus W. Scherer
#include <optional>
#include "unicode/utypes.h"
#include "unicode/localebuilder.h"
#include "unicode/localematcher.h"
@ -605,10 +607,11 @@ private:
const Locale *LocaleMatcher::getBestMatch(const Locale &desiredLocale, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return nullptr; }
int32_t suppIndex = getBestSuppIndex(
std::optional<int32_t> suppIndex = getBestSuppIndex(
getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode),
nullptr, errorCode);
return U_SUCCESS(errorCode) && suppIndex >= 0 ? supportedLocales[suppIndex] : defaultLocale;
return U_SUCCESS(errorCode) && suppIndex.has_value() ? supportedLocales[suppIndex.value()]
: defaultLocale;
}
const Locale *LocaleMatcher::getBestMatch(Locale::Iterator &desiredLocales,
@ -618,12 +621,14 @@ const Locale *LocaleMatcher::getBestMatch(Locale::Iterator &desiredLocales,
return defaultLocale;
}
LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES);
int32_t suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
return U_SUCCESS(errorCode) && suppIndex >= 0 ? supportedLocales[suppIndex] : defaultLocale;
std::optional<int32_t> suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
return U_SUCCESS(errorCode) && suppIndex.has_value() ? supportedLocales[suppIndex.value()]
: defaultLocale;
}
const Locale *LocaleMatcher::getBestMatchForListString(
StringPiece desiredLocaleList, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return nullptr; }
LocalePriorityList list(desiredLocaleList, errorCode);
LocalePriorityList::Iterator iter = list.iterator();
return getBestMatch(iter, errorCode);
@ -634,13 +639,13 @@ LocaleMatcher::Result LocaleMatcher::getBestMatchResult(
if (U_FAILURE(errorCode)) {
return Result(nullptr, defaultLocale, -1, -1, false);
}
int32_t suppIndex = getBestSuppIndex(
std::optional<int32_t> suppIndex = getBestSuppIndex(
getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode),
nullptr, errorCode);
if (U_FAILURE(errorCode) || suppIndex < 0) {
if (U_FAILURE(errorCode) || !suppIndex.has_value()) {
return Result(nullptr, defaultLocale, -1, -1, false);
} else {
return Result(&desiredLocale, supportedLocales[suppIndex], 0, suppIndex, false);
return Result(&desiredLocale, supportedLocales[suppIndex.value()], 0, suppIndex.value(), false);
}
}
@ -650,18 +655,19 @@ LocaleMatcher::Result LocaleMatcher::getBestMatchResult(
return Result(nullptr, defaultLocale, -1, -1, false);
}
LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES);
int32_t suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
if (U_FAILURE(errorCode) || suppIndex < 0) {
std::optional<int32_t> suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
if (U_FAILURE(errorCode) || !suppIndex.has_value()) {
return Result(nullptr, defaultLocale, -1, -1, false);
} else {
return Result(lsrIter.orphanRemembered(), supportedLocales[suppIndex],
lsrIter.getBestDesiredIndex(), suppIndex, true);
return Result(lsrIter.orphanRemembered(), supportedLocales[suppIndex.value()],
lsrIter.getBestDesiredIndex(), suppIndex.value(), true);
}
}
int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remainingIter,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return -1; }
std::optional<int32_t> LocaleMatcher::getBestSuppIndex(LSR desiredLSR,
LocaleLsrIterator *remainingIter,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return std::nullopt; }
int32_t desiredIndex = 0;
int32_t bestSupportedLsrIndex = -1;
for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) {
@ -684,7 +690,7 @@ int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remai
bestShiftedDistance = LocaleDistance::getShiftedDistance(bestIndexAndDistance);
if (remainingIter != nullptr) {
remainingIter->rememberCurrent(desiredIndex, errorCode);
if (U_FAILURE(errorCode)) { return -1; }
if (U_FAILURE(errorCode)) { return std::nullopt; }
}
bestSupportedLsrIndex = LocaleDistance::getIndex(bestIndexAndDistance);
}
@ -695,20 +701,21 @@ int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remai
break;
}
desiredLSR = remainingIter->next(errorCode);
if (U_FAILURE(errorCode)) { return -1; }
if (U_FAILURE(errorCode)) { return std::nullopt; }
++desiredIndex;
}
if (bestSupportedLsrIndex < 0) {
// no good match
return -1;
return std::nullopt;
}
return supportedIndexes[bestSupportedLsrIndex];
}
UBool LocaleMatcher::isMatch(const Locale &desired, const Locale &supported,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return false; }
LSR suppLSR = getMaximalLsrOrUnd(likelySubtags, supported, errorCode);
if (U_FAILURE(errorCode)) { return 0; }
if (U_FAILURE(errorCode)) { return false; }
const LSR *pSuppLSR = &suppLSR;
int32_t indexAndDistance = localeDistance.getBestIndexAndDistance(
getMaximalLsrOrUnd(likelySubtags, desired, errorCode),
@ -718,9 +725,10 @@ UBool LocaleMatcher::isMatch(const Locale &desired, const Locale &supported,
}
double LocaleMatcher::internalMatch(const Locale &desired, const Locale &supported, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return 0.; }
// Returns the inverse of the distance: That is, 1-distance(desired, supported).
LSR suppLSR = getMaximalLsrOrUnd(likelySubtags, supported, errorCode);
if (U_FAILURE(errorCode)) { return 0; }
if (U_FAILURE(errorCode)) { return 0.; }
const LSR *pSuppLSR = &suppLSR;
int32_t indexAndDistance = localeDistance.getBestIndexAndDistance(
getMaximalLsrOrUnd(likelySubtags, desired, errorCode),

View file

@ -101,10 +101,9 @@ icu::UInitOnce ginstalledLocalesInitOnce {};
class AvailableLocalesSink : public ResourceSink {
public:
void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UErrorCode &status) override {
if (U_FAILURE(status)) { return; }
ResourceTable resIndexTable = value.getTable(status);
if (U_FAILURE(status)) {
return;
}
if (U_FAILURE(status)) { return; }
for (int32_t i = 0; resIndexTable.getKeyAndValue(i, key, value); ++i) {
ULocAvailableType type;
if (uprv_strcmp(key, "InstalledLocales") == 0) {
@ -138,7 +137,8 @@ class AvailableLocalesStringEnumeration : public StringEnumeration {
AvailableLocalesStringEnumeration(ULocAvailableType type) : fType(type) {
}
const char* next(int32_t *resultLength, UErrorCode&) override {
const char* next(int32_t *resultLength, UErrorCode &status) override {
if (U_FAILURE(status)) { return nullptr; }
ULocAvailableType actualType = fType;
int32_t actualIndex = fIndex++;
@ -170,11 +170,13 @@ class AvailableLocalesStringEnumeration : public StringEnumeration {
return result;
}
void reset(UErrorCode&) override {
void reset(UErrorCode &status) override {
if (U_FAILURE(status)) { return; }
fIndex = 0;
}
int32_t count(UErrorCode&) const override {
int32_t count(UErrorCode &status) const override {
if (U_FAILURE(status)) { return 0; }
if (fType == ULOC_AVAILABLE_WITH_LEGACY_ALIASES) {
return gAvailableLocaleCounts[ULOC_AVAILABLE_DEFAULT]
+ gAvailableLocaleCounts[ULOC_AVAILABLE_ONLY_LEGACY_ALIASES];

View file

@ -306,6 +306,7 @@ _getStringOrCopyKey(const char *path, const char *locale,
const char *substitute,
char16_t *dest, int32_t destCapacity,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return 0; }
const char16_t *s = nullptr;
int32_t length = 0;
@ -368,14 +369,10 @@ _getDisplayNameForComponent(const char *locale,
UDisplayNameGetter *getter,
const char *tag,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return 0; }
UErrorCode localStatus;
const char* root = nullptr;
/* argument checking */
if (U_FAILURE(errorCode)) {
return 0;
}
if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
@ -422,6 +419,7 @@ uloc_getDisplayScript(const char* locale,
char16_t *dest, int32_t destCapacity,
UErrorCode *pErrorCode)
{
if (U_FAILURE(*pErrorCode)) { return 0; }
UErrorCode err = U_ZERO_ERROR;
int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
ulocimp_getScript, _kScriptsStandAlone, err);

View file

@ -916,6 +916,8 @@ AliasData::loadData(UErrorCode &status)
*/
AliasData*
AliasDataBuilder::build(UErrorCode &status) {
if (U_FAILURE(status)) { return nullptr; }
LocalUResourceBundlePointer metadata(
ures_openDirect(nullptr, "metadata", &status));
LocalUResourceBundlePointer metadataAlias(
@ -1061,7 +1063,7 @@ AliasDataBuilder::build(UErrorCode &status) {
*/
class AliasReplacer {
public:
AliasReplacer(UErrorCode status) :
AliasReplacer(UErrorCode& status) :
language(nullptr), script(nullptr), region(nullptr),
extensions(nullptr),
// store value in variants only once
@ -1126,12 +1128,12 @@ private:
}
// Gather fields and generate locale ID into out.
CharString& outputToString(CharString& out, UErrorCode status);
CharString& outputToString(CharString& out, UErrorCode& status);
// Generate the lookup key.
CharString& generateKey(const char* language, const char* region,
const char* variant, CharString& out,
UErrorCode status);
UErrorCode& status);
void parseLanguageReplacement(const char* replacement,
const char*& replaceLanguage,
@ -1168,8 +1170,9 @@ private:
CharString&
AliasReplacer::generateKey(
const char* language, const char* region, const char* variant,
CharString& out, UErrorCode status)
CharString& out, UErrorCode& status)
{
if (U_FAILURE(status)) { return out; }
out.append(language, status);
if (notEmpty(region)) {
out.append(SEP_CHAR, status)
@ -1587,8 +1590,9 @@ AliasReplacer::replaceTransformedExtensions(
CharString&
AliasReplacer::outputToString(
CharString& out, UErrorCode status)
CharString& out, UErrorCode& status)
{
if (U_FAILURE(status)) { return out; }
out.append(language, status);
if (notEmpty(script)) {
out.append(SEP_CHAR, status)
@ -1778,6 +1782,7 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
bool
canonicalizeLocale(const Locale& locale, CharString& out, UErrorCode& status)
{
if (U_FAILURE(status)) { return false; }
AliasReplacer replacer(status);
return replacer.replace(locale, out, status);
}
@ -1787,6 +1792,8 @@ canonicalizeLocale(const Locale& locale, CharString& out, UErrorCode& status)
bool
isKnownCanonicalizedLocale(const char* locale, UErrorCode& status)
{
if (U_FAILURE(status)) { return false; }
if ( uprv_strcmp(locale, "c") == 0 ||
uprv_strcmp(locale, "en") == 0 ||
uprv_strcmp(locale, "en_US") == 0) {
@ -2453,7 +2460,8 @@ public:
(int32_t)(current - keywords.data()), status);
}
virtual int32_t count(UErrorCode &/*status*/) const override {
virtual int32_t count(UErrorCode& status) const override {
if (U_FAILURE(status)) { return 0; }
const char *kw = keywords.data();
int32_t result = 0;
while(*kw) {
@ -2483,12 +2491,14 @@ public:
}
virtual const UnicodeString* snext(UErrorCode& status) override {
if (U_FAILURE(status)) { return nullptr; }
int32_t resultLength = 0;
const char *s = next(&resultLength, status);
return setChars(s, resultLength, status);
}
virtual void reset(UErrorCode& /*status*/) override {
virtual void reset(UErrorCode& status) override {
if (U_FAILURE(status)) { return; }
current = keywords.data();
}
};
@ -2521,7 +2531,8 @@ public:
if (resultLength != nullptr) *resultLength = 0;
return nullptr;
}
virtual int32_t count(UErrorCode &/*status*/) const override {
virtual int32_t count(UErrorCode& status) const override {
if (U_FAILURE(status)) { return 0; }
const char *kw = keywords.data();
int32_t result = 0;
while(*kw) {
@ -2625,6 +2636,10 @@ void
Locale::getUnicodeKeywordValue(StringPiece keywordName,
ByteSink& sink,
UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
// TODO: Remove the need for a const char* to a NUL terminated buffer.
const CharString keywordName_nul(keywordName, status);
if (U_FAILURE(status)) {
@ -2632,7 +2647,6 @@ Locale::getUnicodeKeywordValue(StringPiece keywordName,
}
const char* legacy_key = uloc_toLegacyKey(keywordName_nul.data());
if (legacy_key == nullptr) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
@ -2705,6 +2719,7 @@ void
Locale::setKeywordValue(StringPiece keywordName,
StringPiece keywordValue,
UErrorCode& status) {
if (U_FAILURE(status)) { return; }
// TODO: Remove the need for a const char* to a NUL terminated buffer.
const CharString keywordName_nul(keywordName, status);
const CharString keywordValue_nul(keywordValue, status);
@ -2715,16 +2730,18 @@ void
Locale::setUnicodeKeywordValue(StringPiece keywordName,
StringPiece keywordValue,
UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
// TODO: Remove the need for a const char* to a NUL terminated buffer.
const CharString keywordName_nul(keywordName, status);
const CharString keywordValue_nul(keywordValue, status);
if (U_FAILURE(status)) {
return;
}
const char* legacy_key = uloc_toLegacyKey(keywordName_nul.data());
if (legacy_key == nullptr) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;

View file

@ -130,17 +130,17 @@ bool CHECK_TRAILING_VARIANT_SIZE(const char* variant, int32_t variantLength) {
return true;
}
bool
void
_uloc_addLikelySubtags(const char* localeID,
icu::ByteSink& sink,
UErrorCode& err) {
if (U_FAILURE(err)) {
return false;
return;
}
if (localeID == nullptr) {
err = U_ILLEGAL_ARGUMENT_ERROR;
return false;
return;
}
icu::CharString lang;
@ -150,12 +150,12 @@ _uloc_addLikelySubtags(const char* localeID,
const char* trailing = nullptr;
ulocimp_getSubtags(localeID, &lang, &script, &region, &variant, &trailing, err);
if (U_FAILURE(err)) {
return false;
return;
}
if (!CHECK_TRAILING_VARIANT_SIZE(variant.data(), variant.length())) {
err = U_ILLEGAL_ARGUMENT_ERROR;
return false;
return;
}
if (lang.length() > 3) {
@ -164,7 +164,7 @@ _uloc_addLikelySubtags(const char* localeID,
lang.clear();
} else {
err = U_ILLEGAL_ARGUMENT_ERROR;
return false;
return;
}
}
@ -172,18 +172,18 @@ _uloc_addLikelySubtags(const char* localeID,
const icu::LikelySubtags* likelySubtags = icu::LikelySubtags::getSingleton(err);
if (U_FAILURE(err)) {
return false;
return;
}
// We need to keep l on the stack because lsr may point into internal
// memory of l.
icu::Locale l = icu::Locale::createFromName(localeID);
if (l.isBogus()) {
err = U_ILLEGAL_ARGUMENT_ERROR;
return false;
return;
}
icu::LSR lsr = likelySubtags->makeMaximizedLsrFrom(l, true, err);
if (U_FAILURE(err)) {
return false;
return;
}
const char* language = lsr.language;
if (uprv_strcmp(language, "und") == 0) {
@ -202,16 +202,8 @@ _uloc_addLikelySubtags(const char* localeID,
trailingLength,
sink,
err);
return U_SUCCESS(err);
}
// Add likely subtags to the sink
// return true if the value in the sink is produced by a match during the lookup
// return false if the value in the sink is the same as input because there are
// no match after the lookup.
bool _ulocimp_addLikelySubtags(const char*, icu::ByteSink&, UErrorCode&);
void
_uloc_minimizeSubtags(const char* localeID,
icu::ByteSink& sink,
@ -290,12 +282,12 @@ uloc_addLikelySubtags(const char* localeID,
maximizedLocaleID, maximizedLocaleIDCapacity);
ulocimp_addLikelySubtags(localeID, sink, *status);
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*status)) {
return sink.Overflowed() ? reslen : -1;
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (sink.Overflowed()) {
*status = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -306,29 +298,17 @@ uloc_addLikelySubtags(const char* localeID,
return reslen;
}
namespace {
bool
_ulocimp_addLikelySubtags(const char* localeID,
icu::ByteSink& sink,
UErrorCode& status) {
U_EXPORT void
ulocimp_addLikelySubtags(const char* localeID,
icu::ByteSink& sink,
UErrorCode& status) {
if (U_FAILURE(status)) { return; }
icu::CharString localeBuffer;
{
icu::CharStringByteSink localeSink(&localeBuffer);
ulocimp_canonicalize(localeID, localeSink, status);
}
if (U_SUCCESS(status)) {
return _uloc_addLikelySubtags(localeBuffer.data(), sink, status);
} else {
return false;
}
}
} // namespace
U_EXPORT void
ulocimp_addLikelySubtags(const char* localeID,
icu::ByteSink& sink,
UErrorCode& status) {
_ulocimp_addLikelySubtags(localeID, sink, status);
_uloc_addLikelySubtags(localeBuffer.data(), sink, status);
}
U_CAPI int32_t U_EXPORT2
@ -344,12 +324,12 @@ uloc_minimizeSubtags(const char* localeID,
minimizedLocaleID, minimizedLocaleIDCapacity);
ulocimp_minimizeSubtags(localeID, sink, false, *status);
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*status)) {
return sink.Overflowed() ? reslen : -1;
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (sink.Overflowed()) {
*status = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -365,6 +345,7 @@ ulocimp_minimizeSubtags(const char* localeID,
icu::ByteSink& sink,
bool favorScript,
UErrorCode& status) {
if (U_FAILURE(status)) { return; }
icu::CharString localeBuffer;
{
icu::CharStringByteSink localeSink(&localeBuffer);

View file

@ -70,6 +70,7 @@ struct LikelySubtagsData {
}
void load(UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
langInfoBundle = ures_openDirect(nullptr, "langInfo", &errorCode);
if (U_FAILURE(errorCode)) { return; }
StackUResourceBundle stackTempBundle;
@ -230,6 +231,7 @@ struct LikelySubtagsData {
private:
bool readStrings(const ResourceTable &table, const char *key, ResourceValue &value,
LocalMemory<int32_t> &indexes, int32_t &length, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return false; }
if (table.findValue(key, value)) {
ResourceArray stringArray = value.getArray(errorCode);
if (U_FAILURE(errorCode)) { return false; }
@ -296,7 +298,7 @@ private:
}
UnicodeString toRegion(const ResourceArray& m49Array, ResourceValue &value, int encoded, UErrorCode &errorCode) {
if (encoded == 0 || encoded == 1) {
if (U_FAILURE(errorCode) || encoded == 0 || encoded == 1) {
return UNICODE_STRING_SIMPLE("");
}
encoded &= 0x00ffffff;
@ -314,6 +316,7 @@ private:
bool readLSREncodedStrings(const ResourceTable &table, const char* key, ResourceValue &value, const ResourceArray& m49Array,
LocalMemory<int32_t> &indexes, int32_t &length, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return false; }
if (table.findValue(key, value)) {
const int32_t* vectors = value.getIntVector(length, errorCode);
if (U_FAILURE(errorCode)) { return false; }
@ -380,6 +383,7 @@ constexpr const char16_t* MACROREGION_HARDCODE[] = {
constexpr char16_t RANGE_MARKER = 0x7E; /* '~' */
void processMacroregionRange(const UnicodeString& regionName, UVector* newMacroRegions, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
int32_t rangeMarkerLocation = regionName.indexOf(RANGE_MARKER);
char16_t buf[6];
regionName.extract(buf,6,status);
@ -399,6 +403,7 @@ void processMacroregionRange(const UnicodeString& regionName, UVector* newMacroR
#if U_DEBUG
UVector* loadMacroregions(UErrorCode &status) {
if (U_FAILURE(status)) { return nullptr; }
LocalPointer<UVector> newMacroRegions(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
LocalUResourceBundlePointer supplementalData(ures_openDirect(nullptr,"supplementalData",&status));
@ -423,6 +428,7 @@ UVector* loadMacroregions(UErrorCode &status) {
#endif // U_DEBUG
UVector* getStaticMacroregions(UErrorCode &status) {
if (U_FAILURE(status)) { return nullptr; }
LocalPointer<UVector> newMacroRegions(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
if (U_FAILURE(status)) {
@ -515,9 +521,10 @@ LikelySubtags::~LikelySubtags() {
LSR LikelySubtags::makeMaximizedLsrFrom(const Locale &locale,
bool returnInputIfUnmatch,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return {}; }
if (locale.isBogus()) {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
return LSR("", "", "", LSR::EXPLICIT_LSR);
return {};
}
const char *name = locale.getName();
if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=")
@ -553,6 +560,7 @@ LSR LikelySubtags::makeMaximizedLsr(const char *language, const char *script, co
const char *variant,
bool returnInputIfUnmatch,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return {}; }
// Handle pseudolocales like en-XA, ar-XB, fr-PSCRACK.
// They should match only themselves,
// not other locales with what looks like the same language and script subtags.
@ -607,6 +615,7 @@ LSR LikelySubtags::makeMaximizedLsr(const char *language, const char *script, co
LSR LikelySubtags::maximize(const char *language, const char *script, const char *region,
bool returnInputIfUnmatch,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return {}; }
return maximize({language, (int32_t)uprv_strlen(language)},
{script, (int32_t)uprv_strlen(script)},
{region, (int32_t)uprv_strlen(region)},
@ -615,10 +624,10 @@ LSR LikelySubtags::maximize(const char *language, const char *script, const char
}
bool LikelySubtags::isMacroregion(StringPiece& region, UErrorCode& errorCode) const {
if (U_FAILURE(errorCode)) { return false; }
// In Java, we use Region class. In C++, since Region is under i18n,
// we read the same data used by Region into gMacroregions avoid dependency
// from common to i18n/region.cpp
if (U_FAILURE(errorCode)) { return false; }
umtx_initOnce(gInitOnce, &LikelySubtags::initLikelySubtags, errorCode);
if (U_FAILURE(errorCode)) { return false; }
UnicodeString str(UnicodeString::fromUTF8(region));
@ -628,9 +637,7 @@ bool LikelySubtags::isMacroregion(StringPiece& region, UErrorCode& errorCode) co
LSR LikelySubtags::maximize(StringPiece language, StringPiece script, StringPiece region,
bool returnInputIfUnmatch,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) {
return LSR(language, script, region, LSR::EXPLICIT_LSR, errorCode);
}
if (U_FAILURE(errorCode)) { return {}; }
if (language.compare("und") == 0) {
language = "";
}
@ -920,10 +927,9 @@ LSR LikelySubtags::minimizeSubtags(StringPiece language, StringPiece script,
StringPiece region,
bool favorScript,
UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) { return {}; }
LSR max = maximize(language, script, region, true, errorCode);
if (U_FAILURE(errorCode)) {
return max;
}
if (U_FAILURE(errorCode)) { return {}; }
// If no match, return it.
if (uprv_strlen(max.language) == 0 &&
uprv_strlen(max.script) == 0 &&
@ -936,9 +942,7 @@ LSR LikelySubtags::minimizeSubtags(StringPiece language, StringPiece script,
}
// try language
LSR test = maximize(max.language, "", "", true, errorCode);
if (U_FAILURE(errorCode)) {
return max;
}
if (U_FAILURE(errorCode)) { return {}; }
if (test.isEquivalentTo(max)) {
return LSR(max.language, "", "", LSR::DONT_CARE_FLAGS, errorCode);
}
@ -947,27 +951,21 @@ LSR LikelySubtags::minimizeSubtags(StringPiece language, StringPiece script,
// favor Region
// try language and region
test = maximize(max.language, "", max.region, true, errorCode);
if (U_FAILURE(errorCode)) {
return max;
}
if (U_FAILURE(errorCode)) { return {}; }
if (test.isEquivalentTo(max)) {
return LSR(max.language, "", max.region, LSR::DONT_CARE_FLAGS, errorCode);
}
}
// try language and script
test = maximize(max.language, max.script, "", true, errorCode);
if (U_FAILURE(errorCode)) {
return max;
}
if (U_FAILURE(errorCode)) { return {}; }
if (test.isEquivalentTo(max)) {
return LSR(max.language, max.script, "", LSR::DONT_CARE_FLAGS, errorCode);
}
if (favorScript) {
// try language and region
test = maximize(max.language, "", max.region, true, errorCode);
if (U_FAILURE(errorCode)) {
return max;
}
if (U_FAILURE(errorCode)) { return {}; }
if (test.isEquivalentTo(max)) {
return LSR(max.language, "", max.region, LSR::DONT_CARE_FLAGS, errorCode);
}

View file

@ -977,6 +977,7 @@ idCmp(const char* id1, const char* id2)
uint32_t
getHostID(const ILcidPosixMap *this_0, const char* posixID, UErrorCode& status)
{
if (U_FAILURE(status)) { return locmap_root->hostID; }
int32_t bestIdx = 0;
int32_t bestIdxDiff = 0;
int32_t posixIDlen = (int32_t)uprv_strlen(posixID);
@ -1004,7 +1005,7 @@ getHostID(const ILcidPosixMap *this_0, const char* posixID, UErrorCode& status)
/*no match found */
status = U_ILLEGAL_ARGUMENT_ERROR;
return this_0->regionMaps->hostID;
return locmap_root->hostID;
}
const char*
@ -1151,7 +1152,7 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr
/* no match found */
*status = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
return 0;
}
/*
@ -1257,6 +1258,14 @@ uprv_convertToLCIDPlatform(const char* localeID, UErrorCode* status)
U_CAPI uint32_t
uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status)
{
if (U_FAILURE(*status) ||
langID == nullptr ||
posixID == nullptr ||
uprv_strlen(langID) < 2 ||
uprv_strlen(posixID) < 2) {
return locmap_root->hostID;
}
// This function does the table lookup when native platform name->lcid conversion isn't available,
// or for locales that don't follow patterns the platform expects.
uint32_t low = 0;
@ -1270,11 +1279,6 @@ uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status)
UErrorCode myStatus;
uint32_t idx;
/* Check for incomplete id. */
if (!langID || !posixID || uprv_strlen(langID) < 2 || uprv_strlen(posixID) < 2) {
return 0;
}
/*Binary search for the map entry for normal cases */
while (high > low) /*binary search*/{
@ -1319,5 +1323,5 @@ uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status)
/* no match found */
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0; /* return international (root) */
return locmap_root->hostID; /* return international (root) */
}

View file

@ -50,6 +50,7 @@ uloc_getTableStringWithFallback(const char *path, const char *locale,
int32_t *pLength,
UErrorCode *pErrorCode)
{
if (U_FAILURE(*pErrorCode)) { return nullptr; }
/* char localeBuffer[ULOC_FULLNAME_CAPACITY*4];*/
const char16_t *item=nullptr;
UErrorCode errorCode;
@ -159,45 +160,47 @@ _uloc_getOrientationHelper(const char* localeId,
{
ULayoutType result = ULOC_LAYOUT_UNKNOWN;
if (!U_FAILURE(status)) {
icu::CharString localeBuffer;
if (U_FAILURE(status)) { return result; }
icu::CharString localeBuffer;
{
icu::CharStringByteSink sink(&localeBuffer);
ulocimp_canonicalize(localeId, sink, status);
}
if (U_FAILURE(status)) { return result; }
int32_t length = 0;
const char16_t* const value =
uloc_getTableStringWithFallback(
nullptr,
localeBuffer.data(),
"layout",
nullptr,
key,
&length,
&status);
if (U_FAILURE(status)) { return result; }
if (length != 0) {
switch(value[0])
{
icu::CharStringByteSink sink(&localeBuffer);
ulocimp_canonicalize(localeId, sink, status);
}
if (!U_FAILURE(status)) {
int32_t length = 0;
const char16_t* const value =
uloc_getTableStringWithFallback(
nullptr,
localeBuffer.data(),
"layout",
nullptr,
key,
&length,
&status);
if (!U_FAILURE(status) && length != 0) {
switch(value[0])
{
case 0x0062: /* 'b' */
result = ULOC_LAYOUT_BTT;
break;
case 0x006C: /* 'l' */
result = ULOC_LAYOUT_LTR;
break;
case 0x0072: /* 'r' */
result = ULOC_LAYOUT_RTL;
break;
case 0x0074: /* 't' */
result = ULOC_LAYOUT_TTB;
break;
default:
status = U_INTERNAL_PROGRAM_ERROR;
break;
}
}
case 0x0062: /* 'b' */
result = ULOC_LAYOUT_BTT;
break;
case 0x006C: /* 'l' */
result = ULOC_LAYOUT_LTR;
break;
case 0x0072: /* 'r' */
result = ULOC_LAYOUT_RTL;
break;
case 0x0074: /* 't' */
result = ULOC_LAYOUT_TTB;
break;
default:
status = U_INTERNAL_PROGRAM_ERROR;
break;
}
}

View file

@ -553,17 +553,19 @@ namespace {
*/
CharString locale_canonKeywordName(const char* keywordName, UErrorCode& status)
{
if (U_FAILURE(status)) { return {}; }
CharString result;
for (; *keywordName != 0; keywordName++) {
if (!UPRV_ISALPHANUM(*keywordName)) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed keyword name */
return result;
return {};
}
result.append(uprv_tolower(*keywordName), status);
}
if (result.isEmpty()) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* empty keyword name */
return {};
}
return result;
@ -592,6 +594,8 @@ ulocimp_getKeywords(const char* localeID,
bool valuesToo,
UErrorCode& status)
{
if (U_FAILURE(status)) { return; }
KeywordStruct keywordList[ULOC_MAX_NO_KEYWORDS];
int32_t maxKeywords = ULOC_MAX_NO_KEYWORDS;
@ -718,13 +722,12 @@ uloc_getKeywordValue(const char* localeID,
CheckedArrayByteSink sink(buffer, bufferCapacity);
ulocimp_getKeywordValue(localeID, keywordName, sink, *status);
if (U_FAILURE(*status)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*status)) {
return reslen;
}
if (sink.Overflowed()) {
*status = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -740,102 +743,102 @@ ulocimp_getKeywordValue(const char* localeID,
icu::ByteSink& sink,
UErrorCode& status)
{
if (U_FAILURE(status)) { return; }
if (localeID == nullptr || keywordName == nullptr || keywordName[0] == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
const char* startSearchHere = nullptr;
const char* nextSeparator = nullptr;
if (localeID != nullptr && U_SUCCESS(status)) {
CharString tempBuffer;
const char* tmpLocaleID;
CharString tempBuffer;
const char* tmpLocaleID;
if (keywordName == nullptr || keywordName[0] == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
CharString canonKeywordName = locale_canonKeywordName(keywordName, status);
if (U_FAILURE(status)) {
return;
}
if (_hasBCP47Extension(localeID)) {
CharStringByteSink sink(&tempBuffer);
ulocimp_forLanguageTag(localeID, -1, sink, nullptr, status);
tmpLocaleID = U_SUCCESS(status) && !tempBuffer.isEmpty() ? tempBuffer.data() : localeID;
} else {
tmpLocaleID=localeID;
}
startSearchHere = locale_getKeywordsStart(tmpLocaleID);
if(startSearchHere == nullptr) {
/* no keywords, return at once */
return;
}
}
CharString canonKeywordName = locale_canonKeywordName(keywordName, status);
if (U_FAILURE(status)) {
return;
}
/* find the first keyword */
while(startSearchHere) {
const char* keyValueTail;
if (_hasBCP47Extension(localeID)) {
CharStringByteSink sink(&tempBuffer);
ulocimp_forLanguageTag(localeID, -1, sink, nullptr, status);
tmpLocaleID = U_SUCCESS(status) && !tempBuffer.isEmpty() ? tempBuffer.data() : localeID;
} else {
tmpLocaleID=localeID;
}
startSearchHere = locale_getKeywordsStart(tmpLocaleID);
if(startSearchHere == nullptr) {
/* no keywords, return at once */
return;
}
/* find the first keyword */
while(startSearchHere) {
const char* keyValueTail;
startSearchHere++; /* skip @ or ; */
nextSeparator = uprv_strchr(startSearchHere, '=');
if(!nextSeparator) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* key must have =value */
return;
startSearchHere++; /* skip @ or ; */
nextSeparator = uprv_strchr(startSearchHere, '=');
if(!nextSeparator) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* key must have =value */
return;
}
/* strip leading & trailing spaces (TC decided to tolerate these) */
while(*startSearchHere == ' ') {
startSearchHere++;
}
keyValueTail = nextSeparator;
while (keyValueTail > startSearchHere && *(keyValueTail-1) == ' ') {
keyValueTail--;
}
/* now keyValueTail points to first char after the keyName */
/* copy & normalize keyName from locale */
if (startSearchHere == keyValueTail) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* empty keyword name in passed-in locale */
return;
}
CharString localeKeywordName;
while (startSearchHere < keyValueTail) {
if (!UPRV_ISALPHANUM(*startSearchHere)) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed keyword name */
return;
}
/* strip leading & trailing spaces (TC decided to tolerate these) */
while(*startSearchHere == ' ') {
startSearchHere++;
}
keyValueTail = nextSeparator;
while (keyValueTail > startSearchHere && *(keyValueTail-1) == ' ') {
localeKeywordName.append(uprv_tolower(*startSearchHere++), status);
}
if (U_FAILURE(status)) {
return;
}
startSearchHere = uprv_strchr(nextSeparator, ';');
if (canonKeywordName == localeKeywordName) {
/* current entry matches the keyword. */
nextSeparator++; /* skip '=' */
/* First strip leading & trailing spaces (TC decided to tolerate these) */
while(*nextSeparator == ' ') {
nextSeparator++;
}
keyValueTail = (startSearchHere)? startSearchHere: nextSeparator + uprv_strlen(nextSeparator);
while(keyValueTail > nextSeparator && *(keyValueTail-1) == ' ') {
keyValueTail--;
}
/* now keyValueTail points to first char after the keyName */
/* copy & normalize keyName from locale */
if (startSearchHere == keyValueTail) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* empty keyword name in passed-in locale */
return;
}
CharString localeKeywordName;
while (startSearchHere < keyValueTail) {
if (!UPRV_ISALPHANUM(*startSearchHere)) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed keyword name */
}
/* Now copy the value, but check well-formedness */
if (nextSeparator == keyValueTail) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* empty key value name in passed-in locale */
return;
}
localeKeywordName.append(uprv_tolower(*startSearchHere++), status);
}
if (U_FAILURE(status)) {
return;
}
startSearchHere = uprv_strchr(nextSeparator, ';');
if (canonKeywordName == localeKeywordName) {
/* current entry matches the keyword. */
nextSeparator++; /* skip '=' */
/* First strip leading & trailing spaces (TC decided to tolerate these) */
while(*nextSeparator == ' ') {
nextSeparator++;
}
keyValueTail = (startSearchHere)? startSearchHere: nextSeparator + uprv_strlen(nextSeparator);
while(keyValueTail > nextSeparator && *(keyValueTail-1) == ' ') {
keyValueTail--;
}
/* Now copy the value, but check well-formedness */
if (nextSeparator == keyValueTail) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* empty key value name in passed-in locale */
while (nextSeparator < keyValueTail) {
if (!UPRV_ISALPHANUM(*nextSeparator) && !UPRV_OK_VALUE_PUNCTUATION(*nextSeparator)) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed key value */
return;
}
while (nextSeparator < keyValueTail) {
if (!UPRV_ISALPHANUM(*nextSeparator) && !UPRV_OK_VALUE_PUNCTUATION(*nextSeparator)) {
status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed key value */
return;
}
/* Should we lowercase value to return here? Tests expect as-is. */
sink.Append(nextSeparator++, 1);
}
return;
}
}
/* Should we lowercase value to return here? Tests expect as-is. */
sink.Append(nextSeparator++, 1);
}
return;
}
}
}
@ -845,9 +848,7 @@ uloc_setKeywordValue(const char* keywordName,
char* buffer, int32_t bufferCapacity,
UErrorCode* status)
{
if (U_FAILURE(*status)) {
return -1;
}
if (U_FAILURE(*status)) { return 0; }
if (bufferCapacity <= 1) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@ -870,8 +871,7 @@ uloc_setKeywordValue(const char* keywordName,
keywords, keywordName, keywordValue, sink, *status);
if (U_FAILURE(*status)) {
// A positive return value is a length, otherwise it's an error code.
return reslen > 0 ? reslen + baseLen : reslen;
return *status == U_BUFFER_OVERFLOW_ERROR ? reslen + baseLen : 0;
}
// See the documentation for this function, it's guaranteed to never
@ -904,6 +904,8 @@ ulocimp_setKeywordValue(const char* keywords,
ByteSink& sink,
UErrorCode& status)
{
if (U_FAILURE(status)) { return 0; }
/* TODO: sorting. removal. */
int32_t needLen = 0;
int32_t rc;
@ -914,9 +916,6 @@ ulocimp_setKeywordValue(const char* keywords,
bool handledInputKeyAndValue = false;
char keyValuePrefix = '@';
if (U_FAILURE(status)) {
return -1;
}
if (status == U_STRING_NOT_TERMINATED_WARNING) {
status = U_ZERO_ERROR;
}
@ -1132,7 +1131,7 @@ inline bool _isBCP47Extension(const char* p) {
* The 'list' param should be LANGUAGES, LANGUAGES_3, COUNTRIES, or
* COUNTRIES_3.
*/
int16_t _findIndex(const char* const* list, const char* key)
std::optional<int16_t> _findIndex(const char* const* list, const char* key)
{
const char* const* anchor = list;
int32_t pass = 0;
@ -1147,26 +1146,20 @@ int16_t _findIndex(const char* const* list, const char* key)
}
++list; /* skip final nullptr *CWB*/
}
return -1;
return std::nullopt;
}
} // namespace
U_CFUNC const char*
uloc_getCurrentCountryID(const char* oldID){
int32_t offset = _findIndex(DEPRECATED_COUNTRIES, oldID);
if (offset >= 0) {
return REPLACEMENT_COUNTRIES[offset];
}
return oldID;
std::optional<int16_t> offset = _findIndex(DEPRECATED_COUNTRIES, oldID);
return offset.has_value() ? REPLACEMENT_COUNTRIES[offset.value()] : oldID;
}
U_CFUNC const char*
uloc_getCurrentLanguageID(const char* oldID){
int32_t offset = _findIndex(DEPRECATED_LANGUAGES, oldID);
if (offset >= 0) {
return REPLACEMENT_LANGUAGES[offset];
}
return oldID;
std::optional<int16_t> offset = _findIndex(DEPRECATED_LANGUAGES, oldID);
return offset.has_value() ? REPLACEMENT_LANGUAGES[offset.value()] : oldID;
}
namespace {
@ -1230,9 +1223,9 @@ _getLanguage(const char* localeID,
/* convert 3 character code to 2 character code if possible *CWB*/
U_ASSERT(capacity >= 4);
buffer[3] = '\0';
int32_t offset = _findIndex(LANGUAGES_3, buffer);
if(offset>=0) {
const char* const alias = LANGUAGES[offset];
std::optional<int16_t> offset = _findIndex(LANGUAGES_3, buffer);
if (offset.has_value()) {
const char* const alias = LANGUAGES[offset.value()];
sink->Append(alias, (int32_t)uprv_strlen(alias));
return;
}
@ -1311,9 +1304,9 @@ _getRegion(const char* localeID,
/* convert 3 character code to 2 character code if possible *CWB*/
U_ASSERT(capacity >= 4);
buffer[3] = '\0';
int32_t offset = _findIndex(COUNTRIES_3, buffer);
if(offset>=0) {
const char* const alias = COUNTRIES[offset];
std::optional<int16_t> offset = _findIndex(COUNTRIES_3, buffer);
if (offset.has_value()) {
const char* const alias = COUNTRIES[offset.value()];
sink->Append(alias, (int32_t)uprv_strlen(alias));
return;
}
@ -1387,6 +1380,7 @@ _getVariant(const char* localeID,
U_EXPORT CharString
ulocimp_getLanguage(const char* localeID, UErrorCode& status) {
if (U_FAILURE(status)) { return {}; }
CharString language;
CharStringByteSink sink(&language);
ulocimp_getSubtags(
@ -1402,6 +1396,7 @@ ulocimp_getLanguage(const char* localeID, UErrorCode& status) {
U_EXPORT CharString
ulocimp_getScript(const char* localeID, UErrorCode& status) {
if (U_FAILURE(status)) { return {}; }
CharString script;
CharStringByteSink sink(&script);
ulocimp_getSubtags(
@ -1417,6 +1412,7 @@ ulocimp_getScript(const char* localeID, UErrorCode& status) {
U_EXPORT CharString
ulocimp_getRegion(const char* localeID, UErrorCode& status) {
if (U_FAILURE(status)) { return {}; }
CharString region;
CharStringByteSink sink(&region);
ulocimp_getSubtags(
@ -1432,6 +1428,7 @@ ulocimp_getRegion(const char* localeID, UErrorCode& status) {
U_EXPORT CharString
ulocimp_getVariant(const char* localeID, UErrorCode& status) {
if (U_FAILURE(status)) { return {}; }
CharString variant;
CharStringByteSink sink(&variant);
ulocimp_getSubtags(
@ -1454,6 +1451,8 @@ ulocimp_getSubtags(
CharString* variant,
const char** pEnd,
UErrorCode& status) {
if (U_FAILURE(status)) { return; }
std::optional<CharStringByteSink> languageSink;
std::optional<CharStringByteSink> scriptSink;
std::optional<CharStringByteSink> regionSink;
@ -1619,12 +1618,11 @@ static const UEnumeration gKeywordsEnum = {
U_CAPI UEnumeration* U_EXPORT2
uloc_openKeywordList(const char *keywordList, int32_t keywordListSize, UErrorCode* status)
{
if (U_FAILURE(*status)) { return nullptr; }
LocalMemory<UKeywordsContext> myContext;
LocalMemory<UEnumeration> result;
if (U_FAILURE(*status)) {
return nullptr;
}
myContext.adoptInstead(static_cast<UKeywordsContext *>(uprv_malloc(sizeof(UKeywordsContext))));
result.adoptInstead(static_cast<UEnumeration *>(uprv_malloc(sizeof(UEnumeration))));
if (myContext.isNull() || result.isNull()) {
@ -1648,13 +1646,13 @@ U_CAPI UEnumeration* U_EXPORT2
uloc_openKeywords(const char* localeID,
UErrorCode* status)
{
CharString tempBuffer;
const char* tmpLocaleID;
if(status==nullptr || U_FAILURE(*status)) {
return 0;
}
CharString tempBuffer;
const char* tmpLocaleID;
if (_hasBCP47Extension(localeID)) {
CharStringByteSink sink(&tempBuffer);
ulocimp_forLanguageTag(localeID, -1, sink, nullptr, *status);
@ -1889,13 +1887,12 @@ uloc_getParent(const char* localeID,
CheckedArrayByteSink sink(parent, parentCapacity);
ulocimp_getParent(localeID, sink, *err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return reslen;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -1910,12 +1907,11 @@ ulocimp_getParent(const char* localeID,
icu::ByteSink& sink,
UErrorCode& err)
{
if (U_FAILURE(err)) { return; }
const char *lastUnderscore;
int32_t i;
if (U_FAILURE(err))
return;
if (localeID == nullptr)
localeID = uloc_getDefault();
@ -1956,13 +1952,12 @@ uloc_getLanguage(const char* localeID,
nullptr,
nullptr,
*err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t length = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return length;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
return length;
@ -1990,13 +1985,12 @@ uloc_getScript(const char* localeID,
nullptr,
nullptr,
*err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t length = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return length;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
return length;
@ -2024,13 +2018,12 @@ uloc_getCountry(const char* localeID,
nullptr,
nullptr,
*err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t length = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return length;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
return length;
@ -2058,13 +2051,12 @@ uloc_getVariant(const char* localeID,
&sink,
nullptr,
*err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t length = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return length;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
return length;
@ -2085,13 +2077,12 @@ uloc_getName(const char* localeID,
CheckedArrayByteSink sink(name, nameCapacity);
ulocimp_getName(localeID, sink, *err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return reslen;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -2121,13 +2112,12 @@ uloc_getBaseName(const char* localeID,
CheckedArrayByteSink sink(name, nameCapacity);
ulocimp_getBaseName(localeID, sink, *err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return reslen;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -2157,13 +2147,12 @@ uloc_canonicalize(const char* localeID,
CheckedArrayByteSink sink(name, nameCapacity);
ulocimp_canonicalize(localeID, sink, *err);
if (U_FAILURE(*err)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return reslen;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -2184,7 +2173,6 @@ ulocimp_canonicalize(const char* localeID,
U_CAPI const char* U_EXPORT2
uloc_getISO3Language(const char* localeID)
{
int16_t offset;
UErrorCode err = U_ZERO_ERROR;
if (localeID == nullptr)
@ -2194,16 +2182,13 @@ uloc_getISO3Language(const char* localeID)
CharString lang = ulocimp_getLanguage(localeID, err);
if (U_FAILURE(err))
return "";
offset = _findIndex(LANGUAGES, lang.data());
if (offset < 0)
return "";
return LANGUAGES_3[offset];
std::optional<int16_t> offset = _findIndex(LANGUAGES, lang.data());
return offset.has_value() ? LANGUAGES_3[offset.value()] : "";
}
U_CAPI const char* U_EXPORT2
uloc_getISO3Country(const char* localeID)
{
int16_t offset;
UErrorCode err = U_ZERO_ERROR;
if (localeID == nullptr)
@ -2213,11 +2198,8 @@ uloc_getISO3Country(const char* localeID)
CharString cntry = ulocimp_getRegion(localeID, err);
if (U_FAILURE(err))
return "";
offset = _findIndex(COUNTRIES, cntry.data());
if (offset < 0)
return "";
return COUNTRIES_3[offset];
std::optional<int16_t> offset = _findIndex(COUNTRIES, cntry.data());
return offset.has_value() ? COUNTRIES_3[offset.value()] : "";
}
U_CAPI uint32_t U_EXPORT2

View file

@ -1169,12 +1169,9 @@ void _sortVariants(VariantListEntry* first) {
void
_appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, bool& hadPosix, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
UErrorCode tmpStatus = U_ZERO_ERROR;
if (U_FAILURE(status)) {
return;
}
icu::CharString buf = ulocimp_getVariant(localeID, tmpStatus);
if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
if (strict) {
@ -1280,6 +1277,8 @@ _appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool str
void
_appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, bool hadPosix, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
icu::MemoryPool<AttributeListEntry> attrPool;
icu::MemoryPool<ExtensionListEntry> extPool;
icu::MemoryPool<icu::CharString> strPool;
@ -1522,6 +1521,8 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool str
*/
void
_appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendTo, icu::MemoryPool<ExtensionListEntry>& extPool, icu::MemoryPool<icu::CharString>& kwdBuf, bool& posixVariant, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
const char *pTag; /* beginning of current subtag */
const char *pKwds; /* beginning of key-type pairs */
bool variantExists = posixVariant;
@ -1782,6 +1783,8 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
void
_appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
int32_t i, n;
int32_t len;
ExtensionListEntry *kwdFirst = nullptr;
@ -1791,10 +1794,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode& status)
icu::MemoryPool<icu::CharString> kwdBuf;
bool posixVariant = false;
if (U_FAILURE(status)) {
return;
}
n = ultag_getExtensionsSize(langtag);
/* resolve locale keywords and reordering keys */
@ -1877,14 +1876,10 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode& status)
}
void
_appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, bool hadPosix, UErrorCode& status) {
(void)hadPosix;
_appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, bool strict, bool /*hadPosix*/, UErrorCode& status) {
if (U_FAILURE(status)) { return; }
UErrorCode tmpStatus = U_ZERO_ERROR;
if (U_FAILURE(status)) {
return;
}
icu::CharString buf = ulocimp_getVariant(localeID, tmpStatus);
if (U_FAILURE(tmpStatus)) {
if (strict) {
@ -1986,6 +1981,8 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, bool s
ULanguageTag*
ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode& status) {
if (U_FAILURE(status)) { return nullptr; }
char *tagBuf;
int16_t next;
char *pSubtag, *pNext, *pLastGoodPosition;
@ -2001,10 +1998,6 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode& sta
*parsedLen = 0;
}
if (U_FAILURE(status)) {
return nullptr;
}
if (tagLen < 0) {
tagLen = (int32_t)uprv_strlen(tag);
}
@ -2583,13 +2576,12 @@ uloc_toLanguageTag(const char* localeID,
icu::CheckedArrayByteSink sink(langtag, langtagCapacity);
ulocimp_toLanguageTag(localeID, sink, strict, *status);
if (U_FAILURE(*status)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*status)) {
return reslen;
}
if (sink.Overflowed()) {
*status = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -2605,6 +2597,8 @@ ulocimp_toLanguageTag(const char* localeID,
icu::ByteSink& sink,
bool strict,
UErrorCode& status) {
if (U_FAILURE(status)) { return; }
icu::CharString canonical;
UErrorCode tmpStatus = U_ZERO_ERROR;
bool hadPosix = false;
@ -2684,13 +2678,12 @@ uloc_forLanguageTag(const char* langtag,
icu::CheckedArrayByteSink sink(localeID, localeIDCapacity);
ulocimp_forLanguageTag(langtag, -1, sink, parsedLength, *status);
if (U_FAILURE(*status)) {
return 0;
}
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*status)) {
return reslen;
}
if (sink.Overflowed()) {
*status = U_BUFFER_OVERFLOW_ERROR;
} else {
@ -2707,6 +2700,8 @@ ulocimp_forLanguageTag(const char* langtag,
icu::ByteSink& sink,
int32_t* parsedLength,
UErrorCode& status) {
if (U_FAILURE(status)) { return; }
bool isEmpty = true;
const char *subtag, *p;
int32_t len;

View file

@ -19,15 +19,17 @@ U_NAMESPACE_USE
ULocale*
ulocale_openForLocaleID(const char* localeID, int32_t length, UErrorCode* err) {
if (U_FAILURE(*err)) { return nullptr; }
CharString str(length < 0 ? StringPiece(localeID) : StringPiece(localeID, length), *err);
if (U_FAILURE(*err)) return nullptr;
if (U_FAILURE(*err)) { return nullptr; }
return EXTERNAL(icu::Locale::createFromName(str.data()).clone());
}
ULocale*
ulocale_openForLanguageTag(const char* tag, int32_t length, UErrorCode* err) {
if (U_FAILURE(*err)) { return nullptr; }
Locale l = icu::Locale::forLanguageTag(length < 0 ? StringPiece(tag) : StringPiece(tag, length), *err);
if (U_FAILURE(*err)) return nullptr;
if (U_FAILURE(*err)) { return nullptr; }
return EXTERNAL(l.clone());
}
@ -57,10 +59,10 @@ int32_t ulocale_get ##N ( \
CONST_INTERNAL(locale)->get ## N( \
keywordLength < 0 ? StringPiece(keyword) : StringPiece(keyword, keywordLength), \
sink, *err); \
int32_t reslen = sink.NumberOfBytesAppended(); \
if (U_FAILURE(*err)) { \
return reslen; \
return 0; \
} \
int32_t reslen = sink.NumberOfBytesAppended(); \
if (sink.Overflowed()) { \
*err = U_BUFFER_OVERFLOW_ERROR; \
} else { \

View file

@ -112,12 +112,13 @@ ULocale* ulocbld_buildULocale(ULocaleBuilder* builder, UErrorCode* err) {
int32_t ulocbld_buildLocaleID(ULocaleBuilder* builder,
char* buffer, int32_t bufferCapacity, UErrorCode* err) {
if (U_FAILURE(*err)) { return 0; }
if (builder == nullptr) {
*err = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
icu::Locale l = INTERNAL(builder)->build(*err);
if (U_FAILURE(*err)) return 0;
if (U_FAILURE(*err)) { return 0; }
int32_t length = (int32_t)(uprv_strlen(l.getName()));
if (0 < length && length <= bufferCapacity) {
uprv_memcpy(buffer, l.getName(), length);
@ -127,18 +128,17 @@ int32_t ulocbld_buildLocaleID(ULocaleBuilder* builder,
int32_t ulocbld_buildLanguageTag(ULocaleBuilder* builder,
char* buffer, int32_t bufferCapacity, UErrorCode* err) {
if (U_FAILURE(*err)) { return 0; }
if (builder == nullptr) {
*err = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
icu::Locale l = INTERNAL(builder)->build(*err);
if (U_FAILURE(*err)) return 0;
if (U_FAILURE(*err)) { return 0; }
CheckedArrayByteSink sink(buffer, bufferCapacity);
l.toLanguageTag(sink, *err);
if (U_FAILURE(*err)) { return 0; }
int32_t reslen = sink.NumberOfBytesAppended();
if (U_FAILURE(*err)) {
return reslen;
}
if (sink.Overflowed()) {
*err = U_BUFFER_OVERFLOW_ERROR;
} else {

View file

@ -11,6 +11,8 @@
#if U_SHOW_CPLUSPLUS_API
#include <optional>
#include "unicode/locid.h"
#include "unicode/stringpiece.h"
#include "unicode/uobject.h"
@ -678,7 +680,7 @@ private:
int32_t putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength, UErrorCode &errorCode);
int32_t getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remainingIter, UErrorCode &errorCode) const;
std::optional<int32_t> getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remainingIter, UErrorCode &errorCode) const;
const LikelySubtags &likelySubtags;
const LocaleDistance &localeDistance;

View file

@ -1183,6 +1183,7 @@ Locale::operator!=(const Locale& other) const
template<typename StringClass> inline StringClass
Locale::toLanguageTag(UErrorCode& status) const
{
if (U_FAILURE(status)) { return {}; }
StringClass result;
StringByteSink<StringClass> sink(&result);
toLanguageTag(sink, status);
@ -1222,6 +1223,7 @@ Locale::getName() const
template<typename StringClass, typename OutputIterator> inline void
Locale::getKeywords(OutputIterator iterator, UErrorCode& status) const
{
if (U_FAILURE(status)) { return; }
LocalPointer<StringEnumeration> keys(createKeywords(status));
if (U_FAILURE(status) || keys.isNull()) {
return;
@ -1239,6 +1241,7 @@ Locale::getKeywords(OutputIterator iterator, UErrorCode& status) const
template<typename StringClass, typename OutputIterator> inline void
Locale::getUnicodeKeywords(OutputIterator iterator, UErrorCode& status) const
{
if (U_FAILURE(status)) { return; }
LocalPointer<StringEnumeration> keys(createUnicodeKeywords(status));
if (U_FAILURE(status) || keys.isNull()) {
return;
@ -1256,6 +1259,7 @@ Locale::getUnicodeKeywords(OutputIterator iterator, UErrorCode& status) const
template<typename StringClass> inline StringClass
Locale::getKeywordValue(StringPiece keywordName, UErrorCode& status) const
{
if (U_FAILURE(status)) { return {}; }
StringClass result;
StringByteSink<StringClass> sink(&result);
getKeywordValue(keywordName, sink, status);
@ -1265,6 +1269,7 @@ Locale::getKeywordValue(StringPiece keywordName, UErrorCode& status) const
template<typename StringClass> inline StringClass
Locale::getUnicodeKeywordValue(StringPiece keywordName, UErrorCode& status) const
{
if (U_FAILURE(status)) { return {}; }
StringClass result;
StringByteSink<StringClass> sink(&result);
getUnicodeKeywordValue(keywordName, sink, status);

View file

@ -201,6 +201,8 @@ ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type,
namespace {
UResourceBundle * measurementTypeBundleForLocale(const char *localeID, const char *measurementType, UErrorCode *status){
if (U_FAILURE(*status)) { return nullptr; }
UResourceBundle *rb;
UResourceBundle *measTypeBundle = nullptr;
@ -279,6 +281,7 @@ ulocdata_getPaperSize(const char* localeID, int32_t *height, int32_t *width, UEr
U_CAPI void U_EXPORT2
ulocdata_getCLDRVersion(UVersionInfo versionArray, UErrorCode *status) {
if (U_FAILURE(*status)) { return; }
UResourceBundle *rb = nullptr;
rb = ures_openDirect(nullptr, "supplementalData", status);
ures_getVersionByKey(rb, "cldrVersion", versionArray, status);

View file

@ -5946,19 +5946,19 @@ const errorData maximizeErrors[] = {
"enfueiujhytdf",
NULL,
U_ILLEGAL_ARGUMENT_ERROR,
-1
0
},
{
"en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
NULL,
U_ILLEGAL_ARGUMENT_ERROR,
-1
0
},
{
"en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
NULL,
U_ILLEGAL_ARGUMENT_ERROR,
-1
0
},
{
"en_Latn_US_POSIX@currency=EURO",
@ -5979,13 +5979,13 @@ const errorData minimizeErrors[] = {
"enfueiujhytdf",
NULL,
U_ILLEGAL_ARGUMENT_ERROR,
-1
0
},
{
"en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
NULL,
U_ILLEGAL_ARGUMENT_ERROR,
-1
0
},
{
"en_Latn_US_POSIX@currency=EURO",
@ -6010,7 +6010,7 @@ static int32_t getExpectedReturnValue(const errorData* data)
}
else
{
return -1;
return 0;
}
}