ICU-22520 Refactor code to remove the use of goto for error handling.
This is to facilitate further refactoring of the locale code, goto
doesn't play all too well with C++ memory handling.
diff --git a/icu4c/source/common/loclikely.cpp b/icu4c/source/common/loclikely.cpp
index c8fa505..f3780c2 100644
--- a/icu4c/source/common/loclikely.cpp
+++ b/icu4c/source/common/loclikely.cpp
@@ -42,16 +42,9 @@
* parameters may be nullptr pointers. If they are, their corresponding length parameters
* must be less than or equal to 0.
*
- * If the length of the new string exceeds the capacity of the output buffer,
- * the function copies as many bytes to the output buffer as it can, and returns
- * the error U_BUFFER_OVERFLOW_ERROR.
- *
* If an illegal argument is provided, the function returns the error
* U_ILLEGAL_ARGUMENT_ERROR.
*
- * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
- * the tag string fits in the output buffer, but the null terminator doesn't.
- *
* @param lang The language tag to use.
* @param langLength The length of the language tag.
* @param script The script tag to use.
@@ -75,62 +68,48 @@ createTagStringWithAlternates(
int32_t trailingLength,
icu::ByteSink& sink,
UErrorCode* err) {
-
if (U_FAILURE(*err)) {
- goto error;
- }
- else if (langLength >= ULOC_LANG_CAPACITY ||
- scriptLength >= ULOC_SCRIPT_CAPACITY ||
- regionLength >= ULOC_COUNTRY_CAPACITY) {
- goto error;
- }
- else {
- UBool regionAppended = false;
-
- if (langLength > 0) {
- sink.Append(lang, langLength);
- }
-
- if (scriptLength > 0) {
- sink.Append("_", 1);
- sink.Append(script, scriptLength);
- }
-
- if (regionLength > 0) {
- sink.Append("_", 1);
- sink.Append(region, regionLength);
-
- regionAppended = true;
- }
-
- if (trailingLength > 0) {
- if (*trailing != '@') {
- sink.Append("_", 1);
- if (!regionAppended) {
- /* extra separator is required */
- sink.Append("_", 1);
- }
- }
-
- /*
- * Copy the trailing data into the supplied buffer.
- */
- sink.Append(trailing, trailingLength);
- }
-
return;
}
-error:
-
- /**
- * An overflow indicates the locale ID passed in
- * is ill-formed. If we got here, and there was
- * no previous error, it's an implicit overflow.
- **/
- if (*err == U_BUFFER_OVERFLOW_ERROR ||
- U_SUCCESS(*err)) {
+ if (langLength >= ULOC_LANG_CAPACITY ||
+ scriptLength >= ULOC_SCRIPT_CAPACITY ||
+ regionLength >= ULOC_COUNTRY_CAPACITY) {
*err = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ UBool regionAppended = false;
+
+ if (langLength > 0) {
+ sink.Append(lang, langLength);
+ }
+
+ if (scriptLength > 0) {
+ sink.Append("_", 1);
+ sink.Append(script, scriptLength);
+ }
+
+ if (regionLength > 0) {
+ sink.Append("_", 1);
+ sink.Append(region, regionLength);
+
+ regionAppended = true;
+ }
+
+ if (trailingLength > 0) {
+ if (*trailing != '@') {
+ sink.Append("_", 1);
+ if (!regionAppended) {
+ /* extra separator is required */
+ sink.Append("_", 1);
+ }
+ }
+
+ /*
+ * Copy the trailing data into the supplied buffer.
+ */
+ sink.Append(trailing, trailingLength);
}
}
@@ -156,21 +135,28 @@ parseTagString(
icu::CharString& region,
UErrorCode* err)
{
- icu::CharString variant;
+ if (U_FAILURE(*err)) {
+ return 0;
+ }
+
+ if (localeID == nullptr) {
+ *err = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
const char* position = localeID;
- if (U_FAILURE(*err) || localeID == nullptr) {
- goto error;
- }
+ {
+ icu::CharString variant;
+ ulocimp_getSubtags(localeID, &lang, &script, ®ion, &variant, &position, *err);
- ulocimp_getSubtags(localeID, &lang, &script, ®ion, &variant, &position, *err);
+ if (U_FAILURE(*err)) {
+ return 0;
+ }
- if(U_FAILURE(*err)) {
- goto error;
- }
-
- if (!variant.isEmpty()) {
- position -= 1 + variant.length();
+ if (!variant.isEmpty()) {
+ position -= 1 + variant.length();
+ }
}
if (_isIDSeparator(*position)) {
@@ -182,21 +168,7 @@ parseTagString(
--position;
}
-exit:
-
return (int32_t)(position - localeID);
-
-error:
-
- /**
- * If we get here, we have no explicit error, it's the result of an
- * illegal argument.
- **/
- if (!U_FAILURE(*err)) {
- *err = U_ILLEGAL_ARGUMENT_ERROR;
- }
-
- goto exit;
}
namespace {
@@ -225,40 +197,30 @@ static UBool
_uloc_addLikelySubtags(const char* localeID,
icu::ByteSink& sink,
UErrorCode* err) {
+ if (U_FAILURE(*err)) {
+ return false;
+ }
+
+ if (localeID == nullptr) {
+ *err = U_ILLEGAL_ARGUMENT_ERROR;
+ return false;
+ }
+
icu::CharString lang;
icu::CharString script;
icu::CharString region;
- const char* trailing = "";
- int32_t trailingLength = 0;
- int32_t trailingIndex = 0;
-
- if(U_FAILURE(*err)) {
- goto error;
- }
- if (localeID == nullptr) {
- goto error;
+ int32_t trailingIndex = parseTagString(localeID, lang, script, region, err);
+ if (U_FAILURE(*err)) {
+ return false;
}
- trailingIndex = parseTagString(
- localeID,
- lang,
- script,
- region,
- err);
- if(U_FAILURE(*err)) {
- /* Overflow indicates an illegal argument error */
- if (*err == U_BUFFER_OVERFLOW_ERROR) {
- *err = U_ILLEGAL_ARGUMENT_ERROR;
- }
-
- goto error;
- }
if (lang.length() > 3) {
if (lang.length() == 4 && script.isEmpty()) {
script = std::move(lang);
lang.clear();
} else {
- goto error;
+ *err = U_ILLEGAL_ARGUMENT_ERROR;
+ return false;
}
}
@@ -266,53 +228,46 @@ _uloc_addLikelySubtags(const char* localeID,
while (_isIDSeparator(localeID[trailingIndex])) {
trailingIndex++;
}
- trailing = &localeID[trailingIndex];
- trailingLength = (int32_t)uprv_strlen(trailing);
+ const char* trailing = &localeID[trailingIndex];
+ int32_t trailingLength = (int32_t)uprv_strlen(trailing);
- if (!CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength)) goto error;
-
- {
- const icu::LikelySubtags* likelySubtags = icu::LikelySubtags::getSingleton(*err);
- if(U_FAILURE(*err)) {
- goto error;
- }
- // 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()) {
- goto error;
- }
- icu::LSR lsr = likelySubtags->makeMaximizedLsrFrom(l, true, *err);
- if(U_FAILURE(*err)) {
- goto error;
- }
- const char* language = lsr.language;
- if (uprv_strcmp(language, "und") == 0) {
- language = "";
- }
- createTagStringWithAlternates(
- language,
- (int32_t)uprv_strlen(language),
- lsr.script,
- (int32_t)uprv_strlen(lsr.script),
- lsr.region,
- (int32_t)uprv_strlen(lsr.region),
- trailing,
- trailingLength,
- sink,
- err);
- if(U_FAILURE(*err)) {
- goto error;
- }
- }
- return true;
-
-error:
-
- if (!U_FAILURE(*err)) {
+ if (!CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength)) {
*err = U_ILLEGAL_ARGUMENT_ERROR;
+ return false;
}
- return false;
+
+ const icu::LikelySubtags* likelySubtags = icu::LikelySubtags::getSingleton(*err);
+ if (U_FAILURE(*err)) {
+ return false;
+ }
+ // 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;
+ }
+ icu::LSR lsr = likelySubtags->makeMaximizedLsrFrom(l, true, *err);
+ if (U_FAILURE(*err)) {
+ return false;
+ }
+ const char* language = lsr.language;
+ if (uprv_strcmp(language, "und") == 0) {
+ language = "";
+ }
+ createTagStringWithAlternates(
+ language,
+ (int32_t)uprv_strlen(language),
+ lsr.script,
+ (int32_t)uprv_strlen(lsr.script),
+ lsr.region,
+ (int32_t)uprv_strlen(lsr.region),
+ trailing,
+ trailingLength,
+ sink,
+ err);
+
+ return U_SUCCESS(*err);
}
// Add likely subtags to the sink
@@ -326,88 +281,63 @@ _uloc_minimizeSubtags(const char* localeID,
icu::ByteSink& sink,
bool favorScript,
UErrorCode* err) {
- icu::CharString maximizedTagBuffer;
+ if (U_FAILURE(*err)) {
+ return;
+ }
+
+ if (localeID == nullptr) {
+ *err = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
icu::CharString lang;
icu::CharString script;
icu::CharString region;
- const char* trailing = "";
- int32_t trailingLength = 0;
- int32_t trailingIndex = 0;
-
- if(U_FAILURE(*err)) {
- goto error;
- }
- else if (localeID == nullptr) {
- goto error;
- }
-
- trailingIndex =
- parseTagString(
- localeID,
- lang,
- script,
- region,
- err);
- if(U_FAILURE(*err)) {
-
- /* Overflow indicates an illegal argument error */
- if (*err == U_BUFFER_OVERFLOW_ERROR) {
- *err = U_ILLEGAL_ARGUMENT_ERROR;
- }
-
- goto error;
+ int32_t trailingIndex = parseTagString(localeID, lang, script, region, err);
+ if (U_FAILURE(*err)) {
+ return;
}
/* Find the spot where the variants or the keywords begin, if any. */
while (_isIDSeparator(localeID[trailingIndex])) {
trailingIndex++;
}
- trailing = &localeID[trailingIndex];
- trailingLength = (int32_t)uprv_strlen(trailing);
+ const char* trailing = &localeID[trailingIndex];
+ int32_t trailingLength = (int32_t)uprv_strlen(trailing);
- if (!CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength)) goto error;
-
- {
- const icu::LikelySubtags* likelySubtags = icu::LikelySubtags::getSingleton(*err);
- if(U_FAILURE(*err)) {
- goto error;
- }
- icu::LSR lsr = likelySubtags->minimizeSubtags(
- lang.toStringPiece(),
- script.toStringPiece(),
- region.toStringPiece(),
- favorScript,
- *err);
- if(U_FAILURE(*err)) {
- goto error;
- }
- const char* language = lsr.language;
- if (uprv_strcmp(language, "und") == 0) {
- language = "";
- }
- createTagStringWithAlternates(
- language,
- (int32_t)uprv_strlen(language),
- lsr.script,
- (int32_t)uprv_strlen(lsr.script),
- lsr.region,
- (int32_t)uprv_strlen(lsr.region),
- trailing,
- trailingLength,
- sink,
- err);
- if(U_FAILURE(*err)) {
- goto error;
- }
+ if (!CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength)) {
+ *err = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
-error:
-
- if (!U_FAILURE(*err)) {
- *err = U_ILLEGAL_ARGUMENT_ERROR;
+ const icu::LikelySubtags* likelySubtags = icu::LikelySubtags::getSingleton(*err);
+ if (U_FAILURE(*err)) {
+ return;
}
+ icu::LSR lsr = likelySubtags->minimizeSubtags(
+ lang.toStringPiece(),
+ script.toStringPiece(),
+ region.toStringPiece(),
+ favorScript,
+ *err);
+ if (U_FAILURE(*err)) {
+ return;
+ }
+ const char* language = lsr.language;
+ if (uprv_strcmp(language, "und") == 0) {
+ language = "";
+ }
+ createTagStringWithAlternates(
+ language,
+ (int32_t)uprv_strlen(language),
+ lsr.script,
+ (int32_t)uprv_strlen(lsr.script),
+ lsr.region,
+ (int32_t)uprv_strlen(lsr.region),
+ trailing,
+ trailingLength,
+ sink,
+ err);
}
U_CAPI int32_t U_EXPORT2