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