14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 * locale state implementation 264887Schin */ 274887Schin 284887Schin #include "lclib.h" 29*8462SApril.Chin@Sun.COM #include "lclang.h" 304887Schin 314887Schin #include <ctype.h> 324887Schin 334887Schin static Lc_numeric_t default_numeric = { '.', -1 }; 344887Schin 354887Schin static Lc_t default_lc = 364887Schin { 374887Schin "C", 384887Schin "POSIX", 39*8462SApril.Chin@Sun.COM &lc_languages[0], 40*8462SApril.Chin@Sun.COM &lc_territories[0], 41*8462SApril.Chin@Sun.COM &lc_charsets[0], 424887Schin 0, 434887Schin LC_default|LC_checked|LC_local, 444887Schin 0, 454887Schin { 464887Schin { &default_lc, 0, 0 }, 474887Schin { &default_lc, 0, 0 }, 484887Schin { &default_lc, 0, 0 }, 494887Schin { &default_lc, 0, 0 }, 504887Schin { &default_lc, 0, 0 }, 514887Schin { &default_lc, 0, (void*)&default_numeric }, 524887Schin { &default_lc, 0, 0 }, 534887Schin { &default_lc, 0, 0 }, 544887Schin { &default_lc, 0, 0 }, 554887Schin { &default_lc, 0, 0 }, 564887Schin { &default_lc, 0, 0 }, 574887Schin { &default_lc, 0, 0 }, 584887Schin { &default_lc, 0, 0 }, 594887Schin { &default_lc, 0, 0 } 604887Schin } 614887Schin }; 624887Schin 634887Schin static Lc_numeric_t debug_numeric = { ',', '.' }; 644887Schin 654887Schin static Lc_t debug_lc = 664887Schin { 674887Schin "debug", 684887Schin "debug", 69*8462SApril.Chin@Sun.COM &lc_languages[1], 70*8462SApril.Chin@Sun.COM &lc_territories[1], 71*8462SApril.Chin@Sun.COM &lc_charsets[0], 724887Schin 0, 734887Schin LC_debug|LC_checked|LC_local, 744887Schin 0, 754887Schin { 764887Schin { &debug_lc, 0, 0 }, 774887Schin { &debug_lc, 0, 0 }, 784887Schin { &debug_lc, 0, 0 }, 794887Schin { &debug_lc, 0, 0 }, 804887Schin { &debug_lc, 0, 0 }, 814887Schin { &debug_lc, 0, (void*)&debug_numeric }, 824887Schin { &debug_lc, 0, 0 }, 834887Schin { &debug_lc, 0, 0 }, 844887Schin { &debug_lc, 0, 0 }, 854887Schin { &debug_lc, 0, 0 }, 864887Schin { &debug_lc, 0, 0 }, 874887Schin { &debug_lc, 0, 0 }, 884887Schin { &debug_lc, 0, 0 }, 894887Schin { &debug_lc, 0, 0 } 904887Schin }, 914887Schin &default_lc 924887Schin }; 934887Schin 944887Schin static Lc_t* lcs = &debug_lc; 954887Schin 964887Schin Lc_t* locales[] = 974887Schin { 984887Schin &default_lc, 994887Schin &default_lc, 1004887Schin &default_lc, 1014887Schin &default_lc, 1024887Schin &default_lc, 1034887Schin &default_lc, 1044887Schin &default_lc, 1054887Schin &default_lc, 1064887Schin &default_lc, 1074887Schin &default_lc, 1084887Schin &default_lc, 1094887Schin &default_lc, 1104887Schin &default_lc, 1114887Schin &default_lc 1124887Schin }; 1134887Schin 1144887Schin /* 1154887Schin * return the internal category index for category 1164887Schin */ 1174887Schin 1184887Schin int 1194887Schin lcindex(int category, int min) 1204887Schin { 1214887Schin switch (category) 1224887Schin { 1234887Schin case LC_ALL: return min ? -1 : AST_LC_ALL; 1244887Schin case LC_ADDRESS: return AST_LC_ADDRESS; 1254887Schin case LC_COLLATE: return AST_LC_COLLATE; 1264887Schin case LC_CTYPE: return AST_LC_CTYPE; 1274887Schin case LC_IDENTIFICATION: return AST_LC_IDENTIFICATION; 1284887Schin case LC_MEASUREMENT: return AST_LC_MEASUREMENT; 1294887Schin case LC_MESSAGES: return AST_LC_MESSAGES; 1304887Schin case LC_MONETARY: return AST_LC_MONETARY; 1314887Schin case LC_NAME: return AST_LC_NAME; 1324887Schin case LC_NUMERIC: return AST_LC_NUMERIC; 1334887Schin case LC_PAPER: return AST_LC_PAPER; 1344887Schin case LC_TELEPHONE: return AST_LC_TELEPHONE; 1354887Schin case LC_TIME: return AST_LC_TIME; 1364887Schin case LC_XLITERATE: return AST_LC_XLITERATE; 1374887Schin } 1384887Schin return -1; 1394887Schin } 1404887Schin 1414887Schin /* 1424887Schin * return the first category table entry 1434887Schin */ 1444887Schin 1454887Schin Lc_category_t* 1464887Schin lccategories(void) 1474887Schin { 148*8462SApril.Chin@Sun.COM return (Lc_category_t*)&lc_categories[0]; 1494887Schin } 1504887Schin 1514887Schin /* 1524887Schin * return the current info for category 1534887Schin */ 1544887Schin 1554887Schin Lc_info_t* 1564887Schin lcinfo(register int category) 1574887Schin { 1584887Schin if ((category = lcindex(category, 0)) < 0) 1594887Schin return 0; 1604887Schin return LCINFO(category); 1614887Schin } 1624887Schin 1634887Schin /* 1644887Schin * return 1 if s matches the alternation pattern p 1654887Schin * if minimum!=0 then at least that many chars must match 1664887Schin * if standard!=0 and s[0] is a digit leading non-digits are ignored in p 1674887Schin */ 1684887Schin 1694887Schin static int 1704887Schin match(const char* s, register const char* p, int minimum, int standard) 1714887Schin { 1724887Schin register const char* t; 1734887Schin const char* x; 1744887Schin int w; 1754887Schin int z; 1764887Schin 1774887Schin z = 0; 1784887Schin do 1794887Schin { 1804887Schin t = s; 1814887Schin if (standard) 1824887Schin { 1834887Schin if (isdigit(*t)) 1844887Schin while (*p && !isdigit(*p)) 1854887Schin p++; 1864887Schin else if (isdigit(*p)) 1874887Schin while (*t && !isdigit(*t)) 1884887Schin t++; 1894887Schin } 1904887Schin if (*p) 1914887Schin { 1924887Schin w = 0; 1934887Schin x = p; 1944887Schin while (*p && *p != '|') 1954887Schin { 1964887Schin if (!*t || *t == ',') 1974887Schin break; 1984887Schin else if (*t == *p) 1994887Schin /*ok*/; 2004887Schin else if (*t == '-') 2014887Schin { 2024887Schin if (standard && isdigit(*p)) 2034887Schin { 2044887Schin t++; 2054887Schin continue; 2064887Schin } 2074887Schin while (*p && *p != '-') 2084887Schin p++; 2094887Schin if (!*p) 2104887Schin break; 2114887Schin } 2124887Schin else if (*p == '-') 2134887Schin { 2144887Schin if (standard && isdigit(*t)) 2154887Schin { 2164887Schin p++; 2174887Schin continue; 2184887Schin } 2194887Schin w = 1; 2204887Schin while (*t && *t != '-') 2214887Schin t++; 2224887Schin if (!*t) 2234887Schin break; 2244887Schin } 2254887Schin else 2264887Schin break; 2274887Schin t++; 2284887Schin p++; 2294887Schin } 2304887Schin if ((!*t || *t == ',') && (!*p || *p == '|' || w)) 2314887Schin return p - x; 2324887Schin if (minimum && z < (p - x) && (p - x) >= minimum) 2334887Schin z = p - x; 2344887Schin } 2354887Schin while (*p && *p != '|') 2364887Schin p++; 2374887Schin } while (*p++); 2384887Schin return z; 2394887Schin } 2404887Schin 2414887Schin /* 2424887Schin * return 1 if s matches the charset names in cp 2434887Schin */ 2444887Schin 2454887Schin static int 2464887Schin match_charset(register const char* s, register const Lc_charset_t* cp) 2474887Schin { 2484887Schin return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1); 2494887Schin } 2504887Schin 2514887Schin /* 2524887Schin * low level for lccanon 2534887Schin */ 2544887Schin 2554887Schin static size_t 2564887Schin canonical(const Lc_language_t* lp, const Lc_territory_t* tp, const Lc_charset_t* cp, const Lc_attribute_list_t* ap, unsigned long flags, char* buf, size_t siz) 2574887Schin { 2584887Schin register int c; 2594887Schin register int u; 2604887Schin register char* s; 2614887Schin register char* e; 2624887Schin register const char* t; 2634887Schin 2644887Schin if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose))) 2654887Schin flags |= LC_abbreviated; 2664887Schin s = buf; 2674887Schin e = &buf[siz - 3]; 2684887Schin if (lp) 2694887Schin { 2704887Schin if (lp->flags & (LC_debug|LC_default)) 2714887Schin { 2724887Schin for (t = lp->code; s < e && (*s = *t++); s++); 2734887Schin *s++ = 0; 2744887Schin return s - buf; 2754887Schin } 2764887Schin if (flags & LC_verbose) 2774887Schin { 2784887Schin u = 1; 2794887Schin t = lp->name; 2804887Schin while (s < e && (c = *t++)) 2814887Schin { 2824887Schin if (u) 2834887Schin { 2844887Schin u = 0; 2854887Schin c = toupper(c); 2864887Schin } 2874887Schin else if (!isalnum(c)) 2884887Schin u = 1; 2894887Schin *s++ = c; 2904887Schin } 2914887Schin } 2924887Schin else 2934887Schin for (t = lp->code; s < e && (*s = *t++); s++); 2944887Schin } 2954887Schin if (s < e) 2964887Schin { 297*8462SApril.Chin@Sun.COM if (tp && tp != &lc_territories[0] && (!(flags & (LC_abbreviated|LC_default)) || !lp || !streq(lp->code, tp->code))) 2984887Schin { 2994887Schin if (lp) 3004887Schin *s++ = '_'; 3014887Schin if (flags & LC_verbose) 3024887Schin { 3034887Schin u = 1; 3044887Schin t = tp->name; 3054887Schin while (s < e && (c = *t++) && c != '|') 3064887Schin { 3074887Schin if (u) 3084887Schin { 3094887Schin u = 0; 3104887Schin c = toupper(c); 3114887Schin } 3124887Schin else if (!isalnum(c)) 3134887Schin u = 1; 3144887Schin *s++ = c; 3154887Schin } 3164887Schin } 3174887Schin else 3184887Schin for (t = tp->code; s < e && (*s = toupper(*t++)); s++); 3194887Schin } 3204887Schin if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e) 3214887Schin { 3224887Schin *s++ = '.'; 3234887Schin for (t = cp->code; s < e && (c = *t++); s++) 3244887Schin { 3254887Schin if (islower(c)) 3264887Schin c = toupper(c); 3274887Schin *s = c; 3284887Schin } 3294887Schin } 3304887Schin for (c = '@'; ap && s < e; ap = ap->next) 3314887Schin if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default)) 3324887Schin { 3334887Schin *s++ = c; 3344887Schin c = ','; 3354887Schin for (t = ap->attribute->name; s < e && (*s = *t++); s++); 3364887Schin } 3374887Schin } 3384887Schin *s++ = 0; 3394887Schin return s - buf; 3404887Schin } 3414887Schin 3424887Schin /* 3434887Schin * generate a canonical locale name in buf 3444887Schin */ 3454887Schin 3464887Schin size_t 3474887Schin lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz) 3484887Schin { 3494887Schin if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default)))) 3504887Schin { 3514887Schin #if _WINIX 3524887Schin char lang[64]; 3534887Schin char code[64]; 3544887Schin char ctry[64]; 3554887Schin 3564887Schin if (lc->index && 3574887Schin GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) && 3584887Schin GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry))) 3594887Schin { 3604887Schin if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code))) 3614887Schin code[0] = 0; 3624887Schin if (!lc->charset || !lc->charset->ms) 3634887Schin return sfsprintf(buf, siz, "%s_%s", lang, ctry); 3644887Schin else if (streq(lc->charset->ms, code)) 3654887Schin return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code); 3664887Schin else 3674887Schin return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms); 3684887Schin } 3694887Schin #endif 3704887Schin buf[0] = '-'; 3714887Schin buf[1] = 0; 3724887Schin return 0; 3734887Schin } 3744887Schin return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz); 3754887Schin } 3764887Schin 3774887Schin /* 3784887Schin * make an Lc_t from a locale name 3794887Schin */ 3804887Schin 3814887Schin Lc_t* 3824887Schin lcmake(const char* name) 3834887Schin { 3844887Schin register int c; 3854887Schin register char* s; 3864887Schin register char* e; 3874887Schin register const char* t; 3884887Schin const char* a; 3894887Schin char* w; 3904887Schin char* language_name; 3914887Schin char* territory_name; 3924887Schin char* charset_name; 3934887Schin char* attributes_name; 3944887Schin Lc_t* lc; 3954887Schin const Lc_map_t* mp; 3964887Schin const Lc_language_t* lp; 3974887Schin const Lc_territory_t* tp; 3984887Schin const Lc_territory_t* tpb; 3994887Schin const Lc_territory_t* primary; 4004887Schin const Lc_charset_t* cp; 4014887Schin const Lc_charset_t* ppa; 4024887Schin const Lc_attribute_t* ap; 4034887Schin Lc_attribute_list_t* ai; 4044887Schin Lc_attribute_list_t* al; 4054887Schin int i; 4064887Schin int n; 4074887Schin int z; 4084887Schin char buf[PATH_MAX / 2]; 4094887Schin char tmp[PATH_MAX / 2]; 4104887Schin 4114887Schin if (!(t = name) || !*t) 4124887Schin return &default_lc; 4134887Schin for (lc = lcs; lc; lc = lc->next) 4144887Schin if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name)) 4154887Schin return lc; 416*8462SApril.Chin@Sun.COM for (mp = lc_maps; mp->code; mp++) 4174887Schin if (streq(t, mp->code)) 4184887Schin { 4194887Schin lp = mp->language; 4204887Schin tp = mp->territory; 4214887Schin cp = mp->charset; 4224887Schin if (!mp->attribute) 4234887Schin al = 0; 4244887Schin else if (al = newof(0, Lc_attribute_list_t, 1, 0)) 4254887Schin al->attribute = mp->attribute; 4264887Schin goto mapped; 4274887Schin } 4284887Schin language_name = buf; 4294887Schin territory_name = charset_name = attributes_name = 0; 4304887Schin s = buf; 4314887Schin e = &buf[sizeof(buf)-2]; 4324887Schin a = 0; 4334887Schin n = 0; 4344887Schin while (s < e && (c = *t++)) 4354887Schin { 4364887Schin if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n) 4374887Schin { 4384887Schin while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n)) 4394887Schin if (!c) 4404887Schin break; 4414887Schin if (isalnum(c) && !n) 4424887Schin *s++ = '-'; 4434887Schin else 4444887Schin { 4454887Schin n = 0; 4464887Schin if (!a) 4474887Schin { 4484887Schin a = t - 1; 4494887Schin while (c && c != '_' && c != '.' && c != '@') 4504887Schin c = *t++; 4514887Schin if (!c) 4524887Schin break; 4534887Schin } 4544887Schin } 4554887Schin } 4564887Schin if (c == '_' && !territory_name) 4574887Schin { 4584887Schin *s++ = 0; 4594887Schin territory_name = s; 4604887Schin } 4614887Schin else if (c == '.' && !charset_name) 4624887Schin { 4634887Schin *s++ = 0; 4644887Schin charset_name = s; 4654887Schin } 4664887Schin else if (c == '@' && !attributes_name) 4674887Schin { 4684887Schin *s++ = 0; 4694887Schin attributes_name = s; 4704887Schin } 4714887Schin else 4724887Schin { 4734887Schin if (isupper(c)) 4744887Schin c = tolower(c); 4754887Schin *s++ = c; 4764887Schin } 4774887Schin } 4784887Schin if ((t = a) && s < e) 4794887Schin { 4804887Schin if (attributes_name) 4814887Schin *s++ = ','; 4824887Schin else 4834887Schin { 4844887Schin *s++ = 0; 4854887Schin attributes_name = s; 4864887Schin } 4874887Schin while (s < e && (c = *t++)) 4884887Schin { 4894887Schin if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n) 4904887Schin { 4914887Schin while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n)) 4924887Schin if (!c) 4934887Schin break; 4944887Schin if (isalnum(c) && !n) 4954887Schin *s++ = '-'; 4964887Schin else 4974887Schin n = 0; 4984887Schin } 4994887Schin if (c == '_' || c == '.' || c == '@') 5004887Schin break; 5014887Schin if (isupper(c)) 5024887Schin c = tolower(c); 5034887Schin *s++ = c; 5044887Schin } 5054887Schin } 5064887Schin *s = 0; 5074887Schin tp = 0; 5084887Schin cp = ppa = 0; 5094887Schin al = 0; 5104887Schin 5114887Schin /* 5124887Schin * language 5134887Schin */ 5144887Schin 5154887Schin n = strlen(s = language_name); 5164887Schin if (n == 2) 517*8462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++); 5184887Schin else if (n == 3) 5194887Schin { 520*8462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++); 5214887Schin if (!lp->code) 5224887Schin { 5234887Schin c = s[2]; 5244887Schin s[2] = 0; 525*8462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++); 5264887Schin s[2] = c; 5274887Schin if (lp->code) 5284887Schin n = 1; 5294887Schin } 5304887Schin } 5314887Schin else 5324887Schin lp = 0; 5334887Schin if (!lp || !lp->code) 5344887Schin { 535*8462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && !match(s, lp->name, 0, 0); lp++); 5364887Schin if (!lp || !lp->code) 5374887Schin { 5384887Schin if (!territory_name) 5394887Schin { 5404887Schin if (n == 2) 541*8462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code && !streq(s, tp->code); tp++); 5424887Schin else 5434887Schin { 5444887Schin z = 0; 5454887Schin tpb = 0; 546*8462SApril.Chin@Sun.COM for (tp = lc_territories; tp->name; tp++) 5474887Schin if ((i = match(s, tp->name, 3, 0)) > z) 5484887Schin { 5494887Schin tpb = tp; 5504887Schin if ((z = i) == n) 5514887Schin break; 5524887Schin } 5534887Schin if (tpb) 5544887Schin tp = tpb; 5554887Schin } 5564887Schin if (tp->code) 5574887Schin lp = tp->languages[0]; 5584887Schin } 5594887Schin if (!lp || !lp->code) 5604887Schin { 5614887Schin /* 5624887Schin * name not in the tables so let 5634887Schin * _ast_setlocale() and/or setlocale() 5644887Schin * handle the validity checks 5654887Schin */ 5664887Schin 5674887Schin s = (char*)name; 5684887Schin z = strlen(s) + 1; 5694887Schin if (!(lp = newof(0, Lc_language_t, 1, z))) 5704887Schin return 0; 5714887Schin name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1); 5724887Schin memcpy((char*)lp->code, s, z - 1); 573*8462SApril.Chin@Sun.COM tp = &lc_territories[0]; 574*8462SApril.Chin@Sun.COM cp = ((Lc_language_t*)lp)->charset = &lc_charsets[0]; 5754887Schin al = 0; 5764887Schin goto override; 5774887Schin } 5784887Schin } 5794887Schin } 5804887Schin 5814887Schin /* 5824887Schin * territory 5834887Schin */ 5844887Schin 5854887Schin if (!tp || !tp->code) 5864887Schin { 5874887Schin if (!(s = territory_name)) 5884887Schin { 5894887Schin n = 0; 5904887Schin primary = 0; 591*8462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code; tp++) 5924887Schin if (tp->languages[0] == lp) 5934887Schin { 5944887Schin if (tp->flags & LC_primary) 5954887Schin { 5964887Schin n = 1; 5974887Schin primary = tp; 5984887Schin break; 5994887Schin } 6004887Schin n++; 6014887Schin primary = tp; 6024887Schin } 6034887Schin if (n == 1) 6044887Schin tp = primary; 6054887Schin s = (char*)lp->code; 6064887Schin } 6074887Schin if (!tp || !tp->code) 6084887Schin { 6094887Schin n = strlen(s); 6104887Schin if (n == 2) 6114887Schin { 612*8462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code; tp++) 6134887Schin if (streq(s, tp->code)) 6144887Schin { 6154887Schin for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++); 6164887Schin if (i >= elementsof(tp->languages)) 6174887Schin tp = 0; 6184887Schin break; 6194887Schin } 6204887Schin } 6214887Schin else 6224887Schin { 623*8462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code; tp++) 6244887Schin if (match(s, tp->name, 3, 0)) 6254887Schin { 6264887Schin for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++); 6274887Schin if (i < elementsof(tp->languages)) 6284887Schin break; 6294887Schin } 6304887Schin } 6314887Schin if (tp && !tp->code) 6324887Schin tp = 0; 6334887Schin } 6344887Schin } 6354887Schin 6364887Schin /* 6374887Schin * attributes -- done here to catch misplaced charset references 6384887Schin */ 6394887Schin 6404887Schin if (s = attributes_name) 6414887Schin { 6424887Schin do 6434887Schin { 6444887Schin for (w = s; *s && *s != ','; s++); 6454887Schin c = *s; 6464887Schin *s = 0; 6474887Schin if (!(cp = lp->charset) || !match_charset(w, cp)) 648*8462SApril.Chin@Sun.COM for (cp = lc_charsets; cp->code; cp++) 6494887Schin if (match_charset(w, cp)) 6504887Schin { 6514887Schin ppa = cp; 6524887Schin break; 6534887Schin } 6544887Schin if (!cp->code) 6554887Schin { 6564887Schin for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++) 6574887Schin if (match(w, ap->name, 5, 0)) 6584887Schin { 6594887Schin if (ai = newof(0, Lc_attribute_list_t, 1, 0)) 6604887Schin { 6614887Schin ai->attribute = ap; 6624887Schin ai->next = al; 6634887Schin al = ai; 6644887Schin } 6654887Schin break; 6664887Schin } 6674887Schin if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1))) 6684887Schin { 6694887Schin ai = (Lc_attribute_list_t*)(ap + 1); 6704887Schin strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w); 6714887Schin ai->attribute = ap; 6724887Schin ai->next = al; 6734887Schin al = ai; 6744887Schin } 6754887Schin } 6764887Schin *s = c; 6774887Schin } while (*s++); 6784887Schin } 6794887Schin 6804887Schin /* 6814887Schin * charset 6824887Schin */ 6834887Schin 6844887Schin if (s = charset_name) 685*8462SApril.Chin@Sun.COM for (cp = lc_charsets; cp->code; cp++) 6864887Schin if (match_charset(s, cp)) 6874887Schin break; 6884887Schin if (!cp || !cp->code) 6894887Schin cp = ppa ? ppa : lp->charset; 6904887Schin mapped: 6914887Schin z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp)); 6924887Schin 6934887Schin /* 6944887Schin * add to the list of possibly active locales 6954887Schin */ 6964887Schin 6974887Schin override: 6984887Schin n = strlen(name) + 1; 6994887Schin if (!(lc = newof(0, Lc_t, 1, n + z))) 7004887Schin return 0; 7014887Schin strcpy((char*)(lc->name = (const char*)(lc + 1)), name); 7024887Schin strcpy((char*)(lc->code = lc->name + n), s); 703*8462SApril.Chin@Sun.COM lc->language = lp ? lp : &lc_languages[0]; 704*8462SApril.Chin@Sun.COM lc->territory = tp ? tp : &lc_territories[0]; 705*8462SApril.Chin@Sun.COM lc->charset = cp ? cp : &lc_charsets[0]; 7064887Schin lc->attributes = al; 7074887Schin for (i = 0; i < elementsof(lc->info); i++) 7084887Schin lc->info[i].lc = lc; 7094887Schin #if _WINIX 7104887Schin n = SUBLANG_DEFAULT; 7114887Schin if (tp) 7124887Schin for (i = 0; i < elementsof(tp->languages); i++) 7134887Schin if (lp == tp->languages[i]) 7144887Schin { 7154887Schin n = tp->indices[i]; 7164887Schin break; 7174887Schin } 7184887Schin lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT); 7194887Schin #endif 7204887Schin lc->next = lcs; 7214887Schin lcs = lc; 7224887Schin return lc; 7234887Schin } 7244887Schin 7254887Schin /* 7264887Schin * return an Lc_t* for each locale in the tables 7274887Schin * one Lc_t is allocated on the first call with lc==0 7284887Schin * this is freed when 0 returned 7294887Schin * the return value is not part of the lcmake() cache 7304887Schin */ 7314887Schin 7324887Schin typedef struct Lc_scan_s 7334887Schin { 7344887Schin Lc_t lc; 7354887Schin Lc_attribute_list_t list; 7364887Schin int territory; 7374887Schin int language; 7384887Schin int attribute; 7394887Schin char buf[256]; 7404887Schin } Lc_scan_t; 7414887Schin 7424887Schin Lc_t* 7434887Schin lcscan(Lc_t* lc) 7444887Schin { 7454887Schin register Lc_scan_t* ls; 7464887Schin 7474887Schin if (!(ls = (Lc_scan_t*)lc)) 7484887Schin { 7494887Schin if (!(ls = newof(0, Lc_scan_t, 1, 0))) 7504887Schin return 0; 7514887Schin ls->lc.code = ls->lc.name = ls->buf; 7524887Schin ls->territory = -1; 7534887Schin ls->language = elementsof(ls->lc.territory->languages); 7544887Schin ls->attribute = elementsof(ls->lc.language->attributes); 7554887Schin } 7564887Schin if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute])) 7574887Schin { 7584887Schin if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language])) 7594887Schin { 760*8462SApril.Chin@Sun.COM if (!lc_territories[++ls->territory].code) 7614887Schin { 7624887Schin free(ls); 7634887Schin return 0; 7644887Schin } 765*8462SApril.Chin@Sun.COM ls->lc.territory = &lc_territories[ls->territory]; 7664887Schin ls->lc.language = ls->lc.territory->languages[ls->language = 0]; 7674887Schin } 7684887Schin if (ls->lc.language) 7694887Schin { 770*8462SApril.Chin@Sun.COM ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &lc_charsets[0]; 7714887Schin ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0]; 7724887Schin } 7734887Schin else 7744887Schin { 775*8462SApril.Chin@Sun.COM ls->lc.charset = &lc_charsets[0]; 7764887Schin ls->list.attribute = 0; 7774887Schin } 7784887Schin } 7794887Schin ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0; 7804887Schin #if _WINIX 7814887Schin if (!ls->lc.language || !ls->lc.language->index) 7824887Schin ls->lc.index = 0; 7834887Schin else 7844887Schin { 7854887Schin if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) && 7864887Schin (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language]))) 7874887Schin ls->lc.index = SUBLANG_DEFAULT; 7884887Schin ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT); 7894887Schin } 7904887Schin #endif 7914887Schin canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf)); 7924887Schin return (Lc_t*)ls; 7934887Schin } 794