/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2010 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* setlocale() intercept
* maintains a bitmask of non-default categories
* and a permanent locale namespace for pointer comparison
* and persistent private data for locale related functions
*/
#include <ast_standards.h>
#include "lclib.h"
#include <ast_wchar.h>
#include <ctype.h>
#include <mc.h>
#include <namval.h>
#include <wctype.h>
#endif
#if _lib_wcwidth
#else
#define wcwidth 0
#endif
#if _lib_wctomb
#else
#define wctomb 0
#endif
#ifdef mblen
#endif
#ifndef AST_LC_CANONICAL
#endif
#ifndef AST_LC_test
#endif
#if _UWIN
#include <ast_windows.h>
extern char* uwin_setlocale(int, const char*);
/*
* convert locale to native locale name in buf
*/
static char*
{
int i;
unsigned long lcid;
unsigned long lang;
unsigned long ctry;
{
return 0;
ctry = 0;
break;
if (!ctry)
{
{
break;
}
if (!ctry)
{
if (!lang)
return 0;
}
}
}
else
lcid = GetUserDefaultLCID();
return 0;
else
return buf;
}
/*
* locale!=0 here
*/
static char*
{
char* usr;
char* sys;
return 0;
/*
* win32 doesn't have LC_MESSAGES
*/
if (category == LC_MESSAGES)
return (char*)locale;
sfprintf(sfstderr, "locale uwin %17s %-24s %-24s\n", lc_categories[lcindex(category, 0)].name, usr, sys);
return sys;
}
#else
#define native_locale(a,b,c) ((char*)0)
#endif
/*
* LC_COLLATE and LC_CTYPE native support
*/
#define mblen 0
#define mbtowc 0
#endif
#if !_lib_strcoll
#define strcoll 0
#endif
#if !_lib_strxfrm
#define strxfrm 0
#endif
/*
* LC_COLLATE and LC_CTYPE debug support
*
* mutibyte debug encoding
*
* DL0 [ '0' .. '4' ] c1 ... c4 DR0
* DL1 [ '0' .. '4' ] c1 ... c4 DR1
*
* with these ligatures
*
* ch CH sst SST
*
* and private collation order
*
* wide character display width is the low order 3 bits
* wctomb() uses DL1...DR1
*/
#if DEBUG_MB_CUR_MAX < MB_LEN_MAX
#endif
static unsigned char debug_order[] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
99, 100, 101, 102, 98, 103, 104, 105,
106, 107, 108, 43, 109, 44, 42, 110,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 111, 112, 113, 114, 115, 116,
117, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85,
86, 87, 88, 89, 90, 91, 92, 93,
94, 95, 96, 118, 119, 120, 121, 97,
122, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135,
136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151,
152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255,
};
static int
{
register const char* q;
register const char* r;
register int w;
register int dr;
wchar_t c;
if (n < 1)
return -1;
if (!s || !*s)
return 0;
switch (((unsigned char*)s)[0])
{
case DL0:
break;
case DL1:
break;
default:
if (p)
return 1;
}
if (n < 2)
return -1;
if ((w = ((unsigned char*)s)[1]) == ((unsigned char*)s)[0])
{
if (p)
*p = w;
return 2;
}
return -1;
if ((w -= '0' - DD) > n)
return -1;
r = s + w - 1;
q = s += 2;
while (q < r && *q)
q++;
if (q != r || *((unsigned char*)q) != dr)
return -1;
if (p)
{
c = 0;
while (--q >= s)
{
c <<= DC;
c |= *((unsigned char*)q);
}
c <<= DZ;
c |= w - DD;
*p = c;
}
return w;
}
static int
{
int w;
int i;
int k;
w = 0;
if (c >= 0 && c <= UCHAR_MAX)
{
w++;
if (s)
*s = c;
}
return -1;
else
{
w++;
if (s)
*s++ = DL1;
c >>= DZ;
w++;
if (s)
*s++ = i + '0';
while (i--)
{
w++;
if (s)
c >>= DC;
}
w++;
if (s)
*s++ = DR1;
}
return w;
}
static int
{
return debug_mbtowc(NiL, s, n);
}
static int
{
if (c >= 0 && c <= UCHAR_MAX)
return 1;
return -1;
return c + DD;
}
static size_t
{
register const char* q;
register const char* r;
register char* e;
char* o;
register size_t z;
register int w;
o = t;
z = 0;
if (e = t)
e += n;
while (s[0])
{
if ((((unsigned char*)s)[0] == DL0 || ((unsigned char*)s)[0] == DL1) && (w = s[1]) >= '0' && w <= ('0' + DC))
{
w -= '0';
q = s + 2;
r = q + w;
while (q < r && *q)
q++;
{
if (t)
{
for (q = s + 2; q < r; q++)
if (t < e)
*t++ = debug_order[*q];
while (w++ < DX)
if (t < e)
*t++ = 1;
}
s = r + 1;
z += DX;
continue;
}
}
if ((s[0] == 'c' || s[0] == 'C') && (s[1] == 'h' || s[1] == 'H'))
{
if (t)
{
if (t < e)
*t++ = debug_order[s[0]];
if (t < e)
*t++ = debug_order[s[1]];
if (t < e)
*t++ = 1;
if (t < e)
*t++ = 1;
}
s += 2;
z += DX;
continue;
}
if ((s[0] == 's' || s[0] == 'S') && (s[1] == 's' || s[1] == 'S') && (s[2] == 't' || s[2] == 'T'))
{
if (t)
{
if (t < e)
*t++ = debug_order[s[0]];
if (t < e)
*t++ = debug_order[s[1]];
if (t < e)
*t++ = debug_order[s[2]];
if (t < e)
*t++ = 1;
}
s += 3;
z += DX;
continue;
}
if (t)
{
if (t < e)
*t++ = debug_order[s[0]];
if (t < e)
*t++ = 1;
if (t < e)
*t++ = 1;
if (t < e)
*t++ = 1;
}
s++;
z += DX;
}
if (!t)
return z;
if (t < e)
*t = 0;
return t - o;
}
static int
debug_strcoll(const char* a, const char* b)
{
}
/*
* default locale
*/
static int
{
}
/*
* called when LC_COLLATE initialized or changes
*/
static int
{
{
}
{
}
else
{
}
return 0;
}
/*
* workaround the interesting sjis that translates unshifted 7 bit ascii!
*/
static int
{
if (n && p && s && (*s == '\\' || *s == '~') && !memcmp(mb_state, mb_state_zero, sizeof(mbstate_t)))
{
*p = *s;
return 1;
}
}
#endif
{
0x00000000,
0x00000000,
0xffffff80,
0xfffff800,
0xffff0000,
0xffe00000,
0xfc000000,
};
{
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6,-1,-1,
};
static int
{
register int m;
register int i;
register int c;
register wchar_t w = 0;
if (!sp || !n)
return 0;
{
if (m > n)
return -1;
if (wp)
{
if (m == 1)
{
return 1;
}
for (i = m - 1; i > 0; i--)
{
c = *++sp;
if ((c&0xc0) != 0x80)
goto invalid;
w = (w<<6) | (c&0x3f);
}
goto invalid;
*wp = w;
}
return m;
}
if (!*sp)
return 0;
#ifdef EILSEQ
#endif
return -1;
}
static int
{
wchar_t w;
return utf8_mbtowc(&w, str, n);
}
/*
* called when LC_CTYPE initialized or changes
*/
static int
{
{
}
else if ((locales[cp->internal]->flags & LC_default) || (ast.mb_cur_max = MB_CUR_MAX) <= 1 || !(ast.mb_len = mblen) || !(ast.mb_towc = mbtowc))
{
}
{
}
else
{
#ifdef mb_state
{
/*
* check for sjis that translates unshifted 7 bit ascii!
*/
char* s;
mbinit();
buf[1] = 0;
*(s = buf) = '\\';
{
}
}
#endif
}
#ifdef mb_state
#endif
: ""
, ast.mb_width == debug_wcwidth ? " debug_wcwidth" : ast.mb_width == wcwidth ? " wcwidth" : ast.mb_width == default_wcwidth ? " default_wcwidth" : ""
);
return 0;
}
/*
* called when LC_NUMERIC initialized or changes
*/
static int
{
{
{
}
else
dp = &default_numeric;
sfprintf(sfstderr, "locale info %17s decimal '%c' thousands '%c'\n", lc_categories[category].name, dp->decimal, dp->thousand >= 0 ? dp->thousand : 'X');
}
return 0;
}
/*
* this table is indexed by AST_LC_[A-Z]*
*/
{
};
typedef struct Unamval_s
{
char* name;
unsigned int value;
} Unamval_t;
{
"debug", AST_LC_debug,
"find", AST_LC_find,
"setlocale", AST_LC_setlocale,
"test", AST_LC_test,
"translate", AST_LC_translate,
0, 0
};
/*
* called by stropt() to set options
*/
static int
setopt(void* a, const void* p, int n, const char* v)
{
if (p)
{
if (n)
else
}
return 0;
}
#if !_lib_setlocale
static char*
{
if (locale)
{
return 0;
}
}
#endif
/*
* set a single AST_LC_* locale category
* the caller must validate category
* lc==0 restores the previous state
*/
static char*
{
const char* sys;
int i;
{
}
if (!lc && (!(lc_categories[category].flags & LC_setlocale) || !(lc = lc_categories[category].prev)) && !(lc = lc_all) && !(lc = lc_categories[category].prev) && !(lc = lang))
sys = 0;
{
{
for (i = 1; i < AST_LC_COUNT; i++)
{
break;
}
}
if (!sys)
{
/*
* check for local override
* currently this means an LC_MESSAGES dir exists
*/
{
}
return 0;
}
{
return 0;
}
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'))
else
}
{
}
else
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]" : "");
}
/*
* set composite AST_LC_ALL locale categories
* return <0:composite-error 0:not-composite >0:composite-ok
*/
static int
{
register const char* t;
register int i;
register int j;
register int k;
int n;
int m;
const char* w;
Lc_t* p;
k = n = 0;
while (s[0] == 'L' && s[1] == 'C' && s[2] == '_')
{
n++;
j = 0;
w = s;
for (i = 1; i < AST_LC_COUNT; i++)
{
s = w;
t = lc_categories[i].name;
while (*t && *s++ == *t++);
if (!*t && *s++ == '=')
{
cat[j++] = i;
if (s[0] != 'L' || s[1] != 'C' || s[2] != '_')
break;
w = s;
i = -1;
}
}
for (s = w; *s && *s != '='; s++);
if (!*s)
{
for (i = 0; i < k; i++)
return -1;
}
w = ++s;
for (;;)
{
if (!*s)
{
p = lcmake(w);
break;
}
else if (*s++ == ';')
{
if ((m = s - w - 1) >= sizeof(buf))
m = sizeof(buf) - 1;
buf[m] = 0;
break;
}
}
for (i = 0; i < j; i++)
if (!initialize)
{
{
for (i = 0; i < k; i++)
return -1;
}
}
}
{
n++;
for (w = ++s; *s && *s != '/'; s++);
if (!*s)
p = lcmake(w);
else
{
if ((j = s - w - 1) >= sizeof(buf))
j = sizeof(buf) - 1;
buf[j] = 0;
}
if (!initialize)
{
if (!single(n, p, 0))
{
for (i = 1; i < n; i++)
return -1;
}
}
lc_categories[n].prev = p;
}
return n;
}
/*
* setlocale() intercept
*
* locale:
* 0 query
* "" initialize from environment (if LC_ALL)
* "" AST_LC_setenv: value unset (defer to LANG)
* "*" AST_LC_setenv: value set (defer to LC_ALL)
* * set (override LC_ALL)
*/
char*
{
register char* s;
register int i;
register int j;
int k;
int f;
Lc_t* p;
static int initialized;
return 0;
if (!locale)
{
/*
* return the current state
*/
return 0;
for (i = 1; i < AST_LC_COUNT; i++)
cat[i] = -1;
for (i = 1, k = 0; i < AST_LC_COUNT; i++)
if (cat[i] < 0)
{
k++;
cat[i] = i;
for (j = i + 1; j < AST_LC_COUNT; j++)
cat[j] = i;
}
if (k == 1)
for (i = 1; i < AST_LC_COUNT; i++)
{
for (j = i, k = cat[i]; j < AST_LC_COUNT; j++)
if (cat[j] == k)
{
cat[j] = -1;
}
}
}
{
initialized = 0;
}
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]" : "");
{
f = LC_setenv;
}
else if (*locale)
{
f = LC_setlocale;
}
else if (category == AST_LC_ALL)
{
if (!initialized)
{
char* u;
/*
* initialize from the environment
*/
u = 0;
if ((s = getenv("LANG")) && *s)
{
s = u;
}
else
lang = 0;
if ((s = getenv("LC_ALL")) && *s)
{
s = u;
}
else
lc_all = 0;
for (i = 1; i < AST_LC_COUNT; i++)
/* explicitly set by setlocale() */;
{
s = u;
}
else
lc_categories[i].prev = 0;
for (i = 1; i < AST_LC_COUNT; i++)
if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
{
while (i--)
return 0;
}
for (i = 1; i < AST_LC_COUNT; i++)
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);
initialized = 1;
}
goto compose;
}
{
f = 0;
p = lcmake("C");
}
else
f = 0;
if (category == AST_LC_LANG)
{
if (lang != p)
{
lang = p;
if (!lc_all)
for (i = 1; i < AST_LC_COUNT; i++)
{
while (i--)
return 0;
}
}
}
else if (category != AST_LC_ALL)
{
if (f || !lc_all)
}
return 0;
else if (lc_all != p)
{
lc_all = p;
for (i = 1; i < AST_LC_COUNT; i++)
if (!single(i, lc_all && !(lc_categories[i].flags & LC_setlocale) ? lc_all : lc_categories[i].prev, 0))
{
while (i--)
return 0;
}
}
goto compose;
}