Refactor wxLog and wxMessageOutput classes to avoid duplication

Add wxMessageOutputWithConv mix-in class to avoid duplicating the same
code in wxLogStream and wxMessageOutputStderr.

Also derive wxLogStderr from wxMessageOutputStderr to reuse its code
without having to create a temporary object of this type (which will be
more expensive now that doing it involves creating a heap-allocated
conversion object copy).
This commit is contained in:
Vadim Zeitlin
2017-10-21 22:06:08 +02:00
parent 6b73bd9136
commit a7dddd9f3b
4 changed files with 72 additions and 74 deletions

View File

@@ -61,6 +61,7 @@ class WXDLLIMPEXP_FWD_BASE wxObject;
#include "wx/dynarray.h" #include "wx/dynarray.h"
#include "wx/hashmap.h" #include "wx/hashmap.h"
#include "wx/msgout.h"
#if wxUSE_THREADS #if wxUSE_THREADS
#include "wx/thread.h" #include "wx/thread.h"
@@ -716,34 +717,31 @@ private:
// log everything to a "FILE *", stderr by default // log everything to a "FILE *", stderr by default
class WXDLLIMPEXP_BASE wxLogStderr : public wxLog class WXDLLIMPEXP_BASE wxLogStderr : public wxLog,
private wxMessageOutputStderr
{ {
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); 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;
const wxMBConv *m_conv;
wxDECLARE_NO_COPY_CLASS(wxLogStderr); wxDECLARE_NO_COPY_CLASS(wxLogStderr);
}; };
#if wxUSE_STD_IOSTREAM #if wxUSE_STD_IOSTREAM
// log everything to an "ostream", cerr by default // log everything to an "ostream", cerr by default
class WXDLLIMPEXP_BASE wxLogStream : public wxLog class WXDLLIMPEXP_BASE wxLogStream : public wxLog,
private wxMessageOutputWithConv
{ {
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); const wxMBConv& conv = wxConvWhateverWorks);
virtual ~wxLogStream();
protected: protected:
// implement sink function // implement sink function
@@ -751,7 +749,8 @@ 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;
wxDECLARE_NO_COPY_CLASS(wxLogStream);
}; };
#endif // wxUSE_STD_IOSTREAM #endif // wxUSE_STD_IOSTREAM

View File

@@ -58,25 +58,51 @@ private:
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// implementation which sends output to stderr or specified file // helper mix-in for output targets that can use difference encodings
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class WXDLLIMPEXP_BASE wxMessageOutputStderr : public wxMessageOutput class WXDLLIMPEXP_BASE wxMessageOutputWithConv
{ {
public:
wxMessageOutputStderr(FILE *fp = stderr,
const wxMBConv &conv = wxConvWhateverWorks);
virtual ~wxMessageOutputStderr();
virtual void Output(const wxString& str) wxOVERRIDE;
protected: protected:
explicit wxMessageOutputWithConv(const wxMBConv& conv)
: m_conv(conv.Clone())
{
}
~wxMessageOutputWithConv()
{
delete m_conv;
}
// return the string with "\n" appended if it doesn't already terminate // return the string with "\n" appended if it doesn't already terminate
// with it (in which case it's returned unchanged) // with it (in which case it's returned unchanged)
wxString AppendLineFeedIfNeeded(const wxString& str); wxString AppendLineFeedIfNeeded(const wxString& str);
// Prepare the given string for output by appending a new line to it, if
// necessary, and converting it to a narrow string using our conversion
// object.
wxCharBuffer PrepareForOutput(const wxString& str);
const wxMBConv* const m_conv;
};
// ----------------------------------------------------------------------------
// implementation which sends output to stderr or specified file
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_BASE wxMessageOutputStderr : public wxMessageOutput,
protected wxMessageOutputWithConv
{
public:
wxMessageOutputStderr(FILE *fp = stderr,
const wxMBConv &conv = wxConvWhateverWorks);
virtual void Output(const wxString& str) wxOVERRIDE;
protected:
FILE *m_fp; FILE *m_fp;
const wxMBConv *m_conv;
wxDECLARE_NO_COPY_CLASS(wxMessageOutputStderr);
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -839,18 +839,9 @@ void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
// wxLogStderr class implementation // wxLogStderr class implementation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxLogStderr::wxLogStderr(FILE *fp, const wxMBConv &conv): wxLogStderr::wxLogStderr(FILE *fp, const wxMBConv& conv)
m_conv(conv.Clone()) : wxMessageOutputStderr(fp ? fp : stderr, conv)
{ {
if ( fp == NULL )
m_fp = stderr;
else
m_fp = fp;
}
wxLogStderr::~wxLogStderr()
{
delete m_conv;
} }
void wxLogStderr::DoLogText(const wxString& msg) void wxLogStderr::DoLogText(const wxString& msg)
@@ -858,7 +849,7 @@ 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, *m_conv).Output(msg); wxMessageOutputStderr::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
@@ -880,8 +871,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, const wxMBConv &conv): wxLogStream::wxLogStream(wxSTD ostream *ostr, const wxMBConv& conv)
m_conv(conv.Clone()) : wxMessageOutputWithConv(conv)
{ {
if ( ostr == NULL ) if ( ostr == NULL )
m_ostr = &wxSTD cerr; m_ostr = &wxSTD cerr;
@@ -889,29 +880,9 @@ m_conv(conv.Clone())
m_ostr = ostr; m_ostr = ostr;
} }
wxLogStream::~wxLogStream()
{
delete m_conv;
}
void wxLogStream::DoLogText(const wxString& msg) void wxLogStream::DoLogText(const wxString& msg)
{ {
wxString msgLF(msg); const wxCharBuffer& buf = PrepareForOutput(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()); m_ostr->write(buf, buf.length());
} }
#endif // wxUSE_STD_IOSTREAM #endif // wxUSE_STD_IOSTREAM

View File

@@ -133,21 +133,10 @@ void wxMessageOutputBest::Output(const wxString& str)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxMessageOutputStderr // wxMessageOutputWithConv
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxMessageOutputStderr::wxMessageOutputStderr(FILE *fp, wxString wxMessageOutputWithConv::AppendLineFeedIfNeeded(const wxString& str)
const wxMBConv &conv):
m_fp(fp), m_conv(conv.Clone())
{
}
wxMessageOutputStderr::~wxMessageOutputStderr()
{
delete m_conv;
}
wxString wxMessageOutputStderr::AppendLineFeedIfNeeded(const wxString& str)
{ {
wxString strLF(str); wxString strLF(str);
if ( strLF.empty() || *strLF.rbegin() != '\n' ) if ( strLF.empty() || *strLF.rbegin() != '\n' )
@@ -156,23 +145,36 @@ wxString wxMessageOutputStderr::AppendLineFeedIfNeeded(const wxString& str)
return strLF; return strLF;
} }
void wxMessageOutputStderr::Output(const wxString& str) wxCharBuffer wxMessageOutputWithConv::PrepareForOutput(const wxString& str)
{ {
wxString strWithLF = AppendLineFeedIfNeeded(str); wxString strWithLF = AppendLineFeedIfNeeded(str);
#if defined(__WINDOWS__) #if defined(__WINDOWS__)
// Determine whether the encoding is UTF-16. In that case, the file // 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 // should have been opened in "wb" mode, and EOL conversion must be done
// here. // here as it won't be done at stdio level.
if ( m_conv->GetMBNulLen() == 2 )
if (m_conv->GetMBNulLen() == 2)
{ {
strWithLF.Replace("\n", "\r\n"); strWithLF.Replace("\n", "\r\n");
} }
#endif #endif // __WINDOWS__
const wxCharBuffer buf = m_conv->cWX2MB(strWithLF.c_str()); return m_conv->cWX2MB(strWithLF.c_str());
}
// ----------------------------------------------------------------------------
// wxMessageOutputStderr
// ----------------------------------------------------------------------------
wxMessageOutputStderr::wxMessageOutputStderr(FILE *fp, const wxMBConv& conv)
: wxMessageOutputWithConv(conv),
m_fp(fp)
{
}
void wxMessageOutputStderr::Output(const wxString& str)
{
const wxCharBuffer& buf = PrepareForOutput(str);
fwrite(buf, buf.length(), 1, m_fp); fwrite(buf, buf.length(), 1, m_fp);
fflush(m_fp); fflush(m_fp);
} }