30#define _RWSTD_TEST_SRC
43# ifdef _RWSTD_NO_PURE_C_HEADERS
47# define _XOPEN_SOURCE 500
49# include <sys/types.h>
83# define LC_MESSAGES _RWSTD_LC_MESSAGES
87# define _RWSTD_NO_LANGINFO
88# define EXE_SUFFIX ".exe"
91#ifndef _RWSTD_NO_LANGINFO
95#if !defined (PATH_MAX) || PATH_MAX < 128 || 4096 < PATH_MAX
102#define TOPDIR "TOPDIR"
103#define BINDIR "BINDIR"
106#if _RWSTD_PATH_SEP == '/'
108# define IS_ABSOLUTE_PATHNAME(path) (_RWSTD_PATH_SEP == *(path))
111# define IS_ABSOLUTE_PATHNAME(path) \
112 ( ( 'A' <= *(path) && 'Z' >= *(path) \
113 || 'a' <= *(path) && 'z' >= *(path)) \
114 && ':' == (path)[1] \
115 && _RWSTD_PATH_SEP == (path)[2])
119#define RELPATH "etc" SLASH "nls"
120#define TESTS_ETC_PATH "tests" SLASH "etc"
124# define RW_CAT_EXT ".cat"
126# define RW_CAT_EXT ".dll"
135 const char* bindir = getenv (
BINDIR);
137 bindir =
".." SLASH "bin";
155 const char* src,
const char *charmap,
const char *locname)
175 + 2 <
sizeof locale_path);
181 strcpy (locale_path, locname);
183 strcat (locale_path,
SLASH);
184 strcat (locale_path, locname);
191 strcat (locale_path,
SLASH);
194 slash = slash ? slash + 1 : src;
196 strcat (locale_path, src);
197 strcat (locale_path,
".");
200 slash = slash ? slash + 1 : charmap;
202 strcat (locale_path, slash);
207#if !defined (_MSC_VER)
209 if (!stat (locale_path, &
sb)) {
212 if (!_stat (locale_path, &
sb)) {
220 char topdir_path_buf [] = __FILE__;
223 const char* topdir = getenv (
TOPDIR);
224 if (!topdir || !*topdir) {
231 topdir = topdir_path_buf;
235 if (!topdir || !*topdir) {
237 "the environment variable %s is %s",
238 TOPDIR, topdir ?
"empty" :
"undefined");
243 const char* bindir = getenv (
BINDIR);
245 bindir =
".." SLASH "bin";
252 strcpy (src_path, topdir);
254 strcat (src_path, src);
259 FILE*
const file_exists = fopen (src_path,
"r");
261 fclose (file_exists);
264 strcat (src_path,
SLASH);
265 strcat (src_path, src);
273 strcpy (charmap_path, topdir);
275 strcat (charmap_path, charmap);
280 FILE*
const file_exists = fopen (charmap_path,
"r");
282 fclose (file_exists);
285 strcat (charmap_path,
SLASH);
286 strcat (charmap_path, charmap);
289 charmap = charmap_path;
295 const int ret =
rw_system (
"%s%slocaledef%s %s -c -f %s -i %s %s",
297 charmap, src, locale_path);
307static char rw_locale_root [
PATH_MAX];
309static void atexit_rm_locale_root ()
359 rw_error (0 ==
atexit (atexit_rm_locale_root), __FILE__, __LINE__,
360 "atexit(atexit_rm_locale_root) failed: %m");
368rw_locales (
int loc_cat,
const char* grep_exp,
bool prepend_c_loc)
370 static char deflocname [3] =
"C\0";
371 static char* slocname = 0;
373 static const size_t grow_size = 5120;
374 static size_t size = 0;
375 static size_t total_size = grow_size;
376 static int last_cat = loc_cat;
379# define _QUIET_MALLOC(n) malloc(n)
380# define _QUIET_FREE(p) free(p)
384# define _QUIET_MALLOC(n) _malloc_dbg (n, _CLIENT_BLOCK, 0, 0)
385# define _QUIET_FREE(p) _free_dbg (p, _CLIENT_BLOCK);
399 if (*slocname && loc_cat == last_cat)
405 char* locname = slocname;
407 char* save_localename = 0;
412 save_localename = strcpy (namebuf, setlocale (loc_cat, 0));
422 if (grep_exp && 80 < strlen (grep_exp)) {
428 grep_exp && *grep_exp
429 ?
rw_system (
"locale -a | grep \"%s\" > %s", grep_exp, fname)
437 FILE *file = fopen (fname,
"r");
446 char last_name [256];
451 strcpy (locname, deflocname);
453 const size_t defnamelen = strlen (deflocname) + 1;
454 locname += defnamelen;
459 while (fgets (linebuf,
int (
sizeof linebuf), file)) {
461 const size_t linelen = strlen (linebuf);
463 linebuf [linelen ? linelen - 1 : 0] =
'\0';
467 if (prepend_c_loc && !strcmp (linebuf, deflocname))
470#ifdef _RWSTD_OS_SUNOS
472 const char iso_8859_pfx[] =
"iso_8859_";
476 if ( !strcmp (
"common", linebuf)
477 ||
sizeof iso_8859_pfx <= linelen
478 && !memcmp (iso_8859_pfx, linebuf,
sizeof iso_8859_pfx - 1))
485 if (total_size <
size) {
486 total_size += grow_size;
493 memcpy (
tmp, slocname, total_size - grow_size);
498 locname = slocname +
size - linelen;
504 strcpy (locname, linebuf);
511 const char *
name = setlocale (loc_cat, linebuf);
515 if (
name && strcmp (last_name,
name)) {
516 strcpy (locname, linebuf);
521 strcpy (last_name,
name);
525 strcpy (locname, linebuf);
536 setlocale (loc_cat, save_localename);
543 return *slocname ? slocname : deflocname;
552_get_mb_char (
char *
buf,
size_t bytes)
569 for (wc =
wchar_t (1); wc !=
wchar_t (0xffff); ++wc) {
571 if (
int (
bytes) == wctomb (
buf, wc)
581#if 2 < _RWSTD_WCHAR_SIZE
585 if (
wchar_t (0xffff) == wc) {
590 for (
int i = 0;
i != 0x100000; ++
i) {
599 if (
int (
bytes) == wctomb (
buf, wc)
622 const char* mbc = _get_mb_char (mb_chars [0],
size_t (-1));
624 if (0 ==
rw_note (0 != mbc, __FILE__, __LINE__,
625 "failed to find any multibyte characters "
626 "in locale \"%s\" with MB_CUR_MAX = %u",
630 size_t mb_cur_max = strlen (mbc);
632 if (_RWSTD_MB_LEN_MAX < mb_cur_max)
633 mb_cur_max = _RWSTD_MB_LEN_MAX;
637 for (
size_t i = mb_cur_max;
i; --
i) {
640 mbc = _get_mb_char (mb_chars [
i - 1],
i);
646 if (0 ==
rw_note (mb_cur_max <=
i, __FILE__, __LINE__,
647 "failed to find %u-byte characters "
648 "in locale \"%s\" with MB_CUR_MAX = %u",
667 char tmp [_RWSTD_MB_LEN_MAX];
671 for (
int i = 0;
i != 65536; ++
i) {
677 const int len = wctomb (
tmp, wc);
679 if ((nbytes == 0 && 0 <
len) || (nbytes != 0 && nbytes ==
len)) {
692#if 2 < _RWSTD_WCHAR_SIZE
697 for (
int i = 0;
i != 0x100000; ++
i) {
700 wchar_t wc =
wchar_t (rand ());
707 const int len = wctomb (
tmp, wc);
709 if ((nbytes == 0 && 0 <
len) || (nbytes != 0 && nbytes ==
len)) {
730 if (2 > _RWSTD_MB_LEN_MAX) {
731 rw_warn (0, __FILE__, __LINE__,
"MB_LEN_MAX = %d, giving up",
736 static const char *mb_locale_name;
738 char saved_locale_name [1024];
739 strcpy (saved_locale_name, setlocale (
LC_CTYPE, 0));
741 _RWSTD_ASSERT (strlen (saved_locale_name) <
sizeof saved_locale_name);
755 if (*mb_cur_max < cur_max) {
756 *mb_cur_max = cur_max;
757 mb_locale_name =
name;
761 if (_RWSTD_MB_LEN_MAX == *mb_cur_max)
767 if (*mb_cur_max < 2) {
768 rw_warn (0, __FILE__, __LINE__,
769 "failed to find a full set of multibyte "
770 "characters in locale \"%s\" with MB_CUR_MAX = %u "
771 "(computed)", mb_locale_name, *mb_cur_max);
779 setlocale (
LC_CTYPE, mb_locale_name);
783 setlocale (
LC_CTYPE, saved_locale_name);
785 return mb_locale_name;
795 static const char* locname;
815 FILE *fout = fopen (srcfname,
"w");
819 "fopen(#%s, \"w\") failed: %m", srcfname);
823 fprintf (fout,
"%s", locale);
834 fout = fopen (cmfname,
"w");
838 "fopen(%#s, \"w\") failed: %m", cmfname);
842 fprintf (fout,
"%s", charmap);
846 locname =
"test-locale";
849 if (0 ==
rw_localedef (
"-w", srcfname, cmfname, locname))
868 if (1 == argc && argv && 0 == argv [0]) {
869 static const char helpstr[] = {
870 "Use the locales specified by the space-parated list of locale"
871 "names given by <arg>.\n"
880 char *args = strchr (argv [0],
'=');
887 const size_t len = strlen (++args);
891 char*
const locale_names =
894 if (0 == locale_names)
897 locale_names [
len] =
'\0';
898 locale_names [
len + 1] =
'\0';
900 memcpy (locale_names, args,
len);
902 for (
char *next = locale_names; ; ) {
903 next = strpbrk (next,
", ");
910 _rw_locale_names = locale_names;
924 FILE*
const f = fopen (catname,
"w");
931 for (
int i = 1; *catalog; ++catalog, ++
i) {
932 fprintf (
f,
"$set %d This is Set %d\n",
i,
i);
933 for (
int j = 1; *catalog; catalog += strlen (catalog) + 1, ++
j)
934 fprintf (
f,
"%d %s\n",
j, catalog);
939 fprintf (
f,
"STRINGTABLE\nBEGIN\n");
941 for (
int i = 1; *catalog; ++catalog) {
942 for (; *catalog; catalog += strlen (catalog) + 1, ++
i)
943 fprintf (
f,
"%d \"%s\"\n",
i, catalog);
946 fprintf (
f,
"END\n");
952 char *cat_name =
new char [strlen (catname) + 1];
953 strcpy (cat_name, catname);
954 if (
char *dot = strrchr (cat_name,
'.'))
970 return 0 != isspace ((
unsigned char)ch);
976 return toupper ((
unsigned char)ch);
982 return tolower ((
unsigned char)ch);
1005_rw_lookup_comparator (
const void* _lhs,
const void* _rhs)
1010 return strcmp (
lhs->native,
rhs->native);
1018 : entries_ (0), count_ (0), table_data_ (0) {
1061 for (
size_t i = 0;
i <
a->count; ++
i)
1062 a->entries [
i].next = &
a->entries [
i+1];
1063 a->entries [
a->count - 1].next = 0;
1078 _rw_reset_locales (&
result);
1086 result.entries = &fallback;
1089 const char*
const fname =
rw_tmpnam (0);
1094 const int status =
rw_system (
"locale -a > %s", fname);
1099 FILE* file = fopen (fname,
"r");
1104 const size_t grow_size = 64;
1107 size_t capacity = 0;
1116 char topdir_path_buf [] = __FILE__;
1119 const char* topdir = getenv (
TOPDIR);
1120 if (!topdir || !*topdir) {
1127 topdir = topdir_path_buf;
1131 if (!topdir || !*topdir) {
1133 "the environment variable %s is %s",
1134 TOPDIR, topdir ?
"empty" :
"undefined");
1142 strcpy (
path, topdir);
1152 while (fgets (locale,
int (
sizeof (locale)), file)) {
1155 if (! (
size < capacity)) {
1156 capacity += grow_size;
1165 memcpy (new_entries, entries, entry_size *
size);
1170 entries = new_entries;
1177 const size_t len = strlen (locale);
1178 locale [
len ?
len - 1 : 0] =
'\0';
1181 if (!setlocale (
LC_CTYPE, locale)) {
1183 rw_note (0, __FILE__, __LINE__,
1184 "setlocale() failed for '%s'", locale);
1191 else if (!strcmp (locale,
"C") || !strcmp (locale,
"POSIX")) {
1198 rw_note (0, __FILE__, __LINE__,
1199 "locale name '%s' was to long for fixed buffer",
1205#ifndef _RWSTD_NO_LANGINFO
1209 for (
const char* charset = nl_langinfo (CODESET);
1222 char* extension = strrchr (locale,
'@');
1224 *extension++ =
'\0';
1227 char* encoding = strrchr (locale,
'.');
1231 for (
int n = 0; encoding [
n]; ++
n)
1235 char* country = strrchr (locale,
'_');
1239 for (
int n = 0; country [
n]; ++
n)
1243 char* language = locale;
1245 for (
int n = 0; language [
n]; ++
n)
1251 const char* planguage =
1254 planguage = language;
1258 const char* pcountry =
1263#ifndef _RWSTD_NO_LANGINFO
1264 const char* pencoding =
1267 pencoding = codeset;
1269 const char* pencoding =
1272 pencoding = encoding;
1276 if (!planguage || !*planguage) {
1284 else if (!pcountry || !*pcountry) {
1292 else if (!pencoding || !*pencoding) {
1303 planguage, pcountry, int (
MB_CUR_MAX), pencoding);
1311 bool duplicate =
false;
1315 for (
size_t e =
size; 0 !=
e; --
e) {
1317 if (!strcmp (entries [
e-1].canonical_name,
1341 result.entries = entries;
1350 _rw_reset_locales (&
result);
1365 wanted = _RWSTD_SIZE_MAX;
1380 strcpy (save_locale, setlocale (
LC_ALL, 0));
1386 static char*
string = 0;
1387 static size_t length = 0;
1388 static size_t capacity = 0;
1412 dummy = dummy->
next;
1437 const size_t add_length = strlen (entry->
locale_name) + 1;
1438 const size_t new_length = length + add_length;
1441 if (! (new_length < capacity)) {
1443 while (capacity < new_length)
1458 memcpy (new_string,
string, length);
1462 string = new_string;
1466 memcpy (
string + length, entry->
locale_name, add_length);
1468 length = new_length;
1471 if (! (
count < wanted))
1475 if (! (
count < wanted))
1480 setlocale (
LC_ALL, save_locale);
1488 string [length+0] =
'\0';
1489 string [length+1] =
'\0';
1509 _rw_lookup_comparator);
1524 strcpy (filename,
path);
1525 strcat (filename,
name);
1527 FILE* file = fopen (filename,
"rb");
1532 const size_t table_data_size = ftell (file);
1536 (
char*)malloc (table_data_size + 1);
1544 const size_t bytes_read =
1545 fread (table_data, 1, table_data_size, file);
1546 if (bytes_read != table_data_size) {
1553 table_data [bytes_read] =
'\0';
1558 size_t capacity = 0;
1561 const char* canonical_name = 0;
1565 char* key = table_data +
offset;
1567 const size_t len = strcspn (key,
"\r\n");
1574 if (!*key || *key ==
'\n'
1579 if (upper_or_lower < 0) {
1580 for (
char*
s = key; *
s; ++
s)
1583 else if (0 < upper_or_lower) {
1584 for (
char*
s = key; *
s; ++
s)
1592 canonical_name = key;
1610 const char* native_name = key;
1614 while (*key && *key !=
',')
1622 for (
char* bey = key - 1;
_rw_isspace (*bey); --bey)
1630 if (! (
size < capacity)) {
1647 memcpy (new_entries, entries, entry_size *
size);
1651 entries = new_entries;
1656 entry->
native = native_name;
1667 qsort (entries,
size, entry_size, _rw_lookup_comparator);
1672 table_data_ = table_data;
1676 "failed to open the file %s", filename);
void count(T, T, const U &,...)
IMPORT_C SInt32 atexit(Void(*function)(Void))
#define _RWSTD_STATIC_CAST(T, x)
#define _RWSTD_ASSERT(ignore)
#define _RWSTD_CONST_CAST(T, x)
_TEST_EXPORT char * rw_shell_expand(const char *shell_expr, _RWSTD_SIZE_T sz, char *s, _RWSTD_SIZE_T n, char sep)
_TEST_EXPORT bool rw_enable(int(*fun)(int, const char *, int, const char *,...), bool enable=true)
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
_TEST_EXPORT int rw_warn(int, const char *, int, const char *,...)
_TEST_EXPORT int rw_putenv(const char *, int=-1)
_TEST_EXPORT const char * rw_tmpnam(char *)
_TEST_EXPORT int rw_fnmatch(const char *, const char *, int)
#define LOCALE_ROOT_ENVAR
char rw_mbchar_array_t[_RWSTD_MB_LEN_MAX][_RWSTD_MB_LEN_MAX]
_TEST_EXPORT int rw_snprintf(char *, _RWSTD_SIZE_T, const char *,...)
_TEST_EXPORT int rw_system(const char *,...)
_rw_locale_entry * entries
struct _rw_locale_entry * next
const char * get_canonical_name(const char *name) const
size_t get_num_entries() const
bool load_from_file(const char *path, const char *file, int upper_or_lower)
const _rw_lookup_entry_t * get_entries() const
_TEST_EXPORT char * rw_locale_query(int loc_cat, const char *query, size_t wanted)
char _rw_tolower(char ch)
_TEST_EXPORT const char * rw_localedef(const char *args, const char *src, const char *charmap, const char *locname)
_TEST_EXPORT const char * rw_create_locale(const char *charmap, const char *locale)
_TEST_EXPORT size_t rw_get_wchars(wchar_t *wbuf, size_t bufsize, int nbytes)
_TEST_EXPORT int rw_create_catalog(const char *catname, const char *catalog)
_TEST_EXPORT const char *const & rw_opt_locales
_TEST_EXPORT size_t rw_get_mb_chars(rw_mbchar_array_t mb_chars)
_TEST_EXPORT const char * rw_set_locale_root()
_TEST_EXPORT int rw_opt_setlocales(int argc, char *argv[])
_TEST_EXPORT char * rw_locales(int loc_cat, const char *grep_exp, bool prepend_c_loc)
char _rw_toupper(char ch)
_TEST_EXPORT const char * rw_find_mb_locale(size_t *mb_cur_max, rw_mbchar_array_t mb_chars)
bool _rw_isspace(char ch)
_TEST_EXPORT int rw_locale(const char *args, const char *fname)
#define IS_ABSOLUTE_PATHNAME(path)