1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2011 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 24 /* 25 * locale state implementation 26 */ 27 28 #include "lclib.h" 29 #include "lclang.h" 30 #include "FEATURE/locale" 31 32 #include <ctype.h> 33 34 typedef struct Local_s 35 { 36 const char* name; 37 int size; 38 } Local_t; 39 40 #undef setlocale /* this file deals with the system locale */ 41 42 static Lc_numeric_t default_numeric = { '.', -1 }; 43 44 static Lc_t default_lc = 45 { 46 "C", 47 "POSIX", 48 &lc_languages[0], 49 &lc_territories[0], 50 &lc_charsets[0], 51 0, 52 LC_default|LC_checked|LC_local, 53 0, 54 { 55 { &default_lc, 0, 0 }, 56 { &default_lc, 0, 0 }, 57 { &default_lc, 0, 0 }, 58 { &default_lc, 0, 0 }, 59 { &default_lc, 0, 0 }, 60 { &default_lc, 0, (void*)&default_numeric }, 61 { &default_lc, 0, 0 }, 62 { &default_lc, 0, 0 }, 63 { &default_lc, 0, 0 }, 64 { &default_lc, 0, 0 }, 65 { &default_lc, 0, 0 }, 66 { &default_lc, 0, 0 }, 67 { &default_lc, 0, 0 }, 68 { &default_lc, 0, 0 } 69 } 70 }; 71 72 static Lc_numeric_t debug_numeric = { ',', '.' }; 73 74 static Lc_t debug_lc = 75 { 76 "debug", 77 "debug", 78 &lc_languages[1], 79 &lc_territories[1], 80 &lc_charsets[0], 81 0, 82 LC_debug|LC_checked|LC_local, 83 0, 84 { 85 { &debug_lc, 0, 0 }, 86 { &debug_lc, 0, 0 }, 87 { &debug_lc, 0, 0 }, 88 { &debug_lc, 0, 0 }, 89 { &debug_lc, 0, 0 }, 90 { &debug_lc, 0, (void*)&debug_numeric }, 91 { &debug_lc, 0, 0 }, 92 { &debug_lc, 0, 0 }, 93 { &debug_lc, 0, 0 }, 94 { &debug_lc, 0, 0 }, 95 { &debug_lc, 0, 0 }, 96 { &debug_lc, 0, 0 }, 97 { &debug_lc, 0, 0 }, 98 { &debug_lc, 0, 0 } 99 }, 100 &default_lc 101 }; 102 103 static Lc_t* lcs = &debug_lc; 104 105 Lc_t* locales[] = 106 { 107 &default_lc, 108 &default_lc, 109 &default_lc, 110 &default_lc, 111 &default_lc, 112 &default_lc, 113 &default_lc, 114 &default_lc, 115 &default_lc, 116 &default_lc, 117 &default_lc, 118 &default_lc, 119 &default_lc, 120 &default_lc 121 }; 122 123 /* 124 * return the internal category index for category 125 */ 126 127 int 128 lcindex(int category, int min) 129 { 130 switch (category) 131 { 132 case LC_ALL: return min ? -1 : AST_LC_ALL; 133 case LC_ADDRESS: return AST_LC_ADDRESS; 134 case LC_COLLATE: return AST_LC_COLLATE; 135 case LC_CTYPE: return AST_LC_CTYPE; 136 case LC_IDENTIFICATION: return AST_LC_IDENTIFICATION; 137 case LC_LANG: return AST_LC_LANG; 138 case LC_MEASUREMENT: return AST_LC_MEASUREMENT; 139 case LC_MESSAGES: return AST_LC_MESSAGES; 140 case LC_MONETARY: return AST_LC_MONETARY; 141 case LC_NAME: return AST_LC_NAME; 142 case LC_NUMERIC: return AST_LC_NUMERIC; 143 case LC_PAPER: return AST_LC_PAPER; 144 case LC_TELEPHONE: return AST_LC_TELEPHONE; 145 case LC_TIME: return AST_LC_TIME; 146 case LC_XLITERATE: return AST_LC_XLITERATE; 147 } 148 return -1; 149 } 150 151 /* 152 * return the first category table entry 153 */ 154 155 Lc_category_t* 156 lccategories(void) 157 { 158 return (Lc_category_t*)&lc_categories[0]; 159 } 160 161 /* 162 * return the current info for category 163 */ 164 165 Lc_info_t* 166 lcinfo(register int category) 167 { 168 if ((category = lcindex(category, 0)) < 0) 169 return 0; 170 return LCINFO(category); 171 } 172 173 /* 174 * return 1 if s matches the alternation pattern p 175 * if minimum!=0 then at least that many chars must match 176 * if standard!=0 and s[0] is a digit leading non-digits are ignored in p 177 */ 178 179 static int 180 match(const char* s, register const char* p, int minimum, int standard) 181 { 182 register const char* t; 183 const char* x; 184 int w; 185 int z; 186 187 z = 0; 188 do 189 { 190 t = s; 191 if (standard) 192 { 193 if (isdigit(*t)) 194 while (*p && !isdigit(*p)) 195 p++; 196 else if (isdigit(*p)) 197 while (*t && !isdigit(*t)) 198 t++; 199 } 200 if (*p) 201 { 202 w = 0; 203 x = p; 204 while (*p && *p != '|') 205 { 206 if (!*t || *t == ',') 207 break; 208 else if (*t == *p) 209 /*ok*/; 210 else if (*t == '-') 211 { 212 if (standard && isdigit(*p)) 213 { 214 t++; 215 continue; 216 } 217 while (*p && *p != '-') 218 p++; 219 if (!*p) 220 break; 221 } 222 else if (*p == '-') 223 { 224 if (standard && isdigit(*t)) 225 { 226 p++; 227 continue; 228 } 229 w = 1; 230 while (*t && *t != '-') 231 t++; 232 if (!*t) 233 break; 234 } 235 else 236 break; 237 t++; 238 p++; 239 } 240 if ((!*t || *t == ',') && (!*p || *p == '|' || w)) 241 return p - x; 242 if (minimum && z < (p - x) && (p - x) >= minimum) 243 z = p - x; 244 } 245 while (*p && *p != '|') 246 p++; 247 } while (*p++); 248 return z; 249 } 250 251 /* 252 * return 1 if s matches the charset names in cp 253 */ 254 255 static int 256 match_charset(register const char* s, register const Lc_charset_t* cp) 257 { 258 return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1); 259 } 260 261 /* 262 * low level for lccanon 263 */ 264 265 static size_t 266 canonical(const Lc_language_t* lp, const Lc_territory_t* tp, const Lc_charset_t* cp, const Lc_attribute_list_t* ap, unsigned long flags, char* buf, size_t siz) 267 { 268 register int c; 269 register int u; 270 register char* s; 271 register char* e; 272 register const char* t; 273 char* p; 274 char* r; 275 276 if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose))) 277 flags |= LC_abbreviated; 278 s = buf; 279 e = &buf[siz - 3]; 280 if (lp) 281 { 282 if (lp->flags & (LC_debug|LC_default)) 283 { 284 for (t = lp->code; s < e && (*s = *t++); s++); 285 *s++ = 0; 286 return s - buf; 287 } 288 if (flags & LC_verbose) 289 { 290 u = 1; 291 t = lp->name; 292 while (s < e && (c = *t++)) 293 { 294 if (u) 295 { 296 u = 0; 297 c = toupper(c); 298 } 299 else if (!isalnum(c)) 300 u = 1; 301 *s++ = c; 302 } 303 } 304 else 305 for (t = lp->code; s < e && (*s = *t++); s++); 306 } 307 if (s < e) 308 { 309 if (tp && tp != &lc_territories[0]) 310 { 311 r = 0; 312 if (lp) 313 { 314 if ((flags & (LC_abbreviated|LC_default)) && streq(lp->code, tp->code)) 315 r = s; 316 *s++ = '_'; 317 } 318 if (flags & LC_verbose) 319 { 320 u = 1; 321 t = tp->name; 322 while (s < e && (c = *t++) && c != '|') 323 { 324 if (u) 325 { 326 u = 0; 327 c = toupper(c); 328 } 329 else if (!isalnum(c)) 330 u = 1; 331 *s++ = c; 332 } 333 } 334 else 335 for (t = tp->code; s < e && (*s = toupper(*t++)); s++); 336 if (r) 337 { 338 *s = 0; 339 if ((p = setlocale(LC_MESSAGES, 0)) && (p = strdup(p))) 340 { 341 if (!setlocale(LC_MESSAGES, buf)) 342 { 343 *r = 0; 344 if (!setlocale(LC_MESSAGES, buf)) 345 *r = '_'; 346 } 347 setlocale(LC_MESSAGES, p); 348 free(p); 349 } 350 } 351 } 352 if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e) 353 { 354 *s++ = '.'; 355 t = cp->code; 356 if (streq(cp->code, "utf8") && (t = _locale_utf8_str)) 357 for (; s < e && (c = *t++); s++) 358 *s = c; 359 else 360 for (t = cp->code; s < e && (c = *t++); s++) 361 { 362 if (islower(c)) 363 c = toupper(c); 364 *s = c; 365 } 366 } 367 for (c = '@'; ap && s < e; ap = ap->next) 368 if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default)) 369 { 370 *s++ = c; 371 c = ','; 372 for (t = ap->attribute->name; s < e && (*s = *t++); s++); 373 } 374 } 375 *s++ = 0; 376 return s - buf; 377 } 378 379 /* 380 * generate a canonical locale name in buf 381 */ 382 383 size_t 384 lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz) 385 { 386 if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default)))) 387 { 388 #if _WINIX 389 char lang[64]; 390 char code[64]; 391 char ctry[64]; 392 393 if (lc->index && 394 GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) && 395 GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry))) 396 { 397 if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code))) 398 code[0] = 0; 399 if (!lc->charset || !lc->charset->ms) 400 return sfsprintf(buf, siz, "%s_%s", lang, ctry); 401 else if (streq(lc->charset->ms, code)) 402 return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code); 403 else 404 return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms); 405 } 406 #endif 407 buf[0] = '-'; 408 buf[1] = 0; 409 return 0; 410 } 411 return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz); 412 } 413 414 /* 415 * make an Lc_t from a locale name 416 */ 417 418 Lc_t* 419 lcmake(const char* name) 420 { 421 register int c; 422 register char* s; 423 register char* e; 424 register const char* t; 425 const char* a; 426 char* w; 427 char* language_name; 428 char* territory_name; 429 char* charset_name; 430 char* attributes_name; 431 Lc_t* lc; 432 const Lc_map_t* mp; 433 const Lc_language_t* lp; 434 const Lc_territory_t* tp; 435 const Lc_territory_t* tpb; 436 const Lc_territory_t* primary; 437 const Lc_charset_t* cp; 438 const Lc_charset_t* ppa; 439 const Lc_attribute_t* ap; 440 Lc_attribute_list_t* ai; 441 Lc_attribute_list_t* al; 442 int i; 443 int n; 444 int z; 445 char buf[PATH_MAX / 2]; 446 char tmp[PATH_MAX / 2]; 447 Local_t local[2]; 448 449 if (!(t = name) || !*t) 450 return &default_lc; 451 for (lc = lcs; lc; lc = lc->next) 452 if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name)) 453 return lc; 454 for (mp = lc_maps; mp->code; mp++) 455 if (streq(t, mp->code)) 456 { 457 lp = mp->language; 458 tp = mp->territory; 459 cp = mp->charset; 460 if (!mp->attribute) 461 al = 0; 462 else if (al = newof(0, Lc_attribute_list_t, 1, 0)) 463 al->attribute = mp->attribute; 464 goto mapped; 465 } 466 language_name = buf; 467 territory_name = charset_name = attributes_name = 0; 468 s = buf; 469 e = &buf[sizeof(buf)-2]; 470 a = 0; 471 n = 0; 472 while (s < e && (c = *t++)) 473 { 474 if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n) 475 { 476 while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n)) 477 if (!c) 478 break; 479 if (isalnum(c) && !n) 480 *s++ = '-'; 481 else 482 { 483 n = 0; 484 if (!a) 485 { 486 a = t - 1; 487 while (c && c != '_' && c != '.' && c != '@') 488 c = *t++; 489 if (!c) 490 break; 491 } 492 } 493 } 494 if (c == '_' && !territory_name) 495 { 496 *s++ = 0; 497 territory_name = s; 498 } 499 else if (c == '.' && !charset_name) 500 { 501 *s++ = 0; 502 charset_name = s; 503 } 504 else if (c == '@' && !attributes_name) 505 { 506 *s++ = 0; 507 attributes_name = s; 508 } 509 else 510 { 511 if (isupper(c)) 512 c = tolower(c); 513 *s++ = c; 514 } 515 } 516 if ((t = a) && s < e) 517 { 518 if (attributes_name) 519 *s++ = ','; 520 else 521 { 522 *s++ = 0; 523 attributes_name = s; 524 } 525 while (s < e && (c = *t++)) 526 { 527 if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n) 528 { 529 while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n)) 530 if (!c) 531 break; 532 if (isalnum(c) && !n) 533 *s++ = '-'; 534 else 535 n = 0; 536 } 537 if (c == '_' || c == '.' || c == '@') 538 break; 539 if (isupper(c)) 540 c = tolower(c); 541 *s++ = c; 542 } 543 } 544 *s = 0; 545 #if AHA 546 if ((ast.locale.set & AST_LC_debug) && !(ast.locale.set & AST_LC_internal)) 547 sfprintf(sfstderr, "locale make %s language=%s territory=%s charset=%s attributes=%s\n", name, language_name, territory_name, charset_name, attributes_name); 548 #endif 549 tp = 0; 550 cp = ppa = 0; 551 al = 0; 552 553 /* 554 * language 555 */ 556 557 n = strlen(s = language_name); 558 if (n == 2) 559 for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++); 560 else if (n == 3) 561 { 562 for (lp = lc_languages; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++); 563 if (!lp->code) 564 { 565 c = s[2]; 566 s[2] = 0; 567 for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++); 568 s[2] = c; 569 if (lp->code) 570 n = 1; 571 } 572 } 573 else if (streq(s, "c") || streq(s, "posix")) 574 lp = &lc_languages[0]; 575 else 576 lp = 0; 577 if (!lp || !lp->code) 578 { 579 for (lp = lc_languages; lp->code && !match(s, lp->name, 0, 0); lp++); 580 if (!lp || !lp->code) 581 { 582 if (!territory_name) 583 { 584 if (n == 2) 585 for (tp = lc_territories; tp->code && !streq(s, tp->code); tp++); 586 else 587 { 588 z = 0; 589 tpb = 0; 590 for (tp = lc_territories; tp->name; tp++) 591 if ((i = match(s, tp->name, 3, 0)) > z) 592 { 593 tpb = tp; 594 if ((z = i) == n) 595 break; 596 } 597 if (tpb) 598 tp = tpb; 599 } 600 if (tp->code) 601 lp = tp->languages[0]; 602 } 603 if (!lp || !lp->code) 604 { 605 /* 606 * name not in the tables so let 607 * _ast_setlocale() and/or setlocale() 608 * handle the validity checks 609 */ 610 611 s = (char*)name; 612 z = strlen(s) + 1; 613 if (!(lp = newof(0, Lc_language_t, 1, z))) 614 return 0; 615 name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1); 616 memcpy((char*)lp->code, s, z - 1); 617 tp = &lc_territories[0]; 618 cp = &lc_charsets[0]; 619 if (charset_name) 620 for (ppa = lc_charsets; ppa->code; ppa++) 621 if (match_charset(charset_name, ppa)) 622 { 623 cp = ppa; 624 break; 625 } 626 ((Lc_language_t*)lp)->charset = cp; 627 al = 0; 628 goto override; 629 } 630 } 631 } 632 633 /* 634 * territory 635 */ 636 637 if (!tp || !tp->code) 638 { 639 if (!(s = territory_name)) 640 { 641 n = 0; 642 primary = 0; 643 for (tp = lc_territories; tp->code; tp++) 644 if (tp->languages[0] == lp) 645 { 646 if (tp->flags & LC_primary) 647 { 648 n = 1; 649 primary = tp; 650 break; 651 } 652 n++; 653 primary = tp; 654 } 655 if (n == 1) 656 tp = primary; 657 s = (char*)lp->code; 658 } 659 if (!tp || !tp->code) 660 { 661 n = strlen(s); 662 if (n == 2) 663 { 664 for (tp = lc_territories; tp->code; tp++) 665 if (streq(s, tp->code)) 666 { 667 if (lp != &lc_languages[0]) 668 { 669 for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++); 670 if (i >= elementsof(tp->languages)) 671 tp = 0; 672 } 673 break; 674 } 675 } 676 else 677 { 678 for (tp = lc_territories; tp->code; tp++) 679 if (match(s, tp->name, 3, 0)) 680 { 681 for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++); 682 if (i < elementsof(tp->languages)) 683 break; 684 } 685 } 686 if (tp && !tp->code) 687 tp = 0; 688 } 689 } 690 691 /* 692 * attributes -- done here to catch misplaced charset references 693 */ 694 695 if (s = attributes_name) 696 { 697 do 698 { 699 for (w = s; *s && *s != ','; s++); 700 c = *s; 701 *s = 0; 702 if (!(cp = lp->charset) || !match_charset(w, cp)) 703 for (cp = lc_charsets; cp->code; cp++) 704 if (match_charset(w, cp)) 705 { 706 ppa = cp; 707 break; 708 } 709 if (!cp->code) 710 { 711 for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++) 712 if (match(w, ap->name, 5, 0)) 713 { 714 if (ai = newof(0, Lc_attribute_list_t, 1, 0)) 715 { 716 ai->attribute = ap; 717 ai->next = al; 718 al = ai; 719 } 720 break; 721 } 722 if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1))) 723 { 724 ai = (Lc_attribute_list_t*)(ap + 1); 725 strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w); 726 ai->attribute = ap; 727 ai->next = al; 728 al = ai; 729 } 730 } 731 *s = c; 732 } while (*s++); 733 } 734 735 /* 736 * charset 737 */ 738 739 if (s = charset_name) 740 for (cp = lc_charsets; cp->code; cp++) 741 if (match_charset(s, cp)) 742 break; 743 #if AHA 744 if ((ast.locale.set & AST_LC_debug) && !(ast.locale.set & AST_LC_internal)) 745 sfprintf(sfstderr, "locale make %s charset_name=%s cp=%s ppa=%s lp=%s\n", name, charset_name, cp ? cp->code : 0, ppa, lp->charset); 746 #endif 747 if (!cp || !cp->code) 748 cp = ppa ? ppa : lp->charset; 749 mapped: 750 z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp)); 751 752 /* 753 * add to the list of possibly active locales 754 */ 755 756 override: 757 n = strlen(name) + 1; 758 local[0].name = default_lc.name; 759 local[0].size = strlen(local[0].name); 760 local[1].name = default_lc.code; 761 local[1].size = strlen(local[1].name); 762 i = -1; 763 for (c = 0; c < elementsof(local); ++c) 764 if (strneq(name, local[c].name, local[c].size)) 765 { 766 switch (name[local[c].size]) 767 { 768 case '.': 769 case '_': 770 case 0: 771 i = c; 772 z += local[!i].size + n; 773 break; 774 } 775 break; 776 } 777 if (!(lc = newof(0, Lc_t, 1, n + z))) 778 return 0; 779 strcpy((char*)(lc->name = (const char*)(lc + 1)), name); 780 lc->code = lc->name + n; 781 if (i >= 0) 782 { 783 lc->flags |= LC_local; 784 strcpy((char*)lc->code, local[!i].name); 785 strcpy((char*)lc->code + local[!i].size, name + local[i].size); 786 } 787 else 788 strcpy((char*)lc->code, s); 789 lc->language = lp ? lp : &lc_languages[0]; 790 lc->territory = tp ? tp : &lc_territories[0]; 791 lc->charset = cp ? cp : &lc_charsets[0]; 792 if (streq(lc->charset->code, "utf8")) 793 lc->flags |= LC_utf8; 794 lc->attributes = al; 795 for (i = 0; i < elementsof(lc->info); i++) 796 lc->info[i].lc = lc; 797 #if _WINIX 798 n = SUBLANG_DEFAULT; 799 if (tp) 800 for (i = 0; i < elementsof(tp->languages); i++) 801 if (lp == tp->languages[i]) 802 { 803 n = tp->indices[i]; 804 break; 805 } 806 lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT); 807 #endif 808 lc->next = lcs; 809 lcs = lc; 810 if ((ast.locale.set & AST_LC_debug) && !(ast.locale.set & AST_LC_internal)) 811 sfprintf(sfstderr, "locale make %17s %16s %16s %16s language=%s territory=%s charset=%s%s\n", "", lc->name, lc->code, "", lc->language->name, lc->territory->name, lc->charset->code, (lc->flags & LC_local) ? " local" : ""); 812 return lc; 813 } 814 815 /* 816 * return an Lc_t* for each locale in the tables 817 * one Lc_t is allocated on the first call with lc==0 818 * this is freed when 0 returned 819 * the return value is not part of the lcmake() cache 820 */ 821 822 typedef struct Lc_scan_s 823 { 824 Lc_t lc; 825 Lc_attribute_list_t list; 826 int territory; 827 int language; 828 int attribute; 829 char buf[256]; 830 } Lc_scan_t; 831 832 Lc_t* 833 lcscan(Lc_t* lc) 834 { 835 register Lc_scan_t* ls; 836 837 if (!(ls = (Lc_scan_t*)lc)) 838 { 839 if (!(ls = newof(0, Lc_scan_t, 1, 0))) 840 return 0; 841 ls->lc.code = ls->lc.name = ls->buf; 842 ls->territory = -1; 843 ls->language = elementsof(ls->lc.territory->languages); 844 ls->attribute = elementsof(ls->lc.language->attributes); 845 } 846 if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute])) 847 { 848 if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language])) 849 { 850 if (!lc_territories[++ls->territory].code) 851 { 852 free(ls); 853 return 0; 854 } 855 ls->lc.territory = &lc_territories[ls->territory]; 856 ls->lc.language = ls->lc.territory->languages[ls->language = 0]; 857 } 858 if (ls->lc.language) 859 { 860 ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &lc_charsets[0]; 861 ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0]; 862 } 863 else 864 { 865 ls->lc.charset = &lc_charsets[0]; 866 ls->list.attribute = 0; 867 } 868 } 869 ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0; 870 #if _WINIX 871 if (!ls->lc.language || !ls->lc.language->index) 872 ls->lc.index = 0; 873 else 874 { 875 if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) && 876 (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language]))) 877 ls->lc.index = SUBLANG_DEFAULT; 878 ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT); 879 } 880 #endif 881 canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf)); 882 return (Lc_t*)ls; 883 } 884