tripwire-open-source/src/core/twlocale.cpp

323 lines
9.8 KiB
C++

//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000-2018 Tripwire,
// Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights
// reserved.
//
// This program is free software. The contents of this file are subject
// to the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version. You may redistribute it and/or modify it
// only in compliance with the GNU General Public License.
//
// This program is distributed in the hope that it will be useful.
// However, this program is distributed AS-IS WITHOUT ANY
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
// FOR A PARTICULAR PURPOSE. Please see the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// Nothing in the GNU General Public License or any other license to use
// the code or files shall permit you to use Tripwire's trademarks,
// service marks, or other intellectual property without Tripwire's
// prior written consent.
//
// If you have any questions, please contact Tripwire, Inc. at either
// info@tripwire.org or www.tripwire.org.
//
///////////////////////////////////////////////////////////////////////////////
// twlocale.cpp
//
//=========================================================================
// INCLUDES
//=========================================================================
#include "stdcore.h"
#include "twlocale.h"
#include "corestrings.h"
//TODO:mdb -- for some reason, this isn't being included on gcc/stlport
// How is this being included for other platforms (I can't find
// references to locale.h anywhere in the code!)
//
#if HAVE_GCC
#include <locale.h>
#endif //HAVE_GCC
//=========================================================================
// STANDARD LIBRARY INCLUDES
//=========================================================================
//=========================================================================
// UTIL FUNCTION PROTOTYPES
//=========================================================================
static TSTRING& util_FormatTimeC(struct tm* ptm, TSTRING& strBuf);
static TSTRING& util_FormatTime(struct tm* ptm, TSTRING& strBuf);
#if !USES_CLIB_DATE_FUNCTION
static TSTRING& util_FormatTimeCPlusPlus(struct tm* ptm, TSTRING& strBuf);
#endif
//=========================================================================
// PUBLIC METHOD CODE
//=========================================================================
#if IS_AROS
# define tzset()
#endif
void cTWLocale::InitGlobalLocale()
{
cDebug d("cTWLocale::InitGlobalLocale");
d.TraceDetail("Attempting to set the program locale from the"
"default \"C\" locale to the system-default locale.");
#if USE_CLIB_LOCALE
char* pchLocale = setlocale(LC_ALL, "");
d.TraceDetail("C++ locale is incomplete or unavailable with this compiler, so"
"only changing the C-language locale. Some C++ locale-specific functionality"
"may not function properly.");
if (pchLocale)
{
d.TraceDebug("locale changed to the system-default locale (non-C++): <%s>\n", pchLocale);
}
else
{
d.TraceDebug("Error: unable to change locale to the system-default.\n"
"It is possible that there is no other locale than\n"
"the \"C\" locale on this platform.\n");
}
#else
std::locale l("");
std::locale::global(l);
d.TraceDebug("locale changed to the system default std::locale (C++): <%s>\n", l.name().c_str());
#endif
}
/*
TSTRING cTWLocale::FormatNumberAsHex( int32 i )
{
//
// preconditions
//
ASSERT( sizeof( long ) >= sizeof( int32 ) ); // must be able to cast to 'long'
//
// convert long to a string
//
TOSTRINGSTREAM sstr;
sstr.imbue( std::locale::classic() );
sstr.setf( std::ios_base::hex, std::ios_base::basefield );
const std::num_put< TCHAR > *pnp = 0, &np = tss::GetFacet( sstr.getloc(), pnp );
np.put( sstr, sstr, sstr.fill(), (long)i );
//
// return it
//
return( sstr.str() );
}
*/
template<class numT, class CharT> class cFormatNumberUtil
{
public:
// TODO:BAM -- these functions should really maybe take a stringstream that has been
// already set up for formatting (basefield, locale, etc.) that way we can merge
//. the FormatNumberAsHex function as well
//
//=============================================================================
// template< class numT, class CharT >
// numT
// cFormatNumberUtil::FormatNumber( const std::basic_string< CharT >& s, bool fCStyleFormatting = false )
//-----------------------------------------------------------------------------
// EFFECTS: Does all actual formatting for FormatNumber methods
static numT Format(const std::basic_string<CharT>& s, bool fCStyleFormatting)
{
static const std::num_get<CharT>* png;
std::basic_istringstream<CharT> ss(s);
std::ios_base::iostate state;
numT n;
if (fCStyleFormatting)
ss.imbue(std::locale::classic());
tss::GetFacet(ss.getloc(), png).get(ss, std::istreambuf_iterator<CharT>(), ss, state, n);
if ((state & std::ios_base::failbit) != 0)
throw eTWLocaleBadNumFormat();
return (n);
}
//=============================================================================
// std::basic_string< CharT >&
// Format( numT n, std::basic_string< CharT >& sBuf )
//-----------------------------------------------------------------------------
// EFFECTS: Does all actual formatting for FormatNumber methods
//
static std::basic_string<CharT>& Format(numT n, std::basic_string<CharT>& sBuf, bool fCStyleFormatting = false)
{
static const std::num_put<CharT>* pnp;
std::basic_ostringstream<CharT> ss;
if (fCStyleFormatting)
ss.imbue(std::locale::classic());
tss::GetFacet(ss.getloc(), pnp).put(ss, ss, ss.fill(), n);
sBuf = ss.str();
return (sBuf);
}
};
/*
TSTRING cTWLocale::FormatNumberClassic( int32 i )
{
TSTRING s;
return cFormatNumberUtil< long, TCHAR >::Format( i, s, true );
}
int32 cTWLocale::FormatNumberClassic( const TSTRING& s )
{
return cFormatNumberUtil< long, TCHAR >::Format( s, true );
}
*/
TSTRING& cTWLocale::FormatNumber(uint64 ui, TSTRING& strBuf)
{
// try to use the int64 version
if (ui <= (uint64)TSS_INT64_MAX)
return (FormatNumber((int64)ui, strBuf));
else
{
#if IS_MSVC
// MSVC can't convert from uint64 to a double for some reason
strBuf = TSS_GetString(cCore, core::STR_NUMBER_TOO_BIG);
return (strBuf);
#else
ASSERT(std::numeric_limits<double>::max() >= TSS_UINT64_MAX);
return (cFormatNumberUtil<double, TCHAR>::Format((double)ui, strBuf));
#endif
}
}
TSTRING& cTWLocale::FormatNumber(int64 i, TSTRING& strBuf)
{
// try to use the int32 version
if (i <= (int64)TSS_INT32_MAX)
return (FormatNumber((int32)i, strBuf));
else
{
ASSERT(std::numeric_limits<double>::max() >= TSS_INT64_MAX);
return (cFormatNumberUtil<double, TCHAR>::Format((double)i, strBuf));
}
}
TSTRING& cTWLocale::FormatNumber(uint32 ui, TSTRING& strBuf)
{
ASSERT(sizeof(unsigned long) >= sizeof(uint32)); // must be able to cast to 'ulong'
return (cFormatNumberUtil<unsigned long, TCHAR>::Format((unsigned long)ui, strBuf));
}
TSTRING& cTWLocale::FormatNumber(int32 i, TSTRING& strBuf)
{
ASSERT(sizeof(long) >= sizeof(int32)); // must be able to cast to 'long'
return (cFormatNumberUtil<long, TCHAR>::Format((long)i, strBuf));
}
TSTRING& cTWLocale::FormatTime(int64 t, TSTRING& strBuf)
{
// clear return string
strBuf.erase();
tzset();
time_t tmpTime = t;
struct tm* ptm = localtime(&tmpTime);
if (ptm)
{
util_FormatTime(ptm, strBuf);
}
else
{
strBuf = TSS_GetString(cCore, core::STR_UNKNOWN_TIME);
}
return (strBuf);
}
//=========================================================================
// UTIL FUNCTION IMPLEMENTATION
//=========================================================================
TSTRING& util_FormatTime(struct tm* ptm, TSTRING& strBuf)
{
ASSERT(ptm);
#if USES_CLIB_DATE_FUNCTION
return util_FormatTimeC(ptm, strBuf);
#else
return util_FormatTimeCPlusPlus(ptm, strBuf);
#endif
}
#if !USES_CLIB_DATE_FUNCTION
TSTRING& util_FormatTimeCPlusPlus(struct tm* ptm, TSTRING& strBuf)
{
ASSERT(ptm);
TOSTRINGSTREAM sstr;
static const std::time_put<TCHAR>* ptp;
//
// format date
//
# if IS_MSVC // MSVC uses old put() signature which didn't have the fill character, (and uses proprietary '#')
tss::GetFacet(sstr.getloc(), ptp).put(sstr, sstr, ptm, 'c', '#');
# else
tss::GetFacet(sstr.getloc(), ptp).put(sstr, sstr, sstr.fill(), ptm, 'c');
# endif
strBuf = sstr.str();
return strBuf;
}
#endif
TSTRING& util_FormatTimeC(struct tm* ptm, TSTRING& strBuf)
{
ASSERT(ptm);
TCHAR achTimeBuf[256];
/* XXX: This should check (#ifdef) for strftime - PH */
size_t nbWritten = _tcsftime(achTimeBuf,
countof(achTimeBuf),
#if IS_MSVC // MSVC uses proprietary '#'
_T("%#c"),
#else
_T("%c"),
#endif
ptm);
if (nbWritten)
strBuf = achTimeBuf;
else
strBuf = TSS_GetString(cCore, core::STR_UNKNOWN_TIME);
return strBuf;
}