1 // 2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See 5 // accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt) 7 // 8 #ifndef BOOST_LOCALE_IMPL_WIN32_API_HPP 9 #define BOOST_LOCALE_IMPL_WIN32_API_HPP 10 11 #include <string> 12 #include <vector> 13 #include <sstream> 14 #include <iomanip> 15 #include <limits> 16 #include <ctime> 17 18 #include "lcid.hpp" 19 20 #ifndef NOMINMAX 21 #define NOMINMAX 22 #endif 23 #ifndef UNICODE 24 #define UNICODE 25 #endif 26 #include <windows.h> 27 28 #include <boost/locale/conversion.hpp> 29 #include <boost/locale/collator.hpp> 30 31 #define BOOST_LOCALE_WINDOWS_2000_API 32 33 #if defined(_WIN32_NT) && _WIN32_NT >= 0x600 && !defined(BOOST_LOCALE_WINDOWS_2000_API) 34 #define BOOST_LOCALE_WINDOWS_VISTA_API 35 #else 36 #define BOOST_LOCALE_WINDOWS_2000_API 37 #endif 38 39 namespace boost { 40 namespace locale { 41 namespace impl_win { 42 43 struct numeric_info { 44 std::wstring thousands_sep; 45 std::wstring decimal_point; 46 std::string grouping; 47 }; 48 collation_level_to_flag(collator_base::level_type level)49 inline DWORD collation_level_to_flag(collator_base::level_type level) 50 { 51 DWORD flags; 52 switch(level) { 53 case collator_base::primary: 54 flags = NORM_IGNORESYMBOLS | NORM_IGNORECASE | NORM_IGNORENONSPACE; 55 break; 56 case collator_base::secondary: 57 flags = NORM_IGNORESYMBOLS | NORM_IGNORECASE; 58 break; 59 case collator_base::tertiary: 60 flags = NORM_IGNORESYMBOLS; 61 break; 62 default: 63 flags = 0; 64 } 65 return flags; 66 } 67 68 69 70 #ifdef BOOST_LOCALE_WINDOWS_2000_API 71 72 class winlocale{ 73 public: winlocale()74 winlocale() : 75 lcid(0) 76 { 77 } 78 winlocale(std::string const & name)79 winlocale(std::string const &name) 80 { 81 lcid = locale_to_lcid(name); 82 } 83 84 unsigned lcid; 85 is_c() const86 bool is_c() const 87 { 88 return lcid == 0; 89 } 90 }; 91 92 93 //////////////////////////////////////////////////////////////////////// 94 /// 95 /// Number Format 96 /// 97 //////////////////////////////////////////////////////////////////////// 98 wcsnumformat_l(winlocale const & l)99 inline numeric_info wcsnumformat_l(winlocale const &l) 100 { 101 numeric_info res; 102 res.decimal_point = L'.'; 103 unsigned lcid = l.lcid; 104 105 if(lcid == 0) 106 return res; 107 108 // limits according to MSDN 109 static const int th_size = 4; 110 static const int de_size = 4; 111 static const int gr_size = 10; 112 113 wchar_t th[th_size]={0}; 114 wchar_t de[de_size]={0}; 115 wchar_t gr[gr_size]={0}; 116 117 if( GetLocaleInfoW(lcid,LOCALE_STHOUSAND,th,th_size)==0 118 || GetLocaleInfoW(lcid,LOCALE_SDECIMAL ,de,de_size)==0 119 || GetLocaleInfoW(lcid,LOCALE_SGROUPING,gr,gr_size)==0) 120 { 121 return res; 122 } 123 res.decimal_point = de; 124 res.thousands_sep = th; 125 bool inf_group = false; 126 for(unsigned i=0;gr[i];i++) { 127 if(gr[i]==L';') 128 continue; 129 if(L'1'<= gr[i] && gr[i]<=L'9') { 130 res.grouping += char(gr[i]-L'0'); 131 } 132 else if(gr[i]==L'0') 133 inf_group = true; 134 } 135 if(!inf_group) { 136 if(std::numeric_limits<char>::is_signed) { 137 res.grouping+=std::numeric_limits<char>::min(); 138 } 139 else { 140 res.grouping+=std::numeric_limits<char>::max(); 141 } 142 } 143 return res; 144 } 145 win_map_string_l(unsigned flags,wchar_t const * begin,wchar_t const * end,winlocale const & l)146 inline std::wstring win_map_string_l(unsigned flags,wchar_t const *begin,wchar_t const *end,winlocale const &l) 147 { 148 std::wstring res; 149 int len = LCMapStringW(l.lcid,flags,begin,end-begin,0,0); 150 if(len == 0) 151 return res; 152 std::vector<wchar_t> buf(len+1); 153 int l2 = LCMapStringW(l.lcid,flags,begin,end-begin,&buf.front(),buf.size()); 154 res.assign(&buf.front(),l2); 155 return res; 156 } 157 158 //////////////////////////////////////////////////////////////////////// 159 /// 160 /// Collation 161 /// 162 //////////////////////////////////////////////////////////////////////// 163 164 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)165 inline int wcscoll_l( collator_base::level_type level, 166 wchar_t const *lb,wchar_t const *le, 167 wchar_t const *rb,wchar_t const *re, 168 winlocale const &l) 169 { 170 return CompareStringW(l.lcid,collation_level_to_flag(level),lb,le-lb,rb,re-rb) - 2; 171 } 172 173 174 //////////////////////////////////////////////////////////////////////// 175 /// 176 /// Money Format 177 /// 178 //////////////////////////////////////////////////////////////////////// 179 wcsfmon_l(double value,winlocale const & l)180 inline std::wstring wcsfmon_l(double value,winlocale const &l) 181 { 182 std::wostringstream ss; 183 ss.imbue(std::locale::classic()); 184 185 ss << std::setprecision(std::numeric_limits<double>::digits10+1) << value; 186 std::wstring sval = ss.str(); 187 int len = GetCurrencyFormatW(l.lcid,0,sval.c_str(),0,0,0); 188 std::vector<wchar_t> buf(len+1); 189 GetCurrencyFormatW(l.lcid,0,sval.c_str(),0,&buf.front(),len); 190 return &buf.front(); 191 } 192 193 //////////////////////////////////////////////////////////////////////// 194 /// 195 /// Time Format 196 /// 197 //////////////////////////////////////////////////////////////////////// 198 199 wcs_format_date_l(wchar_t const * format,SYSTEMTIME const * tm,winlocale const & l)200 inline std::wstring wcs_format_date_l(wchar_t const *format,SYSTEMTIME const *tm,winlocale const &l) 201 { 202 int len = GetDateFormatW(l.lcid,0,tm,format,0,0); 203 std::vector<wchar_t> buf(len+1); 204 GetDateFormatW(l.lcid,0,tm,format,&buf.front(),len); 205 return &buf.front(); 206 } 207 wcs_format_time_l(wchar_t const * format,SYSTEMTIME const * tm,winlocale const & l)208 inline std::wstring wcs_format_time_l(wchar_t const *format,SYSTEMTIME const *tm,winlocale const &l) 209 { 210 int len = GetTimeFormatW(l.lcid,0,tm,format,0,0); 211 std::vector<wchar_t> buf(len+1); 212 GetTimeFormatW(l.lcid,0,tm,format,&buf.front(),len); 213 return &buf.front(); 214 } 215 wcsfold(wchar_t const * begin,wchar_t const * end)216 inline std::wstring wcsfold(wchar_t const *begin,wchar_t const *end) 217 { 218 winlocale l; 219 l.lcid = 0x0409; // en-US 220 return win_map_string_l(LCMAP_LOWERCASE,begin,end,l); 221 } 222 wcsnormalize(norm_type norm,wchar_t const * begin,wchar_t const * end)223 inline std::wstring wcsnormalize(norm_type norm,wchar_t const *begin,wchar_t const *end) 224 { 225 // We use FoldString, under Vista it actually does normalization; 226 // under XP and below it does something similar, half job, better then nothing 227 unsigned flags = 0; 228 switch(norm) { 229 case norm_nfd: 230 flags = MAP_COMPOSITE; 231 break; 232 case norm_nfc: 233 flags = MAP_PRECOMPOSED; 234 break; 235 case norm_nfkd: 236 flags = MAP_FOLDCZONE; 237 break; 238 case norm_nfkc: 239 flags = MAP_FOLDCZONE | MAP_COMPOSITE; 240 break; 241 default: 242 flags = MAP_PRECOMPOSED; 243 } 244 245 int len = FoldStringW(flags,begin,end-begin,0,0); 246 if(len == 0) 247 return std::wstring(); 248 std::vector<wchar_t> v(len+1); 249 len = FoldStringW(flags,begin,end-begin,&v.front(),len+1); 250 return std::wstring(&v.front(),len); 251 } 252 253 254 #endif 255 wcsxfrm_l(collator_base::level_type level,wchar_t const * begin,wchar_t const * end,winlocale const & l)256 inline std::wstring wcsxfrm_l(collator_base::level_type level,wchar_t const *begin,wchar_t const *end,winlocale const &l) 257 { 258 int flag = LCMAP_SORTKEY | collation_level_to_flag(level); 259 260 return win_map_string_l(flag,begin,end,l); 261 } 262 towupper_l(wchar_t const * begin,wchar_t const * end,winlocale const & l)263 inline std::wstring towupper_l(wchar_t const *begin,wchar_t const *end,winlocale const &l) 264 { 265 return win_map_string_l(LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,begin,end,l); 266 } 267 towlower_l(wchar_t const * begin,wchar_t const * end,winlocale const & l)268 inline std::wstring towlower_l(wchar_t const *begin,wchar_t const *end,winlocale const &l) 269 { 270 return win_map_string_l(LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING,begin,end,l); 271 } 272 wcsftime_l(char c,std::tm const * tm,winlocale const & l)273 inline std::wstring wcsftime_l(char c,std::tm const *tm,winlocale const &l) 274 { 275 SYSTEMTIME wtm=SYSTEMTIME(); 276 wtm.wYear = tm->tm_year + 1900; 277 wtm.wMonth = tm->tm_mon+1; 278 wtm.wDayOfWeek = tm->tm_wday; 279 wtm.wDay = tm->tm_mday; 280 wtm.wHour = tm->tm_hour; 281 wtm.wMinute = tm->tm_min; 282 wtm.wSecond = tm->tm_sec; 283 switch(c) { 284 case 'a': // Abbr Weekday 285 return wcs_format_date_l(L"ddd",&wtm,l); 286 case 'A': // Full Weekday 287 return wcs_format_date_l(L"dddd",&wtm,l); 288 case 'b': // Abbr Month 289 return wcs_format_date_l(L"MMM",&wtm,l); 290 case 'B': // Full Month 291 return wcs_format_date_l(L"MMMM",&wtm,l); 292 case 'c': // DateTile Full 293 return wcs_format_date_l(0,&wtm,l) + L" " + wcs_format_time_l(0,&wtm,l); 294 // not supported by WIN ;( 295 // case 'C': // Century -> 1980 -> 19 296 // retur 297 case 'd': // Day of Month [01,31] 298 return wcs_format_date_l(L"dd",&wtm,l); 299 case 'D': // %m/%d/%y 300 return wcs_format_date_l(L"MM/dd/yy",&wtm,l); 301 case 'e': // Day of Month [1,31] 302 return wcs_format_date_l(L"d",&wtm,l); 303 case 'h': // == b 304 return wcs_format_date_l(L"MMM",&wtm,l); 305 case 'H': // 24 clock hour 00,23 306 return wcs_format_time_l(L"HH",&wtm,l); 307 case 'I': // 12 clock hour 01,12 308 return wcs_format_time_l(L"hh",&wtm,l); 309 /* 310 case 'j': // day of year 001,366 311 return "D";*/ 312 case 'm': // month as [01,12] 313 return wcs_format_date_l(L"MM",&wtm,l); 314 case 'M': // minute [00,59] 315 return wcs_format_time_l(L"mm",&wtm,l); 316 case 'n': // \n 317 return L"\n"; 318 case 'p': // am-pm 319 return wcs_format_time_l(L"tt",&wtm,l); 320 case 'r': // time with AM/PM %I:%M:%S %p 321 return wcs_format_time_l(L"hh:mm:ss tt",&wtm,l); 322 case 'R': // %H:%M 323 return wcs_format_time_l(L"HH:mm",&wtm,l); 324 case 'S': // second [00,61] 325 return wcs_format_time_l(L"ss",&wtm,l); 326 case 't': // \t 327 return L"\t"; 328 case 'T': // %H:%M:%S 329 return wcs_format_time_l(L"HH:mm:ss",&wtm,l); 330 /* case 'u': // weekday 1,7 1=Monday 331 case 'U': // week number of year [00,53] Sunday first 332 case 'V': // week number of year [01,53] Moday first 333 case 'w': // weekday 0,7 0=Sunday 334 case 'W': // week number of year [00,53] Moday first, */ 335 case 'x': // Date 336 return wcs_format_date_l(0,&wtm,l); 337 case 'X': // Time 338 return wcs_format_time_l(0,&wtm,l); 339 case 'y': // Year [00-99] 340 return wcs_format_date_l(L"yy",&wtm,l); 341 case 'Y': // Year 1998 342 return wcs_format_date_l(L"yyyy",&wtm,l); 343 case '%': // % 344 return L"%"; 345 default: 346 return L""; 347 } 348 } 349 350 351 352 } // win 353 } // locale 354 } // boost 355 #endif 356 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 357 358