[ create a new paste ] login | about

Link: http://codepad.org/vONfaBsq    [ raw code | fork ]

C++, pasted on Nov 17:
// 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;
}


Create a new paste based on this one


Comments: