i18n: fix non-ASCII mangling under default C locale (#203) - #205
Merged
Conversation
Self-contained 2-line idiom that (a) picks LC_CTYPE etc. up from the environment via setlocale(LC_ALL, "") so wxConvLibc emits real UTF-8 instead of mangling non-ASCII bytes under the default "C" locale, and (b) forces LC_NUMERIC back to "C" so libc printf/scanf decimal handling stays portable across user locales (e.g. de_DE.UTF-8 turning "%.2f" of 3.14 into "3,14" silently). Pure addition — no behaviour change in this commit. Callers wired in follow-ups. Refs amule-org#203.
…ing under C locale (amule-project#203) Three binaries that previously did no locale init at all stayed on the default "C" locale for their whole lifetime, which made wxConvLibc (and unicode2char() in StringFunctions.cpp) collapse every non-ASCII codepoint into '?' or escape it. The classic symptom is a filename like "La.mujer.danesa.1x02.Un.niño.destrozado" surfacing as "La.mujer.danesa.1x02.Un.ni\361o" in amuled output, amulecmd, the web UI, etc. Common deployment trigger: Docker / systemd / cron with LANG/LC_ALL unset. Three call-sites: * src/amuled.cpp -- aMuleInitLocale() at the top of CamuleDaemonApp::Initialize(), right after wxAppConsole::Initialize returns and before any wxString -> char* conversion fires. * src/utils/fileview/FileView.cpp -- aMuleInitLocale() at the top of OnInitCmdLine() (CFileView has no OnInit override, so this is the earliest hook wxApp calls). * src/utils/cas/cas.c -- inline setlocale(LC_ALL, "") + LC_NUMERIC=C at the top of main(). cas is plain C, so calling the C++ helper would require linkage shimming for no real win; the inline pair matches the helper's policy verbatim. amule, amule-remote-gui, alc, alcc, and wxcas already drive locale through wxLocale (m_locale.Init() / InitLocale()), so they're left alone -- the wxLocale codepath calls setlocale internally and was never broken in the C-locale sense. amulecmd and amuleweb get migrated to the new helper in a follow-up commit so this commit's diff is just "add calls, no replace". Closes amule-org#203.
…RIC=C) ExternalConnector.cpp has been calling setlocale(LC_ALL, "") for the connector binaries since amule-project#626. That fixed unicode2char() output for non-ASCII filenames but left LC_NUMERIC at whatever the user's locale specified, which silently breaks any libc printf/scanf decimal path under e.g. de_DE.UTF-8 ("%.2f" of 3.14 -> "3,14"). The aMuleInitLocale helper added in the previous commits forces LC_NUMERIC back to "C" after the LC_ALL grab, eliminating that trap. Behaviour change: LC_NUMERIC is now always "C" for amulecmd and amuleweb regardless of the user's environment. Any code that was silently depending on the user-locale decimal separator in those binaries now sees "C" decimal. None known to do so; flagging here so a future bisect can find this line if something surfaces. Refs amule-org#203.
This was referenced Jun 20, 2026
got3nks
added a commit
that referenced
this pull request
Jun 20, 2026
UPnPBase.cpp has four call sites that rely on tolower() producing
ASCII semantics:
* stdStringIsEqualCI / stdStringStartsWithCI -- the two
case-insensitive std::string helpers used throughout the file.
* CUPnPService::Execute -- direct comparison against 'i' and 'n' to
validate the UPnP argument direction string ("in" / "out").
* CUPnPControlPoint::Callback BYEBYE case -- transforms the
discovered device-type URN to lowercase before matching against
UPnP::Device::IGW.
Under tr_TR.UTF-8 (and any other Turkish-locale variant), libc
tolower('I') returns U+0131 (dotless i) instead of 'i'. This
silently breaks UPnP direction validation, device-type matching,
namespace lowercase comparisons, and HTTP-header lowercasing --
amuled's UPnP auto-portforward stops working for Turkish-locale
users.
Before #205 (i18n: fix non-ASCII mangling under default C locale),
amuled stayed on the C locale throughout its lifetime and these
sites were silently safe. The fix in #205 made amuled pick LC_CTYPE
up from the environment so unicode2char() emits real UTF-8 -- which
exposed the latent Turkish-i issue documented above.
Wrap each tolower() scope in CCtypeAsciiScope -- the project's
existing RAII helper that pins LC_CTYPE = "C" for the duration of
its scope and restores it on destruction. Same pattern already used
in CamuleFileConfig.h (#852) and MaxMindDBDatabase.cpp.
amule (GUI) was already exposed to this bug via wxLocale's
setlocale(LC_ALL) on Turkish-language installs; the wrap fixes it
there too as a free side effect.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix #203:
amuledand several smaller binaries depend on the process locale for UTF-8 handling, and mangle non-ASCII text under the defaultC/POSIXlocale common in headless Docker / systemd / cron deployments whereLANG/LC_ALLis unset.aMuleInitLocale()insrc/libs/common/. Callssetlocale(LC_ALL, "")to pick the user's locale up from the environment, then forcesLC_NUMERICback toCso libc printf/scanf decimal handling stays portable (avoids thede_DE.UTF-8trap where"%.2f"of 3.14 silently becomes"3,14").amuled(the reported bug),fileview, andcas(plain C — inline setlocale pair rather than the C++ helper).amulecmd/amulewebfrom the existingsetlocale(LC_ALL, "")atExternalConnector.cpp:681(added in Changelog #626) to the new helper. Behaviour change called out:LC_NUMERICis now alwaysCfor the connectors regardless of the user's environment.Left alone:
amule,amule-remote-gui,alc,alcc,wxcas— they all drive locale throughwxLocale(m_locale.Init()/InitLocale()), which callssetlocaleinternally and is not affected by this class of bug.Test plan
-DBUILD_EVERYTHING=YES. Exit 0, zero new errors, zero new warnings, all touched targets (amuled,amulecmd,amuleweb,fileview,cas) build cleanly.amule,amulegui,alc,alcc,wxcasalso build (unchanged behaviour confirmed).Notes for reviewers
Three commits, each separately revertable:
setlocaleto the helper (small behaviour change:LC_NUMERIC=Cfor amulecmd/amuleweb).