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 * setlocale() intercept
26da2e3ebdSchin * maintains a bitmask of non-default categories
27da2e3ebdSchin * and a permanent locale namespace for pointer comparison
28da2e3ebdSchin * and persistent private data for locale related functions
29da2e3ebdSchin */
30da2e3ebdSchin
31da2e3ebdSchin #include <ast_standards.h>
32da2e3ebdSchin
33da2e3ebdSchin #include "lclib.h"
34da2e3ebdSchin
35da2e3ebdSchin #include <ast_wchar.h>
36da2e3ebdSchin #include <ctype.h>
37da2e3ebdSchin #include <mc.h>
38da2e3ebdSchin #include <namval.h>
39da2e3ebdSchin
40da2e3ebdSchin #if ( _lib_wcwidth || _lib_wctomb ) && _hdr_wctype
41da2e3ebdSchin #include <wctype.h>
42da2e3ebdSchin #endif
43da2e3ebdSchin
44da2e3ebdSchin #if _lib_wcwidth
45da2e3ebdSchin #undef wcwidth
46da2e3ebdSchin #else
47da2e3ebdSchin #define wcwidth 0
48da2e3ebdSchin #endif
49da2e3ebdSchin
50da2e3ebdSchin #if _lib_wctomb
51da2e3ebdSchin #undef wctomb
52da2e3ebdSchin #else
53da2e3ebdSchin #define wctomb 0
54da2e3ebdSchin #endif
55da2e3ebdSchin
56da2e3ebdSchin #ifdef mblen
57da2e3ebdSchin #undef mblen
58da2e3ebdSchin extern int mblen(const char*, size_t);
59da2e3ebdSchin #endif
60da2e3ebdSchin
61da2e3ebdSchin #undef mbtowc
62da2e3ebdSchin #undef setlocale
63da2e3ebdSchin #undef strcmp
64da2e3ebdSchin #undef strcoll
65da2e3ebdSchin #undef strxfrm
66da2e3ebdSchin #undef valid
67da2e3ebdSchin
68da2e3ebdSchin #ifndef AST_LC_CANONICAL
69da2e3ebdSchin #define AST_LC_CANONICAL LC_abbreviated
70da2e3ebdSchin #endif
71da2e3ebdSchin
7234f9b3eeSRoland Mainz #ifndef AST_LC_test
7334f9b3eeSRoland Mainz #define AST_LC_test (1L<<27)
7434f9b3eeSRoland Mainz #endif
7534f9b3eeSRoland Mainz
76da2e3ebdSchin #if _UWIN
77da2e3ebdSchin
78da2e3ebdSchin #include <ast_windows.h>
79da2e3ebdSchin
80da2e3ebdSchin #undef _lib_setlocale
81da2e3ebdSchin #define _lib_setlocale 1
82da2e3ebdSchin
83da2e3ebdSchin #define setlocale(c,l) native_setlocale(c,l)
84da2e3ebdSchin
85da2e3ebdSchin extern char* uwin_setlocale(int, const char*);
86da2e3ebdSchin
87da2e3ebdSchin /*
88da2e3ebdSchin * convert locale to native locale name in buf
89da2e3ebdSchin */
90da2e3ebdSchin
91da2e3ebdSchin static char*
native_locale(const char * locale,char * buf,size_t siz)92da2e3ebdSchin native_locale(const char* locale, char* buf, size_t siz)
93da2e3ebdSchin {
94da2e3ebdSchin Lc_t* lc;
95da2e3ebdSchin const Lc_attribute_list_t* ap;
96da2e3ebdSchin int i;
97da2e3ebdSchin unsigned long lcid;
98da2e3ebdSchin unsigned long lang;
99da2e3ebdSchin unsigned long ctry;
100da2e3ebdSchin char lbuf[128];
101da2e3ebdSchin char cbuf[128];
102da2e3ebdSchin
103da2e3ebdSchin if (locale && *locale)
104da2e3ebdSchin {
105da2e3ebdSchin if (!(lc = lcmake(locale)))
106da2e3ebdSchin return 0;
107da2e3ebdSchin lang = lc->language->index;
108da2e3ebdSchin ctry = 0;
109da2e3ebdSchin for (ap = lc->attributes; ap; ap = ap->next)
110da2e3ebdSchin if (ctry = ap->attribute->index)
111da2e3ebdSchin break;
112da2e3ebdSchin if (!ctry)
113da2e3ebdSchin {
114da2e3ebdSchin for (i = 0; i < elementsof(lc->territory->languages); i++)
115da2e3ebdSchin if (lc->territory->languages[i] == lc->language)
116da2e3ebdSchin {
117da2e3ebdSchin ctry = lc->territory->indices[i];
118da2e3ebdSchin break;
119da2e3ebdSchin }
120da2e3ebdSchin if (!ctry)
12134f9b3eeSRoland Mainz {
12234f9b3eeSRoland Mainz if (!lang)
12334f9b3eeSRoland Mainz return 0;
124da2e3ebdSchin ctry = SUBLANG_DEFAULT;
125da2e3ebdSchin }
12634f9b3eeSRoland Mainz }
127da2e3ebdSchin lcid = MAKELCID(MAKELANGID(lang, ctry), SORT_DEFAULT);
128da2e3ebdSchin }
129da2e3ebdSchin else
130da2e3ebdSchin lcid = GetUserDefaultLCID();
131da2e3ebdSchin if (GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, lbuf, sizeof(lbuf)) <= 0 ||
132da2e3ebdSchin GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, cbuf, sizeof(cbuf)) <= 0)
133da2e3ebdSchin return 0;
134da2e3ebdSchin if (lc->charset->ms)
135da2e3ebdSchin sfsprintf(buf, siz, "%s_%s.%s", lbuf, cbuf, lc->charset->ms);
136da2e3ebdSchin else
137da2e3ebdSchin sfsprintf(buf, siz, "%s_%s", lbuf, cbuf);
138da2e3ebdSchin return buf;
139da2e3ebdSchin }
140da2e3ebdSchin
141da2e3ebdSchin /*
142da2e3ebdSchin * locale!=0 here
143da2e3ebdSchin */
144da2e3ebdSchin
145da2e3ebdSchin static char*
native_setlocale(int category,const char * locale)146da2e3ebdSchin native_setlocale(int category, const char* locale)
147da2e3ebdSchin {
148da2e3ebdSchin char* usr;
149da2e3ebdSchin char* sys;
150da2e3ebdSchin char buf[256];
151da2e3ebdSchin
15234f9b3eeSRoland Mainz if (!(usr = native_locale(locale, buf, sizeof(buf))))
15334f9b3eeSRoland Mainz return 0;
15434f9b3eeSRoland Mainz
155da2e3ebdSchin /*
156da2e3ebdSchin * win32 doesn't have LC_MESSAGES
157da2e3ebdSchin */
158da2e3ebdSchin
159da2e3ebdSchin if (category == LC_MESSAGES)
160da2e3ebdSchin return (char*)locale;
161da2e3ebdSchin sys = uwin_setlocale(category, usr);
162da2e3ebdSchin if (ast.locale.set & AST_LC_debug)
1637c2fbfb3SApril Chin sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", lc_categories[lcindex(category, 0)].name, usr, sys);
164da2e3ebdSchin return sys;
165da2e3ebdSchin }
166da2e3ebdSchin
167da2e3ebdSchin #else
168da2e3ebdSchin
169da2e3ebdSchin #define native_locale(a,b,c) ((char*)0)
170da2e3ebdSchin
171da2e3ebdSchin #endif
172da2e3ebdSchin
173da2e3ebdSchin /*
174da2e3ebdSchin * LC_COLLATE and LC_CTYPE native support
175da2e3ebdSchin */
176da2e3ebdSchin
177da2e3ebdSchin #if !_lib_mbtowc || MB_LEN_MAX <= 1
178da2e3ebdSchin #define mblen 0
179da2e3ebdSchin #define mbtowc 0
180da2e3ebdSchin #endif
181da2e3ebdSchin
182da2e3ebdSchin #if !_lib_strcoll
183da2e3ebdSchin #define strcoll 0
184da2e3ebdSchin #endif
185da2e3ebdSchin
186da2e3ebdSchin #if !_lib_strxfrm
187da2e3ebdSchin #define strxfrm 0
188da2e3ebdSchin #endif
189da2e3ebdSchin
190da2e3ebdSchin /*
191da2e3ebdSchin * LC_COLLATE and LC_CTYPE debug support
192da2e3ebdSchin *
193da2e3ebdSchin * mutibyte debug encoding
194da2e3ebdSchin *
195da2e3ebdSchin * DL0 [ '0' .. '4' ] c1 ... c4 DR0
196da2e3ebdSchin * DL1 [ '0' .. '4' ] c1 ... c4 DR1
197da2e3ebdSchin *
198da2e3ebdSchin * with these ligatures
199da2e3ebdSchin *
200da2e3ebdSchin * ch CH sst SST
201da2e3ebdSchin *
202da2e3ebdSchin * and private collation order
203da2e3ebdSchin *
204da2e3ebdSchin * wide character display width is the low order 3 bits
205da2e3ebdSchin * wctomb() uses DL1...DR1
206da2e3ebdSchin */
207da2e3ebdSchin
208da2e3ebdSchin #define DEBUG_MB_CUR_MAX 7
209da2e3ebdSchin
210da2e3ebdSchin #if DEBUG_MB_CUR_MAX < MB_LEN_MAX
211da2e3ebdSchin #undef DEBUG_MB_CUR_MAX
212da2e3ebdSchin #define DEBUG_MB_CUR_MAX MB_LEN_MAX
213da2e3ebdSchin #endif
214da2e3ebdSchin
215da2e3ebdSchin #define DL0 '<'
216da2e3ebdSchin #define DL1 0xab /* 8-bit mini << on xterm */
217da2e3ebdSchin #define DR0 '>'
218da2e3ebdSchin #define DR1 0xbb /* 8-bit mini >> on xterm */
219da2e3ebdSchin
220da2e3ebdSchin #define DB ((int)sizeof(wchar_t)*8-1)
221da2e3ebdSchin #define DC 7 /* wchar_t embedded char bits */
222da2e3ebdSchin #define DX (DB/DC) /* wchar_t max embedded chars */
223da2e3ebdSchin #define DZ (DB-DX*DC+1) /* wchar_t embedded size bits */
224da2e3ebdSchin #define DD 3 /* # mb delimiter chars <n...> */
225da2e3ebdSchin
226da2e3ebdSchin static unsigned char debug_order[] =
227da2e3ebdSchin {
228da2e3ebdSchin 0, 1, 2, 3, 4, 5, 6, 7,
229da2e3ebdSchin 8, 9, 10, 11, 12, 13, 14, 15,
230da2e3ebdSchin 16, 17, 18, 19, 20, 21, 22, 23,
231da2e3ebdSchin 24, 25, 26, 27, 28, 29, 30, 31,
232da2e3ebdSchin 99, 100, 101, 102, 98, 103, 104, 105,
233da2e3ebdSchin 106, 107, 108, 43, 109, 44, 42, 110,
234da2e3ebdSchin 32, 33, 34, 35, 36, 37, 38, 39,
235da2e3ebdSchin 40, 41, 111, 112, 113, 114, 115, 116,
236da2e3ebdSchin 117, 71, 72, 73, 74, 75, 76, 77,
237da2e3ebdSchin 78, 79, 80, 81, 82, 83, 84, 85,
238da2e3ebdSchin 86, 87, 88, 89, 90, 91, 92, 93,
239da2e3ebdSchin 94, 95, 96, 118, 119, 120, 121, 97,
240da2e3ebdSchin 122, 45, 46, 47, 48, 49, 50, 51,
241da2e3ebdSchin 52, 53, 54, 55, 56, 57, 58, 59,
242da2e3ebdSchin 60, 61, 62, 63, 64, 65, 66, 67,
243da2e3ebdSchin 68, 69, 70, 123, 124, 125, 126, 127,
244da2e3ebdSchin 128, 129, 130, 131, 132, 133, 134, 135,
245da2e3ebdSchin 136, 137, 138, 139, 140, 141, 142, 143,
246da2e3ebdSchin 144, 145, 146, 147, 148, 149, 150, 151,
247da2e3ebdSchin 152, 153, 154, 155, 156, 157, 158, 159,
248da2e3ebdSchin 160, 161, 162, 163, 164, 165, 166, 167,
249da2e3ebdSchin 168, 169, 170, 171, 172, 173, 174, 175,
250da2e3ebdSchin 176, 177, 178, 179, 180, 181, 182, 183,
251da2e3ebdSchin 184, 185, 186, 187, 188, 189, 190, 191,
252da2e3ebdSchin 192, 193, 194, 195, 196, 197, 198, 199,
253da2e3ebdSchin 200, 201, 202, 203, 204, 205, 206, 207,
254da2e3ebdSchin 208, 209, 210, 211, 212, 213, 214, 215,
255da2e3ebdSchin 216, 217, 218, 219, 220, 221, 222, 223,
256da2e3ebdSchin 224, 225, 226, 227, 228, 229, 230, 231,
257da2e3ebdSchin 232, 233, 234, 235, 236, 237, 238, 239,
258da2e3ebdSchin 240, 241, 242, 243, 244, 245, 246, 247,
259da2e3ebdSchin 248, 249, 250, 251, 252, 253, 254, 255,
260da2e3ebdSchin };
261da2e3ebdSchin
262da2e3ebdSchin static int
debug_mbtowc(register wchar_t * p,register const char * s,size_t n)263da2e3ebdSchin debug_mbtowc(register wchar_t* p, register const char* s, size_t n)
264da2e3ebdSchin {
265da2e3ebdSchin register const char* q;
266da2e3ebdSchin register const char* r;
267da2e3ebdSchin register int w;
268da2e3ebdSchin register int dr;
269da2e3ebdSchin wchar_t c;
270da2e3ebdSchin
271da2e3ebdSchin if (n < 1)
272da2e3ebdSchin return -1;
273da2e3ebdSchin if (!s || !*s)
274da2e3ebdSchin return 0;
275da2e3ebdSchin switch (((unsigned char*)s)[0])
276da2e3ebdSchin {
277da2e3ebdSchin case DL0:
278da2e3ebdSchin dr = DR0;
279da2e3ebdSchin break;
280da2e3ebdSchin case DL1:
281da2e3ebdSchin dr = DR1;
282da2e3ebdSchin break;
283da2e3ebdSchin default:
284da2e3ebdSchin if (p)
285da2e3ebdSchin *p = ((unsigned char*)s)[0] & ((1<<DC)-1);
286da2e3ebdSchin return 1;
287da2e3ebdSchin }
288da2e3ebdSchin if (n < 2)
289da2e3ebdSchin return -1;
290da2e3ebdSchin if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0])
291da2e3ebdSchin {
292da2e3ebdSchin if (p)
293da2e3ebdSchin *p = w;
294da2e3ebdSchin return 2;
295da2e3ebdSchin }
296da2e3ebdSchin if (w < '0' || w > ('0' + DX))
297da2e3ebdSchin return -1;
298da2e3ebdSchin if ((w -= '0' - DD) > n)
299da2e3ebdSchin return -1;
300da2e3ebdSchin r = s + w - 1;
301da2e3ebdSchin q = s += 2;
302da2e3ebdSchin while (q < r && *q)
303da2e3ebdSchin q++;
304da2e3ebdSchin if (q != r || *((unsigned char*)q) != dr)
305da2e3ebdSchin return -1;
306da2e3ebdSchin if (p)
307da2e3ebdSchin {
308da2e3ebdSchin c = 0;
309da2e3ebdSchin while (--q >= s)
310da2e3ebdSchin {
311da2e3ebdSchin c <<= DC;
312da2e3ebdSchin c |= *((unsigned char*)q);
313da2e3ebdSchin }
314da2e3ebdSchin c <<= DZ;
315da2e3ebdSchin c |= w - DD;
316da2e3ebdSchin *p = c;
317da2e3ebdSchin }
318da2e3ebdSchin return w;
319da2e3ebdSchin }
320da2e3ebdSchin
321da2e3ebdSchin static int
debug_wctomb(char * s,wchar_t c)322da2e3ebdSchin debug_wctomb(char* s, wchar_t c)
323da2e3ebdSchin {
324da2e3ebdSchin int w;
325da2e3ebdSchin int i;
326da2e3ebdSchin int k;
327da2e3ebdSchin
328da2e3ebdSchin w = 0;
329da2e3ebdSchin if (c >= 0 && c <= UCHAR_MAX)
330da2e3ebdSchin {
331da2e3ebdSchin w++;
332da2e3ebdSchin if (s)
333da2e3ebdSchin *s = c;
334da2e3ebdSchin }
335da2e3ebdSchin else if ((i = c & ((1<<DZ)-1)) > DX)
336da2e3ebdSchin return -1;
337da2e3ebdSchin else
338da2e3ebdSchin {
339da2e3ebdSchin w++;
340da2e3ebdSchin if (s)
341da2e3ebdSchin *s++ = DL1;
342da2e3ebdSchin c >>= DZ;
343da2e3ebdSchin w++;
344da2e3ebdSchin if (s)
345da2e3ebdSchin *s++ = i + '0';
346da2e3ebdSchin while (i--)
347da2e3ebdSchin {
348da2e3ebdSchin w++;
349da2e3ebdSchin if (s)
350da2e3ebdSchin *s++ = (k = c & ((1<<DC)-1)) ? k : '?';
351da2e3ebdSchin c >>= DC;
352da2e3ebdSchin }
353da2e3ebdSchin w++;
354da2e3ebdSchin if (s)
355da2e3ebdSchin *s++ = DR1;
356da2e3ebdSchin }
357da2e3ebdSchin return w;
358da2e3ebdSchin }
359da2e3ebdSchin
360da2e3ebdSchin static int
debug_mblen(const char * s,size_t n)361da2e3ebdSchin debug_mblen(const char* s, size_t n)
362da2e3ebdSchin {
363da2e3ebdSchin return debug_mbtowc(NiL, s, n);
364da2e3ebdSchin }
365da2e3ebdSchin
366da2e3ebdSchin static int
debug_wcwidth(wchar_t c)367da2e3ebdSchin debug_wcwidth(wchar_t c)
368da2e3ebdSchin {
369da2e3ebdSchin if (c >= 0 && c <= UCHAR_MAX)
370da2e3ebdSchin return 1;
371da2e3ebdSchin if ((c &= ((1<<DZ)-1)) > DX)
372da2e3ebdSchin return -1;
373da2e3ebdSchin return c + DD;
374da2e3ebdSchin }
375da2e3ebdSchin
376da2e3ebdSchin static size_t
debug_strxfrm(register char * t,register const char * s,size_t n)377da2e3ebdSchin debug_strxfrm(register char* t, register const char* s, size_t n)
378da2e3ebdSchin {
379da2e3ebdSchin register const char* q;
380da2e3ebdSchin register const char* r;
381da2e3ebdSchin register char* e;
3827c2fbfb3SApril Chin char* o;
383da2e3ebdSchin register size_t z;
384da2e3ebdSchin register int w;
385da2e3ebdSchin
3867c2fbfb3SApril Chin o = t;
387da2e3ebdSchin z = 0;
388da2e3ebdSchin if (e = t)
389da2e3ebdSchin e += n;
390da2e3ebdSchin while (s[0])
391da2e3ebdSchin {
392da2e3ebdSchin if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC))
393da2e3ebdSchin {
394da2e3ebdSchin w -= '0';
395da2e3ebdSchin q = s + 2;
396da2e3ebdSchin r = q + w;
397da2e3ebdSchin while (q < r && *q)
398da2e3ebdSchin q++;
399da2e3ebdSchin if (*((unsigned char*)q) == DR0 || *((unsigned char*)q) == DR1)
400da2e3ebdSchin {
401da2e3ebdSchin if (t)
402da2e3ebdSchin {
403da2e3ebdSchin for (q = s + 2; q < r; q++)
404da2e3ebdSchin if (t < e)
405da2e3ebdSchin *t++ = debug_order[*q];
406da2e3ebdSchin while (w++ < DX)
407da2e3ebdSchin if (t < e)
408da2e3ebdSchin *t++ = 1;
409da2e3ebdSchin }
410da2e3ebdSchin s = r + 1;
411da2e3ebdSchin z += DX;
412da2e3ebdSchin continue;
413da2e3ebdSchin }
414da2e3ebdSchin }
415da2e3ebdSchin if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H'))
416da2e3ebdSchin {
417da2e3ebdSchin if (t)
418da2e3ebdSchin {
419da2e3ebdSchin if (t < e)
420da2e3ebdSchin *t++ = debug_order[s[0]];
421da2e3ebdSchin if (t < e)
422da2e3ebdSchin *t++ = debug_order[s[1]];
423da2e3ebdSchin if (t < e)
424da2e3ebdSchin *t++ = 1;
425da2e3ebdSchin if (t < e)
426da2e3ebdSchin *t++ = 1;
427da2e3ebdSchin }
428da2e3ebdSchin s += 2;
429da2e3ebdSchin z += DX;
430da2e3ebdSchin continue;
431da2e3ebdSchin }
432da2e3ebdSchin if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T'))
433da2e3ebdSchin {
434da2e3ebdSchin if (t)
435da2e3ebdSchin {
436da2e3ebdSchin if (t < e)
437da2e3ebdSchin *t++ = debug_order[s[0]];
438da2e3ebdSchin if (t < e)
439da2e3ebdSchin *t++ = debug_order[s[1]];
440da2e3ebdSchin if (t < e)
441da2e3ebdSchin *t++ = debug_order[s[2]];
442da2e3ebdSchin if (t < e)
443da2e3ebdSchin *t++ = 1;
444da2e3ebdSchin }
445da2e3ebdSchin s += 3;
446da2e3ebdSchin z += DX;
447da2e3ebdSchin continue;
448da2e3ebdSchin }
449da2e3ebdSchin if (t)
450da2e3ebdSchin {
451da2e3ebdSchin if (t < e)
452da2e3ebdSchin *t++ = debug_order[s[0]];
453da2e3ebdSchin if (t < e)
454da2e3ebdSchin *t++ = 1;
455da2e3ebdSchin if (t < e)
456da2e3ebdSchin *t++ = 1;
457da2e3ebdSchin if (t < e)
458da2e3ebdSchin *t++ = 1;
459da2e3ebdSchin }
460da2e3ebdSchin s++;
461da2e3ebdSchin z += DX;
462da2e3ebdSchin }
4637c2fbfb3SApril Chin if (!t)
4647c2fbfb3SApril Chin return z;
465da2e3ebdSchin if (t < e)
466da2e3ebdSchin *t = 0;
4677c2fbfb3SApril Chin return t - o;
468da2e3ebdSchin }
469da2e3ebdSchin
470da2e3ebdSchin static int
debug_strcoll(const char * a,const char * b)471da2e3ebdSchin debug_strcoll(const char* a, const char* b)
472da2e3ebdSchin {
473da2e3ebdSchin char ab[1024];
474da2e3ebdSchin char bb[1024];
475da2e3ebdSchin
476da2e3ebdSchin debug_strxfrm(ab, a, sizeof(ab) - 1);
477da2e3ebdSchin ab[sizeof(ab)-1] = 0;
478da2e3ebdSchin debug_strxfrm(bb, b, sizeof(bb) - 1);
479da2e3ebdSchin bb[sizeof(bb)-1] = 0;
480da2e3ebdSchin return strcmp(ab, bb);
481da2e3ebdSchin }
482da2e3ebdSchin
483da2e3ebdSchin /*
484da2e3ebdSchin * default locale
485da2e3ebdSchin */
486da2e3ebdSchin
487da2e3ebdSchin static int
default_wcwidth(wchar_t w)488da2e3ebdSchin default_wcwidth(wchar_t w)
489da2e3ebdSchin {
490da2e3ebdSchin return w >= 0 && w <= 255 && !iscntrl(w) ? 1 : -1;
491da2e3ebdSchin }
492da2e3ebdSchin
493da2e3ebdSchin /*
494da2e3ebdSchin * called when LC_COLLATE initialized or changes
495da2e3ebdSchin */
496da2e3ebdSchin
497da2e3ebdSchin static int
set_collate(Lc_category_t * cp)498da2e3ebdSchin set_collate(Lc_category_t* cp)
499da2e3ebdSchin {
500da2e3ebdSchin if (locales[cp->internal]->flags & LC_debug)
501da2e3ebdSchin {
502da2e3ebdSchin ast.collate = debug_strcoll;
503da2e3ebdSchin ast.mb_xfrm = debug_strxfrm;
504da2e3ebdSchin }
505da2e3ebdSchin else if (locales[cp->internal]->flags & LC_default)
506da2e3ebdSchin {
507da2e3ebdSchin ast.collate = strcmp;
508da2e3ebdSchin ast.mb_xfrm = 0;
509da2e3ebdSchin }
510da2e3ebdSchin else
511da2e3ebdSchin {
512da2e3ebdSchin ast.collate = strcoll;
513da2e3ebdSchin ast.mb_xfrm = strxfrm;
514da2e3ebdSchin }
515da2e3ebdSchin return 0;
516da2e3ebdSchin }
517da2e3ebdSchin
518da2e3ebdSchin /*
5197c2fbfb3SApril Chin * workaround the interesting sjis that translates unshifted 7 bit ascii!
5207c2fbfb3SApril Chin */
5217c2fbfb3SApril Chin
5227c2fbfb3SApril Chin #if _hdr_wchar && _typ_mbstate_t && _lib_mbrtowc
5237c2fbfb3SApril Chin
5247c2fbfb3SApril Chin #define mb_state_zero ((mbstate_t*)&ast.pad[sizeof(ast.pad)-2*sizeof(mbstate_t)])
5257c2fbfb3SApril Chin #define mb_state ((mbstate_t*)&ast.pad[sizeof(ast.pad)-sizeof(mbstate_t)])
5267c2fbfb3SApril Chin
5277c2fbfb3SApril Chin static int
sjis_mbtowc(register wchar_t * p,register const char * s,size_t n)5287c2fbfb3SApril Chin sjis_mbtowc(register wchar_t* p, register const char* s, size_t n)
5297c2fbfb3SApril Chin {
5307c2fbfb3SApril Chin if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t)))
5317c2fbfb3SApril Chin {
5327c2fbfb3SApril Chin *p = *s;
5337c2fbfb3SApril Chin return 1;
5347c2fbfb3SApril Chin }
5357c2fbfb3SApril Chin return mbrtowc(p, s, n, mb_state);
5367c2fbfb3SApril Chin }
5377c2fbfb3SApril Chin
5387c2fbfb3SApril Chin #endif
5397c2fbfb3SApril Chin
54034f9b3eeSRoland Mainz #define utf8_wctomb wctomb
54134f9b3eeSRoland Mainz
54234f9b3eeSRoland Mainz static const uint32_t utf8mask[] =
54334f9b3eeSRoland Mainz {
54434f9b3eeSRoland Mainz 0x00000000,
54534f9b3eeSRoland Mainz 0x00000000,
54634f9b3eeSRoland Mainz 0xffffff80,
54734f9b3eeSRoland Mainz 0xfffff800,
54834f9b3eeSRoland Mainz 0xffff0000,
54934f9b3eeSRoland Mainz 0xffe00000,
55034f9b3eeSRoland Mainz 0xfc000000,
55134f9b3eeSRoland Mainz };
55234f9b3eeSRoland Mainz
55334f9b3eeSRoland Mainz static const signed char utf8tab[256] =
55434f9b3eeSRoland Mainz {
55534f9b3eeSRoland Mainz 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55634f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55734f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55834f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55934f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56034f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56134f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56234f9b3eeSRoland Mainz 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56334f9b3eeSRoland Mainz 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56434f9b3eeSRoland Mainz 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56534f9b3eeSRoland Mainz 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56634f9b3eeSRoland Mainz 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56734f9b3eeSRoland Mainz 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56834f9b3eeSRoland Mainz 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56934f9b3eeSRoland Mainz 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
57034f9b3eeSRoland Mainz 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,-1,-1,
57134f9b3eeSRoland Mainz };
57234f9b3eeSRoland Mainz
57334f9b3eeSRoland Mainz static int
utf8_mbtowc(wchar_t * wp,const char * str,size_t n)57434f9b3eeSRoland Mainz utf8_mbtowc(wchar_t* wp, const char* str, size_t n)
57534f9b3eeSRoland Mainz {
57634f9b3eeSRoland Mainz register unsigned char* sp = (unsigned char*)str;
57734f9b3eeSRoland Mainz register int m;
57834f9b3eeSRoland Mainz register int i;
57934f9b3eeSRoland Mainz register int c;
58034f9b3eeSRoland Mainz register wchar_t w = 0;
58134f9b3eeSRoland Mainz
58234f9b3eeSRoland Mainz if (!sp || !n)
58334f9b3eeSRoland Mainz return 0;
58434f9b3eeSRoland Mainz if ((m = utf8tab[*sp]) > 0)
58534f9b3eeSRoland Mainz {
58634f9b3eeSRoland Mainz if (m > n)
58734f9b3eeSRoland Mainz return -1;
58834f9b3eeSRoland Mainz if (wp)
58934f9b3eeSRoland Mainz {
59034f9b3eeSRoland Mainz if (m == 1)
59134f9b3eeSRoland Mainz {
59234f9b3eeSRoland Mainz *wp = *sp;
59334f9b3eeSRoland Mainz return 1;
59434f9b3eeSRoland Mainz }
59534f9b3eeSRoland Mainz w = *sp & ((1<<(8-m))-1);
59634f9b3eeSRoland Mainz for (i = m - 1; i > 0; i--)
59734f9b3eeSRoland Mainz {
59834f9b3eeSRoland Mainz c = *++sp;
59934f9b3eeSRoland Mainz if ((c&0xc0) != 0x80)
60034f9b3eeSRoland Mainz goto invalid;
60134f9b3eeSRoland Mainz w = (w<<6) | (c&0x3f);
60234f9b3eeSRoland Mainz }
60334f9b3eeSRoland Mainz if (!(utf8mask[m] & w) || w >= 0xd800 && (w <= 0xdfff || w >= 0xfffe && w <= 0xffff))
60434f9b3eeSRoland Mainz goto invalid;
60534f9b3eeSRoland Mainz *wp = w;
60634f9b3eeSRoland Mainz }
60734f9b3eeSRoland Mainz return m;
60834f9b3eeSRoland Mainz }
60934f9b3eeSRoland Mainz if (!*sp)
61034f9b3eeSRoland Mainz return 0;
61134f9b3eeSRoland Mainz invalid:
61234f9b3eeSRoland Mainz #ifdef EILSEQ
61334f9b3eeSRoland Mainz errno = EILSEQ;
61434f9b3eeSRoland Mainz #endif
61534f9b3eeSRoland Mainz ast.mb_sync = (const char*)sp - str;
61634f9b3eeSRoland Mainz return -1;
61734f9b3eeSRoland Mainz }
61834f9b3eeSRoland Mainz
61934f9b3eeSRoland Mainz static int
utf8_mblen(const char * str,size_t n)62034f9b3eeSRoland Mainz utf8_mblen(const char* str, size_t n)
62134f9b3eeSRoland Mainz {
62234f9b3eeSRoland Mainz wchar_t w;
62334f9b3eeSRoland Mainz
62434f9b3eeSRoland Mainz return utf8_mbtowc(&w, str, n);
62534f9b3eeSRoland Mainz }
62634f9b3eeSRoland Mainz
6277c2fbfb3SApril Chin /*
628da2e3ebdSchin * called when LC_CTYPE initialized or changes
629da2e3ebdSchin */
630da2e3ebdSchin
631da2e3ebdSchin static int
set_ctype(Lc_category_t * cp)632da2e3ebdSchin set_ctype(Lc_category_t* cp)
633da2e3ebdSchin {
63434f9b3eeSRoland Mainz ast.mb_sync = 0;
635da2e3ebdSchin if (locales[cp->internal]->flags & LC_debug)
636da2e3ebdSchin {
637da2e3ebdSchin ast.mb_cur_max = DEBUG_MB_CUR_MAX;
638da2e3ebdSchin ast.mb_len = debug_mblen;
639da2e3ebdSchin ast.mb_towc = debug_mbtowc;
640da2e3ebdSchin ast.mb_width = debug_wcwidth;
641da2e3ebdSchin ast.mb_conv = debug_wctomb;
642da2e3ebdSchin }
643da2e3ebdSchin else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc))
644da2e3ebdSchin {
645da2e3ebdSchin ast.mb_cur_max = 1;
646da2e3ebdSchin ast.mb_len = 0;
647da2e3ebdSchin ast.mb_towc = 0;
648da2e3ebdSchin ast.mb_width = default_wcwidth;
649da2e3ebdSchin ast.mb_conv = 0;
650da2e3ebdSchin }
65134f9b3eeSRoland Mainz else if ((locales[cp->internal]->flags & LC_utf8) && !(ast.locale.set & AST_LC_test))
65234f9b3eeSRoland Mainz {
65334f9b3eeSRoland Mainz ast.mb_cur_max = 6;
65434f9b3eeSRoland Mainz ast.mb_len = utf8_mblen;
65534f9b3eeSRoland Mainz ast.mb_towc = utf8_mbtowc;
65634f9b3eeSRoland Mainz if (!(ast.mb_width = wcwidth))
65734f9b3eeSRoland Mainz ast.mb_width = default_wcwidth;
65834f9b3eeSRoland Mainz ast.mb_conv = utf8_wctomb;
65934f9b3eeSRoland Mainz }
660da2e3ebdSchin else
661da2e3ebdSchin {
662da2e3ebdSchin if (!(ast.mb_width = wcwidth))
663da2e3ebdSchin ast.mb_width = default_wcwidth;
664da2e3ebdSchin ast.mb_conv = wctomb;
6657c2fbfb3SApril Chin #ifdef mb_state
6667c2fbfb3SApril Chin {
6677c2fbfb3SApril Chin /*
6687c2fbfb3SApril Chin * check for sjis that translates unshifted 7 bit ascii!
6697c2fbfb3SApril Chin */
6707c2fbfb3SApril Chin
6717c2fbfb3SApril Chin char* s;
6727c2fbfb3SApril Chin char buf[2];
6737c2fbfb3SApril Chin
6747c2fbfb3SApril Chin mbinit();
6757c2fbfb3SApril Chin buf[1] = 0;
6767c2fbfb3SApril Chin *(s = buf) = '\\';
6777c2fbfb3SApril Chin if (mbchar(s) != buf[0])
6787c2fbfb3SApril Chin {
6797c2fbfb3SApril Chin memcpy(mb_state, mb_state_zero, sizeof(mbstate_t));
6807c2fbfb3SApril Chin ast.mb_towc = sjis_mbtowc;
6817c2fbfb3SApril Chin }
6827c2fbfb3SApril Chin }
6837c2fbfb3SApril Chin #endif
684da2e3ebdSchin }
68534f9b3eeSRoland Mainz if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
68634f9b3eeSRoland Mainz sfprintf(sfstderr, "locale info %17s MB_CUR_MAX=%d%s%s%s%s\n"
68734f9b3eeSRoland Mainz , cp->name
68834f9b3eeSRoland Mainz , ast.mb_cur_max
68934f9b3eeSRoland Mainz , ast.mb_len == debug_mblen ? " debug_mblen" : ast.mb_len == mblen ? " mblen" : ""
69034f9b3eeSRoland Mainz , ast.mb_towc == debug_mbtowc ? " debug_mbtowc" : ast.mb_towc == mbtowc ? " mbtowc"
69134f9b3eeSRoland Mainz #ifdef mb_state
69234f9b3eeSRoland Mainz : ast.mb_towc == sjis_mbtowc ? " sjis_mbtowc"
69334f9b3eeSRoland Mainz #endif
69434f9b3eeSRoland Mainz : ""
69534f9b3eeSRoland Mainz , ast.mb_width == debug_wcwidth ? " debug_wcwidth" : ast.mb_width == wcwidth ? " wcwidth" : ast.mb_width == default_wcwidth ? " default_wcwidth" : ""
69634f9b3eeSRoland Mainz , ast.mb_conv == debug_wctomb ? " debug_wctomb" : ast.mb_conv == wctomb ? " wctomb" : ""
69734f9b3eeSRoland Mainz );
698da2e3ebdSchin return 0;
699da2e3ebdSchin }
700da2e3ebdSchin
701da2e3ebdSchin /*
702da2e3ebdSchin * called when LC_NUMERIC initialized or changes
703da2e3ebdSchin */
704da2e3ebdSchin
705da2e3ebdSchin static int
set_numeric(Lc_category_t * cp)706da2e3ebdSchin set_numeric(Lc_category_t* cp)
707da2e3ebdSchin {
708da2e3ebdSchin register int category = cp->internal;
709da2e3ebdSchin struct lconv* lp;
710da2e3ebdSchin Lc_numeric_t* dp;
711da2e3ebdSchin
712da2e3ebdSchin static Lc_numeric_t default_numeric = { '.', -1 };
713da2e3ebdSchin
714da2e3ebdSchin if (!LCINFO(category)->data)
715da2e3ebdSchin {
716da2e3ebdSchin if ((lp = localeconv()) && (dp = newof(0, Lc_numeric_t, 1, 0)))
717da2e3ebdSchin {
718da2e3ebdSchin dp->decimal = lp->decimal_point && *lp->decimal_point ? *(unsigned char*)lp->decimal_point : '.';
719da2e3ebdSchin dp->thousand = lp->thousands_sep && *lp->thousands_sep ? *(unsigned char*)lp->thousands_sep : -1;
720da2e3ebdSchin }
721da2e3ebdSchin else
722da2e3ebdSchin dp = &default_numeric;
723da2e3ebdSchin LCINFO(category)->data = (void*)dp;
724da2e3ebdSchin if (ast.locale.set & (AST_LC_debug|AST_LC_setlocale))
7257c2fbfb3SApril Chin sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X');
726da2e3ebdSchin }
727da2e3ebdSchin return 0;
728da2e3ebdSchin }
729da2e3ebdSchin
730da2e3ebdSchin /*
731da2e3ebdSchin * this table is indexed by AST_LC_[A-Z]*
732da2e3ebdSchin */
733da2e3ebdSchin
7347c2fbfb3SApril Chin Lc_category_t lc_categories[] =
735da2e3ebdSchin {
736da2e3ebdSchin { "LC_ALL", LC_ALL, AST_LC_ALL, 0 },
737da2e3ebdSchin { "LC_COLLATE", LC_COLLATE, AST_LC_COLLATE, set_collate },
738da2e3ebdSchin { "LC_CTYPE", LC_CTYPE, AST_LC_CTYPE, set_ctype },
739da2e3ebdSchin { "LC_MESSAGES", LC_MESSAGES, AST_LC_MESSAGES, 0 },
740da2e3ebdSchin { "LC_MONETARY", LC_MONETARY, AST_LC_MONETARY, 0 },
741da2e3ebdSchin { "LC_NUMERIC", LC_NUMERIC, AST_LC_NUMERIC, set_numeric },
742da2e3ebdSchin { "LC_TIME", LC_TIME, AST_LC_TIME, 0 },
743da2e3ebdSchin { "LC_IDENTIFICATION",LC_IDENTIFICATION,AST_LC_IDENTIFICATION,0 },
744da2e3ebdSchin { "LC_ADDRESS", LC_ADDRESS, AST_LC_ADDRESS, 0 },
745da2e3ebdSchin { "LC_NAME", LC_NAME, AST_LC_NAME, 0 },
746da2e3ebdSchin { "LC_TELEPHONE", LC_TELEPHONE, AST_LC_TELEPHONE, 0 },
747da2e3ebdSchin { "LC_XLITERATE", LC_XLITERATE, AST_LC_XLITERATE, 0 },
748da2e3ebdSchin { "LC_MEASUREMENT", LC_MEASUREMENT, AST_LC_MEASUREMENT, 0 },
749da2e3ebdSchin { "LC_PAPER", LC_PAPER, AST_LC_PAPER, 0 },
750da2e3ebdSchin };
751da2e3ebdSchin
75234f9b3eeSRoland Mainz static Lc_t* lang;
75334f9b3eeSRoland Mainz static Lc_t* lc_all;
75434f9b3eeSRoland Mainz
75534f9b3eeSRoland Mainz typedef struct Unamval_s
75634f9b3eeSRoland Mainz {
75734f9b3eeSRoland Mainz char* name;
75834f9b3eeSRoland Mainz unsigned int value;
75934f9b3eeSRoland Mainz } Unamval_t;
76034f9b3eeSRoland Mainz
76134f9b3eeSRoland Mainz static const Unamval_t options[] =
762da2e3ebdSchin {
763da2e3ebdSchin "debug", AST_LC_debug,
764da2e3ebdSchin "find", AST_LC_find,
765da2e3ebdSchin "setlocale", AST_LC_setlocale,
76634f9b3eeSRoland Mainz "test", AST_LC_test,
767da2e3ebdSchin "translate", AST_LC_translate,
768da2e3ebdSchin 0, 0
769da2e3ebdSchin };
770da2e3ebdSchin
771da2e3ebdSchin /*
772da2e3ebdSchin * called by stropt() to set options
773da2e3ebdSchin */
774da2e3ebdSchin
775da2e3ebdSchin static int
setopt(void * a,const void * p,int n,const char * v)776da2e3ebdSchin setopt(void* a, const void* p, int n, const char* v)
777da2e3ebdSchin {
778da2e3ebdSchin if (p)
779da2e3ebdSchin {
780da2e3ebdSchin if (n)
78134f9b3eeSRoland Mainz ast.locale.set |= ((Unamval_t*)p)->value;
782da2e3ebdSchin else
78334f9b3eeSRoland Mainz ast.locale.set &= ~((Unamval_t*)p)->value;
784da2e3ebdSchin }
785da2e3ebdSchin return 0;
786da2e3ebdSchin }
787da2e3ebdSchin
788da2e3ebdSchin #if !_lib_setlocale
789da2e3ebdSchin
790da2e3ebdSchin #define setlocale(c,l) default_setlocale(c,l)
791da2e3ebdSchin
792da2e3ebdSchin static char*
default_setlocale(int category,const char * locale)793da2e3ebdSchin default_setlocale(int category, const char* locale)
794da2e3ebdSchin {
795da2e3ebdSchin Lc_t* lc;
796da2e3ebdSchin
797da2e3ebdSchin if (locale)
798da2e3ebdSchin {
799da2e3ebdSchin if (!(lc = lcmake(locale)) || !(lc->flags & LC_default))
800da2e3ebdSchin return 0;
801da2e3ebdSchin locales[0]->flags &= ~lc->flags;
802da2e3ebdSchin locales[1]->flags &= ~lc->flags;
803da2e3ebdSchin return lc->name;
804da2e3ebdSchin }
805da2e3ebdSchin return (locales[1]->flags & (1<<category)) ? locales[1]->name : locales[0]->name;
806da2e3ebdSchin }
807da2e3ebdSchin
808da2e3ebdSchin #endif
809da2e3ebdSchin
810da2e3ebdSchin /*
811da2e3ebdSchin * set a single AST_LC_* locale category
812da2e3ebdSchin * the caller must validate category
813da2e3ebdSchin * lc==0 restores the previous state
814da2e3ebdSchin */
815da2e3ebdSchin
816da2e3ebdSchin static char*
single(int category,Lc_t * lc,unsigned int flags)817*3e14f97fSRoger A. Faulkner single(int category, Lc_t* lc, unsigned int flags)
818da2e3ebdSchin {
819da2e3ebdSchin const char* sys;
820da2e3ebdSchin int i;
821da2e3ebdSchin
822*3e14f97fSRoger A. Faulkner if (flags & (LC_setenv|LC_setlocale))
823*3e14f97fSRoger A. Faulkner {
824*3e14f97fSRoger A. Faulkner if (!(ast.locale.set & AST_LC_internal))
825*3e14f97fSRoger A. Faulkner lc_categories[category].prev = lc;
826*3e14f97fSRoger A. Faulkner if ((flags & LC_setenv) && lc_all && locales[category])
827*3e14f97fSRoger A. Faulkner return (char*)locales[category]->name;
828*3e14f97fSRoger A. Faulkner }
829*3e14f97fSRoger A. Faulkner if (!lc && (!(lc_categories[category].flags & LC_setlocale) || !(lc = lc_categories[category].prev)) && !(lc = lc_all) && !(lc = lc_categories[category].prev) && !(lc = lang))
830da2e3ebdSchin lc = lcmake(NiL);
831*3e14f97fSRoger A. Faulkner sys = 0;
832da2e3ebdSchin if (locales[category] != lc)
833da2e3ebdSchin {
8347c2fbfb3SApril Chin if (lc_categories[category].external == -lc_categories[category].internal)
835da2e3ebdSchin {
836da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
837da2e3ebdSchin if (locales[i] == lc)
838da2e3ebdSchin {
839da2e3ebdSchin sys = (char*)lc->name;
840da2e3ebdSchin break;
841da2e3ebdSchin }
842da2e3ebdSchin }
843da2e3ebdSchin else if (lc->flags & (LC_debug|LC_local))
8447c2fbfb3SApril Chin sys = setlocale(lc_categories[category].external, lcmake(NiL)->name);
8457c2fbfb3SApril Chin else if (!(sys = setlocale(lc_categories[category].external, lc->name)) &&
8467c2fbfb3SApril Chin (streq(lc->name, lc->code) || !(sys = setlocale(lc_categories[category].external, lc->code))) &&
847da2e3ebdSchin !streq(lc->code, lc->language->code))
8487c2fbfb3SApril Chin sys = setlocale(lc_categories[category].external, lc->language->code);
849da2e3ebdSchin if (!sys)
850da2e3ebdSchin {
851da2e3ebdSchin /*
852da2e3ebdSchin * check for local override
853da2e3ebdSchin * currently this means an LC_MESSAGES dir exists
854da2e3ebdSchin */
855da2e3ebdSchin
856da2e3ebdSchin if (!(lc->flags & LC_checked))
857da2e3ebdSchin {
858da2e3ebdSchin char path[PATH_MAX];
859da2e3ebdSchin
860da2e3ebdSchin if (mcfind(path, lc->code, NiL, LC_MESSAGES, 0))
861da2e3ebdSchin lc->flags |= LC_local;
862da2e3ebdSchin lc->flags |= LC_checked;
863da2e3ebdSchin }
864da2e3ebdSchin if (!(lc->flags & LC_local))
865da2e3ebdSchin return 0;
8667c2fbfb3SApril Chin if (lc_categories[category].external != -lc_categories[category].internal)
8677c2fbfb3SApril Chin setlocale(lc_categories[category].external, lcmake(NiL)->name);
868da2e3ebdSchin }
869da2e3ebdSchin locales[category] = lc;
8707c2fbfb3SApril Chin if (lc_categories[category].setf && (*lc_categories[category].setf)(&lc_categories[category]))
871da2e3ebdSchin {
8727c2fbfb3SApril Chin locales[category] = lc_categories[category].prev;
873da2e3ebdSchin return 0;
874da2e3ebdSchin }
87534f9b3eeSRoland Mainz if ((lc->flags & LC_default) || category == AST_LC_MESSAGES && lc->name[0] == 'e' && lc->name[1] == 'n' && (lc->name[2] == 0 || lc->name[2] == '_' && lc->name[3] == 'U'))
876da2e3ebdSchin ast.locale.set &= ~(1<<category);
877da2e3ebdSchin else
878da2e3ebdSchin ast.locale.set |= (1<<category);
879da2e3ebdSchin }
880*3e14f97fSRoger A. Faulkner else if (lc_categories[category].flags ^ flags)
881*3e14f97fSRoger A. Faulkner {
882*3e14f97fSRoger A. Faulkner lc_categories[category].flags &= ~(LC_setenv|LC_setlocale);
883*3e14f97fSRoger A. Faulkner lc_categories[category].flags |= flags;
884*3e14f97fSRoger A. Faulkner }
885*3e14f97fSRoger A. Faulkner else
886*3e14f97fSRoger A. Faulkner return (char*)lc->name;
887*3e14f97fSRoger A. Faulkner if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
888*3e14f97fSRoger A. Faulkner sfprintf(sfstderr, "locale set %17s %16s %16s %16s %s%s\n", lc_categories[category].name, lc->name, sys, lc_categories[category].prev ? lc_categories[category].prev->name : NiL, (lc_categories[category].flags & LC_setlocale) ? "[setlocale]" : "", (lc_categories[category].flags & LC_setenv) ? "[setenv]" : "");
889da2e3ebdSchin return (char*)lc->name;
890da2e3ebdSchin }
891da2e3ebdSchin
892da2e3ebdSchin /*
893da2e3ebdSchin * set composite AST_LC_ALL locale categories
894da2e3ebdSchin * return <0:composite-error 0:not-composite >0:composite-ok
895da2e3ebdSchin */
896da2e3ebdSchin
897da2e3ebdSchin static int
composite(register const char * s,int initialize)898da2e3ebdSchin composite(register const char* s, int initialize)
899da2e3ebdSchin {
900da2e3ebdSchin register const char* t;
901da2e3ebdSchin register int i;
902da2e3ebdSchin register int j;
903da2e3ebdSchin register int k;
904da2e3ebdSchin int n;
90534f9b3eeSRoland Mainz int m;
906da2e3ebdSchin const char* w;
907da2e3ebdSchin Lc_t* p;
908da2e3ebdSchin int cat[AST_LC_COUNT];
909da2e3ebdSchin int stk[AST_LC_COUNT];
910da2e3ebdSchin char buf[PATH_MAX / 2];
911da2e3ebdSchin
912da2e3ebdSchin k = n = 0;
913da2e3ebdSchin while (s[0] == 'L' && s[1] == 'C' && s[2] == '_')
914da2e3ebdSchin {
915da2e3ebdSchin n++;
916da2e3ebdSchin j = 0;
917da2e3ebdSchin w = s;
918da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
919da2e3ebdSchin {
920da2e3ebdSchin s = w;
9217c2fbfb3SApril Chin t = lc_categories[i].name;
922da2e3ebdSchin while (*t && *s++ == *t++);
923da2e3ebdSchin if (!*t && *s++ == '=')
924da2e3ebdSchin {
925da2e3ebdSchin cat[j++] = i;
926da2e3ebdSchin if (s[0] != 'L' || s[1] != 'C' || s[2] != '_')
927da2e3ebdSchin break;
928da2e3ebdSchin w = s;
929da2e3ebdSchin i = -1;
930da2e3ebdSchin }
931da2e3ebdSchin }
932da2e3ebdSchin for (s = w; *s && *s != '='; s++);
933da2e3ebdSchin if (!*s)
934da2e3ebdSchin {
935da2e3ebdSchin for (i = 0; i < k; i++)
936*3e14f97fSRoger A. Faulkner single(stk[i], NiL, 0);
937da2e3ebdSchin return -1;
938da2e3ebdSchin }
939da2e3ebdSchin w = ++s;
940da2e3ebdSchin for (;;)
941da2e3ebdSchin {
942da2e3ebdSchin if (!*s)
943da2e3ebdSchin {
944da2e3ebdSchin p = lcmake(w);
945da2e3ebdSchin break;
946da2e3ebdSchin }
947da2e3ebdSchin else if (*s++ == ';')
948da2e3ebdSchin {
94934f9b3eeSRoland Mainz if ((m = s - w - 1) >= sizeof(buf))
95034f9b3eeSRoland Mainz m = sizeof(buf) - 1;
95134f9b3eeSRoland Mainz memcpy(buf, w, m);
95234f9b3eeSRoland Mainz buf[m] = 0;
953da2e3ebdSchin p = lcmake(buf);
954da2e3ebdSchin break;
955da2e3ebdSchin }
956da2e3ebdSchin }
957da2e3ebdSchin for (i = 0; i < j; i++)
958da2e3ebdSchin if (!initialize)
959da2e3ebdSchin {
960*3e14f97fSRoger A. Faulkner if (!single(cat[i], p, 0))
961da2e3ebdSchin {
962da2e3ebdSchin for (i = 0; i < k; i++)
963*3e14f97fSRoger A. Faulkner single(stk[i], NiL, 0);
964da2e3ebdSchin return -1;
965da2e3ebdSchin }
966da2e3ebdSchin stk[k++] = cat[i];
967da2e3ebdSchin }
968*3e14f97fSRoger A. Faulkner else if (!lc_categories[cat[i]].prev && !(ast.locale.set & AST_LC_internal))
9697c2fbfb3SApril Chin lc_categories[cat[i]].prev = p;
970da2e3ebdSchin }
97134f9b3eeSRoland Mainz while (s[0] == '/' && s[1] && n < (AST_LC_COUNT - 1))
972da2e3ebdSchin {
973da2e3ebdSchin n++;
974da2e3ebdSchin for (w = ++s; *s && *s != '/'; s++);
975da2e3ebdSchin if (!*s)
976da2e3ebdSchin p = lcmake(w);
977da2e3ebdSchin else
978da2e3ebdSchin {
979da2e3ebdSchin if ((j = s - w - 1) >= sizeof(buf))
980da2e3ebdSchin j = sizeof(buf) - 1;
981da2e3ebdSchin memcpy(buf, w, j);
982da2e3ebdSchin buf[j] = 0;
983da2e3ebdSchin p = lcmake(buf);
984da2e3ebdSchin }
985da2e3ebdSchin if (!initialize)
986da2e3ebdSchin {
987*3e14f97fSRoger A. Faulkner if (!single(n, p, 0))
988da2e3ebdSchin {
989da2e3ebdSchin for (i = 1; i < n; i++)
990*3e14f97fSRoger A. Faulkner single(i, NiL, 0);
991da2e3ebdSchin return -1;
992da2e3ebdSchin }
993da2e3ebdSchin }
994*3e14f97fSRoger A. Faulkner else if (!lc_categories[n].prev && !(ast.locale.set & AST_LC_internal))
9957c2fbfb3SApril Chin lc_categories[n].prev = p;
996da2e3ebdSchin }
997da2e3ebdSchin return n;
998da2e3ebdSchin }
999da2e3ebdSchin
1000da2e3ebdSchin /*
1001da2e3ebdSchin * setlocale() intercept
100234f9b3eeSRoland Mainz *
100334f9b3eeSRoland Mainz * locale:
100434f9b3eeSRoland Mainz * 0 query
1005*3e14f97fSRoger A. Faulkner * "" initialize from environment (if LC_ALL)
1006*3e14f97fSRoger A. Faulkner * "" AST_LC_setenv: value unset (defer to LANG)
1007*3e14f97fSRoger A. Faulkner * "*" AST_LC_setenv: value set (defer to LC_ALL)
1008*3e14f97fSRoger A. Faulkner * * set (override LC_ALL)
1009da2e3ebdSchin */
1010da2e3ebdSchin
1011da2e3ebdSchin char*
_ast_setlocale(int category,const char * locale)1012da2e3ebdSchin _ast_setlocale(int category, const char* locale)
1013da2e3ebdSchin {
1014da2e3ebdSchin register char* s;
1015da2e3ebdSchin register int i;
1016da2e3ebdSchin register int j;
1017da2e3ebdSchin int k;
1018*3e14f97fSRoger A. Faulkner int f;
1019da2e3ebdSchin Lc_t* p;
1020da2e3ebdSchin int cat[AST_LC_COUNT];
1021da2e3ebdSchin
1022da2e3ebdSchin static Sfio_t* sp;
1023da2e3ebdSchin static int initialized;
1024*3e14f97fSRoger A. Faulkner static const char local[] = "local";
1025da2e3ebdSchin
1026da2e3ebdSchin if ((category = lcindex(category, 0)) < 0)
1027da2e3ebdSchin return 0;
1028da2e3ebdSchin if (!locale)
1029da2e3ebdSchin {
1030da2e3ebdSchin /*
1031da2e3ebdSchin * return the current state
1032da2e3ebdSchin */
1033da2e3ebdSchin
1034da2e3ebdSchin compose:
103534f9b3eeSRoland Mainz if (category != AST_LC_ALL && category != AST_LC_LANG)
1036da2e3ebdSchin return (char*)locales[category]->name;
1037da2e3ebdSchin if (!sp && !(sp = sfstropen()))
1038da2e3ebdSchin return 0;
1039da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
1040da2e3ebdSchin cat[i] = -1;
1041da2e3ebdSchin for (i = 1, k = 0; i < AST_LC_COUNT; i++)
1042da2e3ebdSchin if (cat[i] < 0)
1043da2e3ebdSchin {
1044da2e3ebdSchin k++;
1045da2e3ebdSchin cat[i] = i;
1046da2e3ebdSchin for (j = i + 1; j < AST_LC_COUNT; j++)
1047da2e3ebdSchin if (locales[j] == locales[i])
1048da2e3ebdSchin cat[j] = i;
1049da2e3ebdSchin }
1050da2e3ebdSchin if (k == 1)
1051da2e3ebdSchin return (char*)locales[1]->name;
1052da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
1053da2e3ebdSchin if (cat[i] >= 0 && !(locales[i]->flags & LC_default))
1054da2e3ebdSchin {
1055da2e3ebdSchin if (sfstrtell(sp))
1056da2e3ebdSchin sfprintf(sp, ";");
1057da2e3ebdSchin for (j = i, k = cat[i]; j < AST_LC_COUNT; j++)
1058da2e3ebdSchin if (cat[j] == k)
1059da2e3ebdSchin {
1060da2e3ebdSchin cat[j] = -1;
10617c2fbfb3SApril Chin sfprintf(sp, "%s=", lc_categories[j].name);
1062da2e3ebdSchin }
1063da2e3ebdSchin sfprintf(sp, "%s", locales[i]->name);
1064da2e3ebdSchin }
1065da2e3ebdSchin if (!sfstrtell(sp))
1066da2e3ebdSchin return (char*)locales[0]->name;
1067da2e3ebdSchin return sfstruse(sp);
1068da2e3ebdSchin }
1069da2e3ebdSchin if (!ast.locale.serial++)
107034f9b3eeSRoland Mainz {
1071da2e3ebdSchin stropt(getenv("LC_OPTIONS"), options, sizeof(*options), setopt, NiL);
107234f9b3eeSRoland Mainz initialized = 0;
107334f9b3eeSRoland Mainz }
1074*3e14f97fSRoger A. Faulkner if ((ast.locale.set & (AST_LC_debug|AST_LC_setlocale)) && !(ast.locale.set & AST_LC_internal))
1075*3e14f97fSRoger A. Faulkner sfprintf(sfstderr, "locale user %17s %16s %s%s\n", category == AST_LC_LANG ? "LANG" : lc_categories[category].name, locale && !*locale ? "''" : locale, initialized ? "" : "[initial]", (ast.locale.set & AST_LC_setenv) ? "[setenv]" : "");
1076*3e14f97fSRoger A. Faulkner if (ast.locale.set & AST_LC_setenv)
1077*3e14f97fSRoger A. Faulkner {
1078*3e14f97fSRoger A. Faulkner f = LC_setenv;
1079*3e14f97fSRoger A. Faulkner p = *locale ? lcmake(locale) : (Lc_t*)0;
1080*3e14f97fSRoger A. Faulkner }
1081*3e14f97fSRoger A. Faulkner else if (*locale)
1082*3e14f97fSRoger A. Faulkner {
1083*3e14f97fSRoger A. Faulkner f = LC_setlocale;
1084*3e14f97fSRoger A. Faulkner p = lcmake(locale);
1085*3e14f97fSRoger A. Faulkner }
1086*3e14f97fSRoger A. Faulkner else if (category == AST_LC_ALL)
1087*3e14f97fSRoger A. Faulkner {
1088*3e14f97fSRoger A. Faulkner if (!initialized)
1089da2e3ebdSchin {
1090da2e3ebdSchin char* u;
1091da2e3ebdSchin char tmp[256];
1092da2e3ebdSchin
1093da2e3ebdSchin /*
1094da2e3ebdSchin * initialize from the environment
1095da2e3ebdSchin * precedence determined by X/Open
1096da2e3ebdSchin */
1097da2e3ebdSchin
1098da2e3ebdSchin u = 0;
109934f9b3eeSRoland Mainz if ((s = getenv("LANG")) && *s)
1100da2e3ebdSchin {
110134f9b3eeSRoland Mainz if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
110234f9b3eeSRoland Mainz s = u;
110334f9b3eeSRoland Mainz lang = lcmake(s);
110434f9b3eeSRoland Mainz }
110534f9b3eeSRoland Mainz else
110634f9b3eeSRoland Mainz lang = 0;
110734f9b3eeSRoland Mainz if ((s = getenv("LC_ALL")) && *s)
110834f9b3eeSRoland Mainz {
110934f9b3eeSRoland Mainz if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
111034f9b3eeSRoland Mainz s = u;
111134f9b3eeSRoland Mainz lc_all = lcmake(s);
111234f9b3eeSRoland Mainz }
111334f9b3eeSRoland Mainz else
111434f9b3eeSRoland Mainz lc_all = 0;
1115da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
1116*3e14f97fSRoger A. Faulkner if (lc_categories[i].flags & LC_setlocale)
1117*3e14f97fSRoger A. Faulkner /* explicitly set by setlocale() */;
1118*3e14f97fSRoger A. Faulkner else if ((s = getenv(lc_categories[i].name)) && *s)
1119da2e3ebdSchin {
1120da2e3ebdSchin if (streq(s, local) && (u || (u = native_locale(locale, tmp, sizeof(tmp)))))
1121da2e3ebdSchin s = u;
11227c2fbfb3SApril Chin lc_categories[i].prev = lcmake(s);
1123da2e3ebdSchin }
112434f9b3eeSRoland Mainz else
112534f9b3eeSRoland Mainz lc_categories[i].prev = 0;
1126da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
1127*3e14f97fSRoger A. Faulkner if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
1128da2e3ebdSchin {
112934f9b3eeSRoland Mainz while (i--)
1130*3e14f97fSRoger A. Faulkner single(i, NiL, 0);
113134f9b3eeSRoland Mainz return 0;
1132da2e3ebdSchin }
113334f9b3eeSRoland Mainz if (ast.locale.set & AST_LC_debug)
113434f9b3eeSRoland Mainz for (i = 1; i < AST_LC_COUNT; i++)
1135*3e14f97fSRoger A. Faulkner sfprintf(sfstderr, "locale env %17s %16s %16s %16s\n", lc_categories[i].name, locales[i]->name, "", lc_categories[i].prev ? lc_categories[i].prev->name : (char*)0);
113634f9b3eeSRoland Mainz initialized = 1;
1137*3e14f97fSRoger A. Faulkner }
113834f9b3eeSRoland Mainz goto compose;
113934f9b3eeSRoland Mainz }
114034f9b3eeSRoland Mainz else if (category == AST_LC_LANG || !(p = lc_categories[category].prev))
1141*3e14f97fSRoger A. Faulkner {
1142*3e14f97fSRoger A. Faulkner f = 0;
114334f9b3eeSRoland Mainz p = lcmake("C");
1144*3e14f97fSRoger A. Faulkner }
1145*3e14f97fSRoger A. Faulkner else
1146*3e14f97fSRoger A. Faulkner f = 0;
114734f9b3eeSRoland Mainz if (category == AST_LC_LANG)
114834f9b3eeSRoland Mainz {
114934f9b3eeSRoland Mainz if (lang != p)
115034f9b3eeSRoland Mainz {
115134f9b3eeSRoland Mainz lang = p;
115234f9b3eeSRoland Mainz if (!lc_all)
115334f9b3eeSRoland Mainz for (i = 1; i < AST_LC_COUNT; i++)
1154*3e14f97fSRoger A. Faulkner if (!single(i, lc_categories[i].prev, 0))
1155da2e3ebdSchin {
1156da2e3ebdSchin while (i--)
1157*3e14f97fSRoger A. Faulkner single(i, NiL, 0);
1158da2e3ebdSchin return 0;
1159da2e3ebdSchin }
1160da2e3ebdSchin }
1161da2e3ebdSchin }
116234f9b3eeSRoland Mainz else if (category != AST_LC_ALL)
1163*3e14f97fSRoger A. Faulkner {
1164*3e14f97fSRoger A. Faulkner if (f || !lc_all)
1165*3e14f97fSRoger A. Faulkner return single(category, p, f);
1166*3e14f97fSRoger A. Faulkner if (p && !(ast.locale.set & AST_LC_internal))
1167*3e14f97fSRoger A. Faulkner lc_categories[category].prev = p;
1168*3e14f97fSRoger A. Faulkner return (char*)locales[category]->name;
1169*3e14f97fSRoger A. Faulkner }
1170*3e14f97fSRoger A. Faulkner else if (composite(locale, 0) < 0)
1171da2e3ebdSchin return 0;
117234f9b3eeSRoland Mainz else if (lc_all != p)
117334f9b3eeSRoland Mainz {
117434f9b3eeSRoland Mainz lc_all = p;
1175da2e3ebdSchin for (i = 1; i < AST_LC_COUNT; i++)
1176*3e14f97fSRoger A. Faulkner if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
1177da2e3ebdSchin {
1178da2e3ebdSchin while (i--)
1179*3e14f97fSRoger A. Faulkner single(i, NiL, 0);
1180da2e3ebdSchin return 0;
1181da2e3ebdSchin }
1182da2e3ebdSchin }
1183da2e3ebdSchin goto compose;
1184da2e3ebdSchin }
1185