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