intl/icu/source/common/loclikely.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 *
michael@0 4 * Copyright (C) 1997-2012, International Business Machines
michael@0 5 * Corporation and others. All Rights Reserved.
michael@0 6 *
michael@0 7 *******************************************************************************
michael@0 8 * file name: loclikely.cpp
michael@0 9 * encoding: US-ASCII
michael@0 10 * tab size: 8 (not used)
michael@0 11 * indentation:4
michael@0 12 *
michael@0 13 * created on: 2010feb25
michael@0 14 * created by: Markus W. Scherer
michael@0 15 *
michael@0 16 * Code for likely and minimized locale subtags, separated out from other .cpp files
michael@0 17 * that then do not depend on resource bundle code and likely-subtags data.
michael@0 18 */
michael@0 19
michael@0 20 #include "unicode/utypes.h"
michael@0 21 #include "unicode/putil.h"
michael@0 22 #include "unicode/uloc.h"
michael@0 23 #include "unicode/ures.h"
michael@0 24 #include "cmemory.h"
michael@0 25 #include "cstring.h"
michael@0 26 #include "ulocimp.h"
michael@0 27 #include "ustr_imp.h"
michael@0 28
michael@0 29 /**
michael@0 30 * This function looks for the localeID in the likelySubtags resource.
michael@0 31 *
michael@0 32 * @param localeID The tag to find.
michael@0 33 * @param buffer A buffer to hold the matching entry
michael@0 34 * @param bufferLength The length of the output buffer
michael@0 35 * @return A pointer to "buffer" if found, or a null pointer if not.
michael@0 36 */
michael@0 37 static const char* U_CALLCONV
michael@0 38 findLikelySubtags(const char* localeID,
michael@0 39 char* buffer,
michael@0 40 int32_t bufferLength,
michael@0 41 UErrorCode* err) {
michael@0 42 const char* result = NULL;
michael@0 43
michael@0 44 if (!U_FAILURE(*err)) {
michael@0 45 int32_t resLen = 0;
michael@0 46 const UChar* s = NULL;
michael@0 47 UErrorCode tmpErr = U_ZERO_ERROR;
michael@0 48 UResourceBundle* subtags = ures_openDirect(NULL, "likelySubtags", &tmpErr);
michael@0 49 if (U_SUCCESS(tmpErr)) {
michael@0 50 s = ures_getStringByKey(subtags, localeID, &resLen, &tmpErr);
michael@0 51
michael@0 52 if (U_FAILURE(tmpErr)) {
michael@0 53 /*
michael@0 54 * If a resource is missing, it's not really an error, it's
michael@0 55 * just that we don't have any data for that particular locale ID.
michael@0 56 */
michael@0 57 if (tmpErr != U_MISSING_RESOURCE_ERROR) {
michael@0 58 *err = tmpErr;
michael@0 59 }
michael@0 60 }
michael@0 61 else if (resLen >= bufferLength) {
michael@0 62 /* The buffer should never overflow. */
michael@0 63 *err = U_INTERNAL_PROGRAM_ERROR;
michael@0 64 }
michael@0 65 else {
michael@0 66 u_UCharsToChars(s, buffer, resLen + 1);
michael@0 67 result = buffer;
michael@0 68 }
michael@0 69
michael@0 70 ures_close(subtags);
michael@0 71 } else {
michael@0 72 *err = tmpErr;
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 return result;
michael@0 77 }
michael@0 78
michael@0 79 /**
michael@0 80 * Append a tag to a buffer, adding the separator if necessary. The buffer
michael@0 81 * must be large enough to contain the resulting tag plus any separator
michael@0 82 * necessary. The tag must not be a zero-length string.
michael@0 83 *
michael@0 84 * @param tag The tag to add.
michael@0 85 * @param tagLength The length of the tag.
michael@0 86 * @param buffer The output buffer.
michael@0 87 * @param bufferLength The length of the output buffer. This is an input/ouput parameter.
michael@0 88 **/
michael@0 89 static void U_CALLCONV
michael@0 90 appendTag(
michael@0 91 const char* tag,
michael@0 92 int32_t tagLength,
michael@0 93 char* buffer,
michael@0 94 int32_t* bufferLength) {
michael@0 95
michael@0 96 if (*bufferLength > 0) {
michael@0 97 buffer[*bufferLength] = '_';
michael@0 98 ++(*bufferLength);
michael@0 99 }
michael@0 100
michael@0 101 uprv_memmove(
michael@0 102 &buffer[*bufferLength],
michael@0 103 tag,
michael@0 104 tagLength);
michael@0 105
michael@0 106 *bufferLength += tagLength;
michael@0 107 }
michael@0 108
michael@0 109 /**
michael@0 110 * These are the canonical strings for unknown languages, scripts and regions.
michael@0 111 **/
michael@0 112 static const char* const unknownLanguage = "und";
michael@0 113 static const char* const unknownScript = "Zzzz";
michael@0 114 static const char* const unknownRegion = "ZZ";
michael@0 115
michael@0 116 /**
michael@0 117 * Create a tag string from the supplied parameters. The lang, script and region
michael@0 118 * parameters may be NULL pointers. If they are, their corresponding length parameters
michael@0 119 * must be less than or equal to 0.
michael@0 120 *
michael@0 121 * If any of the language, script or region parameters are empty, and the alternateTags
michael@0 122 * parameter is not NULL, it will be parsed for potential language, script and region tags
michael@0 123 * to be used when constructing the new tag. If the alternateTags parameter is NULL, or
michael@0 124 * it contains no language tag, the default tag for the unknown language is used.
michael@0 125 *
michael@0 126 * If the length of the new string exceeds the capacity of the output buffer,
michael@0 127 * the function copies as many bytes to the output buffer as it can, and returns
michael@0 128 * the error U_BUFFER_OVERFLOW_ERROR.
michael@0 129 *
michael@0 130 * If an illegal argument is provided, the function returns the error
michael@0 131 * U_ILLEGAL_ARGUMENT_ERROR.
michael@0 132 *
michael@0 133 * Note that this function can return the warning U_STRING_NOT_TERMINATED_WARNING if
michael@0 134 * the tag string fits in the output buffer, but the null terminator doesn't.
michael@0 135 *
michael@0 136 * @param lang The language tag to use.
michael@0 137 * @param langLength The length of the language tag.
michael@0 138 * @param script The script tag to use.
michael@0 139 * @param scriptLength The length of the script tag.
michael@0 140 * @param region The region tag to use.
michael@0 141 * @param regionLength The length of the region tag.
michael@0 142 * @param trailing Any trailing data to append to the new tag.
michael@0 143 * @param trailingLength The length of the trailing data.
michael@0 144 * @param alternateTags A string containing any alternate tags.
michael@0 145 * @param tag The output buffer.
michael@0 146 * @param tagCapacity The capacity of the output buffer.
michael@0 147 * @param err A pointer to a UErrorCode for error reporting.
michael@0 148 * @return The length of the tag string, which may be greater than tagCapacity, or -1 on error.
michael@0 149 **/
michael@0 150 static int32_t U_CALLCONV
michael@0 151 createTagStringWithAlternates(
michael@0 152 const char* lang,
michael@0 153 int32_t langLength,
michael@0 154 const char* script,
michael@0 155 int32_t scriptLength,
michael@0 156 const char* region,
michael@0 157 int32_t regionLength,
michael@0 158 const char* trailing,
michael@0 159 int32_t trailingLength,
michael@0 160 const char* alternateTags,
michael@0 161 char* tag,
michael@0 162 int32_t tagCapacity,
michael@0 163 UErrorCode* err) {
michael@0 164
michael@0 165 if (U_FAILURE(*err)) {
michael@0 166 goto error;
michael@0 167 }
michael@0 168 else if (tag == NULL ||
michael@0 169 tagCapacity <= 0 ||
michael@0 170 langLength >= ULOC_LANG_CAPACITY ||
michael@0 171 scriptLength >= ULOC_SCRIPT_CAPACITY ||
michael@0 172 regionLength >= ULOC_COUNTRY_CAPACITY) {
michael@0 173 goto error;
michael@0 174 }
michael@0 175 else {
michael@0 176 /**
michael@0 177 * ULOC_FULLNAME_CAPACITY will provide enough capacity
michael@0 178 * that we can build a string that contains the language,
michael@0 179 * script and region code without worrying about overrunning
michael@0 180 * the user-supplied buffer.
michael@0 181 **/
michael@0 182 char tagBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 183 int32_t tagLength = 0;
michael@0 184 int32_t capacityRemaining = tagCapacity;
michael@0 185 UBool regionAppended = FALSE;
michael@0 186
michael@0 187 if (langLength > 0) {
michael@0 188 appendTag(
michael@0 189 lang,
michael@0 190 langLength,
michael@0 191 tagBuffer,
michael@0 192 &tagLength);
michael@0 193 }
michael@0 194 else if (alternateTags == NULL) {
michael@0 195 /*
michael@0 196 * Append the value for an unknown language, if
michael@0 197 * we found no language.
michael@0 198 */
michael@0 199 appendTag(
michael@0 200 unknownLanguage,
michael@0 201 (int32_t)uprv_strlen(unknownLanguage),
michael@0 202 tagBuffer,
michael@0 203 &tagLength);
michael@0 204 }
michael@0 205 else {
michael@0 206 /*
michael@0 207 * Parse the alternateTags string for the language.
michael@0 208 */
michael@0 209 char alternateLang[ULOC_LANG_CAPACITY];
michael@0 210 int32_t alternateLangLength = sizeof(alternateLang);
michael@0 211
michael@0 212 alternateLangLength =
michael@0 213 uloc_getLanguage(
michael@0 214 alternateTags,
michael@0 215 alternateLang,
michael@0 216 alternateLangLength,
michael@0 217 err);
michael@0 218 if(U_FAILURE(*err) ||
michael@0 219 alternateLangLength >= ULOC_LANG_CAPACITY) {
michael@0 220 goto error;
michael@0 221 }
michael@0 222 else if (alternateLangLength == 0) {
michael@0 223 /*
michael@0 224 * Append the value for an unknown language, if
michael@0 225 * we found no language.
michael@0 226 */
michael@0 227 appendTag(
michael@0 228 unknownLanguage,
michael@0 229 (int32_t)uprv_strlen(unknownLanguage),
michael@0 230 tagBuffer,
michael@0 231 &tagLength);
michael@0 232 }
michael@0 233 else {
michael@0 234 appendTag(
michael@0 235 alternateLang,
michael@0 236 alternateLangLength,
michael@0 237 tagBuffer,
michael@0 238 &tagLength);
michael@0 239 }
michael@0 240 }
michael@0 241
michael@0 242 if (scriptLength > 0) {
michael@0 243 appendTag(
michael@0 244 script,
michael@0 245 scriptLength,
michael@0 246 tagBuffer,
michael@0 247 &tagLength);
michael@0 248 }
michael@0 249 else if (alternateTags != NULL) {
michael@0 250 /*
michael@0 251 * Parse the alternateTags string for the script.
michael@0 252 */
michael@0 253 char alternateScript[ULOC_SCRIPT_CAPACITY];
michael@0 254
michael@0 255 const int32_t alternateScriptLength =
michael@0 256 uloc_getScript(
michael@0 257 alternateTags,
michael@0 258 alternateScript,
michael@0 259 sizeof(alternateScript),
michael@0 260 err);
michael@0 261
michael@0 262 if (U_FAILURE(*err) ||
michael@0 263 alternateScriptLength >= ULOC_SCRIPT_CAPACITY) {
michael@0 264 goto error;
michael@0 265 }
michael@0 266 else if (alternateScriptLength > 0) {
michael@0 267 appendTag(
michael@0 268 alternateScript,
michael@0 269 alternateScriptLength,
michael@0 270 tagBuffer,
michael@0 271 &tagLength);
michael@0 272 }
michael@0 273 }
michael@0 274
michael@0 275 if (regionLength > 0) {
michael@0 276 appendTag(
michael@0 277 region,
michael@0 278 regionLength,
michael@0 279 tagBuffer,
michael@0 280 &tagLength);
michael@0 281
michael@0 282 regionAppended = TRUE;
michael@0 283 }
michael@0 284 else if (alternateTags != NULL) {
michael@0 285 /*
michael@0 286 * Parse the alternateTags string for the region.
michael@0 287 */
michael@0 288 char alternateRegion[ULOC_COUNTRY_CAPACITY];
michael@0 289
michael@0 290 const int32_t alternateRegionLength =
michael@0 291 uloc_getCountry(
michael@0 292 alternateTags,
michael@0 293 alternateRegion,
michael@0 294 sizeof(alternateRegion),
michael@0 295 err);
michael@0 296 if (U_FAILURE(*err) ||
michael@0 297 alternateRegionLength >= ULOC_COUNTRY_CAPACITY) {
michael@0 298 goto error;
michael@0 299 }
michael@0 300 else if (alternateRegionLength > 0) {
michael@0 301 appendTag(
michael@0 302 alternateRegion,
michael@0 303 alternateRegionLength,
michael@0 304 tagBuffer,
michael@0 305 &tagLength);
michael@0 306
michael@0 307 regionAppended = TRUE;
michael@0 308 }
michael@0 309 }
michael@0 310
michael@0 311 {
michael@0 312 const int32_t toCopy =
michael@0 313 tagLength >= tagCapacity ? tagCapacity : tagLength;
michael@0 314
michael@0 315 /**
michael@0 316 * Copy the partial tag from our internal buffer to the supplied
michael@0 317 * target.
michael@0 318 **/
michael@0 319 uprv_memcpy(
michael@0 320 tag,
michael@0 321 tagBuffer,
michael@0 322 toCopy);
michael@0 323
michael@0 324 capacityRemaining -= toCopy;
michael@0 325 }
michael@0 326
michael@0 327 if (trailingLength > 0) {
michael@0 328 if (*trailing != '@' && capacityRemaining > 0) {
michael@0 329 tag[tagLength++] = '_';
michael@0 330 --capacityRemaining;
michael@0 331 if (capacityRemaining > 0 && !regionAppended) {
michael@0 332 /* extra separator is required */
michael@0 333 tag[tagLength++] = '_';
michael@0 334 --capacityRemaining;
michael@0 335 }
michael@0 336 }
michael@0 337
michael@0 338 if (capacityRemaining > 0) {
michael@0 339 /*
michael@0 340 * Copy the trailing data into the supplied buffer. Use uprv_memmove, since we
michael@0 341 * don't know if the user-supplied buffers overlap.
michael@0 342 */
michael@0 343 const int32_t toCopy =
michael@0 344 trailingLength >= capacityRemaining ? capacityRemaining : trailingLength;
michael@0 345
michael@0 346 uprv_memmove(
michael@0 347 &tag[tagLength],
michael@0 348 trailing,
michael@0 349 toCopy);
michael@0 350 }
michael@0 351 }
michael@0 352
michael@0 353 tagLength += trailingLength;
michael@0 354
michael@0 355 return u_terminateChars(
michael@0 356 tag,
michael@0 357 tagCapacity,
michael@0 358 tagLength,
michael@0 359 err);
michael@0 360 }
michael@0 361
michael@0 362 error:
michael@0 363
michael@0 364 /**
michael@0 365 * An overflow indicates the locale ID passed in
michael@0 366 * is ill-formed. If we got here, and there was
michael@0 367 * no previous error, it's an implicit overflow.
michael@0 368 **/
michael@0 369 if (*err == U_BUFFER_OVERFLOW_ERROR ||
michael@0 370 U_SUCCESS(*err)) {
michael@0 371 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 372 }
michael@0 373
michael@0 374 return -1;
michael@0 375 }
michael@0 376
michael@0 377 /**
michael@0 378 * Create a tag string from the supplied parameters. The lang, script and region
michael@0 379 * parameters may be NULL pointers. If they are, their corresponding length parameters
michael@0 380 * must be less than or equal to 0. If the lang parameter is an empty string, the
michael@0 381 * default value for an unknown language is written to the output buffer.
michael@0 382 *
michael@0 383 * If the length of the new string exceeds the capacity of the output buffer,
michael@0 384 * the function copies as many bytes to the output buffer as it can, and returns
michael@0 385 * the error U_BUFFER_OVERFLOW_ERROR.
michael@0 386 *
michael@0 387 * If an illegal argument is provided, the function returns the error
michael@0 388 * U_ILLEGAL_ARGUMENT_ERROR.
michael@0 389 *
michael@0 390 * @param lang The language tag to use.
michael@0 391 * @param langLength The length of the language tag.
michael@0 392 * @param script The script tag to use.
michael@0 393 * @param scriptLength The length of the script tag.
michael@0 394 * @param region The region tag to use.
michael@0 395 * @param regionLength The length of the region tag.
michael@0 396 * @param trailing Any trailing data to append to the new tag.
michael@0 397 * @param trailingLength The length of the trailing data.
michael@0 398 * @param tag The output buffer.
michael@0 399 * @param tagCapacity The capacity of the output buffer.
michael@0 400 * @param err A pointer to a UErrorCode for error reporting.
michael@0 401 * @return The length of the tag string, which may be greater than tagCapacity.
michael@0 402 **/
michael@0 403 static int32_t U_CALLCONV
michael@0 404 createTagString(
michael@0 405 const char* lang,
michael@0 406 int32_t langLength,
michael@0 407 const char* script,
michael@0 408 int32_t scriptLength,
michael@0 409 const char* region,
michael@0 410 int32_t regionLength,
michael@0 411 const char* trailing,
michael@0 412 int32_t trailingLength,
michael@0 413 char* tag,
michael@0 414 int32_t tagCapacity,
michael@0 415 UErrorCode* err)
michael@0 416 {
michael@0 417 return createTagStringWithAlternates(
michael@0 418 lang,
michael@0 419 langLength,
michael@0 420 script,
michael@0 421 scriptLength,
michael@0 422 region,
michael@0 423 regionLength,
michael@0 424 trailing,
michael@0 425 trailingLength,
michael@0 426 NULL,
michael@0 427 tag,
michael@0 428 tagCapacity,
michael@0 429 err);
michael@0 430 }
michael@0 431
michael@0 432 /**
michael@0 433 * Parse the language, script, and region subtags from a tag string, and copy the
michael@0 434 * results into the corresponding output parameters. The buffers are null-terminated,
michael@0 435 * unless overflow occurs.
michael@0 436 *
michael@0 437 * The langLength, scriptLength, and regionLength parameters are input/output
michael@0 438 * parameters, and must contain the capacity of their corresponding buffers on
michael@0 439 * input. On output, they will contain the actual length of the buffers, not
michael@0 440 * including the null terminator.
michael@0 441 *
michael@0 442 * If the length of any of the output subtags exceeds the capacity of the corresponding
michael@0 443 * buffer, the function copies as many bytes to the output buffer as it can, and returns
michael@0 444 * the error U_BUFFER_OVERFLOW_ERROR. It will not parse any more subtags once overflow
michael@0 445 * occurs.
michael@0 446 *
michael@0 447 * If an illegal argument is provided, the function returns the error
michael@0 448 * U_ILLEGAL_ARGUMENT_ERROR.
michael@0 449 *
michael@0 450 * @param localeID The locale ID to parse.
michael@0 451 * @param lang The language tag buffer.
michael@0 452 * @param langLength The length of the language tag.
michael@0 453 * @param script The script tag buffer.
michael@0 454 * @param scriptLength The length of the script tag.
michael@0 455 * @param region The region tag buffer.
michael@0 456 * @param regionLength The length of the region tag.
michael@0 457 * @param err A pointer to a UErrorCode for error reporting.
michael@0 458 * @return The number of chars of the localeID parameter consumed.
michael@0 459 **/
michael@0 460 static int32_t U_CALLCONV
michael@0 461 parseTagString(
michael@0 462 const char* localeID,
michael@0 463 char* lang,
michael@0 464 int32_t* langLength,
michael@0 465 char* script,
michael@0 466 int32_t* scriptLength,
michael@0 467 char* region,
michael@0 468 int32_t* regionLength,
michael@0 469 UErrorCode* err)
michael@0 470 {
michael@0 471 const char* position = localeID;
michael@0 472 int32_t subtagLength = 0;
michael@0 473
michael@0 474 if(U_FAILURE(*err) ||
michael@0 475 localeID == NULL ||
michael@0 476 lang == NULL ||
michael@0 477 langLength == NULL ||
michael@0 478 script == NULL ||
michael@0 479 scriptLength == NULL ||
michael@0 480 region == NULL ||
michael@0 481 regionLength == NULL) {
michael@0 482 goto error;
michael@0 483 }
michael@0 484
michael@0 485 subtagLength = ulocimp_getLanguage(position, lang, *langLength, &position);
michael@0 486 u_terminateChars(lang, *langLength, subtagLength, err);
michael@0 487
michael@0 488 /*
michael@0 489 * Note that we explicit consider U_STRING_NOT_TERMINATED_WARNING
michael@0 490 * to be an error, because it indicates the user-supplied tag is
michael@0 491 * not well-formed.
michael@0 492 */
michael@0 493 if(U_FAILURE(*err)) {
michael@0 494 goto error;
michael@0 495 }
michael@0 496
michael@0 497 *langLength = subtagLength;
michael@0 498
michael@0 499 /*
michael@0 500 * If no language was present, use the value of unknownLanguage
michael@0 501 * instead. Otherwise, move past any separator.
michael@0 502 */
michael@0 503 if (*langLength == 0) {
michael@0 504 uprv_strcpy(
michael@0 505 lang,
michael@0 506 unknownLanguage);
michael@0 507 *langLength = (int32_t)uprv_strlen(lang);
michael@0 508 }
michael@0 509 else if (_isIDSeparator(*position)) {
michael@0 510 ++position;
michael@0 511 }
michael@0 512
michael@0 513 subtagLength = ulocimp_getScript(position, script, *scriptLength, &position);
michael@0 514 u_terminateChars(script, *scriptLength, subtagLength, err);
michael@0 515
michael@0 516 if(U_FAILURE(*err)) {
michael@0 517 goto error;
michael@0 518 }
michael@0 519
michael@0 520 *scriptLength = subtagLength;
michael@0 521
michael@0 522 if (*scriptLength > 0) {
michael@0 523 if (uprv_strnicmp(script, unknownScript, *scriptLength) == 0) {
michael@0 524 /**
michael@0 525 * If the script part is the "unknown" script, then don't return it.
michael@0 526 **/
michael@0 527 *scriptLength = 0;
michael@0 528 }
michael@0 529
michael@0 530 /*
michael@0 531 * Move past any separator.
michael@0 532 */
michael@0 533 if (_isIDSeparator(*position)) {
michael@0 534 ++position;
michael@0 535 }
michael@0 536 }
michael@0 537
michael@0 538 subtagLength = ulocimp_getCountry(position, region, *regionLength, &position);
michael@0 539 u_terminateChars(region, *regionLength, subtagLength, err);
michael@0 540
michael@0 541 if(U_FAILURE(*err)) {
michael@0 542 goto error;
michael@0 543 }
michael@0 544
michael@0 545 *regionLength = subtagLength;
michael@0 546
michael@0 547 if (*regionLength > 0) {
michael@0 548 if (uprv_strnicmp(region, unknownRegion, *regionLength) == 0) {
michael@0 549 /**
michael@0 550 * If the region part is the "unknown" region, then don't return it.
michael@0 551 **/
michael@0 552 *regionLength = 0;
michael@0 553 }
michael@0 554 } else if (*position != 0 && *position != '@') {
michael@0 555 /* back up over consumed trailing separator */
michael@0 556 --position;
michael@0 557 }
michael@0 558
michael@0 559 exit:
michael@0 560
michael@0 561 return (int32_t)(position - localeID);
michael@0 562
michael@0 563 error:
michael@0 564
michael@0 565 /**
michael@0 566 * If we get here, we have no explicit error, it's the result of an
michael@0 567 * illegal argument.
michael@0 568 **/
michael@0 569 if (!U_FAILURE(*err)) {
michael@0 570 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 571 }
michael@0 572
michael@0 573 goto exit;
michael@0 574 }
michael@0 575
michael@0 576 static int32_t U_CALLCONV
michael@0 577 createLikelySubtagsString(
michael@0 578 const char* lang,
michael@0 579 int32_t langLength,
michael@0 580 const char* script,
michael@0 581 int32_t scriptLength,
michael@0 582 const char* region,
michael@0 583 int32_t regionLength,
michael@0 584 const char* variants,
michael@0 585 int32_t variantsLength,
michael@0 586 char* tag,
michael@0 587 int32_t tagCapacity,
michael@0 588 UErrorCode* err)
michael@0 589 {
michael@0 590 /**
michael@0 591 * ULOC_FULLNAME_CAPACITY will provide enough capacity
michael@0 592 * that we can build a string that contains the language,
michael@0 593 * script and region code without worrying about overrunning
michael@0 594 * the user-supplied buffer.
michael@0 595 **/
michael@0 596 char tagBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 597 char likelySubtagsBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 598
michael@0 599 if(U_FAILURE(*err)) {
michael@0 600 goto error;
michael@0 601 }
michael@0 602
michael@0 603 /**
michael@0 604 * Try the language with the script and region first.
michael@0 605 **/
michael@0 606 if (scriptLength > 0 && regionLength > 0) {
michael@0 607
michael@0 608 const char* likelySubtags = NULL;
michael@0 609
michael@0 610 createTagString(
michael@0 611 lang,
michael@0 612 langLength,
michael@0 613 script,
michael@0 614 scriptLength,
michael@0 615 region,
michael@0 616 regionLength,
michael@0 617 NULL,
michael@0 618 0,
michael@0 619 tagBuffer,
michael@0 620 sizeof(tagBuffer),
michael@0 621 err);
michael@0 622 if(U_FAILURE(*err)) {
michael@0 623 goto error;
michael@0 624 }
michael@0 625
michael@0 626 likelySubtags =
michael@0 627 findLikelySubtags(
michael@0 628 tagBuffer,
michael@0 629 likelySubtagsBuffer,
michael@0 630 sizeof(likelySubtagsBuffer),
michael@0 631 err);
michael@0 632 if(U_FAILURE(*err)) {
michael@0 633 goto error;
michael@0 634 }
michael@0 635
michael@0 636 if (likelySubtags != NULL) {
michael@0 637 /* Always use the language tag from the
michael@0 638 maximal string, since it may be more
michael@0 639 specific than the one provided. */
michael@0 640 return createTagStringWithAlternates(
michael@0 641 NULL,
michael@0 642 0,
michael@0 643 NULL,
michael@0 644 0,
michael@0 645 NULL,
michael@0 646 0,
michael@0 647 variants,
michael@0 648 variantsLength,
michael@0 649 likelySubtags,
michael@0 650 tag,
michael@0 651 tagCapacity,
michael@0 652 err);
michael@0 653 }
michael@0 654 }
michael@0 655
michael@0 656 /**
michael@0 657 * Try the language with just the script.
michael@0 658 **/
michael@0 659 if (scriptLength > 0) {
michael@0 660
michael@0 661 const char* likelySubtags = NULL;
michael@0 662
michael@0 663 createTagString(
michael@0 664 lang,
michael@0 665 langLength,
michael@0 666 script,
michael@0 667 scriptLength,
michael@0 668 NULL,
michael@0 669 0,
michael@0 670 NULL,
michael@0 671 0,
michael@0 672 tagBuffer,
michael@0 673 sizeof(tagBuffer),
michael@0 674 err);
michael@0 675 if(U_FAILURE(*err)) {
michael@0 676 goto error;
michael@0 677 }
michael@0 678
michael@0 679 likelySubtags =
michael@0 680 findLikelySubtags(
michael@0 681 tagBuffer,
michael@0 682 likelySubtagsBuffer,
michael@0 683 sizeof(likelySubtagsBuffer),
michael@0 684 err);
michael@0 685 if(U_FAILURE(*err)) {
michael@0 686 goto error;
michael@0 687 }
michael@0 688
michael@0 689 if (likelySubtags != NULL) {
michael@0 690 /* Always use the language tag from the
michael@0 691 maximal string, since it may be more
michael@0 692 specific than the one provided. */
michael@0 693 return createTagStringWithAlternates(
michael@0 694 NULL,
michael@0 695 0,
michael@0 696 NULL,
michael@0 697 0,
michael@0 698 region,
michael@0 699 regionLength,
michael@0 700 variants,
michael@0 701 variantsLength,
michael@0 702 likelySubtags,
michael@0 703 tag,
michael@0 704 tagCapacity,
michael@0 705 err);
michael@0 706 }
michael@0 707 }
michael@0 708
michael@0 709 /**
michael@0 710 * Try the language with just the region.
michael@0 711 **/
michael@0 712 if (regionLength > 0) {
michael@0 713
michael@0 714 const char* likelySubtags = NULL;
michael@0 715
michael@0 716 createTagString(
michael@0 717 lang,
michael@0 718 langLength,
michael@0 719 NULL,
michael@0 720 0,
michael@0 721 region,
michael@0 722 regionLength,
michael@0 723 NULL,
michael@0 724 0,
michael@0 725 tagBuffer,
michael@0 726 sizeof(tagBuffer),
michael@0 727 err);
michael@0 728 if(U_FAILURE(*err)) {
michael@0 729 goto error;
michael@0 730 }
michael@0 731
michael@0 732 likelySubtags =
michael@0 733 findLikelySubtags(
michael@0 734 tagBuffer,
michael@0 735 likelySubtagsBuffer,
michael@0 736 sizeof(likelySubtagsBuffer),
michael@0 737 err);
michael@0 738 if(U_FAILURE(*err)) {
michael@0 739 goto error;
michael@0 740 }
michael@0 741
michael@0 742 if (likelySubtags != NULL) {
michael@0 743 /* Always use the language tag from the
michael@0 744 maximal string, since it may be more
michael@0 745 specific than the one provided. */
michael@0 746 return createTagStringWithAlternates(
michael@0 747 NULL,
michael@0 748 0,
michael@0 749 script,
michael@0 750 scriptLength,
michael@0 751 NULL,
michael@0 752 0,
michael@0 753 variants,
michael@0 754 variantsLength,
michael@0 755 likelySubtags,
michael@0 756 tag,
michael@0 757 tagCapacity,
michael@0 758 err);
michael@0 759 }
michael@0 760 }
michael@0 761
michael@0 762 /**
michael@0 763 * Finally, try just the language.
michael@0 764 **/
michael@0 765 {
michael@0 766 const char* likelySubtags = NULL;
michael@0 767
michael@0 768 createTagString(
michael@0 769 lang,
michael@0 770 langLength,
michael@0 771 NULL,
michael@0 772 0,
michael@0 773 NULL,
michael@0 774 0,
michael@0 775 NULL,
michael@0 776 0,
michael@0 777 tagBuffer,
michael@0 778 sizeof(tagBuffer),
michael@0 779 err);
michael@0 780 if(U_FAILURE(*err)) {
michael@0 781 goto error;
michael@0 782 }
michael@0 783
michael@0 784 likelySubtags =
michael@0 785 findLikelySubtags(
michael@0 786 tagBuffer,
michael@0 787 likelySubtagsBuffer,
michael@0 788 sizeof(likelySubtagsBuffer),
michael@0 789 err);
michael@0 790 if(U_FAILURE(*err)) {
michael@0 791 goto error;
michael@0 792 }
michael@0 793
michael@0 794 if (likelySubtags != NULL) {
michael@0 795 /* Always use the language tag from the
michael@0 796 maximal string, since it may be more
michael@0 797 specific than the one provided. */
michael@0 798 return createTagStringWithAlternates(
michael@0 799 NULL,
michael@0 800 0,
michael@0 801 script,
michael@0 802 scriptLength,
michael@0 803 region,
michael@0 804 regionLength,
michael@0 805 variants,
michael@0 806 variantsLength,
michael@0 807 likelySubtags,
michael@0 808 tag,
michael@0 809 tagCapacity,
michael@0 810 err);
michael@0 811 }
michael@0 812 }
michael@0 813
michael@0 814 return u_terminateChars(
michael@0 815 tag,
michael@0 816 tagCapacity,
michael@0 817 0,
michael@0 818 err);
michael@0 819
michael@0 820 error:
michael@0 821
michael@0 822 if (!U_FAILURE(*err)) {
michael@0 823 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 824 }
michael@0 825
michael@0 826 return -1;
michael@0 827 }
michael@0 828
michael@0 829 #define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) \
michael@0 830 { int32_t count = 0; \
michael@0 831 int32_t i; \
michael@0 832 for (i = 0; i < trailingLength; i++) { \
michael@0 833 if (trailing[i] == '-' || trailing[i] == '_') { \
michael@0 834 count = 0; \
michael@0 835 if (count > 8) { \
michael@0 836 goto error; \
michael@0 837 } \
michael@0 838 } else if (trailing[i] == '@') { \
michael@0 839 break; \
michael@0 840 } else if (count > 8) { \
michael@0 841 goto error; \
michael@0 842 } else { \
michael@0 843 count++; \
michael@0 844 } \
michael@0 845 } \
michael@0 846 }
michael@0 847
michael@0 848 static int32_t
michael@0 849 _uloc_addLikelySubtags(const char* localeID,
michael@0 850 char* maximizedLocaleID,
michael@0 851 int32_t maximizedLocaleIDCapacity,
michael@0 852 UErrorCode* err)
michael@0 853 {
michael@0 854 char lang[ULOC_LANG_CAPACITY];
michael@0 855 int32_t langLength = sizeof(lang);
michael@0 856 char script[ULOC_SCRIPT_CAPACITY];
michael@0 857 int32_t scriptLength = sizeof(script);
michael@0 858 char region[ULOC_COUNTRY_CAPACITY];
michael@0 859 int32_t regionLength = sizeof(region);
michael@0 860 const char* trailing = "";
michael@0 861 int32_t trailingLength = 0;
michael@0 862 int32_t trailingIndex = 0;
michael@0 863 int32_t resultLength = 0;
michael@0 864
michael@0 865 if(U_FAILURE(*err)) {
michael@0 866 goto error;
michael@0 867 }
michael@0 868 else if (localeID == NULL ||
michael@0 869 maximizedLocaleID == NULL ||
michael@0 870 maximizedLocaleIDCapacity <= 0) {
michael@0 871 goto error;
michael@0 872 }
michael@0 873
michael@0 874 trailingIndex = parseTagString(
michael@0 875 localeID,
michael@0 876 lang,
michael@0 877 &langLength,
michael@0 878 script,
michael@0 879 &scriptLength,
michael@0 880 region,
michael@0 881 &regionLength,
michael@0 882 err);
michael@0 883 if(U_FAILURE(*err)) {
michael@0 884 /* Overflow indicates an illegal argument error */
michael@0 885 if (*err == U_BUFFER_OVERFLOW_ERROR) {
michael@0 886 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 887 }
michael@0 888
michael@0 889 goto error;
michael@0 890 }
michael@0 891
michael@0 892 /* Find the length of the trailing portion. */
michael@0 893 while (_isIDSeparator(localeID[trailingIndex])) {
michael@0 894 trailingIndex++;
michael@0 895 }
michael@0 896 trailing = &localeID[trailingIndex];
michael@0 897 trailingLength = (int32_t)uprv_strlen(trailing);
michael@0 898
michael@0 899 CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength);
michael@0 900
michael@0 901 resultLength =
michael@0 902 createLikelySubtagsString(
michael@0 903 lang,
michael@0 904 langLength,
michael@0 905 script,
michael@0 906 scriptLength,
michael@0 907 region,
michael@0 908 regionLength,
michael@0 909 trailing,
michael@0 910 trailingLength,
michael@0 911 maximizedLocaleID,
michael@0 912 maximizedLocaleIDCapacity,
michael@0 913 err);
michael@0 914
michael@0 915 if (resultLength == 0) {
michael@0 916 const int32_t localIDLength = (int32_t)uprv_strlen(localeID);
michael@0 917
michael@0 918 /*
michael@0 919 * If we get here, we need to return localeID.
michael@0 920 */
michael@0 921 uprv_memcpy(
michael@0 922 maximizedLocaleID,
michael@0 923 localeID,
michael@0 924 localIDLength <= maximizedLocaleIDCapacity ?
michael@0 925 localIDLength : maximizedLocaleIDCapacity);
michael@0 926
michael@0 927 resultLength =
michael@0 928 u_terminateChars(
michael@0 929 maximizedLocaleID,
michael@0 930 maximizedLocaleIDCapacity,
michael@0 931 localIDLength,
michael@0 932 err);
michael@0 933 }
michael@0 934
michael@0 935 return resultLength;
michael@0 936
michael@0 937 error:
michael@0 938
michael@0 939 if (!U_FAILURE(*err)) {
michael@0 940 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 941 }
michael@0 942
michael@0 943 return -1;
michael@0 944 }
michael@0 945
michael@0 946 static int32_t
michael@0 947 _uloc_minimizeSubtags(const char* localeID,
michael@0 948 char* minimizedLocaleID,
michael@0 949 int32_t minimizedLocaleIDCapacity,
michael@0 950 UErrorCode* err)
michael@0 951 {
michael@0 952 /**
michael@0 953 * ULOC_FULLNAME_CAPACITY will provide enough capacity
michael@0 954 * that we can build a string that contains the language,
michael@0 955 * script and region code without worrying about overrunning
michael@0 956 * the user-supplied buffer.
michael@0 957 **/
michael@0 958 char maximizedTagBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 959 int32_t maximizedTagBufferLength = sizeof(maximizedTagBuffer);
michael@0 960
michael@0 961 char lang[ULOC_LANG_CAPACITY];
michael@0 962 int32_t langLength = sizeof(lang);
michael@0 963 char script[ULOC_SCRIPT_CAPACITY];
michael@0 964 int32_t scriptLength = sizeof(script);
michael@0 965 char region[ULOC_COUNTRY_CAPACITY];
michael@0 966 int32_t regionLength = sizeof(region);
michael@0 967 const char* trailing = "";
michael@0 968 int32_t trailingLength = 0;
michael@0 969 int32_t trailingIndex = 0;
michael@0 970
michael@0 971 if(U_FAILURE(*err)) {
michael@0 972 goto error;
michael@0 973 }
michael@0 974 else if (localeID == NULL ||
michael@0 975 minimizedLocaleID == NULL ||
michael@0 976 minimizedLocaleIDCapacity <= 0) {
michael@0 977 goto error;
michael@0 978 }
michael@0 979
michael@0 980 trailingIndex =
michael@0 981 parseTagString(
michael@0 982 localeID,
michael@0 983 lang,
michael@0 984 &langLength,
michael@0 985 script,
michael@0 986 &scriptLength,
michael@0 987 region,
michael@0 988 &regionLength,
michael@0 989 err);
michael@0 990 if(U_FAILURE(*err)) {
michael@0 991
michael@0 992 /* Overflow indicates an illegal argument error */
michael@0 993 if (*err == U_BUFFER_OVERFLOW_ERROR) {
michael@0 994 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 995 }
michael@0 996
michael@0 997 goto error;
michael@0 998 }
michael@0 999
michael@0 1000 /* Find the spot where the variants or the keywords begin, if any. */
michael@0 1001 while (_isIDSeparator(localeID[trailingIndex])) {
michael@0 1002 trailingIndex++;
michael@0 1003 }
michael@0 1004 trailing = &localeID[trailingIndex];
michael@0 1005 trailingLength = (int32_t)uprv_strlen(trailing);
michael@0 1006
michael@0 1007 CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength);
michael@0 1008
michael@0 1009 createTagString(
michael@0 1010 lang,
michael@0 1011 langLength,
michael@0 1012 script,
michael@0 1013 scriptLength,
michael@0 1014 region,
michael@0 1015 regionLength,
michael@0 1016 NULL,
michael@0 1017 0,
michael@0 1018 maximizedTagBuffer,
michael@0 1019 maximizedTagBufferLength,
michael@0 1020 err);
michael@0 1021 if(U_FAILURE(*err)) {
michael@0 1022 goto error;
michael@0 1023 }
michael@0 1024
michael@0 1025 /**
michael@0 1026 * First, we need to first get the maximization
michael@0 1027 * from AddLikelySubtags.
michael@0 1028 **/
michael@0 1029 maximizedTagBufferLength =
michael@0 1030 uloc_addLikelySubtags(
michael@0 1031 maximizedTagBuffer,
michael@0 1032 maximizedTagBuffer,
michael@0 1033 maximizedTagBufferLength,
michael@0 1034 err);
michael@0 1035
michael@0 1036 if(U_FAILURE(*err)) {
michael@0 1037 goto error;
michael@0 1038 }
michael@0 1039
michael@0 1040 /**
michael@0 1041 * Start first with just the language.
michael@0 1042 **/
michael@0 1043 {
michael@0 1044 char tagBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 1045
michael@0 1046 const int32_t tagBufferLength =
michael@0 1047 createLikelySubtagsString(
michael@0 1048 lang,
michael@0 1049 langLength,
michael@0 1050 NULL,
michael@0 1051 0,
michael@0 1052 NULL,
michael@0 1053 0,
michael@0 1054 NULL,
michael@0 1055 0,
michael@0 1056 tagBuffer,
michael@0 1057 sizeof(tagBuffer),
michael@0 1058 err);
michael@0 1059
michael@0 1060 if(U_FAILURE(*err)) {
michael@0 1061 goto error;
michael@0 1062 }
michael@0 1063 else if (uprv_strnicmp(
michael@0 1064 maximizedTagBuffer,
michael@0 1065 tagBuffer,
michael@0 1066 tagBufferLength) == 0) {
michael@0 1067
michael@0 1068 return createTagString(
michael@0 1069 lang,
michael@0 1070 langLength,
michael@0 1071 NULL,
michael@0 1072 0,
michael@0 1073 NULL,
michael@0 1074 0,
michael@0 1075 trailing,
michael@0 1076 trailingLength,
michael@0 1077 minimizedLocaleID,
michael@0 1078 minimizedLocaleIDCapacity,
michael@0 1079 err);
michael@0 1080 }
michael@0 1081 }
michael@0 1082
michael@0 1083 /**
michael@0 1084 * Next, try the language and region.
michael@0 1085 **/
michael@0 1086 if (regionLength > 0) {
michael@0 1087
michael@0 1088 char tagBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 1089
michael@0 1090 const int32_t tagBufferLength =
michael@0 1091 createLikelySubtagsString(
michael@0 1092 lang,
michael@0 1093 langLength,
michael@0 1094 NULL,
michael@0 1095 0,
michael@0 1096 region,
michael@0 1097 regionLength,
michael@0 1098 NULL,
michael@0 1099 0,
michael@0 1100 tagBuffer,
michael@0 1101 sizeof(tagBuffer),
michael@0 1102 err);
michael@0 1103
michael@0 1104 if(U_FAILURE(*err)) {
michael@0 1105 goto error;
michael@0 1106 }
michael@0 1107 else if (uprv_strnicmp(
michael@0 1108 maximizedTagBuffer,
michael@0 1109 tagBuffer,
michael@0 1110 tagBufferLength) == 0) {
michael@0 1111
michael@0 1112 return createTagString(
michael@0 1113 lang,
michael@0 1114 langLength,
michael@0 1115 NULL,
michael@0 1116 0,
michael@0 1117 region,
michael@0 1118 regionLength,
michael@0 1119 trailing,
michael@0 1120 trailingLength,
michael@0 1121 minimizedLocaleID,
michael@0 1122 minimizedLocaleIDCapacity,
michael@0 1123 err);
michael@0 1124 }
michael@0 1125 }
michael@0 1126
michael@0 1127 /**
michael@0 1128 * Finally, try the language and script. This is our last chance,
michael@0 1129 * since trying with all three subtags would only yield the
michael@0 1130 * maximal version that we already have.
michael@0 1131 **/
michael@0 1132 if (scriptLength > 0 && regionLength > 0) {
michael@0 1133 char tagBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 1134
michael@0 1135 const int32_t tagBufferLength =
michael@0 1136 createLikelySubtagsString(
michael@0 1137 lang,
michael@0 1138 langLength,
michael@0 1139 script,
michael@0 1140 scriptLength,
michael@0 1141 NULL,
michael@0 1142 0,
michael@0 1143 NULL,
michael@0 1144 0,
michael@0 1145 tagBuffer,
michael@0 1146 sizeof(tagBuffer),
michael@0 1147 err);
michael@0 1148
michael@0 1149 if(U_FAILURE(*err)) {
michael@0 1150 goto error;
michael@0 1151 }
michael@0 1152 else if (uprv_strnicmp(
michael@0 1153 maximizedTagBuffer,
michael@0 1154 tagBuffer,
michael@0 1155 tagBufferLength) == 0) {
michael@0 1156
michael@0 1157 return createTagString(
michael@0 1158 lang,
michael@0 1159 langLength,
michael@0 1160 script,
michael@0 1161 scriptLength,
michael@0 1162 NULL,
michael@0 1163 0,
michael@0 1164 trailing,
michael@0 1165 trailingLength,
michael@0 1166 minimizedLocaleID,
michael@0 1167 minimizedLocaleIDCapacity,
michael@0 1168 err);
michael@0 1169 }
michael@0 1170 }
michael@0 1171
michael@0 1172 {
michael@0 1173 /**
michael@0 1174 * If we got here, return the locale ID parameter.
michael@0 1175 **/
michael@0 1176 const int32_t localeIDLength = (int32_t)uprv_strlen(localeID);
michael@0 1177
michael@0 1178 uprv_memcpy(
michael@0 1179 minimizedLocaleID,
michael@0 1180 localeID,
michael@0 1181 localeIDLength <= minimizedLocaleIDCapacity ?
michael@0 1182 localeIDLength : minimizedLocaleIDCapacity);
michael@0 1183
michael@0 1184 return u_terminateChars(
michael@0 1185 minimizedLocaleID,
michael@0 1186 minimizedLocaleIDCapacity,
michael@0 1187 localeIDLength,
michael@0 1188 err);
michael@0 1189 }
michael@0 1190
michael@0 1191 error:
michael@0 1192
michael@0 1193 if (!U_FAILURE(*err)) {
michael@0 1194 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 1195 }
michael@0 1196
michael@0 1197 return -1;
michael@0 1198
michael@0 1199
michael@0 1200 }
michael@0 1201
michael@0 1202 static UBool
michael@0 1203 do_canonicalize(const char* localeID,
michael@0 1204 char* buffer,
michael@0 1205 int32_t bufferCapacity,
michael@0 1206 UErrorCode* err)
michael@0 1207 {
michael@0 1208 uloc_canonicalize(
michael@0 1209 localeID,
michael@0 1210 buffer,
michael@0 1211 bufferCapacity,
michael@0 1212 err);
michael@0 1213
michael@0 1214 if (*err == U_STRING_NOT_TERMINATED_WARNING ||
michael@0 1215 *err == U_BUFFER_OVERFLOW_ERROR) {
michael@0 1216 *err = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 1217
michael@0 1218 return FALSE;
michael@0 1219 }
michael@0 1220 else if (U_FAILURE(*err)) {
michael@0 1221
michael@0 1222 return FALSE;
michael@0 1223 }
michael@0 1224 else {
michael@0 1225 return TRUE;
michael@0 1226 }
michael@0 1227 }
michael@0 1228
michael@0 1229 U_CAPI int32_t U_EXPORT2
michael@0 1230 uloc_addLikelySubtags(const char* localeID,
michael@0 1231 char* maximizedLocaleID,
michael@0 1232 int32_t maximizedLocaleIDCapacity,
michael@0 1233 UErrorCode* err)
michael@0 1234 {
michael@0 1235 char localeBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 1236
michael@0 1237 if (!do_canonicalize(
michael@0 1238 localeID,
michael@0 1239 localeBuffer,
michael@0 1240 sizeof(localeBuffer),
michael@0 1241 err)) {
michael@0 1242 return -1;
michael@0 1243 }
michael@0 1244 else {
michael@0 1245 return _uloc_addLikelySubtags(
michael@0 1246 localeBuffer,
michael@0 1247 maximizedLocaleID,
michael@0 1248 maximizedLocaleIDCapacity,
michael@0 1249 err);
michael@0 1250 }
michael@0 1251 }
michael@0 1252
michael@0 1253 U_CAPI int32_t U_EXPORT2
michael@0 1254 uloc_minimizeSubtags(const char* localeID,
michael@0 1255 char* minimizedLocaleID,
michael@0 1256 int32_t minimizedLocaleIDCapacity,
michael@0 1257 UErrorCode* err)
michael@0 1258 {
michael@0 1259 char localeBuffer[ULOC_FULLNAME_CAPACITY];
michael@0 1260
michael@0 1261 if (!do_canonicalize(
michael@0 1262 localeID,
michael@0 1263 localeBuffer,
michael@0 1264 sizeof(localeBuffer),
michael@0 1265 err)) {
michael@0 1266 return -1;
michael@0 1267 }
michael@0 1268 else {
michael@0 1269 return _uloc_minimizeSubtags(
michael@0 1270 localeBuffer,
michael@0 1271 minimizedLocaleID,
michael@0 1272 minimizedLocaleIDCapacity,
michael@0 1273 err);
michael@0 1274 }
michael@0 1275 }

mercurial