refactor: avoid tr_new() in tr_main_win32() (#3664)

This commit is contained in:
Charles Kerr 2022-08-17 18:26:52 -05:00 committed by GitHub
parent 7fe2cf68b9
commit 36675d183a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 95 additions and 73 deletions

View File

@ -3,7 +3,7 @@
// or any future license endorsed by Mnemosyne LLC. // or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder. // License text can be found in the licenses/ folder.
#include <algorithm> // std::sort #include <algorithm> // for std::sort, std::transform
#include <array> // std::array #include <array> // std::array
#include <cerrno> #include <cerrno>
#include <cfloat> // DBL_DIG #include <cfloat> // DBL_DIG
@ -14,6 +14,7 @@
#include <cstring> /* strerror() */ #include <cstring> /* strerror() */
#include <ctime> // nanosleep() #include <ctime> // nanosleep()
#include <iterator> // for std::back_inserter #include <iterator> // for std::back_inserter
#include <optional>
#include <set> #include <set>
#include <string> #include <string>
#include <string_view> #include <string_view>
@ -379,14 +380,18 @@ bool tr_utf8_validate(std::string_view sv, char const** good_end)
return all_good; return all_good;
} }
static std::string strip_non_utf8(std::string_view sv) namespace
{
namespace tr_strvUtf8Clean_impl
{
std::string strip_non_utf8(std::string_view sv)
{ {
auto out = std::string{}; auto out = std::string{};
utf8::unchecked::replace_invalid(std::data(sv), std::data(sv) + std::size(sv), std::back_inserter(out), '?'); utf8::unchecked::replace_invalid(std::data(sv), std::data(sv) + std::size(sv), std::back_inserter(out), '?');
return out; return out;
} }
static std::string to_utf8(std::string_view sv) std::string to_utf8(std::string_view sv)
{ {
#ifdef HAVE_ICONV #ifdef HAVE_ICONV
size_t const buflen = std::size(sv) * 4 + 10; size_t const buflen = std::size(sv) * 4 + 10;
@ -423,8 +428,13 @@ static std::string to_utf8(std::string_view sv)
return strip_non_utf8(sv); return strip_non_utf8(sv);
} }
} // namespace tr_strvUtf8Clean_impl
} // namespace
std::string tr_strvUtf8Clean(std::string_view cleanme) std::string tr_strvUtf8Clean(std::string_view cleanme)
{ {
using namespace tr_strvUtf8Clean_impl;
if (tr_utf8_validate(cleanme, nullptr)) if (tr_utf8_validate(cleanme, nullptr))
{ {
return std::string{ cleanme }; return std::string{ cleanme };
@ -445,21 +455,6 @@ std::string tr_win32_native_to_utf8(std::wstring_view in)
return out; return out;
} }
static char* tr_win32_native_to_utf8(wchar_t const* text, int text_size)
{
if (text == nullptr)
{
return nullptr;
}
if (text_size < 0)
{
return tr_strvDup(tr_win32_native_to_utf8(text));
}
return tr_strvDup(tr_win32_native_to_utf8({ text, static_cast<size_t>(text_size) }));
}
std::wstring tr_win32_utf8_to_native(std::string_view in) std::wstring tr_win32_utf8_to_native(std::string_view in)
{ {
auto out = std::wstring{}; auto out = std::wstring{};
@ -504,60 +499,68 @@ std::string tr_win32_format_message(uint32_t code)
return text; return text;
} }
static void tr_win32_make_args_utf8(int* argc, char*** argv) namespace
{
namespace tr_main_win32_impl
{ {
int my_argc;
wchar_t** my_wide_argv;
my_wide_argv = CommandLineToArgvW(GetCommandLineW(), &my_argc); std::optional<std::vector<std::string>> win32MakeUtf8Argv()
{
if (my_wide_argv == nullptr) int argc;
auto argv = std::vector<std::string>{};
if (wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); wargv != nullptr)
{ {
return; for (int i = 0; i < argc; ++i)
}
TR_ASSERT(*argc == my_argc);
char** my_argv = tr_new(char*, my_argc + 1);
int processed_argc = 0;
for (int i = 0; i < my_argc; ++i, ++processed_argc)
{
my_argv[i] = tr_win32_native_to_utf8(my_wide_argv[i], -1);
if (my_argv[i] == nullptr)
{ {
break; if (wargv[i] == nullptr)
} {
} break;
}
if (processed_argc < my_argc) auto str = tr_win32_native_to_utf8(wargv[i]);
{ if (std::empty(str))
for (int i = 0; i < processed_argc; ++i) {
{ break;
tr_free(my_argv[i]); }
argv.emplace_back(std::move(str));
} }
tr_free(my_argv); LocalFree(wargv);
} }
else
if (static_cast<int>(std::size(argv)) == argc)
{ {
my_argv[my_argc] = nullptr; return argv;
*argc = my_argc;
*argv = my_argv;
/* TODO: Add atexit handler to cleanup? */
} }
LocalFree(my_wide_argv); return {};
} }
} // namespace tr_main_win32_impl
} // namespace
int tr_main_win32(int argc, char** argv, int (*real_main)(int, char**)) int tr_main_win32(int argc, char** argv, int (*real_main)(int, char**))
{ {
tr_win32_make_args_utf8(&argc, &argv); using namespace tr_main_win32_impl;
SetConsoleCP(CP_UTF8); SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
// build an argv from GetCommandLineW + CommandLineToArgvW
if (auto argv_strs = win32MakeUtf8Argv(); argv_strs)
{
auto argv_cstrs = std::vector<char*>{};
argv_cstrs.reserve(std::size(*argv_strs));
std::transform(
std::begin(*argv_strs),
std::end(*argv_strs),
std::back_inserter(argv_cstrs),
[](auto& str) { return std::data(str); });
argv_cstrs.push_back(nullptr); // argv is nullptr-terminated
return (*real_main)(std::size(*argv_strs), std::data(argv_cstrs));
}
return (*real_main)(argc, argv); return (*real_main)(argc, argv);
} }
@ -567,6 +570,11 @@ int tr_main_win32(int argc, char** argv, int (*real_main)(int, char**))
**** ****
***/ ***/
namespace
{
namespace tr_parseNumberRange_impl
{
struct number_range struct number_range
{ {
int low; int low;
@ -577,7 +585,7 @@ struct number_range
* This should be a single number (ex. "6") or a range (ex. "6-9"). * This should be a single number (ex. "6") or a range (ex. "6-9").
* Anything else is an error and will return failure. * Anything else is an error and will return failure.
*/ */
static bool parseNumberSection(std::string_view str, number_range& range) bool parseNumberSection(std::string_view str, number_range& range)
{ {
auto constexpr Delimiter = "-"sv; auto constexpr Delimiter = "-"sv;
@ -609,6 +617,9 @@ static bool parseNumberSection(std::string_view str, number_range& range)
return true; return true;
} }
} // namespace tr_parseNumberRange_impl
} // namespace
/** /**
* Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an * Given a string like "1-4" or "1-4,6,9,14-51", this allocates and returns an
* array of setmeCount ints of all the values in the array. * array of setmeCount ints of all the values in the array.
@ -617,6 +628,8 @@ static bool parseNumberSection(std::string_view str, number_range& range)
*/ */
std::vector<int> tr_parseNumberRange(std::string_view str) std::vector<int> tr_parseNumberRange(std::string_view str)
{ {
using namespace tr_parseNumberRange_impl;
auto values = std::set<int>{}; auto values = std::set<int>{};
auto token = std::string_view{}; auto token = std::string_view{};
auto range = number_range{}; auto range = number_range{};
@ -785,10 +798,13 @@ uint64_t tr_ntohll(uint64_t x)
/*** /***
**** ****
****
****
***/ ***/
namespace
{
namespace formatter_impl
{
struct formatter_unit struct formatter_unit
{ {
std::array<char, 16> name; std::array<char, 16> name;
@ -805,13 +821,7 @@ enum
TR_FMT_TB TR_FMT_TB
}; };
static void formatter_init( void formatter_init(formatter_units& units, uint64_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
formatter_units& units,
uint64_t kilo,
char const* kb,
char const* mb,
char const* gb,
char const* tb)
{ {
uint64_t value = kilo; uint64_t value = kilo;
tr_strlcpy(std::data(units[TR_FMT_KB].name), kb, std::size(units[TR_FMT_KB].name)); tr_strlcpy(std::data(units[TR_FMT_KB].name), kb, std::size(units[TR_FMT_KB].name));
@ -830,7 +840,7 @@ static void formatter_init(
units[TR_FMT_TB].value = value; units[TR_FMT_TB].value = value;
} }
static char* formatter_get_size_str(formatter_units const& u, char* buf, uint64_t bytes, size_t buflen) char* formatter_get_size_str(formatter_units const& u, char* buf, uint64_t bytes, size_t buflen)
{ {
formatter_unit const* unit = nullptr; formatter_unit const* unit = nullptr;
@ -873,31 +883,39 @@ static char* formatter_get_size_str(formatter_units const& u, char* buf, uint64_
return buf; return buf;
} }
static formatter_units size_units; formatter_units size_units;
formatter_units speed_units;
formatter_units mem_units;
} // namespace formatter_impl
} // namespace
size_t tr_speed_K = 0;
void tr_formatter_size_init(uint64_t kilo, char const* kb, char const* mb, char const* gb, char const* tb) void tr_formatter_size_init(uint64_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{ {
using namespace formatter_impl;
formatter_init(size_units, kilo, kb, mb, gb, tb); formatter_init(size_units, kilo, kb, mb, gb, tb);
} }
std::string tr_formatter_size_B(uint64_t bytes) std::string tr_formatter_size_B(uint64_t bytes)
{ {
using namespace formatter_impl;
auto buf = std::array<char, 64>{}; auto buf = std::array<char, 64>{};
return formatter_get_size_str(size_units, std::data(buf), bytes, std::size(buf)); return formatter_get_size_str(size_units, std::data(buf), bytes, std::size(buf));
} }
static formatter_units speed_units;
size_t tr_speed_K = 0;
void tr_formatter_speed_init(size_t kilo, char const* kb, char const* mb, char const* gb, char const* tb) void tr_formatter_speed_init(size_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{ {
using namespace formatter_impl;
tr_speed_K = kilo; tr_speed_K = kilo;
formatter_init(speed_units, kilo, kb, mb, gb, tb); formatter_init(speed_units, kilo, kb, mb, gb, tb);
} }
std::string tr_formatter_speed_KBps(double KBps) std::string tr_formatter_speed_KBps(double KBps)
{ {
using namespace formatter_impl;
auto speed = KBps; auto speed = KBps;
if (speed <= 999.95) // 0.0 KB to 999.9 KB if (speed <= 999.95) // 0.0 KB to 999.9 KB
@ -921,24 +939,28 @@ std::string tr_formatter_speed_KBps(double KBps)
return fmt::format("{:.1f} {:s}", speed / K, std::data(speed_units[TR_FMT_GB].name)); return fmt::format("{:.1f} {:s}", speed / K, std::data(speed_units[TR_FMT_GB].name));
} }
static formatter_units mem_units;
size_t tr_mem_K = 0; size_t tr_mem_K = 0;
void tr_formatter_mem_init(size_t kilo, char const* kb, char const* mb, char const* gb, char const* tb) void tr_formatter_mem_init(size_t kilo, char const* kb, char const* mb, char const* gb, char const* tb)
{ {
using namespace formatter_impl;
tr_mem_K = kilo; tr_mem_K = kilo;
formatter_init(mem_units, kilo, kb, mb, gb, tb); formatter_init(mem_units, kilo, kb, mb, gb, tb);
} }
std::string tr_formatter_mem_B(size_t bytes_per_second) std::string tr_formatter_mem_B(size_t bytes_per_second)
{ {
using namespace formatter_impl;
auto buf = std::array<char, 64>{}; auto buf = std::array<char, 64>{};
return formatter_get_size_str(mem_units, std::data(buf), bytes_per_second, std::size(buf)); return formatter_get_size_str(mem_units, std::data(buf), bytes_per_second, std::size(buf));
} }
void tr_formatter_get_units(void* vdict) void tr_formatter_get_units(void* vdict)
{ {
using namespace formatter_impl;
auto* dict = static_cast<tr_variant*>(vdict); auto* dict = static_cast<tr_variant*>(vdict);
tr_variantDictReserve(dict, 6); tr_variantDictReserve(dict, 6);