1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * Phong Vo <kpv@research.att.com> * 20*4887Schin * * 21*4887Schin ***********************************************************************/ 22*4887Schin #pragma prototyped 23*4887Schin 24*4887Schin /* 25*4887Schin * locale state implementation 26*4887Schin */ 27*4887Schin 28*4887Schin #include "lclib.h" 29*4887Schin 30*4887Schin #include <ctype.h> 31*4887Schin 32*4887Schin #if _WINIX 33*4887Schin 34*4887Schin #include <ast_windows.h> 35*4887Schin 36*4887Schin #define LANG_CHINESE_SIMPLIFIED LANG_CHINESE 37*4887Schin #define LANG_CHINESE_TRADITIONAL LANG_CHINESE 38*4887Schin #define LANG_NORWEGIAN_BOKMAL LANG_NORWEGIAN 39*4887Schin #define LANG_NORWEGIAN_NYNORSK LANG_NORWEGIAN 40*4887Schin #define LANG_SERBO_CROATIAN LANG_CROATIAN 41*4887Schin 42*4887Schin #define CTRY_CZECH_REPUBLIC CTRY_CZECH 43*4887Schin 44*4887Schin #define SUBLANG_CHINESE_SIMPLIFIED_CHINA SUBLANG_CHINESE_SIMPLIFIED 45*4887Schin #define SUBLANG_CHINESE_SIMPLIFIED_HONG_KONG SUBLANG_CHINESE_HONGKONG 46*4887Schin #define SUBLANG_CHINESE_SIMPLIFIED_SINGAPORE SUBLANG_CHINESE_SINGAPORE 47*4887Schin #define SUBLANG_CHINESE_TRADITIONAL_TAIWAN SUBLANG_CHINESE_TRADITIONAL 48*4887Schin #define SUBLANG_DUTCH_NETHERLANDS_ANTILLES SUBLANG_DUTCH 49*4887Schin #define SUBLANG_DUTCH_BELGIUM SUBLANG_DUTCH_BELGIAN 50*4887Schin #define SUBLANG_ENGLISH_AUSTRALIA SUBLANG_ENGLISH_AUS 51*4887Schin #define SUBLANG_ENGLISH_CANADA SUBLANG_ENGLISH_CAN 52*4887Schin #define SUBLANG_ENGLISH_IRELAND SUBLANG_ENGLISH_EIRE 53*4887Schin #define SUBLANG_ENGLISH_NEW_ZEALAND SUBLANG_ENGLISH_NZ 54*4887Schin #define SUBLANG_ENGLISH_TRINIDAD_TOBAGO SUBLANG_ENGLISH_CARIBBEAN 55*4887Schin #define SUBLANG_ENGLISH_UNITED_KINGDOM SUBLANG_ENGLISH_UK 56*4887Schin #define SUBLANG_ENGLISH_UNITED_STATES SUBLANG_ENGLISH_US 57*4887Schin #define SUBLANG_FRENCH_BELGIUM SUBLANG_FRENCH_BELGIAN 58*4887Schin #define SUBLANG_FRENCH_CANADA SUBLANG_FRENCH_CANADIAN 59*4887Schin #define SUBLANG_FRENCH_SWITZERLAND SUBLANG_FRENCH_SWISS 60*4887Schin #define SUBLANG_GERMAN_AUSTRIA SUBLANG_GERMAN_AUSTRIAN 61*4887Schin #define SUBLANG_GERMAN_SWITZERLAND SUBLANG_GERMAN_SWISS 62*4887Schin #define SUBLANG_ITALIAN_SWITZERLAND SUBLANG_ITALIAN_SWISS 63*4887Schin #define SUBLANG_NORWEGIAN_BOKMAL_NORWAY SUBLANG_NORWEGIAN_BOKMAL 64*4887Schin #define SUBLANG_NORWEGIAN_NORWAY SUBLANG_NORWEGIAN_BOKMAL 65*4887Schin #define SUBLANG_NORWEGIAN_NYNORSK_NORWAY SUBLANG_NORWEGIAN_NYNORSK 66*4887Schin #define SUBLANG_PORTUGUESE_BRAZIL SUBLANG_PORTUGUESE_BRAZILIAN 67*4887Schin 68*4887Schin #endif 69*4887Schin 70*4887Schin #include "lctab.h" 71*4887Schin 72*4887Schin static Lc_numeric_t default_numeric = { '.', -1 }; 73*4887Schin 74*4887Schin static Lc_t default_lc = 75*4887Schin { 76*4887Schin "C", 77*4887Schin "POSIX", 78*4887Schin &language[0], 79*4887Schin &territory[0], 80*4887Schin &charset[0], 81*4887Schin 0, 82*4887Schin LC_default|LC_checked|LC_local, 83*4887Schin 0, 84*4887Schin { 85*4887Schin { &default_lc, 0, 0 }, 86*4887Schin { &default_lc, 0, 0 }, 87*4887Schin { &default_lc, 0, 0 }, 88*4887Schin { &default_lc, 0, 0 }, 89*4887Schin { &default_lc, 0, 0 }, 90*4887Schin { &default_lc, 0, (void*)&default_numeric }, 91*4887Schin { &default_lc, 0, 0 }, 92*4887Schin { &default_lc, 0, 0 }, 93*4887Schin { &default_lc, 0, 0 }, 94*4887Schin { &default_lc, 0, 0 }, 95*4887Schin { &default_lc, 0, 0 }, 96*4887Schin { &default_lc, 0, 0 }, 97*4887Schin { &default_lc, 0, 0 }, 98*4887Schin { &default_lc, 0, 0 } 99*4887Schin } 100*4887Schin }; 101*4887Schin 102*4887Schin static Lc_numeric_t debug_numeric = { ',', '.' }; 103*4887Schin 104*4887Schin static Lc_t debug_lc = 105*4887Schin { 106*4887Schin "debug", 107*4887Schin "debug", 108*4887Schin &language[1], 109*4887Schin &territory[1], 110*4887Schin &charset[0], 111*4887Schin 0, 112*4887Schin LC_debug|LC_checked|LC_local, 113*4887Schin 0, 114*4887Schin { 115*4887Schin { &debug_lc, 0, 0 }, 116*4887Schin { &debug_lc, 0, 0 }, 117*4887Schin { &debug_lc, 0, 0 }, 118*4887Schin { &debug_lc, 0, 0 }, 119*4887Schin { &debug_lc, 0, 0 }, 120*4887Schin { &debug_lc, 0, (void*)&debug_numeric }, 121*4887Schin { &debug_lc, 0, 0 }, 122*4887Schin { &debug_lc, 0, 0 }, 123*4887Schin { &debug_lc, 0, 0 }, 124*4887Schin { &debug_lc, 0, 0 }, 125*4887Schin { &debug_lc, 0, 0 }, 126*4887Schin { &debug_lc, 0, 0 }, 127*4887Schin { &debug_lc, 0, 0 }, 128*4887Schin { &debug_lc, 0, 0 } 129*4887Schin }, 130*4887Schin &default_lc 131*4887Schin }; 132*4887Schin 133*4887Schin static Lc_t* lcs = &debug_lc; 134*4887Schin 135*4887Schin Lc_t* locales[] = 136*4887Schin { 137*4887Schin &default_lc, 138*4887Schin &default_lc, 139*4887Schin &default_lc, 140*4887Schin &default_lc, 141*4887Schin &default_lc, 142*4887Schin &default_lc, 143*4887Schin &default_lc, 144*4887Schin &default_lc, 145*4887Schin &default_lc, 146*4887Schin &default_lc, 147*4887Schin &default_lc, 148*4887Schin &default_lc, 149*4887Schin &default_lc, 150*4887Schin &default_lc 151*4887Schin }; 152*4887Schin 153*4887Schin /* 154*4887Schin * return the internal category index for category 155*4887Schin */ 156*4887Schin 157*4887Schin int 158*4887Schin lcindex(int category, int min) 159*4887Schin { 160*4887Schin switch (category) 161*4887Schin { 162*4887Schin case LC_ALL: return min ? -1 : AST_LC_ALL; 163*4887Schin case LC_ADDRESS: return AST_LC_ADDRESS; 164*4887Schin case LC_COLLATE: return AST_LC_COLLATE; 165*4887Schin case LC_CTYPE: return AST_LC_CTYPE; 166*4887Schin case LC_IDENTIFICATION: return AST_LC_IDENTIFICATION; 167*4887Schin case LC_MEASUREMENT: return AST_LC_MEASUREMENT; 168*4887Schin case LC_MESSAGES: return AST_LC_MESSAGES; 169*4887Schin case LC_MONETARY: return AST_LC_MONETARY; 170*4887Schin case LC_NAME: return AST_LC_NAME; 171*4887Schin case LC_NUMERIC: return AST_LC_NUMERIC; 172*4887Schin case LC_PAPER: return AST_LC_PAPER; 173*4887Schin case LC_TELEPHONE: return AST_LC_TELEPHONE; 174*4887Schin case LC_TIME: return AST_LC_TIME; 175*4887Schin case LC_XLITERATE: return AST_LC_XLITERATE; 176*4887Schin } 177*4887Schin return -1; 178*4887Schin } 179*4887Schin 180*4887Schin /* 181*4887Schin * return the first category table entry 182*4887Schin */ 183*4887Schin 184*4887Schin Lc_category_t* 185*4887Schin lccategories(void) 186*4887Schin { 187*4887Schin return &categories[0]; 188*4887Schin } 189*4887Schin 190*4887Schin /* 191*4887Schin * return the current info for category 192*4887Schin */ 193*4887Schin 194*4887Schin Lc_info_t* 195*4887Schin lcinfo(register int category) 196*4887Schin { 197*4887Schin if ((category = lcindex(category, 0)) < 0) 198*4887Schin return 0; 199*4887Schin return LCINFO(category); 200*4887Schin } 201*4887Schin 202*4887Schin /* 203*4887Schin * return 1 if s matches the alternation pattern p 204*4887Schin * if minimum!=0 then at least that many chars must match 205*4887Schin * if standard!=0 and s[0] is a digit leading non-digits are ignored in p 206*4887Schin */ 207*4887Schin 208*4887Schin static int 209*4887Schin match(const char* s, register const char* p, int minimum, int standard) 210*4887Schin { 211*4887Schin register const char* t; 212*4887Schin const char* x; 213*4887Schin int w; 214*4887Schin int z; 215*4887Schin 216*4887Schin z = 0; 217*4887Schin do 218*4887Schin { 219*4887Schin t = s; 220*4887Schin if (standard) 221*4887Schin { 222*4887Schin if (isdigit(*t)) 223*4887Schin while (*p && !isdigit(*p)) 224*4887Schin p++; 225*4887Schin else if (isdigit(*p)) 226*4887Schin while (*t && !isdigit(*t)) 227*4887Schin t++; 228*4887Schin } 229*4887Schin if (*p) 230*4887Schin { 231*4887Schin w = 0; 232*4887Schin x = p; 233*4887Schin while (*p && *p != '|') 234*4887Schin { 235*4887Schin if (!*t || *t == ',') 236*4887Schin break; 237*4887Schin else if (*t == *p) 238*4887Schin /*ok*/; 239*4887Schin else if (*t == '-') 240*4887Schin { 241*4887Schin if (standard && isdigit(*p)) 242*4887Schin { 243*4887Schin t++; 244*4887Schin continue; 245*4887Schin } 246*4887Schin while (*p && *p != '-') 247*4887Schin p++; 248*4887Schin if (!*p) 249*4887Schin break; 250*4887Schin } 251*4887Schin else if (*p == '-') 252*4887Schin { 253*4887Schin if (standard && isdigit(*t)) 254*4887Schin { 255*4887Schin p++; 256*4887Schin continue; 257*4887Schin } 258*4887Schin w = 1; 259*4887Schin while (*t && *t != '-') 260*4887Schin t++; 261*4887Schin if (!*t) 262*4887Schin break; 263*4887Schin } 264*4887Schin else 265*4887Schin break; 266*4887Schin t++; 267*4887Schin p++; 268*4887Schin } 269*4887Schin if ((!*t || *t == ',') && (!*p || *p == '|' || w)) 270*4887Schin return p - x; 271*4887Schin if (minimum && z < (p - x) && (p - x) >= minimum) 272*4887Schin z = p - x; 273*4887Schin } 274*4887Schin while (*p && *p != '|') 275*4887Schin p++; 276*4887Schin } while (*p++); 277*4887Schin return z; 278*4887Schin } 279*4887Schin 280*4887Schin /* 281*4887Schin * return 1 if s matches the charset names in cp 282*4887Schin */ 283*4887Schin 284*4887Schin static int 285*4887Schin match_charset(register const char* s, register const Lc_charset_t* cp) 286*4887Schin { 287*4887Schin return match(s, cp->code, 0, 1) || match(s, cp->alternates, 3, 1) || cp->ms && match(s, cp->ms, 0, 1); 288*4887Schin } 289*4887Schin 290*4887Schin /* 291*4887Schin * low level for lccanon 292*4887Schin */ 293*4887Schin 294*4887Schin static size_t 295*4887Schin 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) 296*4887Schin { 297*4887Schin register int c; 298*4887Schin register int u; 299*4887Schin register char* s; 300*4887Schin register char* e; 301*4887Schin register const char* t; 302*4887Schin 303*4887Schin if (!(flags & (LC_abbreviated|LC_default|LC_local|LC_qualified|LC_verbose))) 304*4887Schin flags |= LC_abbreviated; 305*4887Schin s = buf; 306*4887Schin e = &buf[siz - 3]; 307*4887Schin if (lp) 308*4887Schin { 309*4887Schin if (lp->flags & (LC_debug|LC_default)) 310*4887Schin { 311*4887Schin for (t = lp->code; s < e && (*s = *t++); s++); 312*4887Schin *s++ = 0; 313*4887Schin return s - buf; 314*4887Schin } 315*4887Schin if (flags & LC_verbose) 316*4887Schin { 317*4887Schin u = 1; 318*4887Schin t = lp->name; 319*4887Schin while (s < e && (c = *t++)) 320*4887Schin { 321*4887Schin if (u) 322*4887Schin { 323*4887Schin u = 0; 324*4887Schin c = toupper(c); 325*4887Schin } 326*4887Schin else if (!isalnum(c)) 327*4887Schin u = 1; 328*4887Schin *s++ = c; 329*4887Schin } 330*4887Schin } 331*4887Schin else 332*4887Schin for (t = lp->code; s < e && (*s = *t++); s++); 333*4887Schin } 334*4887Schin if (s < e) 335*4887Schin { 336*4887Schin if (tp && tp != &territory[0] && (!(flags & (LC_abbreviated|LC_default)) || !lp || !streq(lp->code, tp->code))) 337*4887Schin { 338*4887Schin if (lp) 339*4887Schin *s++ = '_'; 340*4887Schin if (flags & LC_verbose) 341*4887Schin { 342*4887Schin u = 1; 343*4887Schin t = tp->name; 344*4887Schin while (s < e && (c = *t++) && c != '|') 345*4887Schin { 346*4887Schin if (u) 347*4887Schin { 348*4887Schin u = 0; 349*4887Schin c = toupper(c); 350*4887Schin } 351*4887Schin else if (!isalnum(c)) 352*4887Schin u = 1; 353*4887Schin *s++ = c; 354*4887Schin } 355*4887Schin } 356*4887Schin else 357*4887Schin for (t = tp->code; s < e && (*s = toupper(*t++)); s++); 358*4887Schin } 359*4887Schin if (lp && (!(flags & (LC_abbreviated|LC_default)) || cp != lp->charset) && s < e) 360*4887Schin { 361*4887Schin *s++ = '.'; 362*4887Schin for (t = cp->code; s < e && (c = *t++); s++) 363*4887Schin { 364*4887Schin if (islower(c)) 365*4887Schin c = toupper(c); 366*4887Schin *s = c; 367*4887Schin } 368*4887Schin } 369*4887Schin for (c = '@'; ap && s < e; ap = ap->next) 370*4887Schin if (!(flags & (LC_abbreviated|LC_default|LC_verbose)) || !(ap->attribute->flags & LC_default)) 371*4887Schin { 372*4887Schin *s++ = c; 373*4887Schin c = ','; 374*4887Schin for (t = ap->attribute->name; s < e && (*s = *t++); s++); 375*4887Schin } 376*4887Schin } 377*4887Schin *s++ = 0; 378*4887Schin return s - buf; 379*4887Schin } 380*4887Schin 381*4887Schin /* 382*4887Schin * generate a canonical locale name in buf 383*4887Schin */ 384*4887Schin 385*4887Schin size_t 386*4887Schin lccanon(Lc_t* lc, unsigned long flags, char* buf, size_t siz) 387*4887Schin { 388*4887Schin if ((flags & LC_local) && (!lc->language || !(lc->language->flags & (LC_debug|LC_default)))) 389*4887Schin { 390*4887Schin #if _WINIX 391*4887Schin char lang[64]; 392*4887Schin char code[64]; 393*4887Schin char ctry[64]; 394*4887Schin 395*4887Schin if (lc->index && 396*4887Schin GetLocaleInfo(lc->index, LOCALE_SENGLANGUAGE, lang, sizeof(lang)) && 397*4887Schin GetLocaleInfo(lc->index, LOCALE_SENGCOUNTRY, ctry, sizeof(ctry))) 398*4887Schin { 399*4887Schin if (!GetLocaleInfo(lc->index, LOCALE_IDEFAULTANSICODEPAGE, code, sizeof(code))) 400*4887Schin code[0] = 0; 401*4887Schin if (!lc->charset || !lc->charset->ms) 402*4887Schin return sfsprintf(buf, siz, "%s_%s", lang, ctry); 403*4887Schin else if (streq(lc->charset->ms, code)) 404*4887Schin return sfsprintf(buf, siz, "%s_%s.%s", lang, ctry, code); 405*4887Schin else 406*4887Schin return sfsprintf(buf, siz, "%s_%s.%s,%s", lang, ctry, code, lc->charset->ms); 407*4887Schin } 408*4887Schin #endif 409*4887Schin buf[0] = '-'; 410*4887Schin buf[1] = 0; 411*4887Schin return 0; 412*4887Schin } 413*4887Schin return canonical(lc->language, lc->territory, lc->charset, lc->attributes, flags, buf, siz); 414*4887Schin } 415*4887Schin 416*4887Schin /* 417*4887Schin * make an Lc_t from a locale name 418*4887Schin */ 419*4887Schin 420*4887Schin Lc_t* 421*4887Schin lcmake(const char* name) 422*4887Schin { 423*4887Schin register int c; 424*4887Schin register char* s; 425*4887Schin register char* e; 426*4887Schin register const char* t; 427*4887Schin const char* a; 428*4887Schin char* w; 429*4887Schin char* language_name; 430*4887Schin char* territory_name; 431*4887Schin char* charset_name; 432*4887Schin char* attributes_name; 433*4887Schin Lc_t* lc; 434*4887Schin const Lc_map_t* mp; 435*4887Schin const Lc_language_t* lp; 436*4887Schin const Lc_territory_t* tp; 437*4887Schin const Lc_territory_t* tpb; 438*4887Schin const Lc_territory_t* primary; 439*4887Schin const Lc_charset_t* cp; 440*4887Schin const Lc_charset_t* ppa; 441*4887Schin const Lc_attribute_t* ap; 442*4887Schin Lc_attribute_list_t* ai; 443*4887Schin Lc_attribute_list_t* al; 444*4887Schin int i; 445*4887Schin int n; 446*4887Schin int z; 447*4887Schin char buf[PATH_MAX / 2]; 448*4887Schin char tmp[PATH_MAX / 2]; 449*4887Schin 450*4887Schin if (!(t = name) || !*t) 451*4887Schin return &default_lc; 452*4887Schin for (lc = lcs; lc; lc = lc->next) 453*4887Schin if (!strcasecmp(t, lc->code) || !strcasecmp(t, lc->name)) 454*4887Schin return lc; 455*4887Schin for (mp = map; mp->code; mp++) 456*4887Schin if (streq(t, mp->code)) 457*4887Schin { 458*4887Schin lp = mp->language; 459*4887Schin tp = mp->territory; 460*4887Schin cp = mp->charset; 461*4887Schin if (!mp->attribute) 462*4887Schin al = 0; 463*4887Schin else if (al = newof(0, Lc_attribute_list_t, 1, 0)) 464*4887Schin al->attribute = mp->attribute; 465*4887Schin goto mapped; 466*4887Schin } 467*4887Schin language_name = buf; 468*4887Schin territory_name = charset_name = attributes_name = 0; 469*4887Schin s = buf; 470*4887Schin e = &buf[sizeof(buf)-2]; 471*4887Schin a = 0; 472*4887Schin n = 0; 473*4887Schin while (s < e && (c = *t++)) 474*4887Schin { 475*4887Schin if (isspace(c) || (c == '(' || c == '-' && *t == '-') && ++n) 476*4887Schin { 477*4887Schin while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n)) 478*4887Schin if (!c) 479*4887Schin break; 480*4887Schin if (isalnum(c) && !n) 481*4887Schin *s++ = '-'; 482*4887Schin else 483*4887Schin { 484*4887Schin n = 0; 485*4887Schin if (!a) 486*4887Schin { 487*4887Schin a = t - 1; 488*4887Schin while (c && c != '_' && c != '.' && c != '@') 489*4887Schin c = *t++; 490*4887Schin if (!c) 491*4887Schin break; 492*4887Schin } 493*4887Schin } 494*4887Schin } 495*4887Schin if (c == '_' && !territory_name) 496*4887Schin { 497*4887Schin *s++ = 0; 498*4887Schin territory_name = s; 499*4887Schin } 500*4887Schin else if (c == '.' && !charset_name) 501*4887Schin { 502*4887Schin *s++ = 0; 503*4887Schin charset_name = s; 504*4887Schin } 505*4887Schin else if (c == '@' && !attributes_name) 506*4887Schin { 507*4887Schin *s++ = 0; 508*4887Schin attributes_name = s; 509*4887Schin } 510*4887Schin else 511*4887Schin { 512*4887Schin if (isupper(c)) 513*4887Schin c = tolower(c); 514*4887Schin *s++ = c; 515*4887Schin } 516*4887Schin } 517*4887Schin if ((t = a) && s < e) 518*4887Schin { 519*4887Schin if (attributes_name) 520*4887Schin *s++ = ','; 521*4887Schin else 522*4887Schin { 523*4887Schin *s++ = 0; 524*4887Schin attributes_name = s; 525*4887Schin } 526*4887Schin while (s < e && (c = *t++)) 527*4887Schin { 528*4887Schin if (isspace(c) || (c == '(' || c == ')' || c == '-' && *t == '-') && ++n) 529*4887Schin { 530*4887Schin while ((c = *t++) && (isspace(c) || (c == '-' || c == '(' || c == ')') && ++n)) 531*4887Schin if (!c) 532*4887Schin break; 533*4887Schin if (isalnum(c) && !n) 534*4887Schin *s++ = '-'; 535*4887Schin else 536*4887Schin n = 0; 537*4887Schin } 538*4887Schin if (c == '_' || c == '.' || c == '@') 539*4887Schin break; 540*4887Schin if (isupper(c)) 541*4887Schin c = tolower(c); 542*4887Schin *s++ = c; 543*4887Schin } 544*4887Schin } 545*4887Schin *s = 0; 546*4887Schin tp = 0; 547*4887Schin cp = ppa = 0; 548*4887Schin al = 0; 549*4887Schin 550*4887Schin /* 551*4887Schin * language 552*4887Schin */ 553*4887Schin 554*4887Schin n = strlen(s = language_name); 555*4887Schin if (n == 2) 556*4887Schin for (lp = language; lp->code && !streq(s, lp->code); lp++); 557*4887Schin else if (n == 3) 558*4887Schin { 559*4887Schin for (lp = language; lp->code && (!lp->alternates || !match(s, lp->alternates, n, 0)); lp++); 560*4887Schin if (!lp->code) 561*4887Schin { 562*4887Schin c = s[2]; 563*4887Schin s[2] = 0; 564*4887Schin for (lp = language; lp->code && !streq(s, lp->code); lp++); 565*4887Schin s[2] = c; 566*4887Schin if (lp->code) 567*4887Schin n = 1; 568*4887Schin } 569*4887Schin } 570*4887Schin else 571*4887Schin lp = 0; 572*4887Schin if (!lp || !lp->code) 573*4887Schin { 574*4887Schin for (lp = language; lp->code && !match(s, lp->name, 0, 0); lp++); 575*4887Schin if (!lp || !lp->code) 576*4887Schin { 577*4887Schin if (!territory_name) 578*4887Schin { 579*4887Schin if (n == 2) 580*4887Schin for (tp = territory; tp->code && !streq(s, tp->code); tp++); 581*4887Schin else 582*4887Schin { 583*4887Schin z = 0; 584*4887Schin tpb = 0; 585*4887Schin for (tp = territory; tp->name; tp++) 586*4887Schin if ((i = match(s, tp->name, 3, 0)) > z) 587*4887Schin { 588*4887Schin tpb = tp; 589*4887Schin if ((z = i) == n) 590*4887Schin break; 591*4887Schin } 592*4887Schin if (tpb) 593*4887Schin tp = tpb; 594*4887Schin } 595*4887Schin if (tp->code) 596*4887Schin lp = tp->languages[0]; 597*4887Schin } 598*4887Schin if (!lp || !lp->code) 599*4887Schin { 600*4887Schin /* 601*4887Schin * name not in the tables so let 602*4887Schin * _ast_setlocale() and/or setlocale() 603*4887Schin * handle the validity checks 604*4887Schin */ 605*4887Schin 606*4887Schin s = (char*)name; 607*4887Schin z = strlen(s) + 1; 608*4887Schin if (!(lp = newof(0, Lc_language_t, 1, z))) 609*4887Schin return 0; 610*4887Schin name = ((Lc_language_t*)lp)->code = ((Lc_language_t*)lp)->name = (const char*)(lp + 1); 611*4887Schin memcpy((char*)lp->code, s, z - 1); 612*4887Schin tp = &territory[0]; 613*4887Schin cp = ((Lc_language_t*)lp)->charset = &charset[0]; 614*4887Schin al = 0; 615*4887Schin goto override; 616*4887Schin } 617*4887Schin } 618*4887Schin } 619*4887Schin 620*4887Schin /* 621*4887Schin * territory 622*4887Schin */ 623*4887Schin 624*4887Schin if (!tp || !tp->code) 625*4887Schin { 626*4887Schin if (!(s = territory_name)) 627*4887Schin { 628*4887Schin n = 0; 629*4887Schin primary = 0; 630*4887Schin for (tp = territory; tp->code; tp++) 631*4887Schin if (tp->languages[0] == lp) 632*4887Schin { 633*4887Schin if (tp->flags & LC_primary) 634*4887Schin { 635*4887Schin n = 1; 636*4887Schin primary = tp; 637*4887Schin break; 638*4887Schin } 639*4887Schin n++; 640*4887Schin primary = tp; 641*4887Schin } 642*4887Schin if (n == 1) 643*4887Schin tp = primary; 644*4887Schin s = (char*)lp->code; 645*4887Schin } 646*4887Schin if (!tp || !tp->code) 647*4887Schin { 648*4887Schin n = strlen(s); 649*4887Schin if (n == 2) 650*4887Schin { 651*4887Schin for (tp = territory; tp->code; tp++) 652*4887Schin if (streq(s, tp->code)) 653*4887Schin { 654*4887Schin for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++); 655*4887Schin if (i >= elementsof(tp->languages)) 656*4887Schin tp = 0; 657*4887Schin break; 658*4887Schin } 659*4887Schin } 660*4887Schin else 661*4887Schin { 662*4887Schin for (tp = territory; tp->code; tp++) 663*4887Schin if (match(s, tp->name, 3, 0)) 664*4887Schin { 665*4887Schin for (i = 0; i < elementsof(tp->languages) && lp != tp->languages[i]; i++); 666*4887Schin if (i < elementsof(tp->languages)) 667*4887Schin break; 668*4887Schin } 669*4887Schin } 670*4887Schin if (tp && !tp->code) 671*4887Schin tp = 0; 672*4887Schin } 673*4887Schin } 674*4887Schin 675*4887Schin /* 676*4887Schin * attributes -- done here to catch misplaced charset references 677*4887Schin */ 678*4887Schin 679*4887Schin if (s = attributes_name) 680*4887Schin { 681*4887Schin do 682*4887Schin { 683*4887Schin for (w = s; *s && *s != ','; s++); 684*4887Schin c = *s; 685*4887Schin *s = 0; 686*4887Schin if (!(cp = lp->charset) || !match_charset(w, cp)) 687*4887Schin for (cp = charset; cp->code; cp++) 688*4887Schin if (match_charset(w, cp)) 689*4887Schin { 690*4887Schin ppa = cp; 691*4887Schin break; 692*4887Schin } 693*4887Schin if (!cp->code) 694*4887Schin { 695*4887Schin for (i = 0; i < elementsof(lp->attributes) && (ap = lp->attributes[i]); i++) 696*4887Schin if (match(w, ap->name, 5, 0)) 697*4887Schin { 698*4887Schin if (ai = newof(0, Lc_attribute_list_t, 1, 0)) 699*4887Schin { 700*4887Schin ai->attribute = ap; 701*4887Schin ai->next = al; 702*4887Schin al = ai; 703*4887Schin } 704*4887Schin break; 705*4887Schin } 706*4887Schin if (i >= elementsof(lp->attributes) && (ap = newof(0, Lc_attribute_t, 1, sizeof(Lc_attribute_list_t) + s - w + 1))) 707*4887Schin { 708*4887Schin ai = (Lc_attribute_list_t*)(ap + 1); 709*4887Schin strcpy((char*)(((Lc_attribute_t*)ap)->name = (const char*)(ai + 1)), w); 710*4887Schin ai->attribute = ap; 711*4887Schin ai->next = al; 712*4887Schin al = ai; 713*4887Schin } 714*4887Schin } 715*4887Schin *s = c; 716*4887Schin } while (*s++); 717*4887Schin } 718*4887Schin 719*4887Schin /* 720*4887Schin * charset 721*4887Schin */ 722*4887Schin 723*4887Schin if (s = charset_name) 724*4887Schin for (cp = charset; cp->code; cp++) 725*4887Schin if (match_charset(s, cp)) 726*4887Schin break; 727*4887Schin if (!cp || !cp->code) 728*4887Schin cp = ppa ? ppa : lp->charset; 729*4887Schin mapped: 730*4887Schin z = canonical(lp, tp, cp, al, 0, s = tmp, sizeof(tmp)); 731*4887Schin 732*4887Schin /* 733*4887Schin * add to the list of possibly active locales 734*4887Schin */ 735*4887Schin 736*4887Schin override: 737*4887Schin n = strlen(name) + 1; 738*4887Schin if (!(lc = newof(0, Lc_t, 1, n + z))) 739*4887Schin return 0; 740*4887Schin strcpy((char*)(lc->name = (const char*)(lc + 1)), name); 741*4887Schin strcpy((char*)(lc->code = lc->name + n), s); 742*4887Schin lc->language = lp ? lp : &language[0]; 743*4887Schin lc->territory = tp ? tp : &territory[0]; 744*4887Schin lc->charset = cp ? cp : &charset[0]; 745*4887Schin lc->attributes = al; 746*4887Schin for (i = 0; i < elementsof(lc->info); i++) 747*4887Schin lc->info[i].lc = lc; 748*4887Schin #if _WINIX 749*4887Schin n = SUBLANG_DEFAULT; 750*4887Schin if (tp) 751*4887Schin for (i = 0; i < elementsof(tp->languages); i++) 752*4887Schin if (lp == tp->languages[i]) 753*4887Schin { 754*4887Schin n = tp->indices[i]; 755*4887Schin break; 756*4887Schin } 757*4887Schin lc->index = MAKELCID(MAKELANGID(lp->index, n), SORT_DEFAULT); 758*4887Schin #endif 759*4887Schin lc->next = lcs; 760*4887Schin lcs = lc; 761*4887Schin return lc; 762*4887Schin } 763*4887Schin 764*4887Schin /* 765*4887Schin * return an Lc_t* for each locale in the tables 766*4887Schin * one Lc_t is allocated on the first call with lc==0 767*4887Schin * this is freed when 0 returned 768*4887Schin * the return value is not part of the lcmake() cache 769*4887Schin */ 770*4887Schin 771*4887Schin typedef struct Lc_scan_s 772*4887Schin { 773*4887Schin Lc_t lc; 774*4887Schin Lc_attribute_list_t list; 775*4887Schin int territory; 776*4887Schin int language; 777*4887Schin int attribute; 778*4887Schin char buf[256]; 779*4887Schin } Lc_scan_t; 780*4887Schin 781*4887Schin Lc_t* 782*4887Schin lcscan(Lc_t* lc) 783*4887Schin { 784*4887Schin register Lc_scan_t* ls; 785*4887Schin 786*4887Schin if (!(ls = (Lc_scan_t*)lc)) 787*4887Schin { 788*4887Schin if (!(ls = newof(0, Lc_scan_t, 1, 0))) 789*4887Schin return 0; 790*4887Schin ls->lc.code = ls->lc.name = ls->buf; 791*4887Schin ls->territory = -1; 792*4887Schin ls->language = elementsof(ls->lc.territory->languages); 793*4887Schin ls->attribute = elementsof(ls->lc.language->attributes); 794*4887Schin } 795*4887Schin if (++ls->attribute >= elementsof(ls->lc.language->attributes) || !(ls->list.attribute = ls->lc.language->attributes[ls->attribute])) 796*4887Schin { 797*4887Schin if (++ls->language >= elementsof(ls->lc.territory->languages) || !(ls->lc.language = ls->lc.territory->languages[ls->language])) 798*4887Schin { 799*4887Schin if (++ls->territory >= (elementsof(territory) - 1)) 800*4887Schin { 801*4887Schin free(ls); 802*4887Schin return 0; 803*4887Schin } 804*4887Schin ls->lc.territory = &territory[ls->territory]; 805*4887Schin ls->lc.language = ls->lc.territory->languages[ls->language = 0]; 806*4887Schin } 807*4887Schin if (ls->lc.language) 808*4887Schin { 809*4887Schin ls->lc.charset = ls->lc.language->charset ? ls->lc.language->charset : &charset[0]; 810*4887Schin ls->list.attribute = ls->lc.language->attributes[ls->attribute = 0]; 811*4887Schin } 812*4887Schin else 813*4887Schin { 814*4887Schin ls->lc.charset = &charset[0]; 815*4887Schin ls->list.attribute = 0; 816*4887Schin } 817*4887Schin } 818*4887Schin ls->lc.attributes = ls->list.attribute ? &ls->list : (Lc_attribute_list_t*)0; 819*4887Schin #if _WINIX 820*4887Schin if (!ls->lc.language || !ls->lc.language->index) 821*4887Schin ls->lc.index = 0; 822*4887Schin else 823*4887Schin { 824*4887Schin if ((!ls->list.attribute || !(ls->lc.index = ls->list.attribute->index)) && 825*4887Schin (!ls->lc.territory || !(ls->lc.index = ls->lc.territory->indices[ls->language]))) 826*4887Schin ls->lc.index = SUBLANG_DEFAULT; 827*4887Schin ls->lc.index = MAKELCID(MAKELANGID(ls->lc.language->index, ls->lc.index), SORT_DEFAULT); 828*4887Schin } 829*4887Schin #endif 830*4887Schin canonical(ls->lc.language, ls->lc.territory, ls->lc.charset, ls->lc.attributes, 0, ls->buf, sizeof(ls->buf)); 831*4887Schin return (Lc_t*)ls; 832*4887Schin } 833