Allow specifying character set for wxLogStderr and wxLogStream.

Until now, a mixture of non-UTF-8 and UTF-8 could be written in some circumstances.
This commit is contained in:
Lauri Nurmi
2016-02-20 15:07:11 +02:00
parent 1417776d33
commit 6b73bd9136
5 changed files with 104 additions and 11 deletions

View File

@@ -720,13 +720,16 @@ class WXDLLIMPEXP_BASE wxLogStderr : public wxLog
{ {
public: public:
// redirect log output to a FILE // redirect log output to a FILE
wxLogStderr(FILE *fp = NULL); wxLogStderr(FILE *fp = NULL,
const wxMBConv &conv = wxConvWhateverWorks);
virtual ~wxLogStderr();
protected: protected:
// implement sink function // implement sink function
virtual void DoLogText(const wxString& msg) wxOVERRIDE; virtual void DoLogText(const wxString& msg) wxOVERRIDE;
FILE *m_fp; FILE *m_fp;
const wxMBConv *m_conv;
wxDECLARE_NO_COPY_CLASS(wxLogStderr); wxDECLARE_NO_COPY_CLASS(wxLogStderr);
}; };
@@ -738,7 +741,9 @@ class WXDLLIMPEXP_BASE wxLogStream : public wxLog
{ {
public: public:
// redirect log output to an ostream // redirect log output to an ostream
wxLogStream(wxSTD ostream *ostr = (wxSTD ostream *) NULL); wxLogStream(wxSTD ostream *ostr = (wxSTD ostream *) NULL,
const wxMBConv &conv = wxConvWhateverWorks);
virtual ~wxLogStream();
protected: protected:
// implement sink function // implement sink function
@@ -746,6 +751,7 @@ protected:
// using ptr here to avoid including <iostream.h> from this file // using ptr here to avoid including <iostream.h> from this file
wxSTD ostream *m_ostr; wxSTD ostream *m_ostr;
const wxMBConv *m_conv;
}; };
#endif // wxUSE_STD_IOSTREAM #endif // wxUSE_STD_IOSTREAM

View File

@@ -64,7 +64,9 @@ private:
class WXDLLIMPEXP_BASE wxMessageOutputStderr : public wxMessageOutput class WXDLLIMPEXP_BASE wxMessageOutputStderr : public wxMessageOutput
{ {
public: public:
wxMessageOutputStderr(FILE *fp = stderr) : m_fp(fp) { } wxMessageOutputStderr(FILE *fp = stderr,
const wxMBConv &conv = wxConvWhateverWorks);
virtual ~wxMessageOutputStderr();
virtual void Output(const wxString& str) wxOVERRIDE; virtual void Output(const wxString& str) wxOVERRIDE;
@@ -74,6 +76,7 @@ protected:
wxString AppendLineFeedIfNeeded(const wxString& str); wxString AppendLineFeedIfNeeded(const wxString& str);
FILE *m_fp; FILE *m_fp;
const wxMBConv *m_conv;
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -756,8 +756,24 @@ public:
/** /**
Constructs a log target which sends all the log messages to the given Constructs a log target which sends all the log messages to the given
output stream. If it is @NULL, the messages are sent to @c cerr. output stream. If it is @NULL, the messages are sent to @c cerr.
The messages will be written in the encoding specified by the
given @c wxMBConv.
The @a conv argument is only available in wxWidgets 3.1.1 and later.
@note
In practice, it is only advisable to specify @c wxConvUTF8 as
the @a conv.
If using @c wxMBConvUTF16(), the file should be opened in
@c std::ios::binary mode.
@warning
If a log message contains any characters that cannot be converted
to the character set given by @a conv, that message will be
silently ignored, i.e. it will not be written at all.
*/ */
wxLogStream(std::ostream *ostr = NULL); wxLogStream(std::ostream *ostr = NULL,
const wxMBConv &conv = wxConvWhateverWorks);
}; };
@@ -782,8 +798,24 @@ public:
/** /**
Constructs a log target which sends all the log messages to the given Constructs a log target which sends all the log messages to the given
@c FILE. If it is @NULL, the messages are sent to @c stderr. @c FILE. If it is @NULL, the messages are sent to @c stderr.
The messages will be written in the encoding specified by the
given @c wxMBConv.
The @a conv argument is only available in wxWidgets 3.1.1 and later.
@note
In practice, it is only advisable to specify @c wxConvUTF8 as
the @a conv.
If using @c wxMBConvUTF16(), the file should be opened in
@c "wb" mode.
@warning
If a log message contains any characters that cannot be converted
to the character set given by @a conv, that message will be
silently ignored, i.e. it will not be written at all.
*/ */
wxLogStderr(FILE* fp = NULL); wxLogStderr(FILE *fp = NULL,
const wxMBConv &conv = wxConvWhateverWorks);
}; };

View File

@@ -839,7 +839,8 @@ void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
// wxLogStderr class implementation // wxLogStderr class implementation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxLogStderr::wxLogStderr(FILE *fp) wxLogStderr::wxLogStderr(FILE *fp, const wxMBConv &conv):
m_conv(conv.Clone())
{ {
if ( fp == NULL ) if ( fp == NULL )
m_fp = stderr; m_fp = stderr;
@@ -847,12 +848,17 @@ wxLogStderr::wxLogStderr(FILE *fp)
m_fp = fp; m_fp = fp;
} }
wxLogStderr::~wxLogStderr()
{
delete m_conv;
}
void wxLogStderr::DoLogText(const wxString& msg) void wxLogStderr::DoLogText(const wxString& msg)
{ {
// First send it to stderr, even if we don't have it (e.g. in a Windows GUI // First send it to stderr, even if we don't have it (e.g. in a Windows GUI
// application under) it's not a problem to try to use it and it's easier // application under) it's not a problem to try to use it and it's easier
// than determining whether we do have it or not. // than determining whether we do have it or not.
wxMessageOutputStderr(m_fp).Output(msg); wxMessageOutputStderr(m_fp, *m_conv).Output(msg);
// under GUI systems such as Windows or Mac, programs usually don't have // under GUI systems such as Windows or Mac, programs usually don't have
// stderr at all, so show the messages also somewhere else, typically in // stderr at all, so show the messages also somewhere else, typically in
@@ -874,7 +880,8 @@ void wxLogStderr::DoLogText(const wxString& msg)
#if wxUSE_STD_IOSTREAM #if wxUSE_STD_IOSTREAM
#include "wx/ioswrap.h" #include "wx/ioswrap.h"
wxLogStream::wxLogStream(wxSTD ostream *ostr) wxLogStream::wxLogStream(wxSTD ostream *ostr, const wxMBConv &conv):
m_conv(conv.Clone())
{ {
if ( ostr == NULL ) if ( ostr == NULL )
m_ostr = &wxSTD cerr; m_ostr = &wxSTD cerr;
@@ -882,9 +889,30 @@ wxLogStream::wxLogStream(wxSTD ostream *ostr)
m_ostr = ostr; m_ostr = ostr;
} }
wxLogStream::~wxLogStream()
{
delete m_conv;
}
void wxLogStream::DoLogText(const wxString& msg) void wxLogStream::DoLogText(const wxString& msg)
{ {
(*m_ostr) << msg << wxSTD endl; wxString msgLF(msg);
if ( msgLF.empty() || *msgLF.rbegin() != '\n' )
msgLF += '\n';
#if defined(__WINDOWS__)
// Determine whether the encoding is UTF-16. In that case, the file
// should have been opened in "wb" mode, and EOL-style must be handled
// here.
if (m_conv->GetMBNulLen() == 2)
{
msgLF.Replace("\n", "\r\n");
}
#endif
const wxCharBuffer buf = m_conv->cWX2MB(msgLF.c_str());
m_ostr->write(buf, buf.length());
} }
#endif // wxUSE_STD_IOSTREAM #endif // wxUSE_STD_IOSTREAM

View File

@@ -136,6 +136,17 @@ void wxMessageOutputBest::Output(const wxString& str)
// wxMessageOutputStderr // wxMessageOutputStderr
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxMessageOutputStderr::wxMessageOutputStderr(FILE *fp,
const wxMBConv &conv):
m_fp(fp), m_conv(conv.Clone())
{
}
wxMessageOutputStderr::~wxMessageOutputStderr()
{
delete m_conv;
}
wxString wxMessageOutputStderr::AppendLineFeedIfNeeded(const wxString& str) wxString wxMessageOutputStderr::AppendLineFeedIfNeeded(const wxString& str)
{ {
wxString strLF(str); wxString strLF(str);
@@ -147,9 +158,22 @@ wxString wxMessageOutputStderr::AppendLineFeedIfNeeded(const wxString& str)
void wxMessageOutputStderr::Output(const wxString& str) void wxMessageOutputStderr::Output(const wxString& str)
{ {
const wxString strWithLF = AppendLineFeedIfNeeded(str); wxString strWithLF = AppendLineFeedIfNeeded(str);
fprintf(m_fp, "%s", (const char*) strWithLF.mb_str(wxConvWhateverWorks)); #if defined(__WINDOWS__)
// Determine whether the encoding is UTF-16. In that case, the file
// should have been opened in "wb" mode, and EOL-style must be handled
// here.
if (m_conv->GetMBNulLen() == 2)
{
strWithLF.Replace("\n", "\r\n");
}
#endif
const wxCharBuffer buf = m_conv->cWX2MB(strWithLF.c_str());
fwrite(buf, buf.length(), 1, m_fp);
fflush(m_fp); fflush(m_fp);
} }