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 * setlocale() intercept 26 * maintains a bitmask of non-default categories 27 * and a permanent locale namespace for pointer comparison 28 * and persistent private data for locale related functions 29 */ 30 31 #include <ast_standards.h> 32 33 #include "lclib.h" 34 35 #include <ast_wchar.h> 36 #include <ctype.h> 37 #include <mc.h> 38 #include <namval.h> 39 40 #if ( _lib_wcwidth || _lib_wctomb ) && _hdr_wctype 41 #include <wctype.h> 42 #endif 43 44 #if _lib_wcwidth 45 #undef wcwidth 46 #else 47 #define wcwidth 0 48 #endif 49 50 #if _lib_wctomb 51 #undef wctomb 52 #else 53 #define wctomb 0 54 #endif 55 56 #ifdef mblen 57 #undef mblen 58 extern int mblen(const char*, size_t); 59 #endif 60 61 #undef mbtowc 62 #undef setlocale 63 #undef strcmp 64 #undef strcoll 65 #undef strxfrm 66 #undef valid 67 68 #ifndef AST_LC_CANONICAL 69 #define AST_LC_CANONICAL LC_abbreviated 70 #endif 71 72 #if _UWIN 73 74 #include <ast_windows.h> 75 76 #undef _lib_setlocale 77 #define _lib_setlocale 1 78 79 #define setlocale(c,l) native_setlocale(c,l) 80 81 extern char* uwin_setlocale(int, const char*); 82 83 /* 84 * convert locale to native locale name in buf 85 */ 86 87 static char* 88 native_locale(const char* locale, char* buf, size_t siz) 89 { 90 Lc_t* lc; 91 const Lc_attribute_list_t* ap; 92 int i; 93 unsigned long lcid; 94 unsigned long lang; 95 unsigned long ctry; 96 char lbuf[128]; 97 char cbuf[128]; 98 99 if (locale && *locale) 100 { 101 if (!(lc = lcmake(locale))) 102 return 0; 103 lang = lc->language->index; 104 ctry = 0; 105 for (ap = lc->attributes; ap; ap = ap->next) 106 if (ctry = ap->attribute->index) 107 break; 108 if (!ctry) 109 { 110 for (i = 0; i < elementsof(lc->territory->languages); i++) 111 if (lc->territory->languages[i] == lc->language) 112 { 113 ctry = lc->territory->indices[i]; 114 break; 115 } 116 if (!ctry) 117 ctry = SUBLANG_DEFAULT; 118 } 119 lcid = MAKELCID(MAKELANGID(lang, ctry), SORT_DEFAULT); 120 } 121 else 122 lcid = GetUserDefaultLCID(); 123 if (GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lbuf, sizeof(lbuf)) <= 0 || 124 GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, cbuf, sizeof(cbuf)) <= 0) 125 return 0; 126 if (lc->charset->ms) 127 sfsprintf(buf, siz, "%s_%s.%s", lbuf, cbuf, lc->charset->ms); 128 else 129 sfsprintf(buf, siz, "%s_%s", lbuf, cbuf); 130 return buf; 131 } 132 133 /* 134 * locale!=0 here 135 */ 136 137 static char* 138 native_setlocale(int category, const char* locale) 139 { 140 char* usr; 141 char* sys; 142 char buf[256]; 143 144 /* 145 * win32 doesn't have LC_MESSAGES 146 */ 147 148 if (category == LC_MESSAGES) 149 return (char*)locale; 150 if (!(usr = native_locale(locale, buf, sizeof(buf)))) 151 return 0; 152 sys = uwin_setlocale(category, usr); 153 if (ast.locale.set & AST_LC_debug) 154 sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", categories[lcindex(category, 0)].name, usr, sys); 155 return sys; 156 } 157 158 #else 159 160 #define native_locale(a,b,c) ((char*)0) 161 162 #endif 163 164 /* 165 * LC_COLLATE and LC_CTYPE native support 166 */ 167 168 #if !_lib_mbtowc || MB_LEN_MAX <= 1 169 #define mblen 0 170 #define mbtowc 0 171 #endif 172 173 #if !_lib_strcoll 174 #define strcoll 0 175 #endif 176 177 #if !_lib_strxfrm 178 #define strxfrm 0 179 #endif 180 181 /* 182 * LC_COLLATE and LC_CTYPE debug support 183 * 184 * mutibyte debug encoding 185 * 186 * DL0 [ '0' .. '4' ] c1 ... c4 DR0 187 * DL1 [ '0' .. '4' ] c1 ... c4 DR1 188 * 189 * with these ligatures 190 * 191 * ch CH sst SST 192 * 193 * and private collation order 194 * 195 * wide character display width is the low order 3 bits 196 * wctomb() uses DL1...DR1 197 */ 198 199 #define DEBUG_MB_CUR_MAX 7 200 201 #if DEBUG_MB_CUR_MAX < MB_LEN_MAX 202 #undef DEBUG_MB_CUR_MAX 203 #define DEBUG_MB_CUR_MAX MB_LEN_MAX 204 #endif 205 206 #define DL0 '<' 207 #define DL1 0xab /* 8-bit mini << on xterm */ 208 #define DR0 '>' 209 #define DR1 0xbb /* 8-bit mini >> on xterm */ 210 211 #define DB ((int)sizeof(wchar_t)*8-1) 212 #define DC 7 /* wchar_t embedded char bits */ 213 #define DX (DB/DC) /* wchar_t max embedded chars */ 214 #define DZ (DB-DX*DC+1) /* wchar_t embedded size bits */ 215 #define DD 3 /* # mb delimiter chars <n...> */ 216 217 static unsigned char debug_order[] = 218 { 219 0, 1, 2, 3, 4, 5, 6, 7, 220 8, 9, 10, 11, 12, 13, 14, 15, 221 16, 17, 18, 19, 20, 21, 22, 23, 222 24, 25, 26, 27, 28, 29, 30, 31, 223 99, 100, 101, 102, 98, 103, 104, 105, 224 106, 107, 108, 43, 109, 44, 42, 110, 225 32, 33, 34, 35, 36, 37, 38, 39, 226 40, 41, 111, 112, 113, 114, 115, 116, 227 117, 71, 72, 73, 74, 75, 76, 77, 228 78, 79, 80, 81, 82, 83, 84, 85, 229 86, 87, 88, 89, 90, 91, 92, 93, 230 94, 95, 96, 118, 119, 120, 121, 97, 231 122, 45, 46, 47, 48, 49, 50, 51, 232 52, 53, 54, 55, 56, 57, 58, 59, 233 60, 61, 62, 63, 64, 65, 66, 67, 234 68, 69, 70, 123, 124, 125, 126, 127, 235 128, 129, 130, 131, 132, 133, 134, 135, 236 136, 137, 138, 139, 140, 141, 142, 143, 237 144, 145, 146, 147, 148, 149, 150, 151, 238 152, 153, 154, 155, 156, 157, 158, 159, 239 160, 161, 162, 163, 164, 165, 166, 167, 240 168, 169, 170, 171, 172, 173, 174, 175, 241 176, 177, 178, 179, 180, 181, 182, 183, 242 184, 185, 186, 187, 188, 189, 190, 191, 243 192, 193, 194, 195, 196, 197, 198, 199, 244 200, 201, 202, 203, 204, 205, 206, 207, 245 208, 209, 210, 211, 212, 213, 214, 215, 246 216, 217, 218, 219, 220, 221, 222, 223, 247 224, 225, 226, 227, 228, 229, 230, 231, 248 232, 233, 234, 235, 236, 237, 238, 239, 249 240, 241, 242, 243, 244, 245, 246, 247, 250 248, 249, 250, 251, 252, 253, 254, 255, 251 }; 252 253 static int 254 debug_mbtowc(register wchar_t* p, register const char* s, size_t n) 255 { 256 register const char* q; 257 register const char* r; 258 register int w; 259 register int dr; 260 wchar_t c; 261 262 if (n < 1) 263 return -1; 264 if (!s || !*s) 265 return 0; 266 switch (((unsigned char*)s)[0]) 267 { 268 case DL0: 269 dr = DR0; 270 break; 271 case DL1: 272 dr = DR1; 273 break; 274 default: 275 if (p) 276 *p = ((unsigned char*)s)[0] & ((1<<DC)-1); 277 return 1; 278 } 279 if (n < 2) 280 return -1; 281 if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0]) 282 { 283 if (p) 284 *p = w; 285 return 2; 286 } 287 if (w < '0' || w > ('0' + DX)) 288 return -1; 289 if ((w -= '0' - DD) > n) 290 return -1; 291 r = s + w - 1; 292 q = s += 2; 293 while (q < r && *q) 294 q++; 295 if (q != r || *((unsigned char*)q) != dr) 296 return -1; 297 if (p) 298 { 299 c = 0; 300 while (--q >= s) 301 { 302 c <<= DC; 303 c |= *((unsigned char*)q); 304 } 305 c <<= DZ; 306 c |= w - DD; 307 *p = c; 308 } 309 return w; 310 } 311 312 static int 313 debug_wctomb(char* s, wchar_t c) 314 { 315 int w; 316 int i; 317 int k; 318 319 w = 0; 320 if (c >= 0 && c <= UCHAR_MAX) 321 { 322 w++; 323 if (s) 324 *s = c; 325 } 326 else if ((i = c & ((1<<DZ)-1)) > DX) 327 return -1; 328 else 329 { 330 w++; 331 if (s) 332 *s++ = DL1; 333 c >>= DZ; 334 w++; 335 if (s) 336 *s++ = i + '0'; 337 while (i--) 338 { 339 w++; 340 if (s) 341 *s++ = (k = c & ((1<<DC)-1)) ? k : '?'; 342 c >>= DC; 343 } 344 w++; 345 if (s) 346 *s++ = DR1; 347 } 348 return w; 349 } 350 351 static int 352 debug_mblen(const char* s, size_t n) 353 { 354 return debug_mbtowc(NiL, s, n); 355 } 356 357 static int 358 debug_wcwidth(wchar_t c) 359 { 360 if (c >= 0 && c <= UCHAR_MAX) 361 return 1; 362 if ((c &= ((1<<DZ)-1)) > DX) 363 return -1; 364 return c + DD; 365 } 366 367 static size_t 368 debug_strxfrm(register char* t, register const char* s, size_t n) 369 { 370 register const char* q; 371 register const char* r; 372 register char* e; 373 register size_t z; 374 register int w; 375 376 z = 0; 377 if (e = t) 378 e += n; 379 while (s[0]) 380 { 381 if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC)) 382 { 383 w -= '0'; 384 q = s + 2; 385 r = q + w; 386 while (q < r && *q) 387 q++; 388 if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1) 389 { 390 if (t) 391 { 392 for (q = s + 2; q < r; q++) 393 if (t < e) 394 *t++ = debug_order[*q]; 395 while (w++ < DX) 396 if (t < e) 397 *t++ = 1; 398 } 399 s = r + 1; 400 z += DX; 401 continue; 402 } 403 } 404 if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H')) 405 { 406 if (t) 407 { 408 if (t < e) 409 *t++ = debug_order[s[0]]; 410 if (t < e) 411 *t++ = debug_order[s[1]]; 412 if (t < e) 413 *t++ = 1; 414 if (t < e) 415 *t++ = 1; 416 } 417 s += 2; 418 z += DX; 419 continue; 420 } 421 if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T')) 422 { 423 if (t) 424 { 425 if (t < e) 426 *t++ = debug_order[s[0]]; 427 if (t < e) 428 *t++ = debug_order[s[1]]; 429 if (t < e) 430 *t++ = debug_order[s[2]]; 431 if (t < e) 432 *t++ = 1; 433 } 434 s += 3; 435 z += DX; 436 continue; 437 } 438 if (t) 439 { 440 if (t < e) 441 *t++ = debug_order[s[0]]; 442 if (t < e) 443 *t++ = 1; 444 if (t < e) 445 *t++ = 1; 446 if (t < e) 447 *t++ = 1; 448 } 449 s++; 450 z += DX; 451 } 452 if (t < e) 453 *t = 0; 454 return z; 455 } 456 457 static int 458 debug_strcoll(const char* a, const char* b) 459 { 460 char ab[1024]; 461 char bb[1024]; 462 463 debug_strxfrm(ab, a, sizeof(ab) - 1); 464 ab[sizeof(ab)-1] = 0; 465 debug_strxfrm(bb, b, sizeof(bb) - 1); 466 bb[sizeof(bb)-1] = 0; 467 return strcmp(ab, bb); 468 } 469 470 /* 471 * default locale 472 */ 473 474 static int 475 default_wcwidth(wchar_t w) 476 { 477 return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1; 478 } 479 480 /* 481 * called when LC_COLLATE initialized or changes 482 */ 483 484 static int 485 set_collate(Lc_category_t* cp) 486 { 487 if (locales[cp->internal]->flags & LC_debug) 488 { 489 ast.collate = debug_strcoll; 490 ast.mb_xfrm = debug_strxfrm; 491 } 492 else if (locales[cp->internal]->flags & LC_default) 493 { 494 ast.collate = strcmp; 495 ast.mb_xfrm = 0; 496 } 497 else 498 { 499 ast.collate = strcoll; 500 ast.mb_xfrm = strxfrm; 501 } 502 return 0; 503 } 504 505 /* 506 * called when LC_CTYPE initialized or changes 507 */ 508 509 static int 510 set_ctype(Lc_category_t* cp) 511 { 512 if (locales[cp->internal]->flags & LC_debug) 513 { 514 ast.mb_cur_max = DEBUG_MB_CUR_MAX; 515 ast.mb_len = debug_mblen; 516 ast.mb_towc = debug_mbtowc; 517 ast.mb_width = debug_wcwidth; 518 ast.mb_conv = debug_wctomb; 519 } 520 else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc)) 521 { 522 ast.mb_cur_max = 1; 523 ast.mb_len = 0; 524 ast.mb_towc = 0; 525 ast.mb_width = default_wcwidth; 526 ast.mb_conv = 0; 527 } 528 else 529 { 530 if (!(ast.mb_width = wcwidth)) 531 ast.mb_width = default_wcwidth; 532 ast.mb_conv = wctomb; 533 } 534 return 0; 535 } 536 537 /* 538 * called when LC_NUMERIC initialized or changes 539 */ 540 541 static int 542 set_numeric(Lc_category_t* cp) 543 { 544 register int category = cp->internal; 545 struct lconv* lp; 546 Lc_numeric_t* dp; 547 548 static Lc_numeric_t default_numeric = { '.', -1 }; 549 550 if (!LCINFO(category)->data) 551 { 552 if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0))) 553 { 554 dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.'; 555 dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1; 556 } 557 else 558 dp = &default_numeric; 559 LCINFO(category)->data = (void*)dp; 560 if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) 561 sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X'); 562 } 563 return 0; 564 } 565 566 /* 567 * this table is indexed by AST_LC_[A-Z]* 568 */ 569 570 Lc_category_t categories[] = 571 { 572 { "LC_ALL", LC_ALL, AST_LC_ALL, 0 }, 573 { "LC_COLLATE", LC_COLLATE, AST_LC_COLLATE, set_collate }, 574 { "LC_CTYPE", LC_CTYPE, AST_LC_CTYPE, set_ctype }, 575 { "LC_MESSAGES", LC_MESSAGES, AST_LC_MESSAGES, 0 }, 576 { "LC_MONETARY", LC_MONETARY, AST_LC_MONETARY, 0 }, 577 { "LC_NUMERIC", LC_NUMERIC, AST_LC_NUMERIC, set_numeric }, 578 { "LC_TIME", LC_TIME, AST_LC_TIME, 0 }, 579 { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0 }, 580 { "LC_ADDRESS", LC_ADDRESS, AST_LC_ADDRESS, 0 }, 581 { "LC_NAME", LC_NAME, AST_LC_NAME, 0 }, 582 { "LC_TELEPHONE", LC_TELEPHONE, AST_LC_TELEPHONE, 0 }, 583 { "LC_XLITERATE", LC_XLITERATE, AST_LC_XLITERATE, 0 }, 584 { "LC_MEASUREMENT", LC_MEASUREMENT, AST_LC_MEASUREMENT, 0 }, 585 { "LC_PAPER", LC_PAPER, AST_LC_PAPER, 0 }, 586 }; 587 588 static const Namval_t options[] = 589 { 590 "debug", AST_LC_debug, 591 "find", AST_LC_find, 592 "setlocale", AST_LC_setlocale, 593 "translate", AST_LC_translate, 594 0, 0 595 }; 596 597 /* 598 * called by stropt() to set options 599 */ 600 601 static int 602 setopt(void* a, const void* p, int n, const char* v) 603 { 604 if (p) 605 { 606 if (n) 607 ast.locale.set |= ((Namval_t*)p)->value; 608 else 609 ast.locale.set &= ~((Namval_t*)p)->value; 610 } 611 return 0; 612 } 613 614 #if !_lib_setlocale 615 616 #define setlocale(c,l) default_setlocale(c,l) 617 618 static char* 619 default_setlocale(int category, const char* locale) 620 { 621 Lc_t* lc; 622 623 if (locale) 624 { 625 if (!(lc = lcmake(locale)) || !(lc->flags & LC_default)) 626 return 0; 627 locales[0]->flags &= ~lc->flags; 628 locales[1]->flags &= ~lc->flags; 629 return lc->name; 630 } 631 return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name; 632 } 633 634 #endif 635 636 /* 637 * set a single AST_LC_* locale category 638 * the caller must validate category 639 * lc==0 restores the previous state 640 */ 641 642 static char* 643 single(int category, Lc_t* lc) 644 { 645 const char* sys; 646 int i; 647 648 if (!lc && !(lc = categories[category].prev)) 649 lc = lcmake(NiL); 650 if (locales[category] != lc) 651 { 652 if (categories[category].external == -categories[category].internal) 653 { 654 sys = 0; 655 for (i = 1; i < AST_LC_COUNT; i++) 656 if (locales[i] == lc) 657 { 658 sys = (char*)lc->name; 659 break; 660 } 661 } 662 else if (lc->flags & (LC_debug|LC_local)) 663 sys = setlocale(categories[category].external, lcmake(NiL)->name); 664 else if (!(sys = setlocale(categories[category].external, lc->name)) && 665 (streq(lc->name, lc->code) || !(sys = setlocale(categories[category].external, lc->code))) && 666 !streq(lc->code, lc->language->code)) 667 sys = setlocale(categories[category].external, lc->language->code); 668 if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) 669 sfprintf(sfstderr, "locale set %17s %-24s %-24s\n", categories[category].name, lc->name, sys); 670 if (!sys) 671 { 672 /* 673 * check for local override 674 * currently this means an LC_MESSAGES dir exists 675 */ 676 677 if (!(lc->flags & LC_checked)) 678 { 679 char path[PATH_MAX]; 680 681 if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0)) 682 lc->flags |= LC_local; 683 lc->flags |= LC_checked; 684 } 685 if (!(lc->flags & LC_local)) 686 return 0; 687 if (categories[category].external != -categories[category].internal) 688 setlocale(categories[category].external, lcmake(NiL)->name); 689 } 690 locales[category] = lc; 691 if (categories[category].setf && (*categories[category].setf)(&categories[category])) 692 { 693 locales[category] = categories[category].prev; 694 return 0; 695 } 696 if (lc->flags & LC_default) 697 ast.locale.set &= ~(1<<category); 698 else 699 ast.locale.set |= (1<<category); 700 } 701 return (char*)lc->name; 702 } 703 704 /* 705 * set composite AST_LC_ALL locale categories 706 * return <0:composite-error 0:not-composite >0:composite-ok 707 */ 708 709 static int 710 composite(register const char* s, int initialize) 711 { 712 register const char* t; 713 register int i; 714 register int j; 715 register int k; 716 int n; 717 const char* w; 718 Lc_t* p; 719 int cat[AST_LC_COUNT]; 720 int stk[AST_LC_COUNT]; 721 char buf[PATH_MAX / 2]; 722 723 k = n = 0; 724 while (s[0] == 'L' && s[1] == 'C' && s[2] == '_') 725 { 726 n++; 727 j = 0; 728 w = s; 729 for (i = 1; i < AST_LC_COUNT; i++) 730 { 731 s = w; 732 t = categories[i].name; 733 while (*t && *s++ == *t++); 734 if (!*t && *s++ == '=') 735 { 736 cat[j++] = i; 737 if (s[0] != 'L' || s[1] != 'C' || s[2] != '_') 738 break; 739 w = s; 740 i = -1; 741 } 742 } 743 for (s = w; *s && *s != '='; s++); 744 if (!*s) 745 { 746 for (i = 0; i < k; i++) 747 single(stk[i], NiL); 748 return -1; 749 } 750 w = ++s; 751 for (;;) 752 { 753 if (!*s) 754 { 755 p = lcmake(w); 756 break; 757 } 758 else if (*s++ == ';') 759 { 760 if ((n = s - w - 1) >= sizeof(buf)) 761 n = sizeof(buf) - 1; 762 memcpy(buf, w, n); 763 buf[n] = 0; 764 p = lcmake(buf); 765 break; 766 } 767 } 768 for (i = 0; i < j; i++) 769 if (!initialize) 770 { 771 if (!single(cat[i], p)) 772 { 773 for (i = 0; i < k; i++) 774 single(stk[i], NiL); 775 return -1; 776 } 777 stk[k++] = cat[i]; 778 } 779 else if (!categories[cat[i]].prev) 780 categories[cat[i]].prev = p; 781 } 782 while (s[0] == '/' && s[1] && n < AST_LC_COUNT) 783 { 784 n++; 785 for (w = ++s; *s && *s != '/'; s++); 786 if (!*s) 787 p = lcmake(w); 788 else 789 { 790 if ((j = s - w - 1) >= sizeof(buf)) 791 j = sizeof(buf) - 1; 792 memcpy(buf, w, j); 793 buf[j] = 0; 794 p = lcmake(buf); 795 } 796 if (!initialize) 797 { 798 if (!single(n, p)) 799 { 800 for (i = 1; i < n; i++) 801 single(i, NiL); 802 return -1; 803 } 804 } 805 else if (!categories[n].prev) 806 categories[n].prev = p; 807 } 808 return n; 809 } 810 811 /* 812 * setlocale() intercept 813 */ 814 815 char* 816 _ast_setlocale(int category, const char* locale) 817 { 818 register char* s; 819 register int i; 820 register int j; 821 int k; 822 char* a; 823 Lc_t* p; 824 int cat[AST_LC_COUNT]; 825 826 static Sfio_t* sp; 827 static int initialized; 828 static char local[] = "local"; 829 830 if ((category = lcindex(category, 0)) < 0) 831 return 0; 832 if (!locale) 833 { 834 /* 835 * return the current state 836 */ 837 838 compose: 839 if (category != AST_LC_ALL) 840 return (char*)locales[category]->name; 841 if (!sp && !(sp = sfstropen())) 842 return 0; 843 for (i = 1; i < AST_LC_COUNT; i++) 844 cat[i] = -1; 845 for (i = 1, k = 0; i < AST_LC_COUNT; i++) 846 if (cat[i] < 0) 847 { 848 k++; 849 cat[i] = i; 850 for (j = i + 1; j < AST_LC_COUNT; j++) 851 if (locales[j] == locales[i]) 852 cat[j] = i; 853 } 854 if (k == 1) 855 return (char*)locales[1]->name; 856 for (i = 1; i < AST_LC_COUNT; i++) 857 if (cat[i] >= 0 && !(locales[i]->flags & LC_default)) 858 { 859 if (sfstrtell(sp)) 860 sfprintf(sp, ";"); 861 for (j = i, k = cat[i]; j < AST_LC_COUNT; j++) 862 if (cat[j] == k) 863 { 864 cat[j] = -1; 865 sfprintf(sp, "%s=", categories[j].name); 866 } 867 sfprintf(sp, "%s", locales[i]->name); 868 } 869 if (!sfstrtell(sp)) 870 return (char*)locales[0]->name; 871 return sfstruse(sp); 872 } 873 if (!ast.locale.serial++) 874 stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL); 875 if (!*locale) 876 { 877 if (!initialized) 878 { 879 char* u; 880 char tmp[256]; 881 882 /* 883 * initialize from the environment 884 * precedence determined by X/Open 885 */ 886 887 u = 0; 888 if (!(a = getenv("LC_ALL")) || !*a) 889 { 890 for (i = 1; i < AST_LC_COUNT; i++) 891 if ((s = getenv(categories[i].name)) && *s) 892 { 893 if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 894 s = u; 895 categories[i].prev = lcmake(s); 896 } 897 a = getenv("LANG"); 898 } 899 if (a) 900 { 901 if (streq(a, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 902 a = u; 903 if (composite(a, 1)) 904 a = 0; 905 } 906 p = 0; 907 for (i = 1; i < AST_LC_COUNT; i++) 908 { 909 if (!categories[i].prev) 910 { 911 if (!p && !(p = lcmake(a))) 912 break; 913 categories[i].prev = p; 914 } 915 if (!single(i, categories[i].prev)) 916 { 917 while (i--) 918 single(i, NiL); 919 return 0; 920 } 921 } 922 if (ast.locale.set & AST_LC_debug) 923 for (i = 1; i < AST_LC_COUNT; i++) 924 sfprintf(sfstderr, "locale env %17s %s\n", categories[i].name, locales[i]->name); 925 initialized = 1; 926 } 927 goto compose; 928 } 929 else if (category != AST_LC_ALL) 930 return single(category, lcmake(locale)); 931 else if (!(i = composite(locale, 0))) 932 { 933 if (!(p = lcmake(locale))) 934 return 0; 935 for (i = 1; i < AST_LC_COUNT; i++) 936 if (!single(i, p)) 937 { 938 while (i--) 939 single(i, NiL); 940 return 0; 941 } 942 } 943 else if (i < 0) 944 return 0; 945 goto compose; 946 } 947