os/ossrv/stdcpp/tsrc/Stdcpp_test/stdcxx/testengine/src/localedef.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/************************************************************************
sl@0
     2
 *
sl@0
     3
 * localedef.cpp - definitions of locale helpers
sl@0
     4
 *
sl@0
     5
 * $Id: localedef.cpp 290022 2005-09-18 23:59:35Z sebor $
sl@0
     6
 *
sl@0
     7
 ************************************************************************
sl@0
     8
 *
sl@0
     9
 * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
sl@0
    10
 * Software division. Licensed under the Apache License, Version 2.0 (the
sl@0
    11
 * "License");  you may  not use this file except  in compliance with the
sl@0
    12
 * License.    You    may   obtain   a   copy   of    the   License    at
sl@0
    13
 * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
sl@0
    14
 * applicable law  or agreed to  in writing,  software  distributed under
sl@0
    15
 * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
sl@0
    16
 * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
sl@0
    17
 * for the specific language governing permissions  and limitations under
sl@0
    18
 * the License.
sl@0
    19
 *
sl@0
    20
 **************************************************************************/
sl@0
    21
sl@0
    22
// expand _TEST_EXPORT macros
sl@0
    23
#define _RWSTD_TEST_SRC
sl@0
    24
sl@0
    25
#include <localedef.h>
sl@0
    26
sl@0
    27
#include <environ.h>    // for rw_putenv()
sl@0
    28
#include <file.h>       // for SHELL_RM_RF, rw_tmpnam
sl@0
    29
#include <system.h>     // for rw_system()
sl@0
    30
sl@0
    31
sl@0
    32
#if defined __linux__
sl@0
    33
   // on Linux define _XOPEN_SOURCE to get CODESET defined in <langinfo.h>
sl@0
    34
#  define _XOPEN_SOURCE   500   /* Single Unix conformance */
sl@0
    35
   // bring __int32_t into scope (otherwise <wctype.h> fails to compile)
sl@0
    36
#  include <sys/types.h>
sl@0
    37
#endif   // __linux__
sl@0
    38
sl@0
    39
#include <fcntl.h>
sl@0
    40
#include <sys/stat.h>   // for stat
sl@0
    41
sl@0
    42
#if (!defined  (_WIN32) && !defined (_WIN64)) || defined (__SYMBIAN32__)
sl@0
    43
#  include <unistd.h>
sl@0
    44
#  include <sys/wait.h>   // for WIFEXITED(), WIFSIGNALED(), WTERMSIG()
sl@0
    45
#else
sl@0
    46
#  include <io.h>
sl@0
    47
#  include <crtdbg.h> // for _malloc_dbg()
sl@0
    48
#endif
sl@0
    49
sl@0
    50
#include <ios>        // for ios::*
sl@0
    51
#include <limits>     // for numeric_limits
sl@0
    52
#include <locale>     // for money_base::pattern
sl@0
    53
sl@0
    54
#include <assert.h>   // for assert
sl@0
    55
#include <errno.h>    // for EBADF
sl@0
    56
#include <float.h>    // for {FLT,DBL,LDBL}_DIG
sl@0
    57
#include <limits.h>   // for CHAR_BIT, PATH_MAX
sl@0
    58
#include <locale.h>   // for LC_XXX macros, setlocale
sl@0
    59
#include <stdarg.h>   // for va_copy, va_list, ...
sl@0
    60
#include <stdio.h>    // for fgets, remove, sprintf, ...
sl@0
    61
#include <stdlib.h>   // for getenv, free, malloc, realloc
sl@0
    62
#include <string.h>   // for strcat, strcpy, strlen, ...
sl@0
    63
#include <ctype.h>
sl@0
    64
#include <wchar.h>    // for wcslen, ...
sl@0
    65
sl@0
    66
#ifndef PATH_MAX
sl@0
    67
#  define PATH_MAX   1024
sl@0
    68
#endif
sl@0
    69
sl@0
    70
#ifndef _MSC_VER
sl@0
    71
#  include <clocale>
sl@0
    72
#  ifndef LC_MESSAGES
sl@0
    73
#    define LC_MESSAGES _RWSTD_LC_MESSAGES
sl@0
    74
#  endif   // LC_MESSAGES
sl@0
    75
#  include <langinfo.h>
sl@0
    76
#  define EXE_SUFFIX    ""
sl@0
    77
#else   // if MSVC
sl@0
    78
#  define EXE_SUFFIX    ".exe"
sl@0
    79
#endif  // _MSC_VER
sl@0
    80
sl@0
    81
sl@0
    82
#define TOPDIR   "TOPDIR"   /* the TOPDIR environment variable */
sl@0
    83
#define BINDIR   "BINDIR"   /* the BINDIR environment variable */
sl@0
    84
sl@0
    85
sl@0
    86
#if _RWSTD_PATH_SEP == '/'
sl@0
    87
#  define SLASH    "/"
sl@0
    88
#  define IS_ABSOLUTE_PATHNAME(path)   (_RWSTD_PATH_SEP == *(path))
sl@0
    89
#else
sl@0
    90
#  define SLASH    "\\"
sl@0
    91
#  define IS_ABSOLUTE_PATHNAME(path)                    \
sl@0
    92
       (   (   'A' <= *(path) && 'Z' >= *(path)         \
sl@0
    93
            || 'a' <= *(path) && 'z' >= *(path))        \
sl@0
    94
        && ':' == (path)[1]                             \
sl@0
    95
        && _RWSTD_PATH_SEP == (path)[2])
sl@0
    96
#endif
sl@0
    97
sl@0
    98
// relative paths to the etc/nls directory and its subdirectories
sl@0
    99
#if defined (_RWSTD_USE_CONFIG)
sl@0
   100
#  define RELPATH        "etc" SLASH "nls"
sl@0
   101
#  define TESTS_ETC_PATH "tests" SLASH "etc"
sl@0
   102
#else
sl@0
   103
#  define RELPATH        "etc" SLASH "stdlib" SLASH "nls"
sl@0
   104
#  define TESTS_ETC_PATH "tests" SLASH "stdlib" SLASH "etc"
sl@0
   105
#endif  // _RWSTD_USE_CONFIG
sl@0
   106
            
sl@0
   107
/**************************************************************************/
sl@0
   108
sl@0
   109
_TEST_EXPORT int
sl@0
   110
rw_locale (const char *args, const char *fname)
sl@0
   111
{
sl@0
   112
    // use BINDIR to determine the location of the locale command
sl@0
   113
    const char* bindir = getenv ("BINDIR");
sl@0
   114
    if (!bindir)
sl@0
   115
        bindir = ".." SLASH "bin";
sl@0
   116
sl@0
   117
    int ret;
sl@0
   118
sl@0
   119
    if (fname)
sl@0
   120
        ret = rw_system ("%s%slocale%s %s",
sl@0
   121
                         bindir, SLASH, EXE_SUFFIX, args);
sl@0
   122
    else
sl@0
   123
        ret = rw_system ("%s%slocale%s %s >%s",
sl@0
   124
                         bindir, SLASH, EXE_SUFFIX, args, fname);
sl@0
   125
sl@0
   126
    return ret;
sl@0
   127
}
sl@0
   128
sl@0
   129
/**************************************************************************/
sl@0
   130
sl@0
   131
_TEST_EXPORT const char*
sl@0
   132
rw_localedef (const char *args,
sl@0
   133
              const char* src, const char *charmap, const char *locname)
sl@0
   134
{
sl@0
   135
    assert (src && charmap);
sl@0
   136
sl@0
   137
    // create a fully qualified pathname of the locale database
sl@0
   138
    // when (locname == 0), the pathname is computed by appending
sl@0
   139
    // the name of the character map file `charmap' to the name
sl@0
   140
    // of the locale definition file `src'
sl@0
   141
    // otherwise, when `locname' is not a pathname, the pathname
sl@0
   142
    // of the locale database is formed by appending `locname'
sl@0
   143
    // to the name of the locale root directory
sl@0
   144
    static char locale_path [PATH_MAX];
sl@0
   145
sl@0
   146
    const char* locale_root = getenv (LOCALE_ROOT_ENVAR);
sl@0
   147
    if (!locale_root)
sl@0
   148
        locale_root = ".";
sl@0
   149
sl@0
   150
    assert (  strlen (locale_root)
sl@0
   151
            + strlen (src)
sl@0
   152
            + strlen (charmap)
sl@0
   153
            + 2 < sizeof locale_path);
sl@0
   154
sl@0
   155
    strcpy (locale_path, locale_root);
sl@0
   156
sl@0
   157
    if (locname) {
sl@0
   158
        if (strchr (locname, _RWSTD_PATH_SEP))
sl@0
   159
            strcpy (locale_path, locname);
sl@0
   160
        else {
sl@0
   161
            strcat (locale_path, SLASH);
sl@0
   162
            strcat (locale_path, locname);
sl@0
   163
        }
sl@0
   164
    }
sl@0
   165
    else {
sl@0
   166
        // compute the locale pathname from `src', `charmap',
sl@0
   167
        // and `locale_root'
sl@0
   168
        strcpy (locale_path, locale_root);
sl@0
   169
        strcat (locale_path, SLASH);
sl@0
   170
sl@0
   171
        const char *slash = strrchr (src, _RWSTD_PATH_SEP);
sl@0
   172
        slash = slash ? slash + 1 : src;
sl@0
   173
sl@0
   174
        strcat (locale_path, src);
sl@0
   175
        strcat (locale_path, ".");
sl@0
   176
sl@0
   177
        slash = strrchr (charmap, _RWSTD_PATH_SEP);
sl@0
   178
        slash = slash ? slash + 1 : charmap;
sl@0
   179
sl@0
   180
        strcat (locale_path, slash);
sl@0
   181
    }
sl@0
   182
sl@0
   183
    // check to see if the locale database already exists and
sl@0
   184
    // if so, return immediately the locale filename to the caller
sl@0
   185
#if !defined (_MSC_VER)
sl@0
   186
    struct stat sb;
sl@0
   187
    if (!stat (locale_path, &sb)) {
sl@0
   188
#else
sl@0
   189
    struct _stat sb;
sl@0
   190
    if (!_stat (locale_path, &sb)) {
sl@0
   191
#endif
sl@0
   192
        return strrchr (locale_path, _RWSTD_PATH_SEP) + 1;
sl@0
   193
    }
sl@0
   194
sl@0
   195
    // otherwise, try to create the locale database
sl@0
   196
sl@0
   197
    // use TOPDIR to determine the root of the source tree
sl@0
   198
    const char* const topdir = getenv (TOPDIR);
sl@0
   199
    if (!topdir || !*topdir) {
sl@0
   200
        fprintf (stderr, "%s:%d: the environment variable %s is %s\n",
sl@0
   201
                 __FILE__, __LINE__, TOPDIR, topdir ? "empty" : "undefined");
sl@0
   202
        return 0;
sl@0
   203
    }
sl@0
   204
sl@0
   205
    // use BINDIR to determine the location of the localedef command
sl@0
   206
    const char* bindir = getenv ("BINDIR");
sl@0
   207
    if (!bindir)
sl@0
   208
        bindir = ".." SLASH "bin";
sl@0
   209
sl@0
   210
    // if `src' is relative pathname (or a filename) construct the fully
sl@0
   211
    // qualified absolute pathname to the locale definition file from it
sl@0
   212
    char src_path [PATH_MAX];
sl@0
   213
sl@0
   214
    if (!IS_ABSOLUTE_PATHNAME (src)) {
sl@0
   215
        strcpy (src_path, topdir);
sl@0
   216
        strcat (src_path, SLASH RELPATH SLASH "src" SLASH);
sl@0
   217
        strcat (src_path, src);
sl@0
   218
sl@0
   219
        // if the file doesn't exist, see if there is a file
sl@0
   220
        // with that name in the locale root directory (e.g.,
sl@0
   221
        // a temporary file)
sl@0
   222
        FILE* const file_exists = fopen (src_path, "r");
sl@0
   223
        if (file_exists)
sl@0
   224
            fclose (file_exists);
sl@0
   225
        else {
sl@0
   226
            strcpy (src_path, locale_root);
sl@0
   227
            strcat (src_path, SLASH);
sl@0
   228
            strcat (src_path, src);
sl@0
   229
        }
sl@0
   230
sl@0
   231
        src = src_path;
sl@0
   232
    }
sl@0
   233
sl@0
   234
    char charmap_path [PATH_MAX];
sl@0
   235
    if (!IS_ABSOLUTE_PATHNAME (charmap)) {
sl@0
   236
        strcpy (charmap_path, topdir);
sl@0
   237
        strcat (charmap_path, SLASH RELPATH SLASH "charmaps" SLASH);
sl@0
   238
        strcat (charmap_path, charmap);
sl@0
   239
sl@0
   240
        // if the file doesn't exist, see if there is a file
sl@0
   241
        // with that name in the locale root directory (e.g.,
sl@0
   242
        // a temporary file)
sl@0
   243
        FILE* const file_exists = fopen (charmap_path, "r");
sl@0
   244
        if (file_exists)
sl@0
   245
            fclose (file_exists);
sl@0
   246
        else {
sl@0
   247
            strcpy (charmap_path, locale_root);
sl@0
   248
            strcat (charmap_path, SLASH);
sl@0
   249
            strcat (charmap_path, charmap);
sl@0
   250
        }
sl@0
   251
sl@0
   252
        charmap = charmap_path;
sl@0
   253
    }
sl@0
   254
sl@0
   255
    if (!args)
sl@0
   256
        args = "";
sl@0
   257
sl@0
   258
    const int ret = rw_system ("%s%slocaledef%s %s -c -f %s -i %s %s",
sl@0
   259
                               bindir, SLASH, EXE_SUFFIX, args,
sl@0
   260
                               charmap, src, locale_path);
sl@0
   261
sl@0
   262
    // return the unqualified locale file name on success or 0 on failure
sl@0
   263
    return ret ? (char*)0 : strrchr (locale_path, _RWSTD_PATH_SEP) + 1;
sl@0
   264
}
sl@0
   265
sl@0
   266
/**************************************************************************/
sl@0
   267
sl@0
   268
extern "C" {
sl@0
   269
sl@0
   270
static char rw_locale_root [256];
sl@0
   271
sl@0
   272
static void atexit_rm_locale_root ()
sl@0
   273
{
sl@0
   274
    // remove temporary locale databases created by the test
sl@0
   275
    rw_system (SHELL_RM_RF "%s", rw_locale_root);
sl@0
   276
}
sl@0
   277
sl@0
   278
}
sl@0
   279
sl@0
   280
_TEST_EXPORT const char*
sl@0
   281
rw_set_locale_root ()
sl@0
   282
{
sl@0
   283
    // set any additional environment variables defined in
sl@0
   284
    // the RW_PUTENV environment variable (if it exists)
sl@0
   285
    rw_putenv (0);
sl@0
   286
sl@0
   287
    // create a temporary directory for files created by the test
sl@0
   288
    const char* const locale_root = rw_tmpnam (rw_locale_root);
sl@0
   289
    if (!locale_root)
sl@0
   290
        return 0;
sl@0
   291
sl@0
   292
    char envvar [sizeof LOCALE_ROOT_ENVAR + sizeof rw_locale_root] =
sl@0
   293
        LOCALE_ROOT_ENVAR "=";
sl@0
   294
#ifndef __SYMBIAN32__
sl@0
   295
    std::strcat (envvar, locale_root);
sl@0
   296
#else
sl@0
   297
    strcat (envvar, locale_root);
sl@0
   298
#endif
sl@0
   299
    // remove temporary file if mkstemp() rw_tmpnam() called mkstemp()
sl@0
   300
    if (rw_system (SHELL_RM_RF " %s", locale_root)) {
sl@0
   301
sl@0
   302
#if defined (_WIN32) || defined (_WIN64)
sl@0
   303
        // ignore errors on WIN32 where the stupid DEL command
sl@0
   304
        // fails even with /Q /S when the files don't exist
sl@0
   305
#else
sl@0
   306
        // assume a sane implementation of SHELL_RM_RF
sl@0
   307
        return 0;
sl@0
   308
#endif   // _WIN{32,64}
sl@0
   309
    }
sl@0
   310
sl@0
   311
    if (rw_system ("mkdir %s", locale_root))
sl@0
   312
        return 0;
sl@0
   313
sl@0
   314
    // set the "RWSTD_LOCALE_ROOT" environment variable
sl@0
   315
    // where std::locale looks for locale database files
sl@0
   316
    rw_putenv (envvar);
sl@0
   317
sl@0
   318
    if (atexit (atexit_rm_locale_root))
sl@0
   319
        perror ("atexit(atexit_rm_locale_root) failed");
sl@0
   320
sl@0
   321
    return locale_root;
sl@0
   322
}
sl@0
   323
sl@0
   324
/**************************************************************************/
sl@0
   325
sl@0
   326
_TEST_EXPORT char*
sl@0
   327
rw_locales (int loc_cat, const char* grep_exp)
sl@0
   328
{
sl@0
   329
    static char* slocname = 0;
sl@0
   330
sl@0
   331
    static int size       = 0;         // the number of elements in the array
sl@0
   332
    static int total_size = 5120;      // the size of the array
sl@0
   333
    static int last_cat   = loc_cat;   // last category
sl@0
   334
sl@0
   335
    // allocate first time through
sl@0
   336
    if (!slocname) {
sl@0
   337
sl@0
   338
#ifndef _MSC_VER
sl@0
   339
        slocname = _RWSTD_STATIC_CAST (char*, malloc (5120));
sl@0
   340
#else
sl@0
   341
        // prevent this leaked allocation from causing failures
sl@0
   342
        // in tests that keep track of storage allocated in
sl@0
   343
        //  _NORMAL_BLOCKS
sl@0
   344
        slocname = _RWSTD_STATIC_CAST (char*,
sl@0
   345
                       _malloc_dbg (5120, _CLIENT_BLOCK, 0, 0));
sl@0
   346
#endif
sl@0
   347
        *slocname = '\0';
sl@0
   348
    }
sl@0
   349
sl@0
   350
    // return immediately if buffer is already initialized
sl@0
   351
    if (*slocname && loc_cat == last_cat)
sl@0
   352
        return slocname;
sl@0
   353
sl@0
   354
    // remmeber the category we were last called with
sl@0
   355
    last_cat = loc_cat;
sl@0
   356
sl@0
   357
    char* locname = slocname;
sl@0
   358
sl@0
   359
    char* save_localename = 0;
sl@0
   360
    char  namebuf [256];
sl@0
   361
sl@0
   362
    if (loc_cat != _UNUSED_CAT) {
sl@0
   363
        // copy the locale name, the original may be overwitten by libc
sl@0
   364
        save_localename = strcpy (namebuf, setlocale (loc_cat, 0));
sl@0
   365
    }
sl@0
   366
sl@0
   367
    const char* const fname = rw_tmpnam (0);
sl@0
   368
sl@0
   369
    if (!fname) {
sl@0
   370
        return 0;   // error
sl@0
   371
    }
sl@0
   372
sl@0
   373
    // make sure that grep_exp is <= 80 
sl@0
   374
    if (grep_exp && 80 < strlen (grep_exp)) {
sl@0
   375
        abort ();
sl@0
   376
    }
sl@0
   377
sl@0
   378
    // execute a shell command and redirect its output into the file
sl@0
   379
    const int exit_status =
sl@0
   380
          grep_exp && *grep_exp
sl@0
   381
        ? rw_system ("locale -a | grep \"%s\" > %s", grep_exp, fname)
sl@0
   382
        : rw_system ("locale -a > %s", fname);
sl@0
   383
sl@0
   384
    if (exit_status) {
sl@0
   385
        return 0;   // error
sl@0
   386
    }
sl@0
   387
sl@0
   388
    // open file containing the list of installed locales
sl@0
   389
    FILE *file = fopen (fname, "r");
sl@0
   390
sl@0
   391
    if (file) {
sl@0
   392
sl@0
   393
        char linebuf [256];
sl@0
   394
sl@0
   395
        // even simple locale names can be very long (e.g., on HP-UX,
sl@0
   396
        // where a locale name always consists of the names of all
sl@0
   397
        // categories, such as "C C C C C C")
sl@0
   398
        char last_name [256];
sl@0
   399
        *last_name = '\0';
sl@0
   400
sl@0
   401
        // if successful, construct a char array with the locales
sl@0
   402
        while (fgets (linebuf, sizeof linebuf, file)) {
sl@0
   403
sl@0
   404
            linebuf [strlen (linebuf) - 1] = '\0';
sl@0
   405
sl@0
   406
#ifdef _RWSTD_OS_SUNOS
sl@0
   407
sl@0
   408
            // avoid the bad locale named iso_8859_1 on SunOS
sl@0
   409
            if (!strcmp ("iso_8859_1", linebuf))
sl@0
   410
                continue;
sl@0
   411
sl@0
   412
#endif   // _RWSTD_OS_SUNOS
sl@0
   413
sl@0
   414
            // if our buffer is full then dynamically allocate a new one
sl@0
   415
            if ((size += (strlen (linebuf) + 1)) > total_size) {
sl@0
   416
                total_size += 5120;
sl@0
   417
sl@0
   418
                char* tmp =
sl@0
   419
                    _RWSTD_STATIC_CAST (char*, malloc (total_size));
sl@0
   420
sl@0
   421
                memcpy (tmp, slocname, total_size - 5120);
sl@0
   422
                free (slocname);
sl@0
   423
sl@0
   424
                slocname = tmp;
sl@0
   425
                locname  = slocname + size - strlen (linebuf) - 1;
sl@0
   426
            }
sl@0
   427
sl@0
   428
#ifdef _WIN64
sl@0
   429
sl@0
   430
            // prevent a hang (OS/libc bug?)
sl@0
   431
            strcpy (locname, linebuf);
sl@0
   432
            locname += strlen (linebuf) + 1;
sl@0
   433
sl@0
   434
#else   // if !defined (_WIN64)
sl@0
   435
            if (loc_cat != _UNUSED_CAT) {
sl@0
   436
sl@0
   437
                // set the C locale to verify that the name is valid
sl@0
   438
                const char *name = setlocale (loc_cat, linebuf);
sl@0
   439
sl@0
   440
                // if it is and if the actual locale name different
sl@0
   441
                // from the last one, append it to the list
sl@0
   442
                if (name && strcmp (last_name, name)) {
sl@0
   443
                    strcpy (locname, linebuf);
sl@0
   444
                    locname += strlen (linebuf) + 1;
sl@0
   445
sl@0
   446
                    // save the last locale name
sl@0
   447
                    assert (strlen (name) < sizeof last_name);
sl@0
   448
                    strcpy (last_name, name);
sl@0
   449
                }
sl@0
   450
            }
sl@0
   451
            else {
sl@0
   452
                strcpy (locname, linebuf);
sl@0
   453
                locname += strlen (linebuf) + 1;
sl@0
   454
            }
sl@0
   455
sl@0
   456
#endif   // _WIN64
sl@0
   457
sl@0
   458
        }
sl@0
   459
        *locname = '\0';
sl@0
   460
    }
sl@0
   461
sl@0
   462
    if (loc_cat != _UNUSED_CAT)
sl@0
   463
        setlocale (loc_cat, save_localename);
sl@0
   464
sl@0
   465
    // close before removing
sl@0
   466
    fclose (file);
sl@0
   467
sl@0
   468
    remove (fname);
sl@0
   469
sl@0
   470
    return slocname;
sl@0
   471
}