From 59a8dfe83396a4ced99f95f18b3fc4feed286507 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sun, 18 Dec 2016 17:19:57 +0100 Subject: [PATCH] Convert args to UTF-8 under Windows --- CMakeLists.txt | 4 ++-- application/commandlineutils.cpp | 36 ++++++++++++++++++++++++++++++++ application/commandlineutils.h | 16 ++++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 210aacd..f55dae5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,8 +112,8 @@ set(META_APP_AUTHOR "Martchus") set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}") set(META_APP_DESCRIPTION "Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities") set(META_VERSION_MAJOR 4) -set(META_VERSION_MINOR 3) -set(META_VERSION_PATCH 1) +set(META_VERSION_MINOR 4) +set(META_VERSION_PATCH 0) # find required 3rd party libraries include(3rdParty) diff --git a/application/commandlineutils.cpp b/application/commandlineutils.cpp index a1f44b7..b16f73b 100644 --- a/application/commandlineutils.cpp +++ b/application/commandlineutils.cpp @@ -73,6 +73,42 @@ void startConsole() // sync ios::sync_with_stdio(true); } + +/*! + * \brief Convert command line arguments to UTF-8. + * \remarks Only available on Windows (on other platforms we can assume passed arguments are already UTF-8 encoded). + */ +pair >, vector > convertArgsToUtf8() +{ + pair >, vector > res; + int argc; + + LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc); + if(!argv_w || argc <= 0) { + return res; + } + + res.first.reserve(static_cast(argc)); + res.second.reserve(static_cast(argc)); + for(; argv_w; ++argv_w) { + int requiredSize = WideCharToMultiByte(CP_UTF8, 0, *argv_w, -1, nullptr, 0, 0, 0); + if(requiredSize <= 0) { + break; // just stop on error + } + + auto argv = make_unique(static_cast(requiredSize)); + requiredSize = WideCharToMultiByte(CP_UTF8, 0, *argv_w, -1, argv.get(), requiredSize, 0, 0); + if(requiredSize <= 0) { + break; + } + + res.second.emplace_back(argv.get()); + res.first.emplace_back(move(argv)); + } + + LocalFree(argv_w); + return res; +} #endif } // namespace ApplicationUtilities diff --git a/application/commandlineutils.h b/application/commandlineutils.h index 276b14e..fb0f091 100644 --- a/application/commandlineutils.h +++ b/application/commandlineutils.h @@ -5,6 +5,11 @@ #include +#ifdef PLATFORM_WINDOWS +# include "../misc/memory.h" +# include +#endif + namespace ApplicationUtilities { /*! @@ -21,13 +26,20 @@ bool CPP_UTILITIES_EXPORT confirmPrompt(const char *message, Response defaultRes #ifdef PLATFORM_WINDOWS void CPP_UTILITIES_EXPORT startConsole(); -# define CMD_UTILS_START_CONSOLE ::ApplicationUtilities::startConsole(); +std::pair >, std::vector > CPP_UTILITIES_EXPORT convertArgsToUtf8(); +# define CMD_UTILS_START_CONSOLE \ + ::ApplicationUtilities::startConsole(); +# define CMD_UTILS_CONVERT_ARGS_TO_UTF8 \ + auto utf8Args = ::ApplicationUtilities::convertArgsToUtf8(); \ + argv = utf8Args.second.data(); \ + argc = static_cast(utf8Args.second.size()); #else # define CMD_UTILS_START_CONSOLE +# define CMD_UTILS_CONVERT_ARGS_TO_UTF8 #endif /*! - * \brief The Indent class allows printing indentation conveniently, eg. cout << Ident(4) << ... + * \brief The Indentation class allows printing indentation conveniently, eg. cout << Indentation(4) << ... */ class CPP_UTILITIES_EXPORT Indentation {