blob: a41fbde5e6b33310a2d60a1e3ccb8f3f26456023 [file] [log] [blame]
//
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_LOCALE_IMPL_WIN32_API_HPP
#define BOOST_LOCALE_IMPL_WIN32_API_HPP
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <limits>
#include <ctime>
#include "lcid.hpp"
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <boost/locale/conversion.hpp>
#include <boost/locale/collator.hpp>
#define BOOST_LOCALE_WINDOWS_2000_API
#if defined(_WIN32_NT) && _WIN32_NT >= 0x600 && !defined(BOOST_LOCALE_WINDOWS_2000_API)
#define BOOST_LOCALE_WINDOWS_VISTA_API
#else
#define BOOST_LOCALE_WINDOWS_2000_API
#endif
namespace boost {
namespace locale {
namespace impl_win {
struct numeric_info {
std::wstring thousands_sep;
std::wstring decimal_point;
std::string grouping;
};
inline DWORD collation_level_to_flag(collator_base::level_type level)
{
DWORD flags;
switch(level) {
case collator_base::primary:
flags = NORM_IGNORESYMBOLS | NORM_IGNORECASE | NORM_IGNORENONSPACE;
break;
case collator_base::secondary:
flags = NORM_IGNORESYMBOLS | NORM_IGNORECASE;
break;
case collator_base::tertiary:
flags = NORM_IGNORESYMBOLS;
break;
default:
flags = 0;
}
return flags;
}
#ifdef BOOST_LOCALE_WINDOWS_2000_API
class winlocale{
public:
winlocale() :
lcid(0)
{
}
winlocale(std::string const &name)
{
lcid = locale_to_lcid(name);
}
unsigned lcid;
bool is_c() const
{
return lcid == 0;
}
};
////////////////////////////////////////////////////////////////////////
///
/// Number Format
///
////////////////////////////////////////////////////////////////////////
inline numeric_info wcsnumformat_l(winlocale const &l)
{
numeric_info res;
res.decimal_point = L'.';
unsigned lcid = l.lcid;
if(lcid == 0)
return res;
// limits according to MSDN
static const int th_size = 4;
static const int de_size = 4;
static const int gr_size = 10;
wchar_t th[th_size]={0};
wchar_t de[de_size]={0};
wchar_t gr[gr_size]={0};
if( GetLocaleInfoW(lcid,LOCALE_STHOUSAND,th,th_size)==0
|| GetLocaleInfoW(lcid,LOCALE_SDECIMAL ,de,de_size)==0
|| GetLocaleInfoW(lcid,LOCALE_SGROUPING,gr,gr_size)==0)
{
return res;
}
res.decimal_point = de;
res.thousands_sep = th;
bool inf_group = false;
for(unsigned i=0;gr[i];i++) {
if(gr[i]==L';')
continue;
if(L'1'<= gr[i] && gr[i]<=L'9') {
res.grouping += char(gr[i]-L'0');
}
else if(gr[i]==L'0')
inf_group = true;
}
if(!inf_group) {
if(std::numeric_limits<char>::is_signed) {
res.grouping+=std::numeric_limits<char>::min();
}
else {
res.grouping+=std::numeric_limits<char>::max();
}
}
return res;
}
inline std::wstring win_map_string_l(unsigned flags,wchar_t const *begin,wchar_t const *end,winlocale const &l)
{
std::wstring res;
int len = LCMapStringW(l.lcid,flags,begin,end-begin,0,0);
if(len == 0)
return res;
std::vector<wchar_t> buf(len+1);
int l2 = LCMapStringW(l.lcid,flags,begin,end-begin,&buf.front(),buf.size());
res.assign(&buf.front(),l2);
return res;
}
////////////////////////////////////////////////////////////////////////
///
/// Collation
///
////////////////////////////////////////////////////////////////////////
inline int wcscoll_l( collator_base::level_type level,
wchar_t const *lb,wchar_t const *le,
wchar_t const *rb,wchar_t const *re,
winlocale const &l)
{
return CompareStringW(l.lcid,collation_level_to_flag(level),lb,le-lb,rb,re-rb) - 2;
}
////////////////////////////////////////////////////////////////////////
///
/// Money Format
///
////////////////////////////////////////////////////////////////////////
inline std::wstring wcsfmon_l(double value,winlocale const &l)
{
std::wostringstream ss;
ss.imbue(std::locale::classic());
ss << std::setprecision(std::numeric_limits<double>::digits10+1) << value;
std::wstring sval = ss.str();
int len = GetCurrencyFormatW(l.lcid,0,sval.c_str(),0,0,0);
std::vector<wchar_t> buf(len+1);
GetCurrencyFormatW(l.lcid,0,sval.c_str(),0,&buf.front(),len);
return &buf.front();
}
////////////////////////////////////////////////////////////////////////
///
/// Time Format
///
////////////////////////////////////////////////////////////////////////
inline std::wstring wcs_format_date_l(wchar_t const *format,SYSTEMTIME const *tm,winlocale const &l)
{
int len = GetDateFormatW(l.lcid,0,tm,format,0,0);
std::vector<wchar_t> buf(len+1);
GetDateFormatW(l.lcid,0,tm,format,&buf.front(),len);
return &buf.front();
}
inline std::wstring wcs_format_time_l(wchar_t const *format,SYSTEMTIME const *tm,winlocale const &l)
{
int len = GetTimeFormatW(l.lcid,0,tm,format,0,0);
std::vector<wchar_t> buf(len+1);
GetTimeFormatW(l.lcid,0,tm,format,&buf.front(),len);
return &buf.front();
}
inline std::wstring wcsfold(wchar_t const *begin,wchar_t const *end)
{
winlocale l;
l.lcid = 0x0409; // en-US
return win_map_string_l(LCMAP_LOWERCASE,begin,end,l);
}
inline std::wstring wcsnormalize(norm_type norm,wchar_t const *begin,wchar_t const *end)
{
// We use FoldString, under Vista it actually does normalization;
// under XP and below it does something similar, half job, better then nothing
unsigned flags = 0;
switch(norm) {
case norm_nfd:
flags = MAP_COMPOSITE;
break;
case norm_nfc:
flags = MAP_PRECOMPOSED;
break;
case norm_nfkd:
flags = MAP_FOLDCZONE;
break;
case norm_nfkc:
flags = MAP_FOLDCZONE | MAP_COMPOSITE;
break;
default:
flags = MAP_PRECOMPOSED;
}
int len = FoldStringW(flags,begin,end-begin,0,0);
if(len == 0)
return std::wstring();
std::vector<wchar_t> v(len+1);
len = FoldStringW(flags,begin,end-begin,&v.front(),len+1);
return std::wstring(&v.front(),len);
}
#endif
inline std::wstring wcsxfrm_l(collator_base::level_type level,wchar_t const *begin,wchar_t const *end,winlocale const &l)
{
int flag = LCMAP_SORTKEY | collation_level_to_flag(level);
return win_map_string_l(flag,begin,end,l);
}
inline std::wstring towupper_l(wchar_t const *begin,wchar_t const *end,winlocale const &l)
{
return win_map_string_l(LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,begin,end,l);
}
inline std::wstring towlower_l(wchar_t const *begin,wchar_t const *end,winlocale const &l)
{
return win_map_string_l(LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING,begin,end,l);
}
inline std::wstring wcsftime_l(char c,std::tm const *tm,winlocale const &l)
{
SYSTEMTIME wtm=SYSTEMTIME();
wtm.wYear = tm->tm_year + 1900;
wtm.wMonth = tm->tm_mon+1;
wtm.wDayOfWeek = tm->tm_wday;
wtm.wDay = tm->tm_mday;
wtm.wHour = tm->tm_hour;
wtm.wMinute = tm->tm_min;
wtm.wSecond = tm->tm_sec;
switch(c) {
case 'a': // Abbr Weekday
return wcs_format_date_l(L"ddd",&wtm,l);
case 'A': // Full Weekday
return wcs_format_date_l(L"dddd",&wtm,l);
case 'b': // Abbr Month
return wcs_format_date_l(L"MMM",&wtm,l);
case 'B': // Full Month
return wcs_format_date_l(L"MMMM",&wtm,l);
case 'c': // DateTile Full
return wcs_format_date_l(0,&wtm,l) + L" " + wcs_format_time_l(0,&wtm,l);
// not supported by WIN ;(
// case 'C': // Century -> 1980 -> 19
// retur
case 'd': // Day of Month [01,31]
return wcs_format_date_l(L"dd",&wtm,l);
case 'D': // %m/%d/%y
return wcs_format_date_l(L"MM/dd/yy",&wtm,l);
case 'e': // Day of Month [1,31]
return wcs_format_date_l(L"d",&wtm,l);
case 'h': // == b
return wcs_format_date_l(L"MMM",&wtm,l);
case 'H': // 24 clock hour 00,23
return wcs_format_time_l(L"HH",&wtm,l);
case 'I': // 12 clock hour 01,12
return wcs_format_time_l(L"hh",&wtm,l);
/*
case 'j': // day of year 001,366
return "D";*/
case 'm': // month as [01,12]
return wcs_format_date_l(L"MM",&wtm,l);
case 'M': // minute [00,59]
return wcs_format_time_l(L"mm",&wtm,l);
case 'n': // \n
return L"\n";
case 'p': // am-pm
return wcs_format_time_l(L"tt",&wtm,l);
case 'r': // time with AM/PM %I:%M:%S %p
return wcs_format_time_l(L"hh:mm:ss tt",&wtm,l);
case 'R': // %H:%M
return wcs_format_time_l(L"HH:mm",&wtm,l);
case 'S': // second [00,61]
return wcs_format_time_l(L"ss",&wtm,l);
case 't': // \t
return L"\t";
case 'T': // %H:%M:%S
return wcs_format_time_l(L"HH:mm:ss",&wtm,l);
/* case 'u': // weekday 1,7 1=Monday
case 'U': // week number of year [00,53] Sunday first
case 'V': // week number of year [01,53] Moday first
case 'w': // weekday 0,7 0=Sunday
case 'W': // week number of year [00,53] Moday first, */
case 'x': // Date
return wcs_format_date_l(0,&wtm,l);
case 'X': // Time
return wcs_format_time_l(0,&wtm,l);
case 'y': // Year [00-99]
return wcs_format_date_l(L"yy",&wtm,l);
case 'Y': // Year 1998
return wcs_format_date_l(L"yyyy",&wtm,l);
case '%': // %
return L"%";
default:
return L"";
}
}
} // win
} // locale
} // boost
#endif
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4