/***************************************************************************
 *
 * 22.locale.messages.cpp - tests exercising the std::messages facet
 *
 * $Id: 22.locale.messages.cpp 648752 2008-04-16 17:01:56Z faridz $
 *
 ***************************************************************************
 *
 * Licensed to the Apache Software  Foundation (ASF) under one or more
 * contributor  license agreements.  See  the NOTICE  file distributed
 * with  this  work  for  additional information  regarding  copyright
 * ownership.   The ASF  licenses this  file to  you under  the Apache
 * License, Version  2.0 (the  "License"); you may  not use  this file
 * except in  compliance with the License.   You may obtain  a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the  License is distributed on an  "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
 * implied.   See  the License  for  the  specific language  governing
 * permissions and limitations under the License.
 *
 * Copyright 2001-2006 Rogue Wave Software.
 *
 **************************************************************************/

#include <locale>

#include <driver.h>      // for rw_test()
#include <environ.h>     // for rw_putenv()
#include <file.h>        // for rw_nextfd()
#include <rw_locale.h>   // for rw_locales(), rw_create_catalog()
#include <rw_process.h>  // for rw_system()

#include <cstring>   // for strlen()
#include <cstdlib>   // for getenv()
#include <cstdio>    // for remove()
#include <clocale>   // for LC_ALL

#include <cwchar>    // for mbsinit()

#ifndef _RWSTD_NO_NEW_HEADER
#  if defined (_MSC_VER)
#    include <io.h>          // for _open()
#    include <direct.h>      // for getcwd()
#  else
#    include <sys/types.h>
#    include <sys/stat.h>
#    include <unistd.h>      // for getcwd()
#  endif
#  include <fcntl.h>         // for mode flags for _open
#endif   // _RWSTD_NO_NEW_HEADER

#undef open
#undef close

#if defined (_MSC_VER)
#  define open(f,m) _open  (f, _##m)
#  define close(f)  _close (f)
#else
#  define open(f,m) open  (f, m)
#  define close(f)  close (f)
#endif // defined (_MSC_VER)

/***************************************************************************/

template <class charT>
struct CodeCvt: std::codecvt<charT, char, std::mbstate_t>
{
    typedef std::codecvt<charT, char, std::mbstate_t> Base;
    typedef typename Base::extern_type                extern_type;
    typedef typename Base::intern_type                intern_type;
    typedef typename Base::state_type                 state_type;
    typedef typename Base::result                     result;

    static bool used_;
    static bool partial_;
    static bool noconv_;
    static bool check_state_;

    static bool valid_state_;

    CodeCvt (std::size_t ref = 1U)
        : Base (ref) {
        used_ = partial_ = noconv_ = check_state_ = valid_state_ = false;
    }

protected:

    // override base class virtual function to make the messages
    // facet use codecvt<char, char>::in() (the base returns true)
    bool do_always_noconv () const _THROWS (()) {
        return false;
    }

    result
    do_in (state_type         &state,
           const extern_type  *from,
           const extern_type  *from_end,
           const extern_type *&from_next,
           intern_type        *to,
           intern_type        *to_end,
           intern_type       *&to_next) const {

        used_ = true;

#ifndef _RWSTD_NO_MBSINIT

        if (check_state_)
            valid_state_ = std::mbsinit (&state) != 0;

#else   // if (_RWSTD_NO_MBSINIT)

        if (check_state_)
            valid_state_ = true;

#endif   // _RWSTD_NO_MBSINIT

        const result res =
            Base::do_in (state, from, from_end, from_next,
                         to, to_end, to_next);

        if (partial_)
            return std::codecvt_base::partial;

        if (noconv_)
            return std::codecvt_base::noconv;

        return res;
    }
};

template <class charT>
bool CodeCvt<charT>::used_;
template <class charT>
bool CodeCvt<charT>::partial_;
template <class charT>
bool CodeCvt<charT>::noconv_;
template <class charT>
bool CodeCvt<charT>::check_state_;
template <class charT>
bool CodeCvt<charT>::valid_state_;

/***************************************************************************/

// finds the first named locale other than "C" or "POSIX"; returns
// a pointer to the name of the locale on success, 0 on failure
const char*
find_named_locale ()
{
    const char *name = rw_locales (LC_ALL, "");

    if (!name)
        return 0;

    char namebuf [256];

    // get the full name of the "C" locale for comparison with aliases
    const char* const classic_name =
        std::strcpy (namebuf, std::setlocale (LC_ALL, "C"));

    do {
        if (std::strcmp (name, "C") && std::strcmp (name, "POSIX")) {

            // skip over any aliases of the "C" and "POSIX" locales
            const char* const fullname = std::setlocale (LC_ALL, name);
            if (std::strcmp (fullname, classic_name)) {

                // skip over the C and POSIX locales
                _TRY {
                    const std::locale loc (name);
                    _RWSTD_UNUSED (loc);

                    std::setlocale (LC_ALL, "C");
                    return name;
                }
                _CATCH (...) { }
            }
        }
        name += std::strlen (name) + 1;

    } while (*name);

    std::setlocale (LC_ALL, "C");

    return 0;
}

/***************************************************************************/

#ifndef _WIN32
#  define CAT_NAME "./rwstdmessages.cat"
#  define MSG_NAME "rwstdmessages.msg"
#else
#  define CAT_NAME "rwstdmessages.dll"
#  define MSG_NAME "rwstdmessages.rc"
#endif

#define NLS_CAT_NAME "rwstdmessages"

#define MAX_SETS 5
#define MAX_MESSAGES  5


int msg_id (int set, int id)
{
#ifdef _WIN32

    return (set - 1) * 5 + id;

#else

    _RWSTD_UNUSED (set);
    return id;

#endif
}

/***************************************************************************/

static const char* const
messages [MAX_SETS][MAX_MESSAGES] = {
    { "First set, first message",
      "First set, second message",
      "First set, third message",
      "First set, fourth message",
      "First set, fifth message"
    },
    { "Second set, first message",
      "Second set, second message",
      "Second set, third message",
      "Second set, fourth message",
      "Second set, fifth message"
    },
    { "Third set, first message",
      "Third set, second message",
      "Third set, third message",
      "Third set, fourth message",
      "Third set, fifth message"
    },
    { "Fourth set, first message",
      "Fourth set, second message",
      "Fourth set, third message",
      "Fourth set, fourth message",
      "Fourth set, fifth message"
    },
    { "Fifth set, first message",
      "Fifth set, second message",
      "Fifth set, third message",
      "Fifth set, fourth message",
      "Fifth set, fifth message"
    }
};

static std::string catalog;

/***************************************************************************/


template <class charT>
std::basic_string<charT> widen (std::string message)
{
    std::basic_string<charT> result;
    for (std::size_t i = 0; i < message.length(); i++) {
        result.push_back ((charT)message[i]);
    }

    return result;
}

/***************************************************************************/

// Test that the message facet exists in the locale and that
// we can get a reference to it.
template <class charT>
void test_has_facet (const char *loc_name, const char *cname)
{
    // construct a copy of the named locale or default
    // when no name is specified
    const std::locale loc =
        loc_name ? std::locale (loc_name) : std::locale ();

    typedef std::messages<charT> Messages;

    // verify that the facet exists in the locale
    bool facet_exists = std::has_facet<Messages>(loc);

    rw_assert (facet_exists, 0, __LINE__,
               "has_facet<messages<%s> >(locale(%{?}%#s%{;})) == true",
               cname, 0 != loc_name, loc_name);

    try {
        // verify that use facet doesn't throw an exception
        std::use_facet<Messages>(loc);
    }
#ifndef _RWSTD_NO_EXCEPTIONS

    catch (std::exception &ex) {
        rw_assert (0, 0, __LINE__,
                   "use_fact<messages<%s> >(locale(%{?}%#s%{;})) "
                   "unexpectedly threw exception(%#s)",
                   cname, 0 != loc_name, loc_name, ex.what ());
    }
    catch (...) {
        rw_assert (0, 0, __LINE__,
                   "use_fact<messages<%s> >(locale(%{?}%#s%{;})) "
                   "unexpectedly threw an unknown exception",
                   cname, 0 != loc_name, loc_name);
    }

    typedef std::messages_byname<charT> MessagesByname;

    const bool byname = loc_name
        && std::strcmp (loc_name, "C") && std::strcmp (loc_name, "POSIX");
 
    facet_exists = std::has_facet<MessagesByname>(loc);

    rw_assert (byname == facet_exists, 0, __LINE__,
               "has_fact<messages_byname<%s> >(locale(%{?}%#s%{;})) == %b",
               cname, 0 != loc_name, loc_name);

    try {
        // verify that use facet throws an exception only
        // for the default and "C" locales
        std::use_facet<MessagesByname>(loc);

        rw_assert (byname, 0, __LINE__,
                   "use_fact<messages_byname<%s> >(locale(%{?}%#s%{;})) "
                   "failed to throw",
                   cname, 0 != loc_name, loc_name);
    }
    catch (std::exception &ex) {
        rw_assert (!byname, 0, __LINE__,
                   "use_fact<messages_byname<%s> >(locale(%{?}%#s%{;})) "
                   "unexpectedly threw exception(%#s)",
                   cname, 0 != loc_name, loc_name, ex.what ());
    }
    catch (...) {
        rw_assert (0, 0, __LINE__,
                   "use_fact<messages<%s> >(locale(%{?}%#s%{;})) "
                   "unexpectedly threw an unknown exception",
                   cname, 0 != loc_name, loc_name);
    }

#endif   // _RWSTD_NO_EXCEPTIONS

}

/***************************************************************************/

template <class charT>
std::messages_base::catalog
open_catalog (const std::messages<charT> &msgs,
              const char *cat_name, const std::locale &loc,
              int expect, const char *cname, int line)
{
    std::messages_base::catalog cat = -1;

    // expect is set to:
    //   *   0 (or greater) when the caller expects the call to open()
    //         to succeed 
    //   *  -1 when the caller expects the call to open() to fail
    //         by returning -1
    //   *  -2 (or less) when the caller expects the call to open()
    //         to exit by throwing an exception
   const bool expect_success   = expect >= 0;
   const bool expect_failure   = expect == -1;
   const bool expect_exception = expect <  -1;

    const char* const nlspath = std::getenv ("NLSPATH");

    try {
        // an already closed cat should throw an exception
        cat = (msgs.open)(cat_name, loc);

        const bool success =
            expect_success && -1 < cat || expect_failure && cat < 0;

        rw_assert (success, 0, line,
                   "messages<%s>::open(%#s, locale(%#s))"
                   "%{?} > -1%{:}%{?} == -1 %{;}%{;}, got %d"
                   "%{?}; failed to throw an exception%{;}; NLSPATH=%s",
                   cname, cat_name, loc.name ().c_str (),
                   expect_success, expect_failure, cat,
                   expect_exception, nlspath);
    }

#ifndef _RWSTD_NO_EXCEPTIONS

    catch (std::exception &ex) {
        rw_assert (expect_exception, 0, line,
                   "messages<%s>::open(%#s, locale(%#s)) unexpectedly "
                   "threw exception(%#s); NLSPATH=%s",
                   cname, cat_name, loc.name ().c_str (), ex.what (), nlspath);
    }
    catch (...) {
        rw_assert (expect_exception, 0, line,
                   "messages<%s>::open(%#s, locale(%#s)) unexpectedly "
                   "threw an unknown exception; NLSPATH=%s",
                   cname, cat_name, loc.name ().c_str (), nlspath);
    }

#endif   // _RWSTD_NO_EXCEPTIONS

    return cat;
}

/***************************************************************************/

template <class charT>
void
close_catalog (const std::messages<charT> &msgs,
               std::messages_base::catalog cat,
               bool expect_exception,
               const char *cname, int line)
{
    try {
        // an already closed cat should throw an exception
        (msgs.close)(cat);

        rw_assert (!expect_exception, 0, line,
                   "messages<%s>::close(%d) failed "
                   "to throw an expected exception",
                   cname, cat);
    }

#ifndef _RWSTD_NO_EXCEPTIONS

    catch (std::exception &ex) {
        rw_assert (expect_exception, 0, line,
                   "messages<%s>::close(%d) unexpectedly "
                   "threw exception(%#s)",
                   cname, cat, ex.what ());
    }
    catch (...) {
        rw_assert (expect_exception, 0, line,
                   "messages<%s>::close(%d) unexpectedly "
                   "threw an unknown exception",
                   cname, cat);
    }

#endif   // _RWSTD_NO_EXCEPTIONS

}

/***************************************************************************/

template <class charT>
void test_open_close (const char *loc_name, const char *cname)
{
    int fdcount [2];
    int next_fd [2];

#ifndef _WIN32
    next_fd [0] = rw_nextfd (fdcount + 0);
#else
    // don't test file descriptor leaking on Win32 to avoid
    // invalid parameter error
    // catalog functions not uses file descriptors
    next_fd [0] = fdcount [0] = 0;
#endif

    rw_info (0, 0, __LINE__,
             "std::messages<%s>::open() and close() in locale(#%s)",
             cname, loc_name);

    // construct a copy of the named locale or default
    // when no name is specified
    const std::locale loc =
        loc_name ? std::locale (loc_name) : std::locale ();

    const std::messages<charT>& msgs =
        std::use_facet<std::messages<charT> >(loc);

    const std::messages_base::catalog cat =
        open_catalog (msgs, CAT_NAME, loc, 0, cname, __LINE__);

    // close a (presumably successfully) opened catalog
    close_catalog (msgs, cat, cat < 0, cname, __LINE__);

    // an already closed cat should throw an exception
    close_catalog (msgs, cat, true, cname, __LINE__);

    // verify that no file descriptor has leaked
#ifndef _WIN32
    next_fd [1] = rw_nextfd (fdcount + 1);
#else
    next_fd [1] = fdcount [1] = 0;
#endif

    rw_assert (next_fd [1] == next_fd [0] && fdcount [0] == fdcount [1],
               0, __LINE__,
               "std::messages<%s>::close() leaked %d file descriptor(s) "
               "(or descriptor mismatch)",
               cname, fdcount [1] - fdcount [0]);
}

/***************************************************************************/

template <class charT>
void test_get (const char *loc_name,
               const char* const text[5][5],
               const char *cname)
{
    // construct a copy of the named locale or default
    // when no name is specified
    const std::locale loc =
        loc_name ? std::locale (loc_name) : std::locale ();

    const std::messages<charT>& msgs =
        std::use_facet<std::messages<charT> > (loc);

    const charT def[] = {
        'N', 'o', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', '.', '\0'
    };

    std::messages_base::catalog cat = -1;

    cat = open_catalog (msgs, CAT_NAME, loc, 0, cname, __LINE__);

    if (cat < 0)
        return;

    typedef std::char_traits<charT>                     Traits;
    typedef std::allocator<charT>                       Allocator;
    typedef std::basic_string<charT, Traits, Allocator> String;

    for (int setId = 1; setId <= MAX_SETS; ++setId) {

        for (int msgId = 1; msgId <= MAX_MESSAGES; ++msgId) {

            const int id = msg_id (setId, msgId);
            const String got = msgs.get (cat, setId, id, def);

            rw_assert (got == widen<charT>(text [setId - 1][msgId - 1]),
                       0, __LINE__,
                       "messages<%s>::get(%d, %d, %d, %{*Ac}) == %#s, "
                       "got %{#*S}",
                       cname, cat, setId, id,
                       int (sizeof *def), def,
                       text [setId - 1][msgId - 1],
                       int (sizeof (charT)), &got);
        }
    }

    // bad catalog id
    const std::messages_base::catalog bad_cat = 777;

    try {
        // get() will either throw or return `def'
        // when passed a bad catalog id
        const String got = msgs.get (bad_cat, 1, 1, def);

        rw_assert (def == got, 0, __LINE__,
                   "messages<%s>::get(%d, 1, 1, %{*Ac}) == %{*Ac}, got %{#*S}",
                   cname, bad_cat, int (sizeof *def), def,
                   int (sizeof *def), def, int (sizeof (charT)), &got);
    }
#ifndef _RWSTD_NO_EXCEPTIONS

    catch (std::exception &ex) {
        rw_assert (true, 0, __LINE__,
                   "messages<%s>::get(%d, 1, 1, %{*Ac}) unexpectedly threw "
                   "exception(%#s)", cname, bad_cat, int (sizeof *def), def,
                   ex.what ());
    }

#endif   // _RWSTD_NO_EXCEPTIONS

    // Bad set id
#if !defined (_WIN32) && !defined (_WIN64)
    // When we use resource files for the message catalogs
    // the set ids are ignored.
    rw_assert (msgs.get (cat, 777, 1, def) == def, 0, __LINE__,
               "messages<%s>::get(%d, 777, 1, %{#*Ac}) == %{#*Ac}",
               cname, cat, int (sizeof *def), def, int (sizeof *def), def);
#endif   // !defined (_WIN32) && !defined (_WIN64)

    // Bad message id
    rw_assert (msgs.get (cat, 1, 777, def) == def, 0, __LINE__,
               "messages<%s>::get(%d, 777, 1) == \"\"", cname);

    close_catalog (msgs, cat, false, cname, __LINE__);
}

/***************************************************************************/

template <class charT>
void test_use_codecvt (const char *cname)
{
    CodeCvt<charT> cvt (1);

    const std::locale loc (std::locale::classic (), &cvt);

    const charT def[] = {
        'N', 'o', ' ', 'm', 'e', 's', 's', 'a', 'g', 'e', '.', '\0'
    };

    const std::messages<charT>& msgs =
        std::use_facet <std::messages<charT> >(loc);

    cvt.used_ = false;

    std::messages_base::catalog cat = -1;

    cat = open_catalog (msgs, CAT_NAME, loc, 0, cname, __LINE__);

    if (cat < 0)
        return;

    cvt.check_state_ = true;

    const int msgid = msg_id (1, 1);
    std::basic_string<charT> got = msgs.get (cat, 1, msgid, def);
    rw_assert (cvt.used_, 0, __LINE__,
               "messages<%s>::get(%d, 1, %d, const char_type*) "
               "uses codecvt<%1$s, char>", cname, cat, msgid);

    rw_assert (cvt.valid_state_, 0, __LINE__,
               "messages<%s>::get(%d, 1, %d, const char_type*) "
               "initializes mbstate_t argument", cname, cat, msgid);

    cvt.check_state_ = false;
    cvt.partial_     = true;

    got = msgs.get (cat, 1, msgid, def);
    rw_assert (got == def, 0, __LINE__,
               "messages<%s>::get(%d, 1, %d, %{*Ac}) == %{*Ac}",
               cname, cat, msgid, int (sizeof *def), def,
               int (sizeof *def), def);

    cvt.partial_ = false;
    cvt.noconv_  = true;

    got = msgs.get (cat, 1, msgid, def);
    rw_assert (got == widen<charT>(std::string(messages[0][0])), 0, __LINE__,
               "messages<%s>::get(%d, 1, %d, %{*Ac}) == %#s, got %{#*S}",
               cname, cat, msgid, int (sizeof *def), def,
               messages [0][0], int (sizeof (charT)), &got);

    cvt.noconv_ = false;

    close_catalog (msgs, cat, false, cname, __LINE__);

    cvt.used_ = false;
}

/***************************************************************************/


template <class charT>
void test_use_nls_path (const char *cname)
{
    // get working directory
    char cwd [2048];
    cwd [0] = '\0';
    if (!rw_error (0 != getcwd (cwd, 2048), 0, __LINE__,
                   "getcwd(%#p, %u) failed: %{#m} (%m)", cwd, 2048))
        return;

    char* const nlspath = new char [std::strlen (cwd) + 512];

    // create NLSPATH string
    std::sprintf (nlspath, "NLSPATH=%s/%%N.cat", cwd);
    rw_putenv (nlspath);

    const std::locale loc;

    const std::messages<charT>& msgs =
        std::use_facet <std::messages<charT> >(loc);

    const std::messages_base::catalog cat =
        open_catalog (msgs, NLS_CAT_NAME, loc, 0, "char", __LINE__);

    if (-1 < cat)
        close_catalog (msgs, cat, false, cname, __LINE__);

    delete[] nlspath;
}

/***************************************************************************/


template <class charT>
void stress_test (const char *cname)
{
    // NLSPATH must be defined
    RW_ASSERT (0 != std::getenv ("NLSPATH"));

    char catalog_names [24][24];
    const std::size_t NCATS = sizeof catalog_names / sizeof *catalog_names;

    std::messages_base::catalog cats [NCATS];

    // detect descriptor leaks
    const int fd1 = open (__FILE__, O_RDONLY);

    const std::locale loc = std::locale::classic ();

    const std::messages<charT>& msgs =
        std::use_facet<std::messages<charT> > (loc);

    std::size_t i;

    for (i = 0; i < NCATS; i++) {

        char msg_name [NCATS];

#ifndef _WIN32
        std::sprintf (msg_name, "rwstdmessages_%d.msg", int (i));
#else
        std::sprintf (msg_name, "rwstdmessages_%d.rc", int (i));
#endif

        rw_create_catalog (msg_name, catalog.c_str ());

        const char* const dot = std::strrchr (msg_name, '.');
        std::strncpy (catalog_names[i], msg_name, dot - msg_name);
        *(catalog_names[i] + (dot - msg_name)) = '\0';

        // open each catalog (expect success)
        cats [i] = open_catalog (msgs, catalog_names [i],
                                 loc, 0, cname, __LINE__);
    }

    // close smallest first and check for descriptor leaks
    for (i = 0; i < NCATS; ++i) {
        if (-1 != cats [i])
            close_catalog (msgs, cats [i], false, cname, __LINE__);
    }

    int fd2 = open (__FILE__, O_RDONLY);
    rw_assert (fd2 - fd1 == 1, 0, __LINE__,
               "messages<%s>::close() leaked %d file descriptors",
               cname, fd2 - fd1 - 1);

    // open again, close largest first and check for descriptor leaks
    for (i = 0; i < NCATS; ++i) {
        cats [i] = open_catalog (msgs, catalog_names [i],
                                 loc, 0, cname, __LINE__);
    }

    for (i = NCATS; i-- > 0; ) {
        if (-1 != cats [i])
            close_catalog (msgs, cats [i], false, cname, __LINE__);
    }

    // close again fd2
    close (fd2);

    fd2 = open (__FILE__, O_RDONLY);
    rw_assert (fd2 - fd1 == 1, 0, __LINE__,
               "messages<%s>::close() leaked %d file descriptors",
               cname, fd2 - fd1 - 1);

    close (fd1);
    close (fd2);

    rw_system (SHELL_RM_F "rwstdmessages_*");
}

/**************************************************************************/

int opt_has_facet;
int opt_open_close;
int opt_get;
int opt_codecvt;
int opt_nlspath;
int opt_stress_test;


template <class charT>
void test_messages (charT, const char *cname, const char *locname)
{
    if (rw_note (0 <= opt_has_facet, 0, __LINE__,
                 "has_facet<messages<%s> > tests disabled", cname)) {

        // exercise has_facet and use_facet in the default locale
        test_has_facet<charT>(0, cname);

        // exercise has_facet and use_facet in locale("C")
        test_has_facet<charT>("C", cname);

        // exercise has_facet and use_facet in a named locale
        test_has_facet<charT>(locname, cname);
    }

    if (rw_note (0 <= opt_open_close, 0, __LINE__,
                 "messages<%s>::open() and close() tests disabled", cname)) {
        test_open_close<charT>("C", cname);
        test_open_close<charT>(locname, cname);
    }

    if (rw_note (0 <= opt_has_facet, 0, __LINE__,
                 "messages<%s>::get() tests disabled", cname)) {
        test_get<charT>("C", messages, cname);
        test_get<charT>(locname, messages, cname);
    }

    if (rw_note (0 <= opt_has_facet, 0, __LINE__,
                 "messages<%s> codecvt tests disabled", cname))
        test_use_codecvt<charT>(cname);

    if (rw_note (0 <= opt_nlspath, 0, __LINE__,
                 "messages<%s> NLSPATH tests disabled", cname))
        test_use_nls_path<charT>(cname);

    if (rw_note (0 <= opt_has_facet, 0, __LINE__,
                 "messages<%s> codecvt tests disabled", cname))
        stress_test<charT>(cname);
}

/**************************************************************************/

static int
run_test (int, char*[])
{

#ifdef _RWSTD_OS_AIX

    // must do this so that NLSPATH lookup works correctly for both
    // the C and POSIX locales.
    const int p = rw_putenv ("LC__FASTMSG=false");
    rw_note (!p, 0, __LINE__, "failed to set LC__FASTMSG");
    
#endif    // _RWSTD_OS_AIX

#ifdef _RWSTD_NO_DYNAMIC_CAST

    // if dynamic_cast isn't supported then has_facet() can't
    // reliably detect if a facet is installed or not.
    rw_warn (0 != opt_has_facet, 0, __LINE__,
             "dynamic_cast not supported, disabling has_facet tests");

    opt_has_facet = -1;

#endif    // _RWSTD_NO_DYNAMIC_CAST


    for (int i = 0; i < MAX_SETS; ++i) {
        for (int j = 0; j < MAX_MESSAGES; ++j)
            catalog.append (messages [i][j], std::strlen (messages [i][j]) + 1);

        catalog.append (1, '\0');
    }

    const char* const locname = find_named_locale ();

    rw_create_catalog (MSG_NAME, catalog.c_str ());

    test_messages (char (), "char", locname);

#ifndef _RWSTD_NO_WCHAR_T

    test_messages (wchar_t (), "wchar_t", locname);

#endif   // _RWSTD_NO_WCHAR_T

    std::remove (CAT_NAME);

    return 0;
}


/**************************************************************************/

int main (int argc, char *argv[])
{
    return rw_test (argc, argv, __FILE__,
                    "lib.category.messages",
                    0 /* no comment */,
                    run_test,
                    "|-has_facet~ "
                    "|-open_close~ "
                    "|-get~ "
                    "|-codecvt~ "
                    "|-nlspath~ "
                    "|-stress-test~ ",
                    &opt_has_facet,
                    &opt_open_close,
                    &opt_get,
                    &opt_codecvt,
                    &opt_nlspath,
                    &opt_stress_test,
                    (void*)0   /* sentinel */);
}
