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 * locale state implementation
264887Schin */
274887Schin
284887Schin #include "lclib.h"
298462SApril.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",
398462SApril.Chin@Sun.COM &lc_languages[0],
408462SApril.Chin@Sun.COM &lc_territories[0],
418462SApril.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",
698462SApril.Chin@Sun.COM &lc_languages[1],
708462SApril.Chin@Sun.COM &lc_territories[1],
718462SApril.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
lcindex(int category,int min)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;
12810898Sroland.mainz@nrubsig.org case LC_LANG: return AST_LC_LANG;
1294887Schin case LC_MEASUREMENT: return AST_LC_MEASUREMENT;
1304887Schin case LC_MESSAGES: return AST_LC_MESSAGES;
1314887Schin case LC_MONETARY: return AST_LC_MONETARY;
1324887Schin case LC_NAME: return AST_LC_NAME;
1334887Schin case LC_NUMERIC: return AST_LC_NUMERIC;
1344887Schin case LC_PAPER: return AST_LC_PAPER;
1354887Schin case LC_TELEPHONE: return AST_LC_TELEPHONE;
1364887Schin case LC_TIME: return AST_LC_TIME;
1374887Schin case LC_XLITERATE: return AST_LC_XLITERATE;
1384887Schin }
1394887Schin return -1;
1404887Schin }
1414887Schin
1424887Schin /*
1434887Schin * return the first category table entry
1444887Schin */
1454887Schin
1464887Schin Lc_category_t*
lccategories(void)1474887Schin lccategories(void)
1484887Schin {
1498462SApril.Chin@Sun.COM return (Lc_category_t*)&lc_categories[0];
1504887Schin }
1514887Schin
1524887Schin /*
1534887Schin * return the current info for category
1544887Schin */
1554887Schin
1564887Schin Lc_info_t*
lcinfo(register int category)1574887Schin lcinfo(register int category)
1584887Schin {
1594887Schin if ((category = lcindex(category, 0)) < 0)
1604887Schin return 0;
1614887Schin return LCINFO(category);
1624887Schin }
1634887Schin
1644887Schin /*
1654887Schin * return 1 if s matches the alternation pattern p
1664887Schin * if minimum!=0 then at least that many chars must match
1674887Schin * if standard!=0 and s[0] is a digit leading non-digits are ignored in p
1684887Schin */
1694887Schin
1704887Schin static int
match(const char * s,register const char * p,int minimum,int standard)1714887Schin match(const char* s, register const char* p, int minimum, int standard)
1724887Schin {
1734887Schin register const char* t;
1744887Schin const char* x;
1754887Schin int w;
1764887Schin int z;
1774887Schin
1784887Schin z = 0;
1794887Schin do
1804887Schin {
1814887Schin t = s;
1824887Schin if (standard)
1834887Schin {
1844887Schin if (isdigit(*t))
1854887Schin while (*p && !isdigit(*p))
1864887Schin p++;
1874887Schin else if (isdigit(*p))
1884887Schin while (*t && !isdigit(*t))
1894887Schin t++;
1904887Schin }
1914887Schin if (*p)
1924887Schin {
1934887Schin w = 0;
1944887Schin x = p;
1954887Schin while (*p && *p != '|')
1964887Schin {
1974887Schin if (!*t || *t == ',')
1984887Schin break;
1994887Schin else if (*t == *p)
2004887Schin /*ok*/;
2014887Schin else if (*t == '-')
2024887Schin {
2034887Schin if (standard && isdigit(*p))
2044887Schin {
2054887Schin t++;
2064887Schin continue;
2074887Schin }
2084887Schin while (*p && *p != '-')
2094887Schin p++;
2104887Schin if (!*p)
2114887Schin break;
2124887Schin }
2134887Schin else if (*p == '-')
2144887Schin {
2154887Schin if (standard && isdigit(*t))
2164887Schin {
2174887Schin p++;
2184887Schin continue;
2194887Schin }
2204887Schin w = 1;
2214887Schin while (*t && *t != '-')
2224887Schin t++;
2234887Schin if (!*t)
2244887Schin break;
2254887Schin }
2264887Schin else
2274887Schin break;
2284887Schin t++;
2294887Schin p++;
2304887Schin }
2314887Schin if ((!*t || *t == ',') && (!*p || *p == '|' || w))
2324887Schin return p - x;
2334887Schin if (minimum && z < (p - x) && (p - x) >= minimum)
2344887Schin z = p - x;
2354887Schin }
2364887Schin while (*p && *p != '|')
2374887Schin p++;
2384887Schin } while (*p++);
2394887Schin return z;
2404887Schin }
2414887Schin
2424887Schin /*
2434887Schin * return 1 if s matches the charset names in cp
2444887Schin */
2454887Schin
2464887Schin static int
match_charset(register const char * s,register const Lc_charset_t * cp)2474887Schin match_charset(register const char* s, register const Lc_charset_t* cp)
2484887Schin {
2494887Schin return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1);
2504887Schin }
2514887Schin
2524887Schin /*
2534887Schin * low level for lccanon
2544887Schin */
2554887Schin
2564887Schin static size_t
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 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)
2584887Schin {
2594887Schin register int c;
2604887Schin register int u;
2614887Schin register char* s;
2624887Schin register char* e;
2634887Schin register const char* t;
2644887Schin
2654887Schin if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose)))
2664887Schin flags |= LC_abbreviated;
2674887Schin s = buf;
2684887Schin e = &buf[siz - 3];
2694887Schin if (lp)
2704887Schin {
2714887Schin if (lp->flags & (LC_debug|LC_default))
2724887Schin {
2734887Schin for (t = lp->code; s < e && (*s = *t++); s++);
2744887Schin *s++ = 0;
2754887Schin return s - buf;
2764887Schin }
2774887Schin if (flags & LC_verbose)
2784887Schin {
2794887Schin u = 1;
2804887Schin t = lp->name;
2814887Schin while (s < e && (c = *t++))
2824887Schin {
2834887Schin if (u)
2844887Schin {
2854887Schin u = 0;
2864887Schin c = toupper(c);
2874887Schin }
2884887Schin else if (!isalnum(c))
2894887Schin u = 1;
2904887Schin *s++ = c;
2914887Schin }
2924887Schin }
2934887Schin else
2944887Schin for (t = lp->code; s < e && (*s = *t++); s++);
2954887Schin }
2964887Schin if (s < e)
2974887Schin {
2988462SApril.Chin@Sun.COM if (tp && tp != &lc_territories[0] && (!(flags & (LC_abbreviated|LC_default)) || !lp || !streq(lp->code, tp->code)))
2994887Schin {
3004887Schin if (lp)
3014887Schin *s++ = '_';
3024887Schin if (flags & LC_verbose)
3034887Schin {
3044887Schin u = 1;
3054887Schin t = tp->name;
3064887Schin while (s < e && (c = *t++) && c != '|')
3074887Schin {
3084887Schin if (u)
3094887Schin {
3104887Schin u = 0;
3114887Schin c = toupper(c);
3124887Schin }
3134887Schin else if (!isalnum(c))
3144887Schin u = 1;
3154887Schin *s++ = c;
3164887Schin }
3174887Schin }
3184887Schin else
3194887Schin for (t = tp->code; s < e && (*s = toupper(*t++)); s++);
3204887Schin }
3214887Schin if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e)
3224887Schin {
3234887Schin *s++ = '.';
3244887Schin for (t = cp->code; s < e && (c = *t++); s++)
3254887Schin {
3264887Schin if (islower(c))
3274887Schin c = toupper(c);
3284887Schin *s = c;
3294887Schin }
3304887Schin }
3314887Schin for (c = '@'; ap && s < e; ap = ap->next)
3324887Schin if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default))
3334887Schin {
3344887Schin *s++ = c;
3354887Schin c = ',';
3364887Schin for (t = ap->attribute->name; s < e && (*s = *t++); s++);
3374887Schin }
3384887Schin }
3394887Schin *s++ = 0;
3404887Schin return s - buf;
3414887Schin }
3424887Schin
3434887Schin /*
3444887Schin * generate a canonical locale name in buf
3454887Schin */
3464887Schin
3474887Schin size_t
lccanon(Lc_t * lc,unsigned long flags,char * buf,size_t siz)3484887Schin lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz)
3494887Schin {
3504887Schin if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default))))
3514887Schin {
3524887Schin #if _WINIX
3534887Schin char lang[64];
3544887Schin char code[64];
3554887Schin char ctry[64];
3564887Schin
3574887Schin if (lc->index &&
3584887Schin GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) &&
3594887Schin GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry)))
3604887Schin {
3614887Schin if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code)))
3624887Schin code[0] = 0;
3634887Schin if (!lc->charset || !lc->charset->ms)
3644887Schin return sfsprintf(buf, siz, "%s_%s", lang, ctry);
3654887Schin else if (streq(lc->charset->ms, code))
3664887Schin return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code);
3674887Schin else
3684887Schin return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms);
3694887Schin }
3704887Schin #endif
3714887Schin buf[0] = '-';
3724887Schin buf[1] = 0;
3734887Schin return 0;
3744887Schin }
3754887Schin return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz);
3764887Schin }
3774887Schin
3784887Schin /*
3794887Schin * make an Lc_t from a locale name
3804887Schin */
3814887Schin
3824887Schin Lc_t*
lcmake(const char * name)3834887Schin lcmake(const char* name)
3844887Schin {
3854887Schin register int c;
3864887Schin register char* s;
3874887Schin register char* e;
3884887Schin register const char* t;
3894887Schin const char* a;
3904887Schin char* w;
3914887Schin char* language_name;
3924887Schin char* territory_name;
3934887Schin char* charset_name;
3944887Schin char* attributes_name;
3954887Schin Lc_t* lc;
3964887Schin const Lc_map_t* mp;
3974887Schin const Lc_language_t* lp;
3984887Schin const Lc_territory_t* tp;
3994887Schin const Lc_territory_t* tpb;
4004887Schin const Lc_territory_t* primary;
4014887Schin const Lc_charset_t* cp;
4024887Schin const Lc_charset_t* ppa;
4034887Schin const Lc_attribute_t* ap;
4044887Schin Lc_attribute_list_t* ai;
4054887Schin Lc_attribute_list_t* al;
4064887Schin int i;
4074887Schin int n;
4084887Schin int z;
4094887Schin char buf[PATH_MAX / 2];
4104887Schin char tmp[PATH_MAX / 2];
4114887Schin
4124887Schin if (!(t = name) || !*t)
4134887Schin return &default_lc;
4144887Schin for (lc = lcs; lc; lc = lc->next)
4154887Schin if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name))
4164887Schin return lc;
4178462SApril.Chin@Sun.COM for (mp = lc_maps; mp->code; mp++)
4184887Schin if (streq(t, mp->code))
4194887Schin {
4204887Schin lp = mp->language;
4214887Schin tp = mp->territory;
4224887Schin cp = mp->charset;
4234887Schin if (!mp->attribute)
4244887Schin al = 0;
4254887Schin else if (al = newof(0, Lc_attribute_list_t, 1, 0))
4264887Schin al->attribute = mp->attribute;
4274887Schin goto mapped;
4284887Schin }
4294887Schin language_name = buf;
4304887Schin territory_name = charset_name = attributes_name = 0;
4314887Schin s = buf;
4324887Schin e = &buf[sizeof(buf)-2];
4334887Schin a = 0;
4344887Schin n = 0;
4354887Schin while (s < e && (c = *t++))
4364887Schin {
4374887Schin if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n)
4384887Schin {
4394887Schin while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
4404887Schin if (!c)
4414887Schin break;
4424887Schin if (isalnum(c) && !n)
4434887Schin *s++ = '-';
4444887Schin else
4454887Schin {
4464887Schin n = 0;
4474887Schin if (!a)
4484887Schin {
4494887Schin a = t - 1;
4504887Schin while (c && c != '_' && c != '.' && c != '@')
4514887Schin c = *t++;
4524887Schin if (!c)
4534887Schin break;
4544887Schin }
4554887Schin }
4564887Schin }
4574887Schin if (c == '_' && !territory_name)
4584887Schin {
4594887Schin *s++ = 0;
4604887Schin territory_name = s;
4614887Schin }
4624887Schin else if (c == '.' && !charset_name)
4634887Schin {
4644887Schin *s++ = 0;
4654887Schin charset_name = s;
4664887Schin }
4674887Schin else if (c == '@' && !attributes_name)
4684887Schin {
4694887Schin *s++ = 0;
4704887Schin attributes_name = s;
4714887Schin }
4724887Schin else
4734887Schin {
4744887Schin if (isupper(c))
4754887Schin c = tolower(c);
4764887Schin *s++ = c;
4774887Schin }
4784887Schin }
4794887Schin if ((t = a) && s < e)
4804887Schin {
4814887Schin if (attributes_name)
4824887Schin *s++ = ',';
4834887Schin else
4844887Schin {
4854887Schin *s++ = 0;
4864887Schin attributes_name = s;
4874887Schin }
4884887Schin while (s < e && (c = *t++))
4894887Schin {
4904887Schin if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n)
4914887Schin {
4924887Schin while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n))
4934887Schin if (!c)
4944887Schin break;
4954887Schin if (isalnum(c) && !n)
4964887Schin *s++ = '-';
4974887Schin else
4984887Schin n = 0;
4994887Schin }
5004887Schin if (c == '_' || c == '.' || c == '@')
5014887Schin break;
5024887Schin if (isupper(c))
5034887Schin c = tolower(c);
5044887Schin *s++ = c;
5054887Schin }
5064887Schin }
5074887Schin *s = 0;
5084887Schin tp = 0;
5094887Schin cp = ppa = 0;
5104887Schin al = 0;
5114887Schin
5124887Schin /*
5134887Schin * language
5144887Schin */
5154887Schin
5164887Schin n = strlen(s = language_name);
5174887Schin if (n == 2)
5188462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
5194887Schin else if (n == 3)
5204887Schin {
5218462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++);
5224887Schin if (!lp->code)
5234887Schin {
5244887Schin c = s[2];
5254887Schin s[2] = 0;
5268462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && !streq(s, lp->code); lp++);
5274887Schin s[2] = c;
5284887Schin if (lp->code)
5294887Schin n = 1;
5304887Schin }
5314887Schin }
5324887Schin else
5334887Schin lp = 0;
5344887Schin if (!lp || !lp->code)
5354887Schin {
5368462SApril.Chin@Sun.COM for (lp = lc_languages; lp->code && !match(s, lp->name, 0, 0); lp++);
5374887Schin if (!lp || !lp->code)
5384887Schin {
5394887Schin if (!territory_name)
5404887Schin {
5414887Schin if (n == 2)
5428462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code && !streq(s, tp->code); tp++);
5434887Schin else
5444887Schin {
5454887Schin z = 0;
5464887Schin tpb = 0;
5478462SApril.Chin@Sun.COM for (tp = lc_territories; tp->name; tp++)
5484887Schin if ((i = match(s, tp->name, 3, 0)) > z)
5494887Schin {
5504887Schin tpb = tp;
5514887Schin if ((z = i) == n)
5524887Schin break;
5534887Schin }
5544887Schin if (tpb)
5554887Schin tp = tpb;
5564887Schin }
5574887Schin if (tp->code)
5584887Schin lp = tp->languages[0];
5594887Schin }
5604887Schin if (!lp || !lp->code)
5614887Schin {
5624887Schin /*
5634887Schin * name not in the tables so let
5644887Schin * _ast_setlocale() and/or setlocale()
5654887Schin * handle the validity checks
5664887Schin */
5674887Schin
5684887Schin s = (char*)name;
5694887Schin z = strlen(s) + 1;
5704887Schin if (!(lp = newof(0, Lc_language_t, 1, z)))
5714887Schin return 0;
5724887Schin name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1);
5734887Schin memcpy((char*)lp->code, s, z - 1);
5748462SApril.Chin@Sun.COM tp = &lc_territories[0];
5758462SApril.Chin@Sun.COM cp = ((Lc_language_t*)lp)->charset = &lc_charsets[0];
5764887Schin al = 0;
5774887Schin goto override;
5784887Schin }
5794887Schin }
5804887Schin }
5814887Schin
5824887Schin /*
5834887Schin * territory
5844887Schin */
5854887Schin
5864887Schin if (!tp || !tp->code)
5874887Schin {
5884887Schin if (!(s = territory_name))
5894887Schin {
5904887Schin n = 0;
5914887Schin primary = 0;
5928462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code; tp++)
5934887Schin if (tp->languages[0] == lp)
5944887Schin {
5954887Schin if (tp->flags & LC_primary)
5964887Schin {
5974887Schin n = 1;
5984887Schin primary = tp;
5994887Schin break;
6004887Schin }
6014887Schin n++;
6024887Schin primary = tp;
6034887Schin }
6044887Schin if (n == 1)
6054887Schin tp = primary;
6064887Schin s = (char*)lp->code;
6074887Schin }
6084887Schin if (!tp || !tp->code)
6094887Schin {
6104887Schin n = strlen(s);
6114887Schin if (n == 2)
6124887Schin {
6138462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code; tp++)
6144887Schin if (streq(s, tp->code))
6154887Schin {
6164887Schin for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
6174887Schin if (i >= elementsof(tp->languages))
6184887Schin tp = 0;
6194887Schin break;
6204887Schin }
6214887Schin }
6224887Schin else
6234887Schin {
6248462SApril.Chin@Sun.COM for (tp = lc_territories; tp->code; tp++)
6254887Schin if (match(s, tp->name, 3, 0))
6264887Schin {
6274887Schin for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++);
6284887Schin if (i < elementsof(tp->languages))
6294887Schin break;
6304887Schin }
6314887Schin }
6324887Schin if (tp && !tp->code)
6334887Schin tp = 0;
6344887Schin }
6354887Schin }
6364887Schin
6374887Schin /*
6384887Schin * attributes -- done here to catch misplaced charset references
6394887Schin */
6404887Schin
6414887Schin if (s = attributes_name)
6424887Schin {
6434887Schin do
6444887Schin {
6454887Schin for (w = s; *s && *s != ','; s++);
6464887Schin c = *s;
6474887Schin *s = 0;
6484887Schin if (!(cp = lp->charset) || !match_charset(w, cp))
6498462SApril.Chin@Sun.COM for (cp = lc_charsets; cp->code; cp++)
6504887Schin if (match_charset(w, cp))
6514887Schin {
6524887Schin ppa = cp;
6534887Schin break;
6544887Schin }
6554887Schin if (!cp->code)
6564887Schin {
6574887Schin for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++)
6584887Schin if (match(w, ap->name, 5, 0))
6594887Schin {
6604887Schin if (ai = newof(0, Lc_attribute_list_t, 1, 0))
6614887Schin {
6624887Schin ai->attribute = ap;
6634887Schin ai->next = al;
6644887Schin al = ai;
6654887Schin }
6664887Schin break;
6674887Schin }
6684887Schin if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1)))
6694887Schin {
6704887Schin ai = (Lc_attribute_list_t*)(ap + 1);
6714887Schin strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w);
6724887Schin ai->attribute = ap;
6734887Schin ai->next = al;
6744887Schin al = ai;
6754887Schin }
6764887Schin }
6774887Schin *s = c;
6784887Schin } while (*s++);
6794887Schin }
6804887Schin
6814887Schin /*
6824887Schin * charset
6834887Schin */
6844887Schin
6854887Schin if (s = charset_name)
6868462SApril.Chin@Sun.COM for (cp = lc_charsets; cp->code; cp++)
6874887Schin if (match_charset(s, cp))
6884887Schin break;
6894887Schin if (!cp || !cp->code)
6904887Schin cp = ppa ? ppa : lp->charset;
6914887Schin mapped:
6924887Schin z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp));
6934887Schin
6944887Schin /*
6954887Schin * add to the list of possibly active locales
6964887Schin */
6974887Schin
6984887Schin override:
6994887Schin n = strlen(name) + 1;
7004887Schin if (!(lc = newof(0, Lc_t, 1, n + z)))
7014887Schin return 0;
7024887Schin strcpy((char*)(lc->name = (const char*)(lc + 1)), name);
7034887Schin strcpy((char*)(lc->code = lc->name + n), s);
7048462SApril.Chin@Sun.COM lc->language = lp ? lp : &lc_languages[0];
7058462SApril.Chin@Sun.COM lc->territory = tp ? tp : &lc_territories[0];
7068462SApril.Chin@Sun.COM lc->charset = cp ? cp : &lc_charsets[0];
70710898Sroland.mainz@nrubsig.org if (!strcmp(lc->charset->code, "utf8"))
70810898Sroland.mainz@nrubsig.org lc->flags |= LC_utf8;
7094887Schin lc->attributes = al;
7104887Schin for (i = 0; i < elementsof(lc->info); i++)
7114887Schin lc->info[i].lc = lc;
7124887Schin #if _WINIX
7134887Schin n = SUBLANG_DEFAULT;
7144887Schin if (tp)
7154887Schin for (i = 0; i < elementsof(tp->languages); i++)
7164887Schin if (lp == tp->languages[i])
7174887Schin {
7184887Schin n = tp->indices[i];
7194887Schin break;
7204887Schin }
7214887Schin lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT);
7224887Schin #endif
7234887Schin lc->next = lcs;
7244887Schin lcs = lc;
7254887Schin return lc;
7264887Schin }
7274887Schin
7284887Schin /*
7294887Schin * return an Lc_t* for each locale in the tables
7304887Schin * one Lc_t is allocated on the first call with lc==0
7314887Schin * this is freed when 0 returned
7324887Schin * the return value is not part of the lcmake() cache
7334887Schin */
7344887Schin
7354887Schin typedef struct Lc_scan_s
7364887Schin {
7374887Schin Lc_t lc;
7384887Schin Lc_attribute_list_t list;
7394887Schin int territory;
7404887Schin int language;
7414887Schin int attribute;
7424887Schin char buf[256];
7434887Schin } Lc_scan_t;
7444887Schin
7454887Schin Lc_t*
lcscan(Lc_t * lc)7464887Schin lcscan(Lc_t* lc)
7474887Schin {
7484887Schin register Lc_scan_t* ls;
7494887Schin
7504887Schin if (!(ls = (Lc_scan_t*)lc))
7514887Schin {
7524887Schin if (!(ls = newof(0, Lc_scan_t, 1, 0)))
7534887Schin return 0;
7544887Schin ls->lc.code = ls->lc.name = ls->buf;
7554887Schin ls->territory = -1;
7564887Schin ls->language = elementsof(ls->lc.territory->languages);
7574887Schin ls->attribute = elementsof(ls->lc.language->attributes);
7584887Schin }
7594887Schin if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute]))
7604887Schin {
7614887Schin if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language]))
7624887Schin {
7638462SApril.Chin@Sun.COM if (!lc_territories[++ls->territory].code)
7644887Schin {
7654887Schin free(ls);
7664887Schin return 0;
7674887Schin }
7688462SApril.Chin@Sun.COM ls->lc.territory = &lc_territories[ls->territory];
7694887Schin ls->lc.language = ls->lc.territory->languages[ls->language = 0];
7704887Schin }
7714887Schin if (ls->lc.language)
7724887Schin {
7738462SApril.Chin@Sun.COM ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &lc_charsets[0];
7744887Schin ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0];
7754887Schin }
7764887Schin else
7774887Schin {
7788462SApril.Chin@Sun.COM ls->lc.charset = &lc_charsets[0];
7794887Schin ls->list.attribute = 0;
7804887Schin }
7814887Schin }
7824887Schin ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0;
7834887Schin #if _WINIX
7844887Schin if (!ls->lc.language || !ls->lc.language->index)
7854887Schin ls->lc.index = 0;
7864887Schin else
7874887Schin {
7884887Schin if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) &&
7894887Schin (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language])))
7904887Schin ls->lc.index = SUBLANG_DEFAULT;
7914887Schin ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT);
7924887Schin }
7934887Schin #endif
7944887Schin canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf));
7954887Schin return (Lc_t*)ls;
7964887Schin }
797