Skip to content

Commit

Permalink
Pass --no-convert to msgfmt with gettext >= 0.22
Browse files Browse the repository at this point in the history
GNU gettext 0.22 started converting MO files to UTF-8 by default as an optimization for mainly
Linux distros. See
https://git.savannah.gnu.org/gitweb/?p=gettext.git;a=commit;h=5412a4f79929004cb6db15d545e07dc953330e8d

This can however be problematic with other runtimes, so explicitly disable this functionality
and pass --no-convert to msgfmt. This option was only added in 0.22, so this also necessitates
checking gettext version.
  • Loading branch information
vslavik committed Mar 25, 2024
1 parent 2ba1a57 commit d6c69b4
Showing 1 changed file with 101 additions and 36 deletions.
137 changes: 101 additions & 36 deletions src/gexecute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,15 @@ wxString GetPathToAuxBinary(const wxString& program)
#endif // __WXOSX__ || __WXMSW__


bool ReadOutput(wxInputStream& s, wxArrayString& out)
struct ProcessOutput
{
long return_code = -1;
std::vector<wxString> std_out;
std::vector<wxString> std_err;
};


bool ReadOutput(wxInputStream& s, std::vector<wxString>& out)
{
// the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state
s.Reset();
Expand Down Expand Up @@ -115,15 +123,95 @@ bool ReadOutput(wxInputStream& s, wxArrayString& out)
return true;
}

std::pair<long, wxArrayString> DoExecuteGettextImpl(const wxString& cmdline_)

ProcessOutput ExecuteCommandAndCaptureOutput(const wxString& cmdline, const wxExecuteEnv *env)
{
ProcessOutput pout;

wxLogTrace("poedit.execute", "executing: %s", cmdline.c_str());

wxScopedPtr<wxProcess> process(new wxProcess);
process->Redirect();

pout.return_code = wxExecute(cmdline, wxEXEC_BLOCK | wxEXEC_NODISABLE | wxEXEC_NOEVENTS, process.get(), env);
if (pout.return_code != 0)
{
wxLogTrace("poedit.execute", " execution of command failed with exit code %d: %s", (int)pout.return_code, cmdline.c_str());
}

wxInputStream *std_out = process->GetInputStream();
if ( std_out && !ReadOutput(*std_out, pout.std_out) )
pout.return_code = -1;

wxInputStream *std_err = process->GetErrorStream();
if ( std_err && !ReadOutput(*std_err, pout.std_err) )
pout.return_code = -1;

if ( pout.return_code == -1 )
{
BOOST_THROW_EXCEPTION(Exception(wxString::Format(_("Cannot execute program: %s"), cmdline.c_str())));
}

return pout;
}


#define GETTEXT_VERSION_NUM(x, y, z) ((x*1000*1000) + (y*1000) + (z))

// Determine gettext version, return it in the form of XXXYYYZZZ number for version x.y.z
uint32_t GetGettextVersion(const wxString& someGettextBinary)
{
static uint32_t s_version = 0;
if (!s_version)
{
// set old enough fallback version
s_version = GETTEXT_VERSION_NUM(0, 18, 0);

// then determine actual version
auto p = ExecuteCommandAndCaptureOutput(someGettextBinary + " --version", nullptr);
if (p.return_code == 0 && p.std_out.size() > 1)
{
auto line = p.std_out[0].utf8_string();
std::smatch m;
if (std::regex_match(line, m, std::regex(R"(.* (([0-9]+)\.([0-9]+)(\.([0-9]+))?)$)")))
{
const int x = std::stoi(m.str(2));
const int y = std::stoi(m.str(3));
const int z = m[5].matched ? std::stoi(m.str(5)) : 0;
s_version = GETTEXT_VERSION_NUM(x, y, z);
}
}
}
return s_version;
}


wxString GetAuxBinaryInvocationCommand(const wxString& binary)
{
auto exe = GetPathToAuxBinary(binary);

// gettext 0.22 started converting MO files to UTF-8 by default. Don't do that.
// See https://git.savannah.gnu.org/gitweb/?p=gettext.git;a=commit;h=5412a4f79929004cb6db15d545e07dc953330e8d
if (binary == "msgfmt" && GetGettextVersion(exe) >= GETTEXT_VERSION_NUM(0, 22, 0))
{
exe += " --no-convert";
}

return exe;
}


ProcessOutput DoExecuteGettextImpl(const wxString& cmdline_)
{
wxArrayString gstderr;
ProcessOutput pout;

wxExecuteEnv env;
wxString cmdline(cmdline_);

#if defined(__WXOSX__) || defined(__WXMSW__)
wxString binary = cmdline.BeforeFirst(_T(' '));
cmdline = GetPathToAuxBinary(binary) + cmdline.Mid(binary.length());
wxString args = cmdline.Mid(binary.length());
cmdline = GetAuxBinaryInvocationCommand(binary) + args;
wxGetEnvMap(&env.env);
env.env["OUTPUT_CHARSET"] = "UTF-8";

Expand All @@ -134,30 +222,11 @@ std::pair<long, wxArrayString> DoExecuteGettextImpl(const wxString& cmdline_)
env.env["LANG"] = lang;
#endif // __WXOSX__ || __WXMSW__

wxLogTrace("poedit.execute", "executing: %s", cmdline.c_str());

wxScopedPtr<wxProcess> process(new wxProcess);
process->Redirect();

long retcode = wxExecute(cmdline, wxEXEC_BLOCK | wxEXEC_NODISABLE | wxEXEC_NOEVENTS, process.get(), &env);
if (retcode != 0)
{
wxLogTrace("poedit.execute", " execution of command failed with exit code %d: %s", (int)retcode, cmdline.c_str());
}

wxInputStream *std_err = process->GetErrorStream();
if ( std_err && !ReadOutput(*std_err, gstderr) )
retcode = -1;

if ( retcode == -1 )
{
BOOST_THROW_EXCEPTION(Exception(wxString::Format(_("Cannot execute program: %s"), cmdline.c_str())));
}

return std::make_pair(retcode, gstderr);
return ExecuteCommandAndCaptureOutput(cmdline, &env);
}

std::pair<long, wxArrayString> DoExecuteGettext(const wxString& cmdline)

ProcessOutput DoExecuteGettext(const wxString& cmdline)
{
#if wxUSE_GUI
if (wxThread::IsMain())
Expand Down Expand Up @@ -194,12 +263,10 @@ void LogUnrecognizedError(const wxString& err)

bool ExecuteGettext(const wxString& cmdline)
{
wxArrayString gstderr;
long retcode;
std::tie(retcode, gstderr) = DoExecuteGettext(cmdline);
auto output = DoExecuteGettext(cmdline);

wxString pending;
for (auto& ln: gstderr)
for (auto& ln: output.std_err)
{
if (ln.empty())
continue;
Expand All @@ -221,19 +288,17 @@ bool ExecuteGettext(const wxString& cmdline)
if (!pending.empty())
LogUnrecognizedError(pending);

return retcode == 0;
return output.return_code == 0;
}


bool ExecuteGettextAndParseOutput(const wxString& cmdline, GettextErrors& errors)
{
wxArrayString gstderr;
long retcode;
std::tie(retcode, gstderr) = DoExecuteGettext(cmdline);
auto output = DoExecuteGettext(cmdline);

static const std::wregex RE_ERROR(L".*\\.po:([0-9]+)(:[0-9]+)?: (.*)");

for (const auto& ewx: gstderr)
for (const auto& ewx: output.std_err)
{
const auto e = ewx.ToStdWstring();
wxLogTrace("poedit", " stderr: %s", e.c_str());
Expand All @@ -259,7 +324,7 @@ bool ExecuteGettextAndParseOutput(const wxString& cmdline, GettextErrors& errors
}
}

return retcode == 0;
return output.return_code == 0;
}


Expand Down

0 comments on commit d6c69b4

Please sign in to comment.