1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 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", lc_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 char* o; 374 register size_t z; 375 register int w; 376 377 o = t; 378 z = 0; 379 if (e = t) 380 e += n; 381 while (s[0]) 382 { 383 if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC)) 384 { 385 w -= '0'; 386 q = s + 2; 387 r = q + w; 388 while (q < r && *q) 389 q++; 390 if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1) 391 { 392 if (t) 393 { 394 for (q = s + 2; q < r; q++) 395 if (t < e) 396 *t++ = debug_order[*q]; 397 while (w++ < DX) 398 if (t < e) 399 *t++ = 1; 400 } 401 s = r + 1; 402 z += DX; 403 continue; 404 } 405 } 406 if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H')) 407 { 408 if (t) 409 { 410 if (t < e) 411 *t++ = debug_order[s[0]]; 412 if (t < e) 413 *t++ = debug_order[s[1]]; 414 if (t < e) 415 *t++ = 1; 416 if (t < e) 417 *t++ = 1; 418 } 419 s += 2; 420 z += DX; 421 continue; 422 } 423 if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T')) 424 { 425 if (t) 426 { 427 if (t < e) 428 *t++ = debug_order[s[0]]; 429 if (t < e) 430 *t++ = debug_order[s[1]]; 431 if (t < e) 432 *t++ = debug_order[s[2]]; 433 if (t < e) 434 *t++ = 1; 435 } 436 s += 3; 437 z += DX; 438 continue; 439 } 440 if (t) 441 { 442 if (t < e) 443 *t++ = debug_order[s[0]]; 444 if (t < e) 445 *t++ = 1; 446 if (t < e) 447 *t++ = 1; 448 if (t < e) 449 *t++ = 1; 450 } 451 s++; 452 z += DX; 453 } 454 if (!t) 455 return z; 456 if (t < e) 457 *t = 0; 458 return t - o; 459 } 460 461 static int 462 debug_strcoll(const char* a, const char* b) 463 { 464 char ab[1024]; 465 char bb[1024]; 466 467 debug_strxfrm(ab, a, sizeof(ab) - 1); 468 ab[sizeof(ab)-1] = 0; 469 debug_strxfrm(bb, b, sizeof(bb) - 1); 470 bb[sizeof(bb)-1] = 0; 471 return strcmp(ab, bb); 472 } 473 474 /* 475 * default locale 476 */ 477 478 static int 479 default_wcwidth(wchar_t w) 480 { 481 return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1; 482 } 483 484 /* 485 * called when LC_COLLATE initialized or changes 486 */ 487 488 static int 489 set_collate(Lc_category_t* cp) 490 { 491 if (locales[cp->internal]->flags & LC_debug) 492 { 493 ast.collate = debug_strcoll; 494 ast.mb_xfrm = debug_strxfrm; 495 } 496 else if (locales[cp->internal]->flags & LC_default) 497 { 498 ast.collate = strcmp; 499 ast.mb_xfrm = 0; 500 } 501 else 502 { 503 ast.collate = strcoll; 504 ast.mb_xfrm = strxfrm; 505 } 506 return 0; 507 } 508 509 /* 510 * workaround the interesting sjis that translates unshifted 7 bit ascii! 511 */ 512 513 #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc 514 515 #define mb_state_zero ((mbstate_t*)&ast.pad[sizeof(ast.pad)-2*sizeof(mbstate_t)]) 516 #define mb_state ((mbstate_t*)&ast.pad[sizeof(ast.pad)-sizeof(mbstate_t)]) 517 518 static int 519 sjis_mbtowc(register wchar_t* p, register const char* s, size_t n) 520 { 521 if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t))) 522 { 523 *p = *s; 524 return 1; 525 } 526 return mbrtowc(p, s, n, mb_state); 527 } 528 529 #endif 530 531 /* 532 * called when LC_CTYPE initialized or changes 533 */ 534 535 static int 536 set_ctype(Lc_category_t* cp) 537 { 538 if (locales[cp->internal]->flags & LC_debug) 539 { 540 ast.mb_cur_max = DEBUG_MB_CUR_MAX; 541 ast.mb_len = debug_mblen; 542 ast.mb_towc = debug_mbtowc; 543 ast.mb_width = debug_wcwidth; 544 ast.mb_conv = debug_wctomb; 545 } 546 else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc)) 547 { 548 ast.mb_cur_max = 1; 549 ast.mb_len = 0; 550 ast.mb_towc = 0; 551 ast.mb_width = default_wcwidth; 552 ast.mb_conv = 0; 553 } 554 else 555 { 556 if (!(ast.mb_width = wcwidth)) 557 ast.mb_width = default_wcwidth; 558 ast.mb_conv = wctomb; 559 #ifdef mb_state 560 { 561 /* 562 * check for sjis that translates unshifted 7 bit ascii! 563 */ 564 565 char* s; 566 char buf[2]; 567 568 mbinit(); 569 buf[1] = 0; 570 *(s = buf) = '\\'; 571 if (mbchar(s) != buf[0]) 572 { 573 memcpy(mb_state, mb_state_zero, sizeof(mbstate_t)); 574 ast.mb_towc = sjis_mbtowc; 575 } 576 } 577 #endif 578 } 579 return 0; 580 } 581 582 /* 583 * called when LC_NUMERIC initialized or changes 584 */ 585 586 static int 587 set_numeric(Lc_category_t* cp) 588 { 589 register int category = cp->internal; 590 struct lconv* lp; 591 Lc_numeric_t* dp; 592 593 static Lc_numeric_t default_numeric = { '.', -1 }; 594 595 if (!LCINFO(category)->data) 596 { 597 if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0))) 598 { 599 dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.'; 600 dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1; 601 } 602 else 603 dp = &default_numeric; 604 LCINFO(category)->data = (void*)dp; 605 if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) 606 sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X'); 607 } 608 return 0; 609 } 610 611 /* 612 * this table is indexed by AST_LC_[A-Z]* 613 */ 614 615 Lc_category_t lc_categories[] = 616 { 617 { "LC_ALL", LC_ALL, AST_LC_ALL, 0 }, 618 { "LC_COLLATE", LC_COLLATE, AST_LC_COLLATE, set_collate }, 619 { "LC_CTYPE", LC_CTYPE, AST_LC_CTYPE, set_ctype }, 620 { "LC_MESSAGES", LC_MESSAGES, AST_LC_MESSAGES, 0 }, 621 { "LC_MONETARY", LC_MONETARY, AST_LC_MONETARY, 0 }, 622 { "LC_NUMERIC", LC_NUMERIC, AST_LC_NUMERIC, set_numeric }, 623 { "LC_TIME", LC_TIME, AST_LC_TIME, 0 }, 624 { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0 }, 625 { "LC_ADDRESS", LC_ADDRESS, AST_LC_ADDRESS, 0 }, 626 { "LC_NAME", LC_NAME, AST_LC_NAME, 0 }, 627 { "LC_TELEPHONE", LC_TELEPHONE, AST_LC_TELEPHONE, 0 }, 628 { "LC_XLITERATE", LC_XLITERATE, AST_LC_XLITERATE, 0 }, 629 { "LC_MEASUREMENT", LC_MEASUREMENT, AST_LC_MEASUREMENT, 0 }, 630 { "LC_PAPER", LC_PAPER, AST_LC_PAPER, 0 }, 631 }; 632 633 static const Namval_t options[] = 634 { 635 "debug", AST_LC_debug, 636 "find", AST_LC_find, 637 "setlocale", AST_LC_setlocale, 638 "translate", AST_LC_translate, 639 0, 0 640 }; 641 642 /* 643 * called by stropt() to set options 644 */ 645 646 static int 647 setopt(void* a, const void* p, int n, const char* v) 648 { 649 if (p) 650 { 651 if (n) 652 ast.locale.set |= ((Namval_t*)p)->value; 653 else 654 ast.locale.set &= ~((Namval_t*)p)->value; 655 } 656 return 0; 657 } 658 659 #if !_lib_setlocale 660 661 #define setlocale(c,l) default_setlocale(c,l) 662 663 static char* 664 default_setlocale(int category, const char* locale) 665 { 666 Lc_t* lc; 667 668 if (locale) 669 { 670 if (!(lc = lcmake(locale)) || !(lc->flags & LC_default)) 671 return 0; 672 locales[0]->flags &= ~lc->flags; 673 locales[1]->flags &= ~lc->flags; 674 return lc->name; 675 } 676 return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name; 677 } 678 679 #endif 680 681 /* 682 * set a single AST_LC_* locale category 683 * the caller must validate category 684 * lc==0 restores the previous state 685 */ 686 687 static char* 688 single(int category, Lc_t* lc) 689 { 690 const char* sys; 691 int i; 692 693 if (!lc && !(lc = lc_categories[category].prev)) 694 lc = lcmake(NiL); 695 if (locales[category] != lc) 696 { 697 if (lc_categories[category].external == -lc_categories[category].internal) 698 { 699 sys = 0; 700 for (i = 1; i < AST_LC_COUNT; i++) 701 if (locales[i] == lc) 702 { 703 sys = (char*)lc->name; 704 break; 705 } 706 } 707 else if (lc->flags & (LC_debug|LC_local)) 708 sys = setlocale(lc_categories[category].external, lcmake(NiL)->name); 709 else if (!(sys = setlocale(lc_categories[category].external, lc->name)) && 710 (streq(lc->name, lc->code) || !(sys = setlocale(lc_categories[category].external, lc->code))) && 711 !streq(lc->code, lc->language->code)) 712 sys = setlocale(lc_categories[category].external, lc->language->code); 713 if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) 714 sfprintf(sfstderr, "locale set %17s %-24s %-24s\n", lc_categories[category].name, lc->name, sys); 715 if (!sys) 716 { 717 /* 718 * check for local override 719 * currently this means an LC_MESSAGES dir exists 720 */ 721 722 if (!(lc->flags & LC_checked)) 723 { 724 char path[PATH_MAX]; 725 726 if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0)) 727 lc->flags |= LC_local; 728 lc->flags |= LC_checked; 729 } 730 if (!(lc->flags & LC_local)) 731 return 0; 732 if (lc_categories[category].external != -lc_categories[category].internal) 733 setlocale(lc_categories[category].external, lcmake(NiL)->name); 734 } 735 locales[category] = lc; 736 if (lc_categories[category].setf && (*lc_categories[category].setf)(&lc_categories[category])) 737 { 738 locales[category] = lc_categories[category].prev; 739 return 0; 740 } 741 if (lc->flags & LC_default) 742 ast.locale.set &= ~(1<<category); 743 else 744 ast.locale.set |= (1<<category); 745 } 746 return (char*)lc->name; 747 } 748 749 /* 750 * set composite AST_LC_ALL locale categories 751 * return <0:composite-error 0:not-composite >0:composite-ok 752 */ 753 754 static int 755 composite(register const char* s, int initialize) 756 { 757 register const char* t; 758 register int i; 759 register int j; 760 register int k; 761 int n; 762 const char* w; 763 Lc_t* p; 764 int cat[AST_LC_COUNT]; 765 int stk[AST_LC_COUNT]; 766 char buf[PATH_MAX / 2]; 767 768 k = n = 0; 769 while (s[0] == 'L' && s[1] == 'C' && s[2] == '_') 770 { 771 n++; 772 j = 0; 773 w = s; 774 for (i = 1; i < AST_LC_COUNT; i++) 775 { 776 s = w; 777 t = lc_categories[i].name; 778 while (*t && *s++ == *t++); 779 if (!*t && *s++ == '=') 780 { 781 cat[j++] = i; 782 if (s[0] != 'L' || s[1] != 'C' || s[2] != '_') 783 break; 784 w = s; 785 i = -1; 786 } 787 } 788 for (s = w; *s && *s != '='; s++); 789 if (!*s) 790 { 791 for (i = 0; i < k; i++) 792 single(stk[i], NiL); 793 return -1; 794 } 795 w = ++s; 796 for (;;) 797 { 798 if (!*s) 799 { 800 p = lcmake(w); 801 break; 802 } 803 else if (*s++ == ';') 804 { 805 if ((n = s - w - 1) >= sizeof(buf)) 806 n = sizeof(buf) - 1; 807 memcpy(buf, w, n); 808 buf[n] = 0; 809 p = lcmake(buf); 810 break; 811 } 812 } 813 for (i = 0; i < j; i++) 814 if (!initialize) 815 { 816 if (!single(cat[i], p)) 817 { 818 for (i = 0; i < k; i++) 819 single(stk[i], NiL); 820 return -1; 821 } 822 stk[k++] = cat[i]; 823 } 824 else if (!lc_categories[cat[i]].prev) 825 lc_categories[cat[i]].prev = p; 826 } 827 while (s[0] == '/' && s[1] && n < AST_LC_COUNT) 828 { 829 n++; 830 for (w = ++s; *s && *s != '/'; s++); 831 if (!*s) 832 p = lcmake(w); 833 else 834 { 835 if ((j = s - w - 1) >= sizeof(buf)) 836 j = sizeof(buf) - 1; 837 memcpy(buf, w, j); 838 buf[j] = 0; 839 p = lcmake(buf); 840 } 841 if (!initialize) 842 { 843 if (!single(n, p)) 844 { 845 for (i = 1; i < n; i++) 846 single(i, NiL); 847 return -1; 848 } 849 } 850 else if (!lc_categories[n].prev) 851 lc_categories[n].prev = p; 852 } 853 return n; 854 } 855 856 /* 857 * setlocale() intercept 858 */ 859 860 char* 861 _ast_setlocale(int category, const char* locale) 862 { 863 register char* s; 864 register int i; 865 register int j; 866 int k; 867 char* a; 868 Lc_t* p; 869 int cat[AST_LC_COUNT]; 870 871 static Sfio_t* sp; 872 static int initialized; 873 static char local[] = "local"; 874 875 if ((category = lcindex(category, 0)) < 0) 876 return 0; 877 if (!locale) 878 { 879 /* 880 * return the current state 881 */ 882 883 compose: 884 if (category != AST_LC_ALL) 885 return (char*)locales[category]->name; 886 if (!sp && !(sp = sfstropen())) 887 return 0; 888 for (i = 1; i < AST_LC_COUNT; i++) 889 cat[i] = -1; 890 for (i = 1, k = 0; i < AST_LC_COUNT; i++) 891 if (cat[i] < 0) 892 { 893 k++; 894 cat[i] = i; 895 for (j = i + 1; j < AST_LC_COUNT; j++) 896 if (locales[j] == locales[i]) 897 cat[j] = i; 898 } 899 if (k == 1) 900 return (char*)locales[1]->name; 901 for (i = 1; i < AST_LC_COUNT; i++) 902 if (cat[i] >= 0 && !(locales[i]->flags & LC_default)) 903 { 904 if (sfstrtell(sp)) 905 sfprintf(sp, ";"); 906 for (j = i, k = cat[i]; j < AST_LC_COUNT; j++) 907 if (cat[j] == k) 908 { 909 cat[j] = -1; 910 sfprintf(sp, "%s=", lc_categories[j].name); 911 } 912 sfprintf(sp, "%s", locales[i]->name); 913 } 914 if (!sfstrtell(sp)) 915 return (char*)locales[0]->name; 916 return sfstruse(sp); 917 } 918 if (!ast.locale.serial++) 919 stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL); 920 if (*locale) 921 p = lcmake(locale); 922 else if (!initialized) 923 { 924 char* u; 925 char tmp[256]; 926 927 /* 928 * initialize from the environment 929 * precedence determined by X/Open 930 */ 931 932 u = 0; 933 if (!(a = getenv("LC_ALL")) || !*a) 934 { 935 for (i = 1; i < AST_LC_COUNT; i++) 936 if ((s = getenv(lc_categories[i].name)) && *s) 937 { 938 if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 939 s = u; 940 lc_categories[i].prev = lcmake(s); 941 } 942 a = getenv("LANG"); 943 } 944 if (a) 945 { 946 if (streq(a, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 947 a = u; 948 if (composite(a, 1)) 949 a = 0; 950 } 951 p = 0; 952 for (i = 1; i < AST_LC_COUNT; i++) 953 { 954 if (!lc_categories[i].prev) 955 { 956 if (!p && !(p = lcmake(a))) 957 break; 958 lc_categories[i].prev = p; 959 } 960 if (!single(i, lc_categories[i].prev)) 961 { 962 while (i--) 963 single(i, NiL); 964 return 0; 965 } 966 } 967 if (ast.locale.set & AST_LC_debug) 968 for (i = 1; i < AST_LC_COUNT; i++) 969 sfprintf(sfstderr, "locale env %17s %s\n", lc_categories[i].name, locales[i]->name); 970 initialized = 1; 971 goto compose; 972 } 973 else if (!(p = lc_categories[category].prev)) 974 p = lcmake("C"); 975 if (category != AST_LC_ALL) 976 return single(category, p); 977 else if (!(i = composite(locale, 0))) 978 { 979 if (!p) 980 return 0; 981 for (i = 1; i < AST_LC_COUNT; i++) 982 if (!single(i, p)) 983 { 984 while (i--) 985 single(i, NiL); 986 return 0; 987 } 988 } 989 else if (i < 0) 990 return 0; 991 goto compose; 992 } 993