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