I've recently had to print some national symbols in windows console using Mingw and found, that I got nothing in the output, if I use wide strings.
So, I studied the problem and found out that it is locale problem. I was unable to find somewhere complete solution, so I had to write something, that seems to work.
So, I decided to publish it here for review, or may be I should publish it somewhere it it worth.
- I've tested in Mingw 4.7.0 using Russian locale.
- It should probably correctly convert wide strings to national OEM encoded strings.
Code:
#ifndef CUSTOM_LOCALE_H
#define CUSTOM_LOCALE_H
#if (__cplusplus >= 201103L)
#define CUSTOM_LOCALE_OVERRIDE override
#else
#define CUSTOM_LOCALE_OVERRIDE
#endif
#include <locale>
#include <iostream>
#include <windows.h>
namespace custom_locale
{
class CustomLocale : public std::codecvt <wchar_t, char, std::mbstate_t> {
public:
explicit CustomLocale ( size_t r = 0 ) : std::codecvt <wchar_t, char, std::mbstate_t> (r) {}
protected:
result do_in (state_type&, const char* from, const char* from_end,
const char*& from_next, wchar_t* to, wchar_t* to_end, wchar_t*& to_next ) const CUSTOM_LOCALE_OVERRIDE
{
std::size_t size = from_end - from;
std::size_t buffer_size = to_end - to;
std::size_t written = MultiByteToWideChar(CP_OEMCP, 0, from, size, to, buffer_size);
to_next = to + written;
if (written == 0) {
return error;
}
else if (written != buffer_size) {
return partial;
}
else {
return ok;
}
}
result do_out (state_type&, const wchar_t* from, const wchar_t* from_end,
const wchar_t*& from_next, char* to, char* to_end, char*& to_next ) const CUSTOM_LOCALE_OVERRIDE
{
std::size_t size = from_end - from;
std::size_t buffer_size = to_end - to;
std::size_t written = WideCharToMultiByte(CP_OEMCP, 0, from, size, to, buffer_size, 0, 0);
to_next = to + written;
if (written == 0) {
return error;
}
else if (written != buffer_size) {
return partial;
}
else {
return ok;
}
}
result do_unshift ( state_type&, char*, char*, char*& ) const CUSTOM_LOCALE_OVERRIDE { return ok; }
int do_encoding () const throw () CUSTOM_LOCALE_OVERRIDE { return 1; }
bool do_always_noconv () const throw () CUSTOM_LOCALE_OVERRIDE { return false; }
int do_length ( state_type& state, const char* from, const char* from_end, size_t max ) const CUSTOM_LOCALE_OVERRIDE
{
return std::codecvt <wchar_t, char, std::mbstate_t>::do_length ( state, from, from_end, max );
}
int do_max_length () const throw () CUSTOM_LOCALE_OVERRIDE
{
return std::codecvt <wchar_t, char, std::mbstate_t>::do_max_length ();
}
};
inline void init()
{
std::locale loc ( std::locale(), new CustomLocale() );
std::ios_base::sync_with_stdio (false);
std::wcout.imbue(loc);
std::wcin.imbue(loc);
}
}
#endif
Example:
#include "custom_locale.h"
int main ()
{
custom_locale::init();
std::wstring s(L"привет");
std::wcout << s << '\n';
std::wstring u;
std::wcin >> u;
s += L' ' + u;
std::wcout << s << '\n';
return 0;
}