// This source code is Windows-specific and it's specific to the g++ compiler.
// Note: for C++11 may need to use "-U __STRICT_ANSI__" in the g++ command line.
#define __MSVCRT_VERSION__ 0x0800 // Includes declaration of '_fileno'.
// Standard library
#include <assert.h>
#include <iostream>
#include <stdexcept> // std::runtime_error
#include <stdio.h> // stdout
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#include <streambuf> // std::basic_streambuf
using namespace std;
// Semi-documented Boost
#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
// Windows specific:
#include <io.h> // _fileno, _isatty
#undef UNICODE
#define UNICODE
#undef STRICT
#define STRICT
#undef NOMINMAX
#define NOMINMAX
#include <windows.h> // WriteConsole
// g++-specific:
#include <ext/stdio_filebuf.h> // __gnu_cxx::stdio_filebuf
class DirectOutputBuffer
: public basic_streambuf< wchar_t >
{
protected:
virtual streamsize xsputn( wchar_t const* const s, streamsize const n )
{
static HANDLE const outputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
DWORD nCharactersWritten = 0;
bool writeSucceeded = !!WriteConsole(
outputHandle, s, n, &nCharactersWritten, 0
);
return (writeSucceeded? nCharactersWritten : 0);
}
virtual int_type overflow( int_type const c )
{
typedef traits_type Traits;
bool const cIsEOF = Traits::eq_int_type( c, Traits::eof() );
int_type const failureValue = Traits::eof();
int_type const successValue = (cIsEOF? Traits::not_eof( c ) : c);
if( !cIsEOF )
{
char_type const ch = Traits::to_char_type( c );
streamsize const nCharactersWritten = xsputn( &ch, 1 );
return (nCharactersWritten == 1? successValue : failureValue);
}
return successValue;
}
};
bool isConsoleOutput( int const fileNo )
{
int const stdOutputFileNo = 1; // More generally needs to check also stderr.
return (fileNo == stdOutputFileNo && _isatty( fileNo ));
}
void clear( wostream& stream )
{
stream.clear();
stream.flush();
assert( !!stream );
}
void setDirectConsoleOutput( wostream& stream )
{
static DirectOutputBuffer buffer; // More generally also needs buffer for stderr.
clear( stream );
stream.rdbuf( &buffer );
}
void setUtf8Translation( wostream& stream, FILE* const fileStream )
{
typedef __gnu_cxx::stdio_filebuf< wchar_t > FileBuf;
//typedef codecvt< wchar_t, char, __gnu_cxx::encoding_state > ConversionFacet;
typedef boost::filesystem::detail::utf8_codecvt_facet ConversionFacet;
// More generally also needs buffer for stderr.
static FileBuf buffer( fileStream, ios_base::out ); // Supports imbuing.
clear( stream );
stream.rdbuf( &buffer );
stream.imbue( locale( locale(), new ConversionFacet() ) );
}
void setUtf8Mode( wostream& stream, FILE* const fileStream )
{
if( isConsoleOutput( _fileno( fileStream ) ) )
{
setDirectConsoleOutput( stream );
}
else
{
setUtf8Translation( stream, fileStream );
}
}
int main()
{
setUtf8Mode( wcout, stdout );
wcout << L"Blåbærsyltetøy! 日本国 кошка!" << endl;
}