1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2010 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 #ifndef AST_LC_test 73 #define AST_LC_test (1L<<27) 74 #endif 75 76 #if _UWIN 77 78 #include <ast_windows.h> 79 80 #undef _lib_setlocale 81 #define _lib_setlocale 1 82 83 #define setlocale(c,l) native_setlocale(c,l) 84 85 extern char* uwin_setlocale(int, const char*); 86 87 /* 88 * convert locale to native locale name in buf 89 */ 90 91 static char* 92 native_locale(const char* locale, char* buf, size_t siz) 93 { 94 Lc_t* lc; 95 const Lc_attribute_list_t* ap; 96 int i; 97 unsigned long lcid; 98 unsigned long lang; 99 unsigned long ctry; 100 char lbuf[128]; 101 char cbuf[128]; 102 103 if (locale && *locale) 104 { 105 if (!(lc = lcmake(locale))) 106 return 0; 107 lang = lc->language->index; 108 ctry = 0; 109 for (ap = lc->attributes; ap; ap = ap->next) 110 if (ctry = ap->attribute->index) 111 break; 112 if (!ctry) 113 { 114 for (i = 0; i < elementsof(lc->territory->languages); i++) 115 if (lc->territory->languages[i] == lc->language) 116 { 117 ctry = lc->territory->indices[i]; 118 break; 119 } 120 if (!ctry) 121 { 122 if (!lang) 123 return 0; 124 ctry = SUBLANG_DEFAULT; 125 } 126 } 127 lcid = MAKELCID(MAKELANGID(lang, ctry), SORT_DEFAULT); 128 } 129 else 130 lcid = GetUserDefaultLCID(); 131 if (GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lbuf, sizeof(lbuf)) <= 0 || 132 GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, cbuf, sizeof(cbuf)) <= 0) 133 return 0; 134 if (lc->charset->ms) 135 sfsprintf(buf, siz, "%s_%s.%s", lbuf, cbuf, lc->charset->ms); 136 else 137 sfsprintf(buf, siz, "%s_%s", lbuf, cbuf); 138 return buf; 139 } 140 141 /* 142 * locale!=0 here 143 */ 144 145 static char* 146 native_setlocale(int category, const char* locale) 147 { 148 char* usr; 149 char* sys; 150 char buf[256]; 151 152 if (!(usr = native_locale(locale, buf, sizeof(buf)))) 153 return 0; 154 155 /* 156 * win32 doesn't have LC_MESSAGES 157 */ 158 159 if (category == LC_MESSAGES) 160 return (char*)locale; 161 sys = uwin_setlocale(category, usr); 162 if (ast.locale.set & AST_LC_debug) 163 sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", lc_categories[lcindex(category, 0)].name, usr, sys); 164 return sys; 165 } 166 167 #else 168 169 #define native_locale(a,b,c) ((char*)0) 170 171 #endif 172 173 /* 174 * LC_COLLATE and LC_CTYPE native support 175 */ 176 177 #if !_lib_mbtowc || MB_LEN_MAX <= 1 178 #define mblen 0 179 #define mbtowc 0 180 #endif 181 182 #if !_lib_strcoll 183 #define strcoll 0 184 #endif 185 186 #if !_lib_strxfrm 187 #define strxfrm 0 188 #endif 189 190 /* 191 * LC_COLLATE and LC_CTYPE debug support 192 * 193 * mutibyte debug encoding 194 * 195 * DL0 [ '0' .. '4' ] c1 ... c4 DR0 196 * DL1 [ '0' .. '4' ] c1 ... c4 DR1 197 * 198 * with these ligatures 199 * 200 * ch CH sst SST 201 * 202 * and private collation order 203 * 204 * wide character display width is the low order 3 bits 205 * wctomb() uses DL1...DR1 206 */ 207 208 #define DEBUG_MB_CUR_MAX 7 209 210 #if DEBUG_MB_CUR_MAX < MB_LEN_MAX 211 #undef DEBUG_MB_CUR_MAX 212 #define DEBUG_MB_CUR_MAX MB_LEN_MAX 213 #endif 214 215 #define DL0 '<' 216 #define DL1 0xab /* 8-bit mini << on xterm */ 217 #define DR0 '>' 218 #define DR1 0xbb /* 8-bit mini >> on xterm */ 219 220 #define DB ((int)sizeof(wchar_t)*8-1) 221 #define DC 7 /* wchar_t embedded char bits */ 222 #define DX (DB/DC) /* wchar_t max embedded chars */ 223 #define DZ (DB-DX*DC+1) /* wchar_t embedded size bits */ 224 #define DD 3 /* # mb delimiter chars <n...> */ 225 226 static unsigned char debug_order[] = 227 { 228 0, 1, 2, 3, 4, 5, 6, 7, 229 8, 9, 10, 11, 12, 13, 14, 15, 230 16, 17, 18, 19, 20, 21, 22, 23, 231 24, 25, 26, 27, 28, 29, 30, 31, 232 99, 100, 101, 102, 98, 103, 104, 105, 233 106, 107, 108, 43, 109, 44, 42, 110, 234 32, 33, 34, 35, 36, 37, 38, 39, 235 40, 41, 111, 112, 113, 114, 115, 116, 236 117, 71, 72, 73, 74, 75, 76, 77, 237 78, 79, 80, 81, 82, 83, 84, 85, 238 86, 87, 88, 89, 90, 91, 92, 93, 239 94, 95, 96, 118, 119, 120, 121, 97, 240 122, 45, 46, 47, 48, 49, 50, 51, 241 52, 53, 54, 55, 56, 57, 58, 59, 242 60, 61, 62, 63, 64, 65, 66, 67, 243 68, 69, 70, 123, 124, 125, 126, 127, 244 128, 129, 130, 131, 132, 133, 134, 135, 245 136, 137, 138, 139, 140, 141, 142, 143, 246 144, 145, 146, 147, 148, 149, 150, 151, 247 152, 153, 154, 155, 156, 157, 158, 159, 248 160, 161, 162, 163, 164, 165, 166, 167, 249 168, 169, 170, 171, 172, 173, 174, 175, 250 176, 177, 178, 179, 180, 181, 182, 183, 251 184, 185, 186, 187, 188, 189, 190, 191, 252 192, 193, 194, 195, 196, 197, 198, 199, 253 200, 201, 202, 203, 204, 205, 206, 207, 254 208, 209, 210, 211, 212, 213, 214, 215, 255 216, 217, 218, 219, 220, 221, 222, 223, 256 224, 225, 226, 227, 228, 229, 230, 231, 257 232, 233, 234, 235, 236, 237, 238, 239, 258 240, 241, 242, 243, 244, 245, 246, 247, 259 248, 249, 250, 251, 252, 253, 254, 255, 260 }; 261 262 static int 263 debug_mbtowc(register wchar_t* p, register const char* s, size_t n) 264 { 265 register const char* q; 266 register const char* r; 267 register int w; 268 register int dr; 269 wchar_t c; 270 271 if (n < 1) 272 return -1; 273 if (!s || !*s) 274 return 0; 275 switch (((unsigned char*)s)[0]) 276 { 277 case DL0: 278 dr = DR0; 279 break; 280 case DL1: 281 dr = DR1; 282 break; 283 default: 284 if (p) 285 *p = ((unsigned char*)s)[0] & ((1<<DC)-1); 286 return 1; 287 } 288 if (n < 2) 289 return -1; 290 if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0]) 291 { 292 if (p) 293 *p = w; 294 return 2; 295 } 296 if (w < '0' || w > ('0' + DX)) 297 return -1; 298 if ((w -= '0' - DD) > n) 299 return -1; 300 r = s + w - 1; 301 q = s += 2; 302 while (q < r && *q) 303 q++; 304 if (q != r || *((unsigned char*)q) != dr) 305 return -1; 306 if (p) 307 { 308 c = 0; 309 while (--q >= s) 310 { 311 c <<= DC; 312 c |= *((unsigned char*)q); 313 } 314 c <<= DZ; 315 c |= w - DD; 316 *p = c; 317 } 318 return w; 319 } 320 321 static int 322 debug_wctomb(char* s, wchar_t c) 323 { 324 int w; 325 int i; 326 int k; 327 328 w = 0; 329 if (c >= 0 && c <= UCHAR_MAX) 330 { 331 w++; 332 if (s) 333 *s = c; 334 } 335 else if ((i = c & ((1<<DZ)-1)) > DX) 336 return -1; 337 else 338 { 339 w++; 340 if (s) 341 *s++ = DL1; 342 c >>= DZ; 343 w++; 344 if (s) 345 *s++ = i + '0'; 346 while (i--) 347 { 348 w++; 349 if (s) 350 *s++ = (k = c & ((1<<DC)-1)) ? k : '?'; 351 c >>= DC; 352 } 353 w++; 354 if (s) 355 *s++ = DR1; 356 } 357 return w; 358 } 359 360 static int 361 debug_mblen(const char* s, size_t n) 362 { 363 return debug_mbtowc(NiL, s, n); 364 } 365 366 static int 367 debug_wcwidth(wchar_t c) 368 { 369 if (c >= 0 && c <= UCHAR_MAX) 370 return 1; 371 if ((c &= ((1<<DZ)-1)) > DX) 372 return -1; 373 return c + DD; 374 } 375 376 static size_t 377 debug_strxfrm(register char* t, register const char* s, size_t n) 378 { 379 register const char* q; 380 register const char* r; 381 register char* e; 382 char* o; 383 register size_t z; 384 register int w; 385 386 o = t; 387 z = 0; 388 if (e = t) 389 e += n; 390 while (s[0]) 391 { 392 if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC)) 393 { 394 w -= '0'; 395 q = s + 2; 396 r = q + w; 397 while (q < r && *q) 398 q++; 399 if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1) 400 { 401 if (t) 402 { 403 for (q = s + 2; q < r; q++) 404 if (t < e) 405 *t++ = debug_order[*q]; 406 while (w++ < DX) 407 if (t < e) 408 *t++ = 1; 409 } 410 s = r + 1; 411 z += DX; 412 continue; 413 } 414 } 415 if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H')) 416 { 417 if (t) 418 { 419 if (t < e) 420 *t++ = debug_order[s[0]]; 421 if (t < e) 422 *t++ = debug_order[s[1]]; 423 if (t < e) 424 *t++ = 1; 425 if (t < e) 426 *t++ = 1; 427 } 428 s += 2; 429 z += DX; 430 continue; 431 } 432 if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T')) 433 { 434 if (t) 435 { 436 if (t < e) 437 *t++ = debug_order[s[0]]; 438 if (t < e) 439 *t++ = debug_order[s[1]]; 440 if (t < e) 441 *t++ = debug_order[s[2]]; 442 if (t < e) 443 *t++ = 1; 444 } 445 s += 3; 446 z += DX; 447 continue; 448 } 449 if (t) 450 { 451 if (t < e) 452 *t++ = debug_order[s[0]]; 453 if (t < e) 454 *t++ = 1; 455 if (t < e) 456 *t++ = 1; 457 if (t < e) 458 *t++ = 1; 459 } 460 s++; 461 z += DX; 462 } 463 if (!t) 464 return z; 465 if (t < e) 466 *t = 0; 467 return t - o; 468 } 469 470 static int 471 debug_strcoll(const char* a, const char* b) 472 { 473 char ab[1024]; 474 char bb[1024]; 475 476 debug_strxfrm(ab, a, sizeof(ab) - 1); 477 ab[sizeof(ab)-1] = 0; 478 debug_strxfrm(bb, b, sizeof(bb) - 1); 479 bb[sizeof(bb)-1] = 0; 480 return strcmp(ab, bb); 481 } 482 483 /* 484 * default locale 485 */ 486 487 static int 488 default_wcwidth(wchar_t w) 489 { 490 return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1; 491 } 492 493 /* 494 * called when LC_COLLATE initialized or changes 495 */ 496 497 static int 498 set_collate(Lc_category_t* cp) 499 { 500 if (locales[cp->internal]->flags & LC_debug) 501 { 502 ast.collate = debug_strcoll; 503 ast.mb_xfrm = debug_strxfrm; 504 } 505 else if (locales[cp->internal]->flags & LC_default) 506 { 507 ast.collate = strcmp; 508 ast.mb_xfrm = 0; 509 } 510 else 511 { 512 ast.collate = strcoll; 513 ast.mb_xfrm = strxfrm; 514 } 515 return 0; 516 } 517 518 /* 519 * workaround the interesting sjis that translates unshifted 7 bit ascii! 520 */ 521 522 #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc 523 524 #define mb_state_zero ((mbstate_t*)&ast.pad[sizeof(ast.pad)-2*sizeof(mbstate_t)]) 525 #define mb_state ((mbstate_t*)&ast.pad[sizeof(ast.pad)-sizeof(mbstate_t)]) 526 527 static int 528 sjis_mbtowc(register wchar_t* p, register const char* s, size_t n) 529 { 530 if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t))) 531 { 532 *p = *s; 533 return 1; 534 } 535 return mbrtowc(p, s, n, mb_state); 536 } 537 538 #endif 539 540 #define utf8_wctomb wctomb 541 542 static const uint32_t utf8mask[] = 543 { 544 0x00000000, 545 0x00000000, 546 0xffffff80, 547 0xfffff800, 548 0xffff0000, 549 0xffe00000, 550 0xfc000000, 551 }; 552 553 static const signed char utf8tab[256] = 554 { 555 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 556 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 557 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 558 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 559 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 560 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 561 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 562 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 563 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 564 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 565 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 567 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 568 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 569 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 570 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,-1,-1, 571 }; 572 573 static int 574 utf8_mbtowc(wchar_t* wp, const char* str, size_t n) 575 { 576 register unsigned char* sp = (unsigned char*)str; 577 register int m; 578 register int i; 579 register int c; 580 register wchar_t w = 0; 581 582 if (!sp || !n) 583 return 0; 584 if ((m = utf8tab[*sp]) > 0) 585 { 586 if (m > n) 587 return -1; 588 if (wp) 589 { 590 if (m == 1) 591 { 592 *wp = *sp; 593 return 1; 594 } 595 w = *sp & ((1<<(8-m))-1); 596 for (i = m - 1; i > 0; i--) 597 { 598 c = *++sp; 599 if ((c&0xc0) != 0x80) 600 goto invalid; 601 w = (w<<6) | (c&0x3f); 602 } 603 if (!(utf8mask[m] & w) || w >= 0xd800 && (w <= 0xdfff || w >= 0xfffe && w <= 0xffff)) 604 goto invalid; 605 *wp = w; 606 } 607 return m; 608 } 609 if (!*sp) 610 return 0; 611 invalid: 612 #ifdef EILSEQ 613 errno = EILSEQ; 614 #endif 615 ast.mb_sync = (const char*)sp - str; 616 return -1; 617 } 618 619 static int 620 utf8_mblen(const char* str, size_t n) 621 { 622 wchar_t w; 623 624 return utf8_mbtowc(&w, str, n); 625 } 626 627 /* 628 * called when LC_CTYPE initialized or changes 629 */ 630 631 static int 632 set_ctype(Lc_category_t* cp) 633 { 634 ast.mb_sync = 0; 635 if (locales[cp->internal]->flags & LC_debug) 636 { 637 ast.mb_cur_max = DEBUG_MB_CUR_MAX; 638 ast.mb_len = debug_mblen; 639 ast.mb_towc = debug_mbtowc; 640 ast.mb_width = debug_wcwidth; 641 ast.mb_conv = debug_wctomb; 642 } 643 else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc)) 644 { 645 ast.mb_cur_max = 1; 646 ast.mb_len = 0; 647 ast.mb_towc = 0; 648 ast.mb_width = default_wcwidth; 649 ast.mb_conv = 0; 650 } 651 else if ((locales[cp->internal]->flags & LC_utf8) && !(ast.locale.set & AST_LC_test)) 652 { 653 ast.mb_cur_max = 6; 654 ast.mb_len = utf8_mblen; 655 ast.mb_towc = utf8_mbtowc; 656 if (!(ast.mb_width = wcwidth)) 657 ast.mb_width = default_wcwidth; 658 ast.mb_conv = utf8_wctomb; 659 } 660 else 661 { 662 if (!(ast.mb_width = wcwidth)) 663 ast.mb_width = default_wcwidth; 664 ast.mb_conv = wctomb; 665 #ifdef mb_state 666 { 667 /* 668 * check for sjis that translates unshifted 7 bit ascii! 669 */ 670 671 char* s; 672 char buf[2]; 673 674 mbinit(); 675 buf[1] = 0; 676 *(s = buf) = '\\'; 677 if (mbchar(s) != buf[0]) 678 { 679 memcpy(mb_state, mb_state_zero, sizeof(mbstate_t)); 680 ast.mb_towc = sjis_mbtowc; 681 } 682 } 683 #endif 684 } 685 if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) 686 sfprintf(sfstderr, "locale info %17s MB_CUR_MAX=%d%s%s%s%s\n" 687 , cp->name 688 , ast.mb_cur_max 689 , ast.mb_len == debug_mblen ? " debug_mblen" : ast.mb_len == mblen ? " mblen" : "" 690 , ast.mb_towc == debug_mbtowc ? " debug_mbtowc" : ast.mb_towc == mbtowc ? " mbtowc" 691 #ifdef mb_state 692 : ast.mb_towc == sjis_mbtowc ? " sjis_mbtowc" 693 #endif 694 : "" 695 , ast.mb_width == debug_wcwidth ? " debug_wcwidth" : ast.mb_width == wcwidth ? " wcwidth" : ast.mb_width == default_wcwidth ? " default_wcwidth" : "" 696 , ast.mb_conv == debug_wctomb ? " debug_wctomb" : ast.mb_conv == wctomb ? " wctomb" : "" 697 ); 698 return 0; 699 } 700 701 /* 702 * called when LC_NUMERIC initialized or changes 703 */ 704 705 static int 706 set_numeric(Lc_category_t* cp) 707 { 708 register int category = cp->internal; 709 struct lconv* lp; 710 Lc_numeric_t* dp; 711 712 static Lc_numeric_t default_numeric = { '.', -1 }; 713 714 if (!LCINFO(category)->data) 715 { 716 if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0))) 717 { 718 dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.'; 719 dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1; 720 } 721 else 722 dp = &default_numeric; 723 LCINFO(category)->data = (void*)dp; 724 if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) 725 sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X'); 726 } 727 return 0; 728 } 729 730 /* 731 * this table is indexed by AST_LC_[A-Z]* 732 */ 733 734 Lc_category_t lc_categories[] = 735 { 736 { "LC_ALL", LC_ALL, AST_LC_ALL, 0 }, 737 { "LC_COLLATE", LC_COLLATE, AST_LC_COLLATE, set_collate }, 738 { "LC_CTYPE", LC_CTYPE, AST_LC_CTYPE, set_ctype }, 739 { "LC_MESSAGES", LC_MESSAGES, AST_LC_MESSAGES, 0 }, 740 { "LC_MONETARY", LC_MONETARY, AST_LC_MONETARY, 0 }, 741 { "LC_NUMERIC", LC_NUMERIC, AST_LC_NUMERIC, set_numeric }, 742 { "LC_TIME", LC_TIME, AST_LC_TIME, 0 }, 743 { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0 }, 744 { "LC_ADDRESS", LC_ADDRESS, AST_LC_ADDRESS, 0 }, 745 { "LC_NAME", LC_NAME, AST_LC_NAME, 0 }, 746 { "LC_TELEPHONE", LC_TELEPHONE, AST_LC_TELEPHONE, 0 }, 747 { "LC_XLITERATE", LC_XLITERATE, AST_LC_XLITERATE, 0 }, 748 { "LC_MEASUREMENT", LC_MEASUREMENT, AST_LC_MEASUREMENT, 0 }, 749 { "LC_PAPER", LC_PAPER, AST_LC_PAPER, 0 }, 750 }; 751 752 static Lc_t* lang; 753 static Lc_t* lc_all; 754 755 typedef struct Unamval_s 756 { 757 char* name; 758 unsigned int value; 759 } Unamval_t; 760 761 static const Unamval_t options[] = 762 { 763 "debug", AST_LC_debug, 764 "find", AST_LC_find, 765 "setlocale", AST_LC_setlocale, 766 "test", AST_LC_test, 767 "translate", AST_LC_translate, 768 0, 0 769 }; 770 771 /* 772 * called by stropt() to set options 773 */ 774 775 static int 776 setopt(void* a, const void* p, int n, const char* v) 777 { 778 if (p) 779 { 780 if (n) 781 ast.locale.set |= ((Unamval_t*)p)->value; 782 else 783 ast.locale.set &= ~((Unamval_t*)p)->value; 784 } 785 return 0; 786 } 787 788 #if !_lib_setlocale 789 790 #define setlocale(c,l) default_setlocale(c,l) 791 792 static char* 793 default_setlocale(int category, const char* locale) 794 { 795 Lc_t* lc; 796 797 if (locale) 798 { 799 if (!(lc = lcmake(locale)) || !(lc->flags & LC_default)) 800 return 0; 801 locales[0]->flags &= ~lc->flags; 802 locales[1]->flags &= ~lc->flags; 803 return lc->name; 804 } 805 return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name; 806 } 807 808 #endif 809 810 /* 811 * set a single AST_LC_* locale category 812 * the caller must validate category 813 * lc==0 restores the previous state 814 */ 815 816 static char* 817 single(int category, Lc_t* lc, unsigned int flags) 818 { 819 const char* sys; 820 int i; 821 822 if (flags & (LC_setenv|LC_setlocale)) 823 { 824 if (!(ast.locale.set & AST_LC_internal)) 825 lc_categories[category].prev = lc; 826 if ((flags & LC_setenv) && lc_all && locales[category]) 827 return (char*)locales[category]->name; 828 } 829 if (!lc && (!(lc_categories[category].flags & LC_setlocale) || !(lc = lc_categories[category].prev)) && !(lc = lc_all) && !(lc = lc_categories[category].prev) && !(lc = lang)) 830 lc = lcmake(NiL); 831 sys = 0; 832 if (locales[category] != lc) 833 { 834 if (lc_categories[category].external == -lc_categories[category].internal) 835 { 836 for (i = 1; i < AST_LC_COUNT; i++) 837 if (locales[i] == lc) 838 { 839 sys = (char*)lc->name; 840 break; 841 } 842 } 843 else if (lc->flags & (LC_debug|LC_local)) 844 sys = setlocale(lc_categories[category].external, lcmake(NiL)->name); 845 else if (!(sys = setlocale(lc_categories[category].external, lc->name)) && 846 (streq(lc->name, lc->code) || !(sys = setlocale(lc_categories[category].external, lc->code))) && 847 !streq(lc->code, lc->language->code)) 848 sys = setlocale(lc_categories[category].external, lc->language->code); 849 if (!sys) 850 { 851 /* 852 * check for local override 853 * currently this means an LC_MESSAGES dir exists 854 */ 855 856 if (!(lc->flags & LC_checked)) 857 { 858 char path[PATH_MAX]; 859 860 if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0)) 861 lc->flags |= LC_local; 862 lc->flags |= LC_checked; 863 } 864 if (!(lc->flags & LC_local)) 865 return 0; 866 if (lc_categories[category].external != -lc_categories[category].internal) 867 setlocale(lc_categories[category].external, lcmake(NiL)->name); 868 } 869 locales[category] = lc; 870 if (lc_categories[category].setf && (*lc_categories[category].setf)(&lc_categories[category])) 871 { 872 locales[category] = lc_categories[category].prev; 873 return 0; 874 } 875 if ((lc->flags & LC_default) || category == AST_LC_MESSAGES && lc->name[0] == 'e' && lc->name[1] == 'n' && (lc->name[2] == 0 || lc->name[2] == '_' && lc->name[3] == 'U')) 876 ast.locale.set &= ~(1<<category); 877 else 878 ast.locale.set |= (1<<category); 879 } 880 else if (lc_categories[category].flags ^ flags) 881 { 882 lc_categories[category].flags &= ~(LC_setenv|LC_setlocale); 883 lc_categories[category].flags |= flags; 884 } 885 else 886 return (char*)lc->name; 887 if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal)) 888 sfprintf(sfstderr, "locale set %17s %16s %16s %16s %s%s\n", lc_categories[category].name, lc->name, sys, lc_categories[category].prev ? lc_categories[category].prev->name : NiL, (lc_categories[category].flags & LC_setlocale) ? "[setlocale]" : "", (lc_categories[category].flags & LC_setenv) ? "[setenv]" : ""); 889 return (char*)lc->name; 890 } 891 892 /* 893 * set composite AST_LC_ALL locale categories 894 * return <0:composite-error 0:not-composite >0:composite-ok 895 */ 896 897 static int 898 composite(register const char* s, int initialize) 899 { 900 register const char* t; 901 register int i; 902 register int j; 903 register int k; 904 int n; 905 int m; 906 const char* w; 907 Lc_t* p; 908 int cat[AST_LC_COUNT]; 909 int stk[AST_LC_COUNT]; 910 char buf[PATH_MAX / 2]; 911 912 k = n = 0; 913 while (s[0] == 'L' && s[1] == 'C' && s[2] == '_') 914 { 915 n++; 916 j = 0; 917 w = s; 918 for (i = 1; i < AST_LC_COUNT; i++) 919 { 920 s = w; 921 t = lc_categories[i].name; 922 while (*t && *s++ == *t++); 923 if (!*t && *s++ == '=') 924 { 925 cat[j++] = i; 926 if (s[0] != 'L' || s[1] != 'C' || s[2] != '_') 927 break; 928 w = s; 929 i = -1; 930 } 931 } 932 for (s = w; *s && *s != '='; s++); 933 if (!*s) 934 { 935 for (i = 0; i < k; i++) 936 single(stk[i], NiL, 0); 937 return -1; 938 } 939 w = ++s; 940 for (;;) 941 { 942 if (!*s) 943 { 944 p = lcmake(w); 945 break; 946 } 947 else if (*s++ == ';') 948 { 949 if ((m = s - w - 1) >= sizeof(buf)) 950 m = sizeof(buf) - 1; 951 memcpy(buf, w, m); 952 buf[m] = 0; 953 p = lcmake(buf); 954 break; 955 } 956 } 957 for (i = 0; i < j; i++) 958 if (!initialize) 959 { 960 if (!single(cat[i], p, 0)) 961 { 962 for (i = 0; i < k; i++) 963 single(stk[i], NiL, 0); 964 return -1; 965 } 966 stk[k++] = cat[i]; 967 } 968 else if (!lc_categories[cat[i]].prev && !(ast.locale.set & AST_LC_internal)) 969 lc_categories[cat[i]].prev = p; 970 } 971 while (s[0] == '/' && s[1] && n < (AST_LC_COUNT - 1)) 972 { 973 n++; 974 for (w = ++s; *s && *s != '/'; s++); 975 if (!*s) 976 p = lcmake(w); 977 else 978 { 979 if ((j = s - w - 1) >= sizeof(buf)) 980 j = sizeof(buf) - 1; 981 memcpy(buf, w, j); 982 buf[j] = 0; 983 p = lcmake(buf); 984 } 985 if (!initialize) 986 { 987 if (!single(n, p, 0)) 988 { 989 for (i = 1; i < n; i++) 990 single(i, NiL, 0); 991 return -1; 992 } 993 } 994 else if (!lc_categories[n].prev && !(ast.locale.set & AST_LC_internal)) 995 lc_categories[n].prev = p; 996 } 997 return n; 998 } 999 1000 /* 1001 * setlocale() intercept 1002 * 1003 * locale: 1004 * 0 query 1005 * "" initialize from environment (if LC_ALL) 1006 * "" AST_LC_setenv: value unset (defer to LANG) 1007 * "*" AST_LC_setenv: value set (defer to LC_ALL) 1008 * * set (override LC_ALL) 1009 */ 1010 1011 char* 1012 _ast_setlocale(int category, const char* locale) 1013 { 1014 register char* s; 1015 register int i; 1016 register int j; 1017 int k; 1018 int f; 1019 Lc_t* p; 1020 int cat[AST_LC_COUNT]; 1021 1022 static Sfio_t* sp; 1023 static int initialized; 1024 static const char local[] = "local"; 1025 1026 if ((category = lcindex(category, 0)) < 0) 1027 return 0; 1028 if (!locale) 1029 { 1030 /* 1031 * return the current state 1032 */ 1033 1034 compose: 1035 if (category != AST_LC_ALL && category != AST_LC_LANG) 1036 return (char*)locales[category]->name; 1037 if (!sp && !(sp = sfstropen())) 1038 return 0; 1039 for (i = 1; i < AST_LC_COUNT; i++) 1040 cat[i] = -1; 1041 for (i = 1, k = 0; i < AST_LC_COUNT; i++) 1042 if (cat[i] < 0) 1043 { 1044 k++; 1045 cat[i] = i; 1046 for (j = i + 1; j < AST_LC_COUNT; j++) 1047 if (locales[j] == locales[i]) 1048 cat[j] = i; 1049 } 1050 if (k == 1) 1051 return (char*)locales[1]->name; 1052 for (i = 1; i < AST_LC_COUNT; i++) 1053 if (cat[i] >= 0 && !(locales[i]->flags & LC_default)) 1054 { 1055 if (sfstrtell(sp)) 1056 sfprintf(sp, ";"); 1057 for (j = i, k = cat[i]; j < AST_LC_COUNT; j++) 1058 if (cat[j] == k) 1059 { 1060 cat[j] = -1; 1061 sfprintf(sp, "%s=", lc_categories[j].name); 1062 } 1063 sfprintf(sp, "%s", locales[i]->name); 1064 } 1065 if (!sfstrtell(sp)) 1066 return (char*)locales[0]->name; 1067 return sfstruse(sp); 1068 } 1069 if (!ast.locale.serial++) 1070 { 1071 stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL); 1072 initialized = 0; 1073 } 1074 if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal)) 1075 sfprintf(sfstderr, "locale user %17s %16s %s%s\n", category == AST_LC_LANG ? "LANG" : lc_categories[category].name, locale && !*locale ? "''" : locale, initialized ? "" : "[initial]", (ast.locale.set & AST_LC_setenv) ? "[setenv]" : ""); 1076 if (ast.locale.set & AST_LC_setenv) 1077 { 1078 f = LC_setenv; 1079 p = *locale ? lcmake(locale) : (Lc_t*)0; 1080 } 1081 else if (*locale) 1082 { 1083 f = LC_setlocale; 1084 p = lcmake(locale); 1085 } 1086 else if (category == AST_LC_ALL) 1087 { 1088 if (!initialized) 1089 { 1090 char* u; 1091 char tmp[256]; 1092 1093 /* 1094 * initialize from the environment 1095 * precedence determined by X/Open 1096 */ 1097 1098 u = 0; 1099 if ((s = getenv("LANG")) && *s) 1100 { 1101 if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 1102 s = u; 1103 lang = lcmake(s); 1104 } 1105 else 1106 lang = 0; 1107 if ((s = getenv("LC_ALL")) && *s) 1108 { 1109 if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 1110 s = u; 1111 lc_all = lcmake(s); 1112 } 1113 else 1114 lc_all = 0; 1115 for (i = 1; i < AST_LC_COUNT; i++) 1116 if (lc_categories[i].flags & LC_setlocale) 1117 /* explicitly set by setlocale() */; 1118 else if ((s = getenv(lc_categories[i].name)) && *s) 1119 { 1120 if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp))))) 1121 s = u; 1122 lc_categories[i].prev = lcmake(s); 1123 } 1124 else 1125 lc_categories[i].prev = 0; 1126 for (i = 1; i < AST_LC_COUNT; i++) 1127 if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0)) 1128 { 1129 while (i--) 1130 single(i, NiL, 0); 1131 return 0; 1132 } 1133 if (ast.locale.set & AST_LC_debug) 1134 for (i = 1; i < AST_LC_COUNT; i++) 1135 sfprintf(sfstderr, "locale env %17s %16s %16s %16s\n", lc_categories[i].name, locales[i]->name, "", lc_categories[i].prev ? lc_categories[i].prev->name : (char*)0); 1136 initialized = 1; 1137 } 1138 goto compose; 1139 } 1140 else if (category == AST_LC_LANG || !(p = lc_categories[category].prev)) 1141 { 1142 f = 0; 1143 p = lcmake("C"); 1144 } 1145 else 1146 f = 0; 1147 if (category == AST_LC_LANG) 1148 { 1149 if (lang != p) 1150 { 1151 lang = p; 1152 if (!lc_all) 1153 for (i = 1; i < AST_LC_COUNT; i++) 1154 if (!single(i, lc_categories[i].prev, 0)) 1155 { 1156 while (i--) 1157 single(i, NiL, 0); 1158 return 0; 1159 } 1160 } 1161 } 1162 else if (category != AST_LC_ALL) 1163 { 1164 if (f || !lc_all) 1165 return single(category, p, f); 1166 if (p && !(ast.locale.set & AST_LC_internal)) 1167 lc_categories[category].prev = p; 1168 return (char*)locales[category]->name; 1169 } 1170 else if (composite(locale, 0) < 0) 1171 return 0; 1172 else if (lc_all != p) 1173 { 1174 lc_all = p; 1175 for (i = 1; i < AST_LC_COUNT; i++) 1176 if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0)) 1177 { 1178 while (i--) 1179 single(i, NiL, 0); 1180 return 0; 1181 } 1182 } 1183 goto compose; 1184 } 1185