diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7b9ca0ea..a30dc985 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -306,6 +306,7 @@ set(common_SRCS serverlist.cpp pathfinder.cpp convert_json.cpp + gettext.cpp ${JTHREAD_SRCS} ${common_SCRIPT_SRCS} ${UTIL_SRCS} diff --git a/src/cguittfont/irrUString.h b/src/cguittfont/irrUString.h index f41fa1f7..21109ea4 100644 --- a/src/cguittfont/irrUString.h +++ b/src/cguittfont/irrUString.h @@ -205,6 +205,10 @@ inline core::array getUnicodeBOM(EUTF_ENCODE mode) case EUTFE_UTF32_LE: COPY_ARRAY(BOM_ENCODE_UTF32_LE, BOM_ENCODE_UTF32_LEN); break; + case EUTFE_NONE: + // TODO sapier: fixed warning only, + // don't know if something needs to be done here + break; } return ret; @@ -257,7 +261,7 @@ public: _set(c); return *this; } - + //! Increments the value by 1. //! \return Myself. _ustring16_iterator_access& operator++() @@ -392,7 +396,7 @@ public: return unicode::toUTF32(a[pos], a[pos + 1]); } } - + //! Sets a uchar32_t at our current position. void _set(uchar32_t c) { @@ -707,7 +711,6 @@ public: //! Moves the iterator to the end of the string. void toEnd() { - const uchar16_t* a = ref->c_str(); pos = ref->size_raw(); } @@ -732,12 +735,13 @@ public: typedef typename _Base::const_pointer const_pointer; typedef typename _Base::const_reference const_reference; + typedef typename _Base::value_type value_type; typedef typename _Base::difference_type difference_type; typedef typename _Base::distance_type distance_type; typedef access pointer; typedef access reference; - + using _Base::pos; using _Base::ref; @@ -2096,7 +2100,7 @@ public: } #endif - + //! Appends a number to this ustring16. //! \param c Number to append. //! \return A reference to our current string. @@ -2958,7 +2962,7 @@ public: if (endian != unicode::EUTFEE_NATIVE && getEndianness() != endian) { for (u32 i = 0; i <= used; ++i) - *ptr++ = unicode::swapEndian16(*ptr); + ptr[i] = unicode::swapEndian16(ptr[i]); } ret.set_used(used + (addBOM ? unicode::BOM_UTF16_LEN : 0)); ret.push_back(0); diff --git a/src/gettext.cpp b/src/gettext.cpp new file mode 100644 index 00000000..455c7858 --- /dev/null +++ b/src/gettext.cpp @@ -0,0 +1,259 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include +#include +#include +#include "gettext.h" +#include "util/string.h" + +#if USE_GETTEXT and defined(_MSC_VER) +#include +#include +#include +#include "filesys.h" + +#define setlocale(category,localename) \ + setlocale(category,MSVC_LocaleLookup(localename)) + +static std::map glb_supported_locales; + +/******************************************************************************/ +BOOL CALLBACK UpdateLocaleCallback(LPTSTR pStr) +{ + char* endptr = 0; + int LOCALEID = strtol(pStr,&endptr,16); + + wchar_t buffer[LOCALE_NAME_MAX_LENGTH]; + memset(buffer,0,sizeof(buffer)); + if (GetLocaleInfoW( + LOCALEID, + LOCALE_SISO639LANGNAME, + buffer, + LOCALE_NAME_MAX_LENGTH)) { + + std::wstring name = buffer; + + memset(buffer,0,sizeof(buffer)); + GetLocaleInfoW( + LOCALEID, + LOCALE_SISO3166CTRYNAME, + buffer, + LOCALE_NAME_MAX_LENGTH); + + std::wstring country = buffer; + + memset(buffer,0,sizeof(buffer)); + GetLocaleInfoW( + LOCALEID, + LOCALE_SENGLISHLANGUAGENAME, + buffer, + LOCALE_NAME_MAX_LENGTH); + + std::wstring languagename = buffer; + + /* set both short and long variant */ + glb_supported_locales[name] = languagename; + glb_supported_locales[name + L"_" + country] = languagename; + } + return true; +} + +/******************************************************************************/ +const char* MSVC_LocaleLookup(const char* raw_shortname) { + + /* NULL is used to read locale only so we need to return it too */ + if (raw_shortname == NULL) return NULL; + + std::string shortname(raw_shortname); + if (shortname == "C") return "C"; + if (shortname == "") return ""; + + static std::string last_raw_value = ""; + static std::string last_full_name = ""; + static bool first_use = true; + + if (last_raw_value == shortname) { + return last_full_name.c_str(); + } + + if (first_use) { + EnumSystemLocalesA(UpdateLocaleCallback,LCID_SUPPORTED | LCID_ALTERNATE_SORTS); + first_use = false; + } + + last_raw_value = shortname; + + if (glb_supported_locales.find(narrow_to_wide(shortname)) != glb_supported_locales.end()) { + last_full_name = wide_to_narrow(glb_supported_locales[narrow_to_wide(shortname)]); + return last_full_name.c_str(); + } + + /* empty string is system default */ + errorstream << "MSVC_LocaleLookup: unsupported locale: \"" << shortname + << "\" switching to system default!" << std::endl; + return ""; +} + +#endif + +/******************************************************************************/ +#ifdef _MSC_VER +void init_gettext(const char *path,std::string configured_language,int argc, char** argv) { +#else +void init_gettext(const char *path,std::string configured_language) { +#endif +#if USE_GETTEXT + /** first try to set user override environment **/ + if (configured_language.length() != 0) { +#ifndef _WIN32 + /* add user specified locale to environment */ + setenv("LANGUAGE", configured_language.c_str(), 1); + + /* reload locale with changed environment */ + setlocale(LC_ALL, ""); +#elif defined(_MSC_VER) + std::string current_language_var(""); + if (getenv("LANGUAGE") != 0) { + current_language_var = std::string(getenv("LANGUAGE")); + } + + char *lang_str = (char*)calloc(10 + configured_language.length(), sizeof(char)); + strcat(lang_str, "LANGUAGE="); + strcat(lang_str, configured_language.c_str()); + putenv(lang_str); + + SetEnvironmentVariableA("LANGUAGE",configured_language.c_str()); + + //very very dirty workaround to force gettext to see the right environment + if (current_language_var != configured_language) { + STARTUPINFO startupinfo; + PROCESS_INFORMATION processinfo; + memset(&startupinfo,0,sizeof(startupinfo)); + memset(&processinfo,0,sizeof(processinfo)); + errorstream << "MSVC localization workaround aktive restating minetest in new environment!" << std::endl; + + std::string parameters = ""; + + for (unsigned int i=1;i < argc; i++) { + if (parameters != "") { + parameters += " "; + } + parameters += argv[i]; + } + + const char* ptr_parameters = 0; + + if (parameters != "") { + ptr_parameters = parameters.c_str(); + } + + /** users may start by short name in commandline without extention **/ + std::string appname = argv[0]; + if (appname.substr(appname.length() -4) != ".exe") { + appname += ".exe"; + } + + if (!CreateProcess(appname.c_str(), + (char*) ptr_parameters, + NULL, + NULL, + false, + DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT, + NULL, + NULL, + &startupinfo, + &processinfo)) { + char buffer[1024]; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + buffer, + sizeof(buffer)-1, + NULL); + errorstream << "*******************************************************" << std::endl; + errorstream << "CMD: " << appname << std::endl; + errorstream << "Failed to restart with current locale: " << std::endl; + errorstream << buffer; + errorstream << "Expect language to be broken!" << std::endl; + errorstream << "*******************************************************" << std::endl; + } + else { + exit(0); + } + } + + setlocale(LC_ALL,configured_language.c_str()); +#else // Mingw + char *lang_str = (char*)calloc(10 + configured_language.length(), sizeof(char)); + strcat(lang_str, "LANGUAGE="); + strcat(lang_str, configured_language.c_str()); + putenv(lang_str); + + setlocale(LC_ALL, ""); +#endif // ifndef _WIN32 + } + else { + /* set current system default locale */ + setlocale(LC_ALL, ""); + } + +#if defined(_WIN32) + if (getenv("LANGUAGE") != 0) { + setlocale(LC_ALL, getenv("LANGUAGE")); + } +#ifdef _MSC_VER + else if (getenv("LANG") != 0) { + setlocale(LC_ALL, getenv("LANG")); + } +#endif +#endif + + bindtextdomain(PROJECT_NAME, path); + textdomain(PROJECT_NAME); + +#if defined(_WIN32) + // Set character encoding for Win32 + char *tdomain = textdomain( (char *) NULL ); + if( tdomain == NULL ) + { + errorstream << "Warning: domainname parameter is the null pointer" << + ", default domain is not set" << std::endl; + tdomain = (char *) "messages"; + } + /* char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" ); + //errorstream << "Gettext debug: domainname = " << tdomain << "; codeset = "<< codeset << std::endl; +#endif // defined(_WIN32) + + /* no matter what locale is used we need number format to be "C" */ + /* to ensure formspec parameters are evaluated correct! */ + + + setlocale(LC_NUMERIC,"C"); + infostream << "Message locale is now set to: " + << setlocale(LC_ALL,0) << std::endl; + +#endif // if USE_GETTEXT +} + + + + diff --git a/src/gettext.h b/src/gettext.h index fd32e082..862274a3 100644 --- a/src/gettext.h +++ b/src/gettext.h @@ -1,4 +1,25 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + #ifndef GETTEXT_HEADER +#define GETTEXT_HEADER + #include "config.h" // for USE_GETTEXT #include "log.h" @@ -18,34 +39,16 @@ #define _WIN32_WINNT 0x0501 #endif #include + +#endif // #if defined(_WIN32) + +#ifdef _MSC_VER +void init_gettext(const char *path,std::string configured_language,int argc, char** argv); +#else +void init_gettext(const char *path,std::string configured_language); #endif -inline void init_gettext(const char *path) { -#if USE_GETTEXT - // don't do this if MSVC compiler is used, it gives an assertion fail - #ifndef _MSC_VER - setlocale(LC_MESSAGES, ""); - #endif - bindtextdomain(PROJECT_NAME, path); - textdomain(PROJECT_NAME); -#if defined(_WIN32) - // As linux is successfully switched to UTF-8 completely at about year 2005 - // Windows still uses obsolete codepage based locales because you - // cannot recompile closed-source applications - - // Set character encoding for Win32 - char *tdomain = textdomain( (char *) NULL ); - if( tdomain == NULL ) - { - fprintf( stderr, "warning: domainname parameter is the null pointer, default domain is not set\n" ); - tdomain = (char *) "messages"; - } - /*char *codeset = */bind_textdomain_codeset( tdomain, "UTF-8" ); - //fprintf( stdout, "%s: debug: domainname = %s; codeset = %s\n", argv[0], tdomain, codeset ); -#endif // defined(_WIN32) -#endif -} - +/******************************************************************************/ inline wchar_t* chartowchar_t(const char *str) { wchar_t* nstr = 0; @@ -69,26 +72,18 @@ inline wchar_t* chartowchar_t(const char *str) return nstr; } +/******************************************************************************/ inline wchar_t* wgettext(const char *str) { return chartowchar_t(gettext(str)); } -inline void changeCtype(const char *l) -{ - /*char *ret = NULL; - ret = setlocale(LC_CTYPE, l); - if(ret == NULL) - infostream<<"locale could not be set"< rect(0, 0, 400, 50); rect = rect + v2s32(size.X/2-400/2, size.Y/2-50/2-25); @@ -108,7 +108,6 @@ void GUIDeathScreen::regenerateGui(v2u32 screensize) delete[] text; Environment->setFocus(e); } - changeCtype("C"); } void GUIDeathScreen::drawMenu() diff --git a/src/guiFileSelectMenu.cpp b/src/guiFileSelectMenu.cpp index 54ab62df..e98b025c 100644 --- a/src/guiFileSelectMenu.cpp +++ b/src/guiFileSelectMenu.cpp @@ -31,13 +31,11 @@ GUIModalMenu(env, parent, id, menumgr) m_formname = formname; m_text_dst = 0; m_accepted = false; - m_previous_locale = setlocale(LC_ALL,0); } GUIFileSelectMenu::~GUIFileSelectMenu() { removeChildren(); - setlocale(LC_ALL,m_previous_locale.c_str()); } void GUIFileSelectMenu::removeChildren() diff --git a/src/guiFileSelectMenu.h b/src/guiFileSelectMenu.h index 987a9f2e..e37d3d8d 100644 --- a/src/guiFileSelectMenu.h +++ b/src/guiFileSelectMenu.h @@ -66,8 +66,6 @@ private: gui::IGUIFileOpenDialog* m_fileOpenDialog; - std::string m_previous_locale; - bool m_running; TextDest *m_text_dst; diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index aa1e2d9c..eecd2c1b 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -1629,7 +1629,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) std::vector elements = split(m_formspec_string,']'); - for (unsigned int i=0;i< elements.size();i++) { parseElement(&mydata,elements[i]); } @@ -1648,7 +1647,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) recalculateAbsolutePosition(false); mydata.basepos = getBasePos(); - changeCtype(""); { v2s32 pos = mydata.basepos; pos.Y = ((m_fields.size()+2)*60); @@ -1659,7 +1657,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) Environment->addButton(mydata.rect, this, 257, text); delete[] text; } - changeCtype("C"); + } //set initial focus if parser didn't set it diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp index c660ed87..85222431 100644 --- a/src/guiKeyChangeMenu.cpp +++ b/src/guiKeyChangeMenu.cpp @@ -113,7 +113,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) recalculateAbsolutePosition(false); v2s32 topleft(0, 0); - changeCtype(""); + { core::rect < s32 > rect(0, 0, 600, 40); rect += topleft + v2s32(25, 3); @@ -196,9 +196,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON, text ); delete[] text; - } - changeCtype("C"); - + } } void GUIKeyChangeMenu::drawMenu() @@ -265,7 +263,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0 && event.KeyInput.PressedDown) { - changeCtype(""); + bool prefer_character = shift_down; KeyPress kp(event.KeyInput, prefer_character); @@ -313,7 +311,6 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) this->key_used.push_back(kp); - changeCtype("C"); // Allow characters made with shift if(shift_went_down){ shift_down = true; @@ -339,12 +336,6 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) } if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) { - if(event.GUIEvent.Caller->getID() != GUI_ID_BACK_BUTTON && - event.GUIEvent.Caller->getID() != GUI_ID_ABORT_BUTTON) - { - changeCtype(""); - } - switch (event.GUIEvent.Caller->getID()) { case GUI_ID_BACK_BUTTON: //back @@ -377,8 +368,6 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) break; } Environment->setFocus(this); - //Buttons - changeCtype("C"); } } return Parent ? Parent->OnEvent(event) : false; diff --git a/src/guiMessageMenu.cpp b/src/guiMessageMenu.cpp index c6592e51..dd9c0a26 100644 --- a/src/guiMessageMenu.cpp +++ b/src/guiMessageMenu.cpp @@ -99,7 +99,7 @@ void GUIMessageMenu::regenerateGui(v2u32 screensize) Environment->addStaticText(m_message_text.c_str(), rect, false, true, this, -1); } - changeCtype(""); + int bw = 140; { core::rect rect(0, 0, bw, 30); @@ -111,7 +111,6 @@ void GUIMessageMenu::regenerateGui(v2u32 screensize) Environment->setFocus(e); delete[] text; } - changeCtype("C"); } void GUIMessageMenu::drawMenu() diff --git a/src/guiPasswordChange.cpp b/src/guiPasswordChange.cpp index 8b55234c..c8a2214b 100644 --- a/src/guiPasswordChange.cpp +++ b/src/guiPasswordChange.cpp @@ -100,7 +100,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) Add stuff */ s32 ypos = 50; - changeCtype(""); { core::rect rect(0, 0, 110, 20); rect += topleft_client + v2s32(35, ypos+6); @@ -108,7 +107,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) Environment->addStaticText(text, rect, false, true, this, -1); delete[] text; } - changeCtype("C"); { core::rect rect(0, 0, 230, 30); rect += topleft_client + v2s32(160, ypos); @@ -118,7 +116,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) e->setPasswordBox(true); } ypos += 50; - changeCtype(""); { core::rect rect(0, 0, 110, 20); rect += topleft_client + v2s32(35, ypos+6); @@ -126,7 +123,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) Environment->addStaticText(text, rect, false, true, this, -1); delete[] text; } - changeCtype("C"); { core::rect rect(0, 0, 230, 30); rect += topleft_client + v2s32(160, ypos); @@ -135,7 +131,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) e->setPasswordBox(true); } ypos += 50; - changeCtype(""); { core::rect rect(0, 0, 110, 20); rect += topleft_client + v2s32(35, ypos+6); @@ -143,7 +138,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) Environment->addStaticText(text, rect, false, true, this, -1); delete[] text; } - changeCtype("C"); { core::rect rect(0, 0, 230, 30); rect += topleft_client + v2s32(160, ypos); @@ -153,7 +147,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) } ypos += 50; - changeCtype(""); { core::rect rect(0, 0, 140, 30); rect = rect + v2s32(size.X/2-140/2, ypos); @@ -174,8 +167,6 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) e->setVisible(false); delete[] text; } - changeCtype("C"); - } void GUIPasswordChange::drawMenu() diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp index ba103b74..d7a51488 100644 --- a/src/guiPauseMenu.cpp +++ b/src/guiPauseMenu.cpp @@ -116,7 +116,6 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize) const s32 btn_gap = 20; const s32 btn_num = m_simple_singleplayer_mode ? 4 : 5; s32 btn_y = size.Y/2-((btn_num*btn_height+(btn_num-1)*btn_gap))/2; - changeCtype(""); { core::rect rect(0, 0, 140, btn_height); rect = rect + v2s32(size.X/2-140/2, btn_y); @@ -201,7 +200,6 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize) Environment->addStaticText(narrow_to_wide(os.str()).c_str(), rect, false, true, this, 259); } - changeCtype("C"); } void GUIPauseMenu::drawMenu() diff --git a/src/guiTextInputMenu.cpp b/src/guiTextInputMenu.cpp index 9285aaa8..535bf497 100644 --- a/src/guiTextInputMenu.cpp +++ b/src/guiTextInputMenu.cpp @@ -133,7 +133,6 @@ void GUITextInputMenu::regenerateGui(v2u32 screensize) evt.KeyInput.Shift = 0; e->OnEvent(evt); } - changeCtype(""); { core::rect rect(0, 0, 140, 30); rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25); @@ -142,7 +141,6 @@ void GUITextInputMenu::regenerateGui(v2u32 screensize) text); delete[] text; } - changeCtype("C"); } void GUITextInputMenu::drawMenu() diff --git a/src/guiVolumeChange.cpp b/src/guiVolumeChange.cpp index 2f462b77..5e7476bb 100644 --- a/src/guiVolumeChange.cpp +++ b/src/guiVolumeChange.cpp @@ -101,7 +101,6 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize) /* Add stuff */ - changeCtype(""); { core::rect rect(0, 0, 120, 20); rect = rect + v2s32(size.X/2-60, size.Y/2-35); @@ -132,7 +131,6 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize) e->setMax(100); e->setPos(volume); } - changeCtype(""); } void GUIVolumeChange::drawMenu() diff --git a/src/main.cpp b/src/main.cpp index 455138d5..ea66f133 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -750,20 +750,6 @@ int main(int argc, char *argv[]) log_add_output_all_levs(&main_dstream_no_stderr_log_out); log_register_thread("main"); - - // This enables internatonal characters input - if( setlocale(LC_ALL, "") == NULL ) - { - fprintf( stderr, "%s: warning: could not set default locale\n", argv[0] ); - } - - // Set locale. This is for forcing '.' as the decimal point. - try { - std::locale::global(std::locale(std::locale(""), "C", std::locale::numeric)); - setlocale(LC_NUMERIC, "C"); - } catch (const std::exception& ex) { - errorstream<<"Could not set numeric locale to C"<get("language"),argc,argv); #else - char *lang_str = (char*)calloc(10 + language.length(), sizeof(char)); - strcat(lang_str, "LANGUAGE="); - strcat(lang_str, language.c_str()); - putenv(lang_str); + init_gettext((porting::path_share + DIR_DELIM + "locale").c_str(),g_settings->get("language")); #endif - } /* Game parameters diff --git a/src/util/pointer.h b/src/util/pointer.h index f6568333..ba43b784 100644 --- a/src/util/pointer.h +++ b/src/util/pointer.h @@ -197,6 +197,7 @@ public: else data = NULL; refcount = new unsigned int; + memset(data,0,sizeof(T)*m_size); (*refcount) = 1; } SharedBuffer(const SharedBuffer &buffer) diff --git a/src/util/string.cpp b/src/util/string.cpp index a2312baf..39a14598 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -41,8 +41,9 @@ std::string wide_to_narrow(const std::wstring& wcs) size_t mbl = wcs.size()*4; SharedBuffer mbs(mbl+1); size_t l = wcstombs(*mbs, wcs.c_str(), mbl); - if(l == (size_t)(-1)) - mbs[0] = 0; + if(l == (size_t)(-1)) { + return "Character conversion failed!"; + } else mbs[l] = 0; return *mbs;