Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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;
}
share|improve this question

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.