14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin
244887Schin /*
254887Schin * setlocale() intercept
264887Schin * maintains a bitmask of non-default categories
274887Schin * and a permanent locale namespace for pointer comparison
284887Schin * and persistent private data for locale related functions
294887Schin */
304887Schin
314887Schin #include <ast_standards.h>
324887Schin
334887Schin #include "lclib.h"
344887Schin
354887Schin #include <ast_wchar.h>
364887Schin #include <ctype.h>
374887Schin #include <mc.h>
384887Schin #include <namval.h>
394887Schin
404887Schin #if ( _lib_wcwidth || _lib_wctomb ) && _hdr_wctype
414887Schin #include <wctype.h>
424887Schin #endif
434887Schin
444887Schin #if _lib_wcwidth
454887Schin #undef wcwidth
464887Schin #else
474887Schin #define wcwidth 0
484887Schin #endif
494887Schin
504887Schin #if _lib_wctomb
514887Schin #undef wctomb
524887Schin #else
534887Schin #define wctomb 0
544887Schin #endif
554887Schin
564887Schin #ifdef mblen
574887Schin #undef mblen
584887Schin extern int mblen(const char*, size_t);
594887Schin #endif
604887Schin
614887Schin #undef mbtowc
624887Schin #undef setlocale
634887Schin #undef strcmp
644887Schin #undef strcoll
654887Schin #undef strxfrm
664887Schin #undef valid
674887Schin
684887Schin #ifndef AST_LC_CANONICAL
694887Schin #define AST_LC_CANONICAL LC_abbreviated
704887Schin #endif
714887Schin
7210898Sroland.mainz@nrubsig.org #ifndef AST_LC_test
7310898Sroland.mainz@nrubsig.org #define AST_LC_test (1L<<27)
7410898Sroland.mainz@nrubsig.org #endif
7510898Sroland.mainz@nrubsig.org
764887Schin #if _UWIN
774887Schin
784887Schin #include <ast_windows.h>
794887Schin
804887Schin #undef _lib_setlocale
814887Schin #define _lib_setlocale 1
824887Schin
834887Schin #define setlocale(c,l) native_setlocale(c,l)
844887Schin
854887Schin extern char* uwin_setlocale(int, const char*);
864887Schin
874887Schin /*
884887Schin * convert locale to native locale name in buf
894887Schin */
904887Schin
914887Schin static char*
native_locale(const char * locale,char * buf,size_t siz)924887Schin native_locale(const char* locale, char* buf, size_t siz)
934887Schin {
944887Schin Lc_t* lc;
954887Schin const Lc_attribute_list_t* ap;
964887Schin int i;
974887Schin unsigned long lcid;
984887Schin unsigned long lang;
994887Schin unsigned long ctry;
1004887Schin char lbuf[128];
1014887Schin char cbuf[128];
1024887Schin
1034887Schin if (locale && *locale)
1044887Schin {
1054887Schin if (!(lc = lcmake(locale)))
1064887Schin return 0;
1074887Schin lang = lc->language->index;
1084887Schin ctry = 0;
1094887Schin for (ap = lc->attributes; ap; ap = ap->next)
1104887Schin if (ctry = ap->attribute->index)
1114887Schin break;
1124887Schin if (!ctry)
1134887Schin {
1144887Schin for (i = 0; i < elementsof(lc->territory->languages); i++)
1154887Schin if (lc->territory->languages[i] == lc->language)
1164887Schin {
1174887Schin ctry = lc->territory->indices[i];
1184887Schin break;
1194887Schin }
1204887Schin if (!ctry)
12110898Sroland.mainz@nrubsig.org {
12210898Sroland.mainz@nrubsig.org if (!lang)
12310898Sroland.mainz@nrubsig.org return 0;
1244887Schin ctry = SUBLANG_DEFAULT;
12510898Sroland.mainz@nrubsig.org }
1264887Schin }
1274887Schin lcid = MAKELCID(MAKELANGID(lang, ctry), SORT_DEFAULT);
1284887Schin }
1294887Schin else
1304887Schin lcid = GetUserDefaultLCID();
1314887Schin if (GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lbuf, sizeof(lbuf)) <= 0 ||
1324887Schin GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, cbuf, sizeof(cbuf)) <= 0)
1334887Schin return 0;
1344887Schin if (lc->charset->ms)
1354887Schin sfsprintf(buf, siz, "%s_%s.%s", lbuf, cbuf, lc->charset->ms);
1364887Schin else
1374887Schin sfsprintf(buf, siz, "%s_%s", lbuf, cbuf);
1384887Schin return buf;
1394887Schin }
1404887Schin
1414887Schin /*
1424887Schin * locale!=0 here
1434887Schin */
1444887Schin
1454887Schin static char*
native_setlocale(int category,const char * locale)1464887Schin native_setlocale(int category, const char* locale)
1474887Schin {
1484887Schin char* usr;
1494887Schin char* sys;
1504887Schin char buf[256];
1514887Schin
15210898Sroland.mainz@nrubsig.org if (!(usr = native_locale(locale, buf, sizeof(buf))))
15310898Sroland.mainz@nrubsig.org return 0;
15410898Sroland.mainz@nrubsig.org
1554887Schin /*
1564887Schin * win32 doesn't have LC_MESSAGES
1574887Schin */
1584887Schin
1594887Schin if (category == LC_MESSAGES)
1604887Schin return (char*)locale;
1614887Schin sys = uwin_setlocale(category, usr);
1624887Schin if (ast.locale.set & AST_LC_debug)
1638462SApril.Chin@Sun.COM sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", lc_categories[lcindex(category, 0)].name, usr, sys);
1644887Schin return sys;
1654887Schin }
1664887Schin
1674887Schin #else
1684887Schin
1694887Schin #define native_locale(a,b,c) ((char*)0)
1704887Schin
1714887Schin #endif
1724887Schin
1734887Schin /*
1744887Schin * LC_COLLATE and LC_CTYPE native support
1754887Schin */
1764887Schin
1774887Schin #if !_lib_mbtowc || MB_LEN_MAX <= 1
1784887Schin #define mblen 0
1794887Schin #define mbtowc 0
1804887Schin #endif
1814887Schin
1824887Schin #if !_lib_strcoll
1834887Schin #define strcoll 0
1844887Schin #endif
1854887Schin
1864887Schin #if !_lib_strxfrm
1874887Schin #define strxfrm 0
1884887Schin #endif
1894887Schin
1904887Schin /*
1914887Schin * LC_COLLATE and LC_CTYPE debug support
1924887Schin *
1934887Schin * mutibyte debug encoding
1944887Schin *
1954887Schin * DL0 [ '0' .. '4' ] c1 ... c4 DR0
1964887Schin * DL1 [ '0' .. '4' ] c1 ... c4 DR1
1974887Schin *
1984887Schin * with these ligatures
1994887Schin *
2004887Schin * ch CH sst SST
2014887Schin *
2024887Schin * and private collation order
2034887Schin *
2044887Schin * wide character display width is the low order 3 bits
2054887Schin * wctomb() uses DL1...DR1
2064887Schin */
2074887Schin
2084887Schin #define DEBUG_MB_CUR_MAX 7
2094887Schin
2104887Schin #if DEBUG_MB_CUR_MAX < MB_LEN_MAX
2114887Schin #undef DEBUG_MB_CUR_MAX
2124887Schin #define DEBUG_MB_CUR_MAX MB_LEN_MAX
2134887Schin #endif
2144887Schin
2154887Schin #define DL0 '<'
2164887Schin #define DL1 0xab /* 8-bit mini << on xterm */
2174887Schin #define DR0 '>'
2184887Schin #define DR1 0xbb /* 8-bit mini >> on xterm */
2194887Schin
2204887Schin #define DB ((int)sizeof(wchar_t)*8-1)
2214887Schin #define DC 7 /* wchar_t embedded char bits */
2224887Schin #define DX (DB/DC) /* wchar_t max embedded chars */
2234887Schin #define DZ (DB-DX*DC+1) /* wchar_t embedded size bits */
2244887Schin #define DD 3 /* # mb delimiter chars <n...> */
2254887Schin
2264887Schin static unsigned char debug_order[] =
2274887Schin {
2284887Schin 0, 1, 2, 3, 4, 5, 6, 7,
2294887Schin 8, 9, 10, 11, 12, 13, 14, 15,
2304887Schin 16, 17, 18, 19, 20, 21, 22, 23,
2314887Schin 24, 25, 26, 27, 28, 29, 30, 31,
2324887Schin 99, 100, 101, 102, 98, 103, 104, 105,
2334887Schin 106, 107, 108, 43, 109, 44, 42, 110,
2344887Schin 32, 33, 34, 35, 36, 37, 38, 39,
2354887Schin 40, 41, 111, 112, 113, 114, 115, 116,
2364887Schin 117, 71, 72, 73, 74, 75, 76, 77,
2374887Schin 78, 79, 80, 81, 82, 83, 84, 85,
2384887Schin 86, 87, 88, 89, 90, 91, 92, 93,
2394887Schin 94, 95, 96, 118, 119, 120, 121, 97,
2404887Schin 122, 45, 46, 47, 48, 49, 50, 51,
2414887Schin 52, 53, 54, 55, 56, 57, 58, 59,
2424887Schin 60, 61, 62, 63, 64, 65, 66, 67,
2434887Schin 68, 69, 70, 123, 124, 125, 126, 127,
2444887Schin 128, 129, 130, 131, 132, 133, 134, 135,
2454887Schin 136, 137, 138, 139, 140, 141, 142, 143,
2464887Schin 144, 145, 146, 147, 148, 149, 150, 151,
2474887Schin 152, 153, 154, 155, 156, 157, 158, 159,
2484887Schin 160, 161, 162, 163, 164, 165, 166, 167,
2494887Schin 168, 169, 170, 171, 172, 173, 174, 175,
2504887Schin 176, 177, 178, 179, 180, 181, 182, 183,
2514887Schin 184, 185, 186, 187, 188, 189, 190, 191,
2524887Schin 192, 193, 194, 195, 196, 197, 198, 199,
2534887Schin 200, 201, 202, 203, 204, 205, 206, 207,
2544887Schin 208, 209, 210, 211, 212, 213, 214, 215,
2554887Schin 216, 217, 218, 219, 220, 221, 222, 223,
2564887Schin 224, 225, 226, 227, 228, 229, 230, 231,
2574887Schin 232, 233, 234, 235, 236, 237, 238, 239,
2584887Schin 240, 241, 242, 243, 244, 245, 246, 247,
2594887Schin 248, 249, 250, 251, 252, 253, 254, 255,
2604887Schin };
2614887Schin
2624887Schin static int
debug_mbtowc(register wchar_t * p,register const char * s,size_t n)2634887Schin debug_mbtowc(register wchar_t* p, register const char* s, size_t n)
2644887Schin {
2654887Schin register const char* q;
2664887Schin register const char* r;
2674887Schin register int w;
2684887Schin register int dr;
2694887Schin wchar_t c;
2704887Schin
2714887Schin if (n < 1)
2724887Schin return -1;
2734887Schin if (!s || !*s)
2744887Schin return 0;
2754887Schin switch (((unsigned char*)s)[0])
2764887Schin {
2774887Schin case DL0:
2784887Schin dr = DR0;
2794887Schin break;
2804887Schin case DL1:
2814887Schin dr = DR1;
2824887Schin break;
2834887Schin default:
2844887Schin if (p)
2854887Schin *p = ((unsigned char*)s)[0] & ((1<<DC)-1);
2864887Schin return 1;
2874887Schin }
2884887Schin if (n < 2)
2894887Schin return -1;
2904887Schin if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0])
2914887Schin {
2924887Schin if (p)
2934887Schin *p = w;
2944887Schin return 2;
2954887Schin }
2964887Schin if (w < '0' || w > ('0' + DX))
2974887Schin return -1;
2984887Schin if ((w -= '0' - DD) > n)
2994887Schin return -1;
3004887Schin r = s + w - 1;
3014887Schin q = s += 2;
3024887Schin while (q < r && *q)
3034887Schin q++;
3044887Schin if (q != r || *((unsigned char*)q) != dr)
3054887Schin return -1;
3064887Schin if (p)
3074887Schin {
3084887Schin c = 0;
3094887Schin while (--q >= s)
3104887Schin {
3114887Schin c <<= DC;
3124887Schin c |= *((unsigned char*)q);
3134887Schin }
3144887Schin c <<= DZ;
3154887Schin c |= w - DD;
3164887Schin *p = c;
3174887Schin }
3184887Schin return w;
3194887Schin }
3204887Schin
3214887Schin static int
debug_wctomb(char * s,wchar_t c)3224887Schin debug_wctomb(char* s, wchar_t c)
3234887Schin {
3244887Schin int w;
3254887Schin int i;
3264887Schin int k;
3274887Schin
3284887Schin w = 0;
3294887Schin if (c >= 0 && c <= UCHAR_MAX)
3304887Schin {
3314887Schin w++;
3324887Schin if (s)
3334887Schin *s = c;
3344887Schin }
3354887Schin else if ((i = c & ((1<<DZ)-1)) > DX)
3364887Schin return -1;
3374887Schin else
3384887Schin {
3394887Schin w++;
3404887Schin if (s)
3414887Schin *s++ = DL1;
3424887Schin c >>= DZ;
3434887Schin w++;
3444887Schin if (s)
3454887Schin *s++ = i + '0';
3464887Schin while (i--)
3474887Schin {
3484887Schin w++;
3494887Schin if (s)
3504887Schin *s++ = (k = c & ((1<<DC)-1)) ? k : '?';
3514887Schin c >>= DC;
3524887Schin }
3534887Schin w++;
3544887Schin if (s)
3554887Schin *s++ = DR1;
3564887Schin }
3574887Schin return w;
3584887Schin }
3594887Schin
3604887Schin static int
debug_mblen(const char * s,size_t n)3614887Schin debug_mblen(const char* s, size_t n)
3624887Schin {
3634887Schin return debug_mbtowc(NiL, s, n);
3644887Schin }
3654887Schin
3664887Schin static int
debug_wcwidth(wchar_t c)3674887Schin debug_wcwidth(wchar_t c)
3684887Schin {
3694887Schin if (c >= 0 && c <= UCHAR_MAX)
3704887Schin return 1;
3714887Schin if ((c &= ((1<<DZ)-1)) > DX)
3724887Schin return -1;
3734887Schin return c + DD;
3744887Schin }
3754887Schin
3764887Schin static size_t
debug_strxfrm(register char * t,register const char * s,size_t n)3774887Schin debug_strxfrm(register char* t, register const char* s, size_t n)
3784887Schin {
3794887Schin register const char* q;
3804887Schin register const char* r;
3814887Schin register char* e;
3828462SApril.Chin@Sun.COM char* o;
3834887Schin register size_t z;
3844887Schin register int w;
3854887Schin
3868462SApril.Chin@Sun.COM o = t;
3874887Schin z = 0;
3884887Schin if (e = t)
3894887Schin e += n;
3904887Schin while (s[0])
3914887Schin {
3924887Schin if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC))
3934887Schin {
3944887Schin w -= '0';
3954887Schin q = s + 2;
3964887Schin r = q + w;
3974887Schin while (q < r && *q)
3984887Schin q++;
3994887Schin if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1)
4004887Schin {
4014887Schin if (t)
4024887Schin {
4034887Schin for (q = s + 2; q < r; q++)
4044887Schin if (t < e)
4054887Schin *t++ = debug_order[*q];
4064887Schin while (w++ < DX)
4074887Schin if (t < e)
4084887Schin *t++ = 1;
4094887Schin }
4104887Schin s = r + 1;
4114887Schin z += DX;
4124887Schin continue;
4134887Schin }
4144887Schin }
4154887Schin if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H'))
4164887Schin {
4174887Schin if (t)
4184887Schin {
4194887Schin if (t < e)
4204887Schin *t++ = debug_order[s[0]];
4214887Schin if (t < e)
4224887Schin *t++ = debug_order[s[1]];
4234887Schin if (t < e)
4244887Schin *t++ = 1;
4254887Schin if (t < e)
4264887Schin *t++ = 1;
4274887Schin }
4284887Schin s += 2;
4294887Schin z += DX;
4304887Schin continue;
4314887Schin }
4324887Schin if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T'))
4334887Schin {
4344887Schin if (t)
4354887Schin {
4364887Schin if (t < e)
4374887Schin *t++ = debug_order[s[0]];
4384887Schin if (t < e)
4394887Schin *t++ = debug_order[s[1]];
4404887Schin if (t < e)
4414887Schin *t++ = debug_order[s[2]];
4424887Schin if (t < e)
4434887Schin *t++ = 1;
4444887Schin }
4454887Schin s += 3;
4464887Schin z += DX;
4474887Schin continue;
4484887Schin }
4494887Schin if (t)
4504887Schin {
4514887Schin if (t < e)
4524887Schin *t++ = debug_order[s[0]];
4534887Schin if (t < e)
4544887Schin *t++ = 1;
4554887Schin if (t < e)
4564887Schin *t++ = 1;
4574887Schin if (t < e)
4584887Schin *t++ = 1;
4594887Schin }
4604887Schin s++;
4614887Schin z += DX;
4624887Schin }
4638462SApril.Chin@Sun.COM if (!t)
4648462SApril.Chin@Sun.COM return z;
4654887Schin if (t < e)
4664887Schin *t = 0;
4678462SApril.Chin@Sun.COM return t - o;
4684887Schin }
4694887Schin
4704887Schin static int
debug_strcoll(const char * a,const char * b)4714887Schin debug_strcoll(const char* a, const char* b)
4724887Schin {
4734887Schin char ab[1024];
4744887Schin char bb[1024];
4754887Schin
4764887Schin debug_strxfrm(ab, a, sizeof(ab) - 1);
4774887Schin ab[sizeof(ab)-1] = 0;
4784887Schin debug_strxfrm(bb, b, sizeof(bb) - 1);
4794887Schin bb[sizeof(bb)-1] = 0;
4804887Schin return strcmp(ab, bb);
4814887Schin }
4824887Schin
4834887Schin /*
4844887Schin * default locale
4854887Schin */
4864887Schin
4874887Schin static int
default_wcwidth(wchar_t w)4884887Schin default_wcwidth(wchar_t w)
4894887Schin {
4904887Schin return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1;
4914887Schin }
4924887Schin
4934887Schin /*
4944887Schin * called when LC_COLLATE initialized or changes
4954887Schin */
4964887Schin
4974887Schin static int
set_collate(Lc_category_t * cp)4984887Schin set_collate(Lc_category_t* cp)
4994887Schin {
5004887Schin if (locales[cp->internal]->flags & LC_debug)
5014887Schin {
5024887Schin ast.collate = debug_strcoll;
5034887Schin ast.mb_xfrm = debug_strxfrm;
5044887Schin }
5054887Schin else if (locales[cp->internal]->flags & LC_default)
5064887Schin {
5074887Schin ast.collate = strcmp;
5084887Schin ast.mb_xfrm = 0;
5094887Schin }
5104887Schin else
5114887Schin {
5124887Schin ast.collate = strcoll;
5134887Schin ast.mb_xfrm = strxfrm;
5144887Schin }
5154887Schin return 0;
5164887Schin }
5174887Schin
5184887Schin /*
5198462SApril.Chin@Sun.COM * workaround the interesting sjis that translates unshifted 7 bit ascii!
5208462SApril.Chin@Sun.COM */
5218462SApril.Chin@Sun.COM
5228462SApril.Chin@Sun.COM #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc
5238462SApril.Chin@Sun.COM
5248462SApril.Chin@Sun.COM #define mb_state_zero ((mbstate_t*)&ast.pad[sizeof(ast.pad)-2*sizeof(mbstate_t)])
5258462SApril.Chin@Sun.COM #define mb_state ((mbstate_t*)&ast.pad[sizeof(ast.pad)-sizeof(mbstate_t)])
5268462SApril.Chin@Sun.COM
5278462SApril.Chin@Sun.COM static int
sjis_mbtowc(register wchar_t * p,register const char * s,size_t n)5288462SApril.Chin@Sun.COM sjis_mbtowc(register wchar_t* p, register const char* s, size_t n)
5298462SApril.Chin@Sun.COM {
5308462SApril.Chin@Sun.COM if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t)))
5318462SApril.Chin@Sun.COM {
5328462SApril.Chin@Sun.COM *p = *s;
5338462SApril.Chin@Sun.COM return 1;
5348462SApril.Chin@Sun.COM }
5358462SApril.Chin@Sun.COM return mbrtowc(p, s, n, mb_state);
5368462SApril.Chin@Sun.COM }
5378462SApril.Chin@Sun.COM
5388462SApril.Chin@Sun.COM #endif
5398462SApril.Chin@Sun.COM
54010898Sroland.mainz@nrubsig.org #define utf8_wctomb wctomb
54110898Sroland.mainz@nrubsig.org
54210898Sroland.mainz@nrubsig.org static const uint32_t utf8mask[] =
54310898Sroland.mainz@nrubsig.org {
54410898Sroland.mainz@nrubsig.org 0x00000000,
54510898Sroland.mainz@nrubsig.org 0x00000000,
54610898Sroland.mainz@nrubsig.org 0xffffff80,
54710898Sroland.mainz@nrubsig.org 0xfffff800,
54810898Sroland.mainz@nrubsig.org 0xffff0000,
54910898Sroland.mainz@nrubsig.org 0xffe00000,
55010898Sroland.mainz@nrubsig.org 0xfc000000,
55110898Sroland.mainz@nrubsig.org };
55210898Sroland.mainz@nrubsig.org
55310898Sroland.mainz@nrubsig.org static const signed char utf8tab[256] =
55410898Sroland.mainz@nrubsig.org {
55510898Sroland.mainz@nrubsig.org 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55610898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55710898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55810898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55910898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56010898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56110898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56210898Sroland.mainz@nrubsig.org 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56310898Sroland.mainz@nrubsig.org 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56410898Sroland.mainz@nrubsig.org 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56510898Sroland.mainz@nrubsig.org 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56610898Sroland.mainz@nrubsig.org 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56710898Sroland.mainz@nrubsig.org 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56810898Sroland.mainz@nrubsig.org 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56910898Sroland.mainz@nrubsig.org 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
57010898Sroland.mainz@nrubsig.org 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,-1,-1,
57110898Sroland.mainz@nrubsig.org };
57210898Sroland.mainz@nrubsig.org
57310898Sroland.mainz@nrubsig.org static int
utf8_mbtowc(wchar_t * wp,const char * str,size_t n)57410898Sroland.mainz@nrubsig.org utf8_mbtowc(wchar_t* wp, const char* str, size_t n)
57510898Sroland.mainz@nrubsig.org {
57610898Sroland.mainz@nrubsig.org register unsigned char* sp = (unsigned char*)str;
57710898Sroland.mainz@nrubsig.org register int m;
57810898Sroland.mainz@nrubsig.org register int i;
57910898Sroland.mainz@nrubsig.org register int c;
58010898Sroland.mainz@nrubsig.org register wchar_t w = 0;
58110898Sroland.mainz@nrubsig.org
58210898Sroland.mainz@nrubsig.org if (!sp || !n)
58310898Sroland.mainz@nrubsig.org return 0;
58410898Sroland.mainz@nrubsig.org if ((m = utf8tab[*sp]) > 0)
58510898Sroland.mainz@nrubsig.org {
58610898Sroland.mainz@nrubsig.org if (m > n)
58710898Sroland.mainz@nrubsig.org return -1;
58810898Sroland.mainz@nrubsig.org if (wp)
58910898Sroland.mainz@nrubsig.org {
59010898Sroland.mainz@nrubsig.org if (m == 1)
59110898Sroland.mainz@nrubsig.org {
59210898Sroland.mainz@nrubsig.org *wp = *sp;
59310898Sroland.mainz@nrubsig.org return 1;
59410898Sroland.mainz@nrubsig.org }
59510898Sroland.mainz@nrubsig.org w = *sp & ((1<<(8-m))-1);
59610898Sroland.mainz@nrubsig.org for (i = m - 1; i > 0; i--)
59710898Sroland.mainz@nrubsig.org {
59810898Sroland.mainz@nrubsig.org c = *++sp;
59910898Sroland.mainz@nrubsig.org if ((c&0xc0) != 0x80)
60010898Sroland.mainz@nrubsig.org goto invalid;
60110898Sroland.mainz@nrubsig.org w = (w<<6) | (c&0x3f);
60210898Sroland.mainz@nrubsig.org }
60310898Sroland.mainz@nrubsig.org if (!(utf8mask[m] & w) || w >= 0xd800 && (w <= 0xdfff || w >= 0xfffe && w <= 0xffff))
60410898Sroland.mainz@nrubsig.org goto invalid;
60510898Sroland.mainz@nrubsig.org *wp = w;
60610898Sroland.mainz@nrubsig.org }
60710898Sroland.mainz@nrubsig.org return m;
60810898Sroland.mainz@nrubsig.org }
60910898Sroland.mainz@nrubsig.org if (!*sp)
61010898Sroland.mainz@nrubsig.org return 0;
61110898Sroland.mainz@nrubsig.org invalid:
61210898Sroland.mainz@nrubsig.org #ifdef EILSEQ
61310898Sroland.mainz@nrubsig.org errno = EILSEQ;
61410898Sroland.mainz@nrubsig.org #endif
61510898Sroland.mainz@nrubsig.org ast.mb_sync = (const char*)sp - str;
61610898Sroland.mainz@nrubsig.org return -1;
61710898Sroland.mainz@nrubsig.org }
61810898Sroland.mainz@nrubsig.org
61910898Sroland.mainz@nrubsig.org static int
utf8_mblen(const char * str,size_t n)62010898Sroland.mainz@nrubsig.org utf8_mblen(const char* str, size_t n)
62110898Sroland.mainz@nrubsig.org {
62210898Sroland.mainz@nrubsig.org wchar_t w;
62310898Sroland.mainz@nrubsig.org
62410898Sroland.mainz@nrubsig.org return utf8_mbtowc(&w, str, n);
62510898Sroland.mainz@nrubsig.org }
62610898Sroland.mainz@nrubsig.org
6278462SApril.Chin@Sun.COM /*
6284887Schin * called when LC_CTYPE initialized or changes
6294887Schin */
6304887Schin
6314887Schin static int
set_ctype(Lc_category_t * cp)6324887Schin set_ctype(Lc_category_t* cp)
6334887Schin {
63410898Sroland.mainz@nrubsig.org ast.mb_sync = 0;
6354887Schin if (locales[cp->internal]->flags & LC_debug)
6364887Schin {
6374887Schin ast.mb_cur_max = DEBUG_MB_CUR_MAX;
6384887Schin ast.mb_len = debug_mblen;
6394887Schin ast.mb_towc = debug_mbtowc;
6404887Schin ast.mb_width = debug_wcwidth;
6414887Schin ast.mb_conv = debug_wctomb;
6424887Schin }
6434887Schin else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc))
6444887Schin {
6454887Schin ast.mb_cur_max = 1;
6464887Schin ast.mb_len = 0;
6474887Schin ast.mb_towc = 0;
6484887Schin ast.mb_width = default_wcwidth;
6494887Schin ast.mb_conv = 0;
6504887Schin }
65110898Sroland.mainz@nrubsig.org else if ((locales[cp->internal]->flags & LC_utf8) && !(ast.locale.set & AST_LC_test))
65210898Sroland.mainz@nrubsig.org {
65310898Sroland.mainz@nrubsig.org ast.mb_cur_max = 6;
65410898Sroland.mainz@nrubsig.org ast.mb_len = utf8_mblen;
65510898Sroland.mainz@nrubsig.org ast.mb_towc = utf8_mbtowc;
65610898Sroland.mainz@nrubsig.org if (!(ast.mb_width = wcwidth))
65710898Sroland.mainz@nrubsig.org ast.mb_width = default_wcwidth;
65810898Sroland.mainz@nrubsig.org ast.mb_conv = utf8_wctomb;
65910898Sroland.mainz@nrubsig.org }
6604887Schin else
6614887Schin {
6624887Schin if (!(ast.mb_width = wcwidth))
6634887Schin ast.mb_width = default_wcwidth;
6644887Schin ast.mb_conv = wctomb;
6658462SApril.Chin@Sun.COM #ifdef mb_state
6668462SApril.Chin@Sun.COM {
6678462SApril.Chin@Sun.COM /*
6688462SApril.Chin@Sun.COM * check for sjis that translates unshifted 7 bit ascii!
6698462SApril.Chin@Sun.COM */
6708462SApril.Chin@Sun.COM
6718462SApril.Chin@Sun.COM char* s;
6728462SApril.Chin@Sun.COM char buf[2];
6738462SApril.Chin@Sun.COM
6748462SApril.Chin@Sun.COM mbinit();
6758462SApril.Chin@Sun.COM buf[1] = 0;
6768462SApril.Chin@Sun.COM *(s = buf) = '\\';
6778462SApril.Chin@Sun.COM if (mbchar(s) != buf[0])
6788462SApril.Chin@Sun.COM {
6798462SApril.Chin@Sun.COM memcpy(mb_state, mb_state_zero, sizeof(mbstate_t));
6808462SApril.Chin@Sun.COM ast.mb_towc = sjis_mbtowc;
6818462SApril.Chin@Sun.COM }
6828462SApril.Chin@Sun.COM }
6838462SApril.Chin@Sun.COM #endif
6844887Schin }
68510898Sroland.mainz@nrubsig.org if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
68610898Sroland.mainz@nrubsig.org sfprintf(sfstderr, "locale info %17s MB_CUR_MAX=%d%s%s%s%s\n"
68710898Sroland.mainz@nrubsig.org , cp->name
68810898Sroland.mainz@nrubsig.org , ast.mb_cur_max
68910898Sroland.mainz@nrubsig.org , ast.mb_len == debug_mblen ? " debug_mblen" : ast.mb_len == mblen ? " mblen" : ""
69010898Sroland.mainz@nrubsig.org , ast.mb_towc == debug_mbtowc ? " debug_mbtowc" : ast.mb_towc == mbtowc ? " mbtowc"
69110898Sroland.mainz@nrubsig.org #ifdef mb_state
69210898Sroland.mainz@nrubsig.org : ast.mb_towc == sjis_mbtowc ? " sjis_mbtowc"
69310898Sroland.mainz@nrubsig.org #endif
69410898Sroland.mainz@nrubsig.org : ""
69510898Sroland.mainz@nrubsig.org , ast.mb_width == debug_wcwidth ? " debug_wcwidth" : ast.mb_width == wcwidth ? " wcwidth" : ast.mb_width == default_wcwidth ? " default_wcwidth" : ""
69610898Sroland.mainz@nrubsig.org , ast.mb_conv == debug_wctomb ? " debug_wctomb" : ast.mb_conv == wctomb ? " wctomb" : ""
69710898Sroland.mainz@nrubsig.org );
6984887Schin return 0;
6994887Schin }
7004887Schin
7014887Schin /*
7024887Schin * called when LC_NUMERIC initialized or changes
7034887Schin */
7044887Schin
7054887Schin static int
set_numeric(Lc_category_t * cp)7064887Schin set_numeric(Lc_category_t* cp)
7074887Schin {
7084887Schin register int category = cp->internal;
7094887Schin struct lconv* lp;
7104887Schin Lc_numeric_t* dp;
7114887Schin
7124887Schin static Lc_numeric_t default_numeric = { '.', -1 };
7134887Schin
7144887Schin if (!LCINFO(category)->data)
7154887Schin {
7164887Schin if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0)))
7174887Schin {
7184887Schin dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.';
7194887Schin dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1;
7204887Schin }
7214887Schin else
7224887Schin dp = &default_numeric;
7234887Schin LCINFO(category)->data = (void*)dp;
7244887Schin if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
7258462SApril.Chin@Sun.COM sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X');
7264887Schin }
7274887Schin return 0;
7284887Schin }
7294887Schin
7304887Schin /*
7314887Schin * this table is indexed by AST_LC_[A-Z]*
7324887Schin */
7334887Schin
7348462SApril.Chin@Sun.COM Lc_category_t lc_categories[] =
7354887Schin {
7364887Schin { "LC_ALL", LC_ALL, AST_LC_ALL, 0 },
7374887Schin { "LC_COLLATE", LC_COLLATE, AST_LC_COLLATE, set_collate },
7384887Schin { "LC_CTYPE", LC_CTYPE, AST_LC_CTYPE, set_ctype },
7394887Schin { "LC_MESSAGES", LC_MESSAGES, AST_LC_MESSAGES, 0 },
7404887Schin { "LC_MONETARY", LC_MONETARY, AST_LC_MONETARY, 0 },
7414887Schin { "LC_NUMERIC", LC_NUMERIC, AST_LC_NUMERIC, set_numeric },
7424887Schin { "LC_TIME", LC_TIME, AST_LC_TIME, 0 },
7434887Schin { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0 },
7444887Schin { "LC_ADDRESS", LC_ADDRESS, AST_LC_ADDRESS, 0 },
7454887Schin { "LC_NAME", LC_NAME, AST_LC_NAME, 0 },
7464887Schin { "LC_TELEPHONE", LC_TELEPHONE, AST_LC_TELEPHONE, 0 },
7474887Schin { "LC_XLITERATE", LC_XLITERATE, AST_LC_XLITERATE, 0 },
7484887Schin { "LC_MEASUREMENT", LC_MEASUREMENT, AST_LC_MEASUREMENT, 0 },
7494887Schin { "LC_PAPER", LC_PAPER, AST_LC_PAPER, 0 },
7504887Schin };
7514887Schin
75210898Sroland.mainz@nrubsig.org static Lc_t* lang;
75310898Sroland.mainz@nrubsig.org static Lc_t* lc_all;
75410898Sroland.mainz@nrubsig.org
75510898Sroland.mainz@nrubsig.org typedef struct Unamval_s
75610898Sroland.mainz@nrubsig.org {
75710898Sroland.mainz@nrubsig.org char* name;
75810898Sroland.mainz@nrubsig.org unsigned int value;
75910898Sroland.mainz@nrubsig.org } Unamval_t;
76010898Sroland.mainz@nrubsig.org
76110898Sroland.mainz@nrubsig.org static const Unamval_t options[] =
7624887Schin {
7634887Schin "debug", AST_LC_debug,
7644887Schin "find", AST_LC_find,
7654887Schin "setlocale", AST_LC_setlocale,
76610898Sroland.mainz@nrubsig.org "test", AST_LC_test,
7674887Schin "translate", AST_LC_translate,
7684887Schin 0, 0
7694887Schin };
7704887Schin
7714887Schin /*
7724887Schin * called by stropt() to set options
7734887Schin */
7744887Schin
7754887Schin static int
setopt(void * a,const void * p,int n,const char * v)7764887Schin setopt(void* a, const void* p, int n, const char* v)
7774887Schin {
7784887Schin if (p)
7794887Schin {
7804887Schin if (n)
78110898Sroland.mainz@nrubsig.org ast.locale.set |= ((Unamval_t*)p)->value;
7824887Schin else
78310898Sroland.mainz@nrubsig.org ast.locale.set &= ~((Unamval_t*)p)->value;
7844887Schin }
7854887Schin return 0;
7864887Schin }
7874887Schin
7884887Schin #if !_lib_setlocale
7894887Schin
7904887Schin #define setlocale(c,l) default_setlocale(c,l)
7914887Schin
7924887Schin static char*
default_setlocale(int category,const char * locale)7934887Schin default_setlocale(int category, const char* locale)
7944887Schin {
7954887Schin Lc_t* lc;
7964887Schin
7974887Schin if (locale)
7984887Schin {
7994887Schin if (!(lc = lcmake(locale)) || !(lc->flags & LC_default))
8004887Schin return 0;
8014887Schin locales[0]->flags &= ~lc->flags;
8024887Schin locales[1]->flags &= ~lc->flags;
8034887Schin return lc->name;
8044887Schin }
8054887Schin return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name;
8064887Schin }
8074887Schin
8084887Schin #endif
8094887Schin
8104887Schin /*
8114887Schin * set a single AST_LC_* locale category
8124887Schin * the caller must validate category
8134887Schin * lc==0 restores the previous state
8144887Schin */
8154887Schin
8164887Schin static char*
single(int category,Lc_t * lc,unsigned int flags)817*12068SRoger.Faulkner@Oracle.COM single(int category, Lc_t* lc, unsigned int flags)
8184887Schin {
8194887Schin const char* sys;
8204887Schin int i;
8214887Schin
822*12068SRoger.Faulkner@Oracle.COM if (flags & (LC_setenv|LC_setlocale))
823*12068SRoger.Faulkner@Oracle.COM {
824*12068SRoger.Faulkner@Oracle.COM if (!(ast.locale.set & AST_LC_internal))
825*12068SRoger.Faulkner@Oracle.COM lc_categories[category].prev = lc;
826*12068SRoger.Faulkner@Oracle.COM if ((flags & LC_setenv) && lc_all && locales[category])
827*12068SRoger.Faulkner@Oracle.COM return (char*)locales[category]->name;
828*12068SRoger.Faulkner@Oracle.COM }
829*12068SRoger.Faulkner@Oracle.COM if (!lc && (!(lc_categories[category].flags & LC_setlocale) || !(lc = lc_categories[category].prev)) && !(lc = lc_all) && !(lc = lc_categories[category].prev) && !(lc = lang))
8304887Schin lc = lcmake(NiL);
831*12068SRoger.Faulkner@Oracle.COM sys = 0;
8324887Schin if (locales[category] != lc)
8334887Schin {
8348462SApril.Chin@Sun.COM if (lc_categories[category].external == -lc_categories[category].internal)
8354887Schin {
8364887Schin for (i = 1; i < AST_LC_COUNT; i++)
8374887Schin if (locales[i] == lc)
8384887Schin {
8394887Schin sys = (char*)lc->name;
8404887Schin break;
8414887Schin }
8424887Schin }
8434887Schin else if (lc->flags & (LC_debug|LC_local))
8448462SApril.Chin@Sun.COM sys = setlocale(lc_categories[category].external, lcmake(NiL)->name);
8458462SApril.Chin@Sun.COM else if (!(sys = setlocale(lc_categories[category].external, lc->name)) &&
8468462SApril.Chin@Sun.COM (streq(lc->name, lc->code) || !(sys = setlocale(lc_categories[category].external, lc->code))) &&
8474887Schin !streq(lc->code, lc->language->code))
8488462SApril.Chin@Sun.COM sys = setlocale(lc_categories[category].external, lc->language->code);
8494887Schin if (!sys)
8504887Schin {
8514887Schin /*
8524887Schin * check for local override
8534887Schin * currently this means an LC_MESSAGES dir exists
8544887Schin */
8554887Schin
8564887Schin if (!(lc->flags & LC_checked))
8574887Schin {
8584887Schin char path[PATH_MAX];
8594887Schin
8604887Schin if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0))
8614887Schin lc->flags |= LC_local;
8624887Schin lc->flags |= LC_checked;
8634887Schin }
8644887Schin if (!(lc->flags & LC_local))
8654887Schin return 0;
8668462SApril.Chin@Sun.COM if (lc_categories[category].external != -lc_categories[category].internal)
8678462SApril.Chin@Sun.COM setlocale(lc_categories[category].external, lcmake(NiL)->name);
8684887Schin }
8694887Schin locales[category] = lc;
8708462SApril.Chin@Sun.COM if (lc_categories[category].setf && (*lc_categories[category].setf)(&lc_categories[category]))
8714887Schin {
8728462SApril.Chin@Sun.COM locales[category] = lc_categories[category].prev;
8734887Schin return 0;
8744887Schin }
87510898Sroland.mainz@nrubsig.org 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'))
8764887Schin ast.locale.set &= ~(1<<category);
8774887Schin else
8784887Schin ast.locale.set |= (1<<category);
8794887Schin }
880*12068SRoger.Faulkner@Oracle.COM else if (lc_categories[category].flags ^ flags)
881*12068SRoger.Faulkner@Oracle.COM {
882*12068SRoger.Faulkner@Oracle.COM lc_categories[category].flags &= ~(LC_setenv|LC_setlocale);
883*12068SRoger.Faulkner@Oracle.COM lc_categories[category].flags |= flags;
884*12068SRoger.Faulkner@Oracle.COM }
885*12068SRoger.Faulkner@Oracle.COM else
886*12068SRoger.Faulkner@Oracle.COM return (char*)lc->name;
887*12068SRoger.Faulkner@Oracle.COM if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
888*12068SRoger.Faulkner@Oracle.COM 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]" : "");
8894887Schin return (char*)lc->name;
8904887Schin }
8914887Schin
8924887Schin /*
8934887Schin * set composite AST_LC_ALL locale categories
8944887Schin * return <0:composite-error 0:not-composite >0:composite-ok
8954887Schin */
8964887Schin
8974887Schin static int
composite(register const char * s,int initialize)8984887Schin composite(register const char* s, int initialize)
8994887Schin {
9004887Schin register const char* t;
9014887Schin register int i;
9024887Schin register int j;
9034887Schin register int k;
9044887Schin int n;
90510898Sroland.mainz@nrubsig.org int m;
9064887Schin const char* w;
9074887Schin Lc_t* p;
9084887Schin int cat[AST_LC_COUNT];
9094887Schin int stk[AST_LC_COUNT];
9104887Schin char buf[PATH_MAX / 2];
9114887Schin
9124887Schin k = n = 0;
9134887Schin while (s[0] == 'L' && s[1] == 'C' && s[2] == '_')
9144887Schin {
9154887Schin n++;
9164887Schin j = 0;
9174887Schin w = s;
9184887Schin for (i = 1; i < AST_LC_COUNT; i++)
9194887Schin {
9204887Schin s = w;
9218462SApril.Chin@Sun.COM t = lc_categories[i].name;
9224887Schin while (*t && *s++ == *t++);
9234887Schin if (!*t && *s++ == '=')
9244887Schin {
9254887Schin cat[j++] = i;
9264887Schin if (s[0] != 'L' || s[1] != 'C' || s[2] != '_')
9274887Schin break;
9284887Schin w = s;
9294887Schin i = -1;
9304887Schin }
9314887Schin }
9324887Schin for (s = w; *s && *s != '='; s++);
9334887Schin if (!*s)
9344887Schin {
9354887Schin for (i = 0; i < k; i++)
936*12068SRoger.Faulkner@Oracle.COM single(stk[i], NiL, 0);
9374887Schin return -1;
9384887Schin }
9394887Schin w = ++s;
9404887Schin for (;;)
9414887Schin {
9424887Schin if (!*s)
9434887Schin {
9444887Schin p = lcmake(w);
9454887Schin break;
9464887Schin }
9474887Schin else if (*s++ == ';')
9484887Schin {
94910898Sroland.mainz@nrubsig.org if ((m = s - w - 1) >= sizeof(buf))
95010898Sroland.mainz@nrubsig.org m = sizeof(buf) - 1;
95110898Sroland.mainz@nrubsig.org memcpy(buf, w, m);
95210898Sroland.mainz@nrubsig.org buf[m] = 0;
9534887Schin p = lcmake(buf);
9544887Schin break;
9554887Schin }
9564887Schin }
9574887Schin for (i = 0; i < j; i++)
9584887Schin if (!initialize)
9594887Schin {
960*12068SRoger.Faulkner@Oracle.COM if (!single(cat[i], p, 0))
9614887Schin {
9624887Schin for (i = 0; i < k; i++)
963*12068SRoger.Faulkner@Oracle.COM single(stk[i], NiL, 0);
9644887Schin return -1;
9654887Schin }
9664887Schin stk[k++] = cat[i];
9674887Schin }
968*12068SRoger.Faulkner@Oracle.COM else if (!lc_categories[cat[i]].prev && !(ast.locale.set & AST_LC_internal))
9698462SApril.Chin@Sun.COM lc_categories[cat[i]].prev = p;
9704887Schin }
97110898Sroland.mainz@nrubsig.org while (s[0] == '/' && s[1] && n < (AST_LC_COUNT - 1))
9724887Schin {
9734887Schin n++;
9744887Schin for (w = ++s; *s && *s != '/'; s++);
9754887Schin if (!*s)
9764887Schin p = lcmake(w);
9774887Schin else
9784887Schin {
9794887Schin if ((j = s - w - 1) >= sizeof(buf))
9804887Schin j = sizeof(buf) - 1;
9814887Schin memcpy(buf, w, j);
9824887Schin buf[j] = 0;
9834887Schin p = lcmake(buf);
9844887Schin }
9854887Schin if (!initialize)
9864887Schin {
987*12068SRoger.Faulkner@Oracle.COM if (!single(n, p, 0))
9884887Schin {
9894887Schin for (i = 1; i < n; i++)
990*12068SRoger.Faulkner@Oracle.COM single(i, NiL, 0);
9914887Schin return -1;
9924887Schin }
9934887Schin }
994*12068SRoger.Faulkner@Oracle.COM else if (!lc_categories[n].prev && !(ast.locale.set & AST_LC_internal))
9958462SApril.Chin@Sun.COM lc_categories[n].prev = p;
9964887Schin }
9974887Schin return n;
9984887Schin }
9994887Schin
10004887Schin /*
10014887Schin * setlocale() intercept
100210898Sroland.mainz@nrubsig.org *
100310898Sroland.mainz@nrubsig.org * locale:
100410898Sroland.mainz@nrubsig.org * 0 query
1005*12068SRoger.Faulkner@Oracle.COM * "" initialize from environment (if LC_ALL)
1006*12068SRoger.Faulkner@Oracle.COM * "" AST_LC_setenv: value unset (defer to LANG)
1007*12068SRoger.Faulkner@Oracle.COM * "*" AST_LC_setenv: value set (defer to LC_ALL)
1008*12068SRoger.Faulkner@Oracle.COM * * set (override LC_ALL)
10094887Schin */
10104887Schin
10114887Schin char*
_ast_setlocale(int category,const char * locale)10124887Schin _ast_setlocale(int category, const char* locale)
10134887Schin {
10144887Schin register char* s;
10154887Schin register int i;
10164887Schin register int j;
10174887Schin int k;
1018*12068SRoger.Faulkner@Oracle.COM int f;
10194887Schin Lc_t* p;
10204887Schin int cat[AST_LC_COUNT];
10214887Schin
10224887Schin static Sfio_t* sp;
10234887Schin static int initialized;
1024*12068SRoger.Faulkner@Oracle.COM static const char local[] = "local";
10254887Schin
10264887Schin if ((category = lcindex(category, 0)) < 0)
10274887Schin return 0;
10284887Schin if (!locale)
10294887Schin {
10304887Schin /*
10314887Schin * return the current state
10324887Schin */
10334887Schin
10344887Schin compose:
103510898Sroland.mainz@nrubsig.org if (category != AST_LC_ALL && category != AST_LC_LANG)
10364887Schin return (char*)locales[category]->name;
10374887Schin if (!sp && !(sp = sfstropen()))
10384887Schin return 0;
10394887Schin for (i = 1; i < AST_LC_COUNT; i++)
10404887Schin cat[i] = -1;
10414887Schin for (i = 1, k = 0; i < AST_LC_COUNT; i++)
10424887Schin if (cat[i] < 0)
10434887Schin {
10444887Schin k++;
10454887Schin cat[i] = i;
10464887Schin for (j = i + 1; j < AST_LC_COUNT; j++)
10474887Schin if (locales[j] == locales[i])
10484887Schin cat[j] = i;
10494887Schin }
10504887Schin if (k == 1)
10514887Schin return (char*)locales[1]->name;
10524887Schin for (i = 1; i < AST_LC_COUNT; i++)
10534887Schin if (cat[i] >= 0 && !(locales[i]->flags & LC_default))
10544887Schin {
10554887Schin if (sfstrtell(sp))
10564887Schin sfprintf(sp, ";");
10574887Schin for (j = i, k = cat[i]; j < AST_LC_COUNT; j++)
10584887Schin if (cat[j] == k)
10594887Schin {
10604887Schin cat[j] = -1;
10618462SApril.Chin@Sun.COM sfprintf(sp, "%s=", lc_categories[j].name);
10624887Schin }
10634887Schin sfprintf(sp, "%s", locales[i]->name);
10644887Schin }
10654887Schin if (!sfstrtell(sp))
10664887Schin return (char*)locales[0]->name;
10674887Schin return sfstruse(sp);
10684887Schin }
10694887Schin if (!ast.locale.serial++)
107010898Sroland.mainz@nrubsig.org {
10714887Schin stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL);
107210898Sroland.mainz@nrubsig.org initialized = 0;
107310898Sroland.mainz@nrubsig.org }
1074*12068SRoger.Faulkner@Oracle.COM if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
1075*12068SRoger.Faulkner@Oracle.COM 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*12068SRoger.Faulkner@Oracle.COM if (ast.locale.set & AST_LC_setenv)
10774887Schin {
1078*12068SRoger.Faulkner@Oracle.COM f = LC_setenv;
1079*12068SRoger.Faulkner@Oracle.COM p = *locale ? lcmake(locale) : (Lc_t*)0;
1080*12068SRoger.Faulkner@Oracle.COM }
1081*12068SRoger.Faulkner@Oracle.COM else if (*locale)
1082*12068SRoger.Faulkner@Oracle.COM {
1083*12068SRoger.Faulkner@Oracle.COM f = LC_setlocale;
1084*12068SRoger.Faulkner@Oracle.COM p = lcmake(locale);
1085*12068SRoger.Faulkner@Oracle.COM }
1086*12068SRoger.Faulkner@Oracle.COM else if (category == AST_LC_ALL)
1087*12068SRoger.Faulkner@Oracle.COM {
1088*12068SRoger.Faulkner@Oracle.COM if (!initialized)
10898462SApril.Chin@Sun.COM {
1090*12068SRoger.Faulkner@Oracle.COM char* u;
1091*12068SRoger.Faulkner@Oracle.COM char tmp[256];
1092*12068SRoger.Faulkner@Oracle.COM
1093*12068SRoger.Faulkner@Oracle.COM /*
1094*12068SRoger.Faulkner@Oracle.COM * initialize from the environment
1095*12068SRoger.Faulkner@Oracle.COM * precedence determined by X/Open
1096*12068SRoger.Faulkner@Oracle.COM */
1097*12068SRoger.Faulkner@Oracle.COM
1098*12068SRoger.Faulkner@Oracle.COM u = 0;
1099*12068SRoger.Faulkner@Oracle.COM if ((s = getenv("LANG")) && *s)
1100*12068SRoger.Faulkner@Oracle.COM {
1101*12068SRoger.Faulkner@Oracle.COM if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
1102*12068SRoger.Faulkner@Oracle.COM s = u;
1103*12068SRoger.Faulkner@Oracle.COM lang = lcmake(s);
1104*12068SRoger.Faulkner@Oracle.COM }
1105*12068SRoger.Faulkner@Oracle.COM else
1106*12068SRoger.Faulkner@Oracle.COM lang = 0;
1107*12068SRoger.Faulkner@Oracle.COM if ((s = getenv("LC_ALL")) && *s)
11084887Schin {
110910898Sroland.mainz@nrubsig.org if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
111010898Sroland.mainz@nrubsig.org s = u;
1111*12068SRoger.Faulkner@Oracle.COM lc_all = lcmake(s);
11124887Schin }
111310898Sroland.mainz@nrubsig.org else
1114*12068SRoger.Faulkner@Oracle.COM lc_all = 0;
11158462SApril.Chin@Sun.COM for (i = 1; i < AST_LC_COUNT; i++)
1116*12068SRoger.Faulkner@Oracle.COM if (lc_categories[i].flags & LC_setlocale)
1117*12068SRoger.Faulkner@Oracle.COM /* explicitly set by setlocale() */;
1118*12068SRoger.Faulkner@Oracle.COM else if ((s = getenv(lc_categories[i].name)) && *s)
1119*12068SRoger.Faulkner@Oracle.COM {
1120*12068SRoger.Faulkner@Oracle.COM if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
1121*12068SRoger.Faulkner@Oracle.COM s = u;
1122*12068SRoger.Faulkner@Oracle.COM lc_categories[i].prev = lcmake(s);
1123*12068SRoger.Faulkner@Oracle.COM }
1124*12068SRoger.Faulkner@Oracle.COM else
1125*12068SRoger.Faulkner@Oracle.COM lc_categories[i].prev = 0;
1126*12068SRoger.Faulkner@Oracle.COM for (i = 1; i < AST_LC_COUNT; i++)
1127*12068SRoger.Faulkner@Oracle.COM if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
1128*12068SRoger.Faulkner@Oracle.COM {
1129*12068SRoger.Faulkner@Oracle.COM while (i--)
1130*12068SRoger.Faulkner@Oracle.COM single(i, NiL, 0);
1131*12068SRoger.Faulkner@Oracle.COM return 0;
1132*12068SRoger.Faulkner@Oracle.COM }
1133*12068SRoger.Faulkner@Oracle.COM if (ast.locale.set & AST_LC_debug)
1134*12068SRoger.Faulkner@Oracle.COM for (i = 1; i < AST_LC_COUNT; i++)
1135*12068SRoger.Faulkner@Oracle.COM 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*12068SRoger.Faulkner@Oracle.COM initialized = 1;
1137*12068SRoger.Faulkner@Oracle.COM }
11384887Schin goto compose;
11394887Schin }
114010898Sroland.mainz@nrubsig.org else if (category == AST_LC_LANG || !(p = lc_categories[category].prev))
1141*12068SRoger.Faulkner@Oracle.COM {
1142*12068SRoger.Faulkner@Oracle.COM f = 0;
11438462SApril.Chin@Sun.COM p = lcmake("C");
1144*12068SRoger.Faulkner@Oracle.COM }
1145*12068SRoger.Faulkner@Oracle.COM else
1146*12068SRoger.Faulkner@Oracle.COM f = 0;
114710898Sroland.mainz@nrubsig.org if (category == AST_LC_LANG)
114810898Sroland.mainz@nrubsig.org {
114910898Sroland.mainz@nrubsig.org if (lang != p)
115010898Sroland.mainz@nrubsig.org {
115110898Sroland.mainz@nrubsig.org lang = p;
115210898Sroland.mainz@nrubsig.org if (!lc_all)
115310898Sroland.mainz@nrubsig.org for (i = 1; i < AST_LC_COUNT; i++)
1154*12068SRoger.Faulkner@Oracle.COM if (!single(i, lc_categories[i].prev, 0))
115510898Sroland.mainz@nrubsig.org {
115610898Sroland.mainz@nrubsig.org while (i--)
1157*12068SRoger.Faulkner@Oracle.COM single(i, NiL, 0);
115810898Sroland.mainz@nrubsig.org return 0;
115910898Sroland.mainz@nrubsig.org }
116010898Sroland.mainz@nrubsig.org }
116110898Sroland.mainz@nrubsig.org }
116210898Sroland.mainz@nrubsig.org else if (category != AST_LC_ALL)
1163*12068SRoger.Faulkner@Oracle.COM {
1164*12068SRoger.Faulkner@Oracle.COM if (f || !lc_all)
1165*12068SRoger.Faulkner@Oracle.COM return single(category, p, f);
1166*12068SRoger.Faulkner@Oracle.COM if (p && !(ast.locale.set & AST_LC_internal))
1167*12068SRoger.Faulkner@Oracle.COM lc_categories[category].prev = p;
1168*12068SRoger.Faulkner@Oracle.COM return (char*)locales[category]->name;
1169*12068SRoger.Faulkner@Oracle.COM }
1170*12068SRoger.Faulkner@Oracle.COM else if (composite(locale, 0) < 0)
117110898Sroland.mainz@nrubsig.org return 0;
117210898Sroland.mainz@nrubsig.org else if (lc_all != p)
11734887Schin {
117410898Sroland.mainz@nrubsig.org lc_all = p;
11754887Schin for (i = 1; i < AST_LC_COUNT; i++)
1176*12068SRoger.Faulkner@Oracle.COM if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
11774887Schin {
11784887Schin while (i--)
1179*12068SRoger.Faulkner@Oracle.COM single(i, NiL, 0);
11804887Schin return 0;
11814887Schin }
11824887Schin }
11834887Schin goto compose;
11844887Schin }
1185