1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
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
31 #include <ast_standards.h>
35 #include <ast_wchar.h>
40 #if ( _lib_wcwidth || _lib_wctomb ) && _hdr_wctype
58 extern int mblen(const char*, size_t);
68 #ifndef AST_LC_CANONICAL
69 #define AST_LC_CANONICAL LC_abbreviated
73 #define AST_LC_test (1L<<27)
78 #include <ast_windows.h>
81 #define _lib_setlocale 1
83 #define setlocale(c,l) native_setlocale(c,l)
85 extern char* uwin_setlocale(int, const char*);
88 * convert locale to native locale name in buf
92 native_locale(const char* locale
, char* buf
, size_t siz
)
95 const Lc_attribute_list_t
* ap
;
103 if (locale
&& *locale
)
105 if (!(lc
= lcmake(locale
)))
107 lang
= lc
->language
->index
;
109 for (ap
= lc
->attributes
; ap
; ap
= ap
->next
)
110 if (ctry
= ap
->attribute
->index
)
114 for (i
= 0; i
< elementsof(lc
->territory
->languages
); i
++)
115 if (lc
->territory
->languages
[i
] == lc
->language
)
117 ctry
= lc
->territory
->indices
[i
];
124 ctry
= SUBLANG_DEFAULT
;
127 lcid
= MAKELCID(MAKELANGID(lang
, ctry
), SORT_DEFAULT
);
130 lcid
= GetUserDefaultLCID();
131 if (GetLocaleInfo(lcid
, LOCALE_SENGLANGUAGE
, lbuf
, sizeof(lbuf
)) <= 0 ||
132 GetLocaleInfo(lcid
, LOCALE_SENGCOUNTRY
, cbuf
, sizeof(cbuf
)) <= 0)
135 sfsprintf(buf
, siz
, "%s_%s.%s", lbuf
, cbuf
, lc
->charset
->ms
);
137 sfsprintf(buf
, siz
, "%s_%s", lbuf
, cbuf
);
146 native_setlocale(int category
, const char* locale
)
152 if (!(usr
= native_locale(locale
, buf
, sizeof(buf
))))
156 * win32 doesn't have LC_MESSAGES
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
);
169 #define native_locale(a,b,c) ((char*)0)
174 * LC_COLLATE and LC_CTYPE native support
177 #if !_lib_mbtowc || MB_LEN_MAX <= 1
191 * LC_COLLATE and LC_CTYPE debug support
193 * mutibyte debug encoding
195 * DL0 [ '0' .. '4' ] c1 ... c4 DR0
196 * DL1 [ '0' .. '4' ] c1 ... c4 DR1
198 * with these ligatures
202 * and private collation order
204 * wide character display width is the low order 3 bits
205 * wctomb() uses DL1...DR1
208 #define DEBUG_MB_CUR_MAX 7
210 #if DEBUG_MB_CUR_MAX < MB_LEN_MAX
211 #undef DEBUG_MB_CUR_MAX
212 #define DEBUG_MB_CUR_MAX MB_LEN_MAX
216 #define DL1 0xab /* 8-bit mini << on xterm */
218 #define DR1 0xbb /* 8-bit mini >> on xterm */
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...> */
226 static unsigned char debug_order
[] =
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,
263 debug_mbtowc(register wchar_t* p
, register const char* s
, size_t n
)
265 register const char* q
;
266 register const char* r
;
275 switch (((unsigned char*)s
)[0])
285 *p
= ((unsigned char*)s
)[0] & ((1<<DC
)-1);
290 if ((w
= ((unsigned char*)s
)[1]) == ((unsigned char*)s
)[0])
296 if (w
< '0' || w
> ('0' + DX
))
298 if ((w
-= '0' - DD
) > n
)
304 if (q
!= r
|| *((unsigned char*)q
) != dr
)
312 c
|= *((unsigned char*)q
);
322 debug_wctomb(char* s
, wchar_t c
)
329 if (c
>= 0 && c
<= UCHAR_MAX
)
335 else if ((i
= c
& ((1<<DZ
)-1)) > DX
)
350 *s
++ = (k
= c
& ((1<<DC
)-1)) ? k
: '?';
361 debug_mblen(const char* s
, size_t n
)
363 return debug_mbtowc(NiL
, s
, n
);
367 debug_wcwidth(wchar_t c
)
369 if (c
>= 0 && c
<= UCHAR_MAX
)
371 if ((c
&= ((1<<DZ
)-1)) > DX
)
377 debug_strxfrm(register char* t
, register const char* s
, size_t n
)
379 register const char* q
;
380 register const char* r
;
392 if ((((unsigned char*)s
)[0] == DL0
|| ((unsigned char*)s
)[0] == DL1
) && (w
= s
[1]) >= '0' && w
<= ('0' + DC
))
399 if (*((unsigned char*)q
) == DR0
|| *((unsigned char*)q
) == DR1
)
403 for (q
= s
+ 2; q
< r
; q
++)
405 *t
++ = debug_order
[*q
];
415 if ((s
[0] == 'c' || s
[0] == 'C') && (s
[1] == 'h' || s
[1] == 'H'))
420 *t
++ = debug_order
[s
[0]];
422 *t
++ = debug_order
[s
[1]];
432 if ((s
[0] == 's' || s
[0] == 'S') && (s
[1] == 's' || s
[1] == 'S') && (s
[2] == 't' || s
[2] == 'T'))
437 *t
++ = debug_order
[s
[0]];
439 *t
++ = debug_order
[s
[1]];
441 *t
++ = debug_order
[s
[2]];
452 *t
++ = debug_order
[s
[0]];
471 debug_strcoll(const char* a
, const char* b
)
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
);
488 default_wcwidth(wchar_t w
)
490 return w
>= 0 && w
<= 255 && !iscntrl(w
) ? 1 : -1;
494 * called when LC_COLLATE initialized or changes
498 set_collate(Lc_category_t
* cp
)
500 if (locales
[cp
->internal
]->flags
& LC_debug
)
502 ast
.collate
= debug_strcoll
;
503 ast
.mb_xfrm
= debug_strxfrm
;
505 else if (locales
[cp
->internal
]->flags
& LC_default
)
507 ast
.collate
= strcmp
;
512 ast
.collate
= strcoll
;
513 ast
.mb_xfrm
= strxfrm
;
519 * workaround the interesting sjis that translates unshifted 7 bit ascii!
522 #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc
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)])
528 sjis_mbtowc(register wchar_t* p
, register const char* s
, size_t n
)
530 if (n
&& p
&& s
&& (*s
== '\\' || *s
== '~') && !memcmp(mb_state
, mb_state_zero
, sizeof(mbstate_t)))
535 return mbrtowc(p
, s
, n
, mb_state
);
540 #define utf8_wctomb wctomb
542 static const uint32_t utf8mask
[] =
553 static const signed char utf8tab
[256] =
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,
574 utf8_mbtowc(wchar_t* wp
, const char* str
, size_t n
)
576 register unsigned char* sp
= (unsigned char*)str
;
580 register wchar_t w
= 0;
584 if ((m
= utf8tab
[*sp
]) > 0)
595 w
= *sp
& ((1<<(8-m
))-1);
596 for (i
= m
- 1; i
> 0; i
--)
599 if ((c
&0xc0) != 0x80)
601 w
= (w
<<6) | (c
&0x3f);
603 if (!(utf8mask
[m
] & w
) || w
>= 0xd800 && (w
<= 0xdfff || w
>= 0xfffe && w
<= 0xffff))
615 ast
.mb_sync
= (const char*)sp
- str
;
620 utf8_mblen(const char* str
, size_t n
)
624 return utf8_mbtowc(&w
, str
, n
);
628 * called when LC_CTYPE initialized or changes
632 set_ctype(Lc_category_t
* cp
)
635 if (locales
[cp
->internal
]->flags
& LC_debug
)
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
;
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
))
648 ast
.mb_width
= default_wcwidth
;
651 else if ((locales
[cp
->internal
]->flags
& LC_utf8
) && !(ast
.locale
.set
& AST_LC_test
))
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
;
662 if (!(ast
.mb_width
= wcwidth
))
663 ast
.mb_width
= default_wcwidth
;
664 ast
.mb_conv
= wctomb
;
668 * check for sjis that translates unshifted 7 bit ascii!
677 if (mbchar(s
) != buf
[0])
679 memcpy(mb_state
, mb_state_zero
, sizeof(mbstate_t));
680 ast
.mb_towc
= sjis_mbtowc
;
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"
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"
692 : ast
.mb_towc
== sjis_mbtowc
? " sjis_mbtowc"
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" : ""
702 * called when LC_NUMERIC initialized or changes
706 set_numeric(Lc_category_t
* cp
)
708 register int category
= cp
->internal
;
712 static Lc_numeric_t default_numeric
= { '.', -1 };
714 if (!LCINFO(category
)->data
)
716 if ((lp
= localeconv()) && (dp
= newof(0, Lc_numeric_t
, 1, 0)))
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;
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');
731 * this table is indexed by AST_LC_[A-Z]*
734 Lc_category_t lc_categories
[] =
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 },
755 typedef struct Unamval_s
761 static const Unamval_t options
[] =
763 "debug", AST_LC_debug
,
765 "setlocale", AST_LC_setlocale
,
767 "translate", AST_LC_translate
,
772 * called by stropt() to set options
776 setopt(void* a
, const void* p
, int n
, const char* v
)
781 ast
.locale
.set
|= ((Unamval_t
*)p
)->value
;
783 ast
.locale
.set
&= ~((Unamval_t
*)p
)->value
;
790 #define setlocale(c,l) default_setlocale(c,l)
793 default_setlocale(int category
, const char* locale
)
799 if (!(lc
= lcmake(locale
)) || !(lc
->flags
& LC_default
))
801 locales
[0]->flags
&= ~lc
->flags
;
802 locales
[1]->flags
&= ~lc
->flags
;
805 return (locales
[1]->flags
& (1<<category
)) ? locales
[1]->name
: locales
[0]->name
;
811 * set a single AST_LC_* locale category
812 * the caller must validate category
813 * lc==0 restores the previous state
817 single(int category
, Lc_t
* lc
, unsigned int flags
)
822 if (flags
& (LC_setenv
|LC_setlocale
))
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
;
829 if (!lc
&& (!(lc_categories
[category
].flags
& LC_setlocale
) || !(lc
= lc_categories
[category
].prev
)) && !(lc
= lc_all
) && !(lc
= lc_categories
[category
].prev
) && !(lc
= lang
))
832 if (locales
[category
] != lc
)
834 if (lc_categories
[category
].external
== -lc_categories
[category
].internal
)
836 for (i
= 1; i
< AST_LC_COUNT
; i
++)
837 if (locales
[i
] == lc
)
839 sys
= (char*)lc
->name
;
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
);
852 * check for local override
853 * currently this means an LC_MESSAGES dir exists
856 if (!(lc
->flags
& LC_checked
))
860 if (mcfind(path
, lc
->code
, NiL
, LC_MESSAGES
, 0))
861 lc
->flags
|= LC_local
;
862 lc
->flags
|= LC_checked
;
864 if (!(lc
->flags
& LC_local
))
866 if (lc_categories
[category
].external
!= -lc_categories
[category
].internal
)
867 setlocale(lc_categories
[category
].external
, lcmake(NiL
)->name
);
869 locales
[category
] = lc
;
870 if (lc_categories
[category
].setf
&& (*lc_categories
[category
].setf
)(&lc_categories
[category
]))
872 locales
[category
] = lc_categories
[category
].prev
;
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
);
878 ast
.locale
.set
|= (1<<category
);
880 else if (lc_categories
[category
].flags
^ flags
)
882 lc_categories
[category
].flags
&= ~(LC_setenv
|LC_setlocale
);
883 lc_categories
[category
].flags
|= flags
;
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
;
893 * set composite AST_LC_ALL locale categories
894 * return <0:composite-error 0:not-composite >0:composite-ok
898 composite(register const char* s
, int initialize
)
900 register const char* t
;
908 int cat
[AST_LC_COUNT
];
909 int stk
[AST_LC_COUNT
];
910 char buf
[PATH_MAX
/ 2];
913 while (s
[0] == 'L' && s
[1] == 'C' && s
[2] == '_')
918 for (i
= 1; i
< AST_LC_COUNT
; i
++)
921 t
= lc_categories
[i
].name
;
922 while (*t
&& *s
++ == *t
++);
923 if (!*t
&& *s
++ == '=')
926 if (s
[0] != 'L' || s
[1] != 'C' || s
[2] != '_')
932 for (s
= w
; *s
&& *s
!= '='; s
++);
935 for (i
= 0; i
< k
; i
++)
936 single(stk
[i
], NiL
, 0);
947 else if (*s
++ == ';')
949 if ((m
= s
- w
- 1) >= sizeof(buf
))
957 for (i
= 0; i
< j
; i
++)
960 if (!single(cat
[i
], p
, 0))
962 for (i
= 0; i
< k
; i
++)
963 single(stk
[i
], NiL
, 0);
968 else if (!lc_categories
[cat
[i
]].prev
&& !(ast
.locale
.set
& AST_LC_internal
))
969 lc_categories
[cat
[i
]].prev
= p
;
971 while (s
[0] == '/' && s
[1] && n
< (AST_LC_COUNT
- 1))
974 for (w
= ++s
; *s
&& *s
!= '/'; s
++);
979 if ((j
= s
- w
- 1) >= sizeof(buf
))
987 if (!single(n
, p
, 0))
989 for (i
= 1; i
< n
; i
++)
994 else if (!lc_categories
[n
].prev
&& !(ast
.locale
.set
& AST_LC_internal
))
995 lc_categories
[n
].prev
= p
;
1001 * setlocale() intercept
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)
1012 _ast_setlocale(int category
, const char* locale
)
1020 int cat
[AST_LC_COUNT
];
1023 static int initialized
;
1024 static const char local
[] = "local";
1026 if ((category
= lcindex(category
, 0)) < 0)
1031 * return the current state
1035 if (category
!= AST_LC_ALL
&& category
!= AST_LC_LANG
)
1036 return (char*)locales
[category
]->name
;
1037 if (!sp
&& !(sp
= sfstropen()))
1039 for (i
= 1; i
< AST_LC_COUNT
; i
++)
1041 for (i
= 1, k
= 0; i
< AST_LC_COUNT
; i
++)
1046 for (j
= i
+ 1; j
< AST_LC_COUNT
; j
++)
1047 if (locales
[j
] == locales
[i
])
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
))
1057 for (j
= i
, k
= cat
[i
]; j
< AST_LC_COUNT
; j
++)
1061 sfprintf(sp
, "%s=", lc_categories
[j
].name
);
1063 sfprintf(sp
, "%s", locales
[i
]->name
);
1066 return (char*)locales
[0]->name
;
1067 return sfstruse(sp
);
1069 if (!ast
.locale
.serial
++)
1071 stropt(getenv("LC_OPTIONS"), options
, sizeof(*options
), setopt
, NiL
);
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
)
1079 p
= *locale
? lcmake(locale
) : (Lc_t
*)0;
1086 else if (category
== AST_LC_ALL
)
1094 * initialize from the environment
1095 * precedence determined by X/Open
1099 if ((s
= getenv("LANG")) && *s
)
1101 if (streq(s
, local
) && (u
|| (u
= native_locale(locale
, tmp
, sizeof(tmp
)))))
1107 if ((s
= getenv("LC_ALL")) && *s
)
1109 if (streq(s
, local
) && (u
|| (u
= native_locale(locale
, tmp
, sizeof(tmp
)))))
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
)
1120 if (streq(s
, local
) && (u
|| (u
= native_locale(locale
, tmp
, sizeof(tmp
)))))
1122 lc_categories
[i
].prev
= lcmake(s
);
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))
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);
1140 else if (category
== AST_LC_LANG
|| !(p
= lc_categories
[category
].prev
))
1147 if (category
== AST_LC_LANG
)
1153 for (i
= 1; i
< AST_LC_COUNT
; i
++)
1154 if (!single(i
, lc_categories
[i
].prev
, 0))
1162 else if (category
!= AST_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
;
1170 else if (composite(locale
, 0) < 0)
1172 else if (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))