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