From 9163c6e24ee111e361ea970430d73a98c03ae3a7 Mon Sep 17 00:00:00 2001 From: Marcus Holland-Moritz Date: Mon, 26 Jun 2023 23:59:11 +0200 Subject: [PATCH] Initial Unicode support for command line arguments on Windows --- include/dwarfs/builtin_script.h | 7 ++-- include/dwarfs/program_options_helpers.h | 42 ++++++++++++++++++++++++ include/dwarfs/types.h | 2 ++ src/dwarfs/builtin_script.cpp | 9 +++-- src/mkdwarfs_main.cpp | 30 ++++++++++------- 5 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 include/dwarfs/program_options_helpers.h diff --git a/include/dwarfs/builtin_script.h b/include/dwarfs/builtin_script.h index be9249ee..73742e56 100644 --- a/include/dwarfs/builtin_script.h +++ b/include/dwarfs/builtin_script.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -38,7 +39,9 @@ class builtin_script : public script { builtin_script(logger& lgr); ~builtin_script(); - void set_root_path(std::string const& path) { impl_->set_root_path(path); } + void set_root_path(std::filesystem::path const& path) { + impl_->set_root_path(path); + } void add_filter_rule(std::string const& rule) { impl_->add_filter_rule(rule); } @@ -62,7 +65,7 @@ class builtin_script : public script { public: virtual ~impl() = default; - virtual void set_root_path(std::string const& path) = 0; + virtual void set_root_path(std::filesystem::path const& path) = 0; virtual void add_filter_rule(std::string const& rule) = 0; virtual void add_filter_rules(std::istream& is) = 0; virtual void add_transformer(std::unique_ptr&& xfm) = 0; diff --git a/include/dwarfs/program_options_helpers.h b/include/dwarfs/program_options_helpers.h new file mode 100644 index 00000000..eb44717a --- /dev/null +++ b/include/dwarfs/program_options_helpers.h @@ -0,0 +1,42 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of dwarfs. + * + * dwarfs is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * dwarfs 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with dwarfs. If not, see . + */ + +#pragma once + +#include + +#include "dwarfs/types.h" + +namespace dwarfs { + +#ifdef _WIN32 +template +auto po_sys_value(T* v) { + return boost::program_options::wvalue(v); +} +#else +template +auto po_sys_value(T* v) { + return boost::program_options::value(v); +} +#endif + +} // namespace dwarfs diff --git a/include/dwarfs/types.h b/include/dwarfs/types.h index b83aec7f..706b7374 100644 --- a/include/dwarfs/types.h +++ b/include/dwarfs/types.h @@ -30,9 +30,11 @@ using file_off_t = int64_t; #ifdef _WIN32 using sys_char = wchar_t; using sys_string = std::wstring; +#define SYS_CERR std::wcerr #else using sys_char = char; using sys_string = std::string; +#define SYS_CERR std::cerr #endif } // namespace dwarfs diff --git a/src/dwarfs/builtin_script.cpp b/src/dwarfs/builtin_script.cpp index a1e04d85..f0e7d098 100644 --- a/src/dwarfs/builtin_script.cpp +++ b/src/dwarfs/builtin_script.cpp @@ -30,6 +30,7 @@ #include "dwarfs/entry_interface.h" #include "dwarfs/entry_transformer.h" #include "dwarfs/logger.h" +#include "dwarfs/util.h" namespace dwarfs { @@ -57,7 +58,7 @@ class builtin_script_ : public builtin_script::impl { public: builtin_script_(logger& lgr); - void set_root_path(std::string const& path) override; + void set_root_path(std::filesystem::path const& path) override; void add_filter_rule(std::string const& rule) override; void add_filter_rules(std::istream& is) override; @@ -182,8 +183,10 @@ builtin_script_::builtin_script_(logger& lgr) : log_(lgr) {} template -void builtin_script_::set_root_path(std::string const& path) { - root_path_ = path; +void builtin_script_::set_root_path( + std::filesystem::path const& path) { + // TODO: this whole thing needs to be windowsized + root_path_ = u8string_to_string(path.u8string()); } template diff --git a/src/mkdwarfs_main.cpp b/src/mkdwarfs_main.cpp index 2c7510e0..048e6ef8 100644 --- a/src/mkdwarfs_main.cpp +++ b/src/mkdwarfs_main.cpp @@ -71,6 +71,7 @@ #include "dwarfs/options.h" #include "dwarfs/options_interface.h" #include "dwarfs/os_access_generic.h" +#include "dwarfs/program_options_helpers.h" #include "dwarfs/progress.h" #include "dwarfs/scanner.h" #include "dwarfs/script.h" @@ -378,11 +379,11 @@ int mkdwarfs_main(int argc, sys_char** argv) { const size_t num_cpu = std::max(folly::hardware_concurrency(), 1u); block_manager::config cfg; - std::string path, output, memory_limit, script_arg, compression, header, - schema_compression, metadata_compression, log_level_str, timestamp, - time_resolution, order, progress_mode, recompress_opts, pack_metadata, - file_hash_algo, debug_filter, max_similarity_size, input_list_str, - chmod_str; + sys_string path_str, output_str; + std::string memory_limit, script_arg, compression, header, schema_compression, + metadata_compression, log_level_str, timestamp, time_resolution, order, + progress_mode, recompress_opts, pack_metadata, file_hash_algo, + debug_filter, max_similarity_size, input_list_str, chmod_str; std::vector filter; size_t num_workers, num_scanner_workers; bool no_progress = false, remove_header = false, no_section_index = false, @@ -416,13 +417,13 @@ int mkdwarfs_main(int argc, sys_char** argv) { po::options_description opts("Command line options"); opts.add_options() ("input,i", - po::value(&path), + po_sys_value(&path_str), "path to root directory or source filesystem") ("input-list", po::value(&input_list_str), "file containing list of paths relative to root directory") ("output,o", - po::value(&output), + po_sys_value(&output_str), "filesystem output name") ("force,f", po::value(&force_overwrite)->zero_tokens(), @@ -549,6 +550,8 @@ int mkdwarfs_main(int argc, sys_char** argv) { po::variables_map vm; + auto& err_out = SYS_CERR; + try { auto parsed = po::parse_command_line(argc, argv, opts); @@ -559,8 +562,8 @@ int mkdwarfs_main(int argc, sys_char** argv) { po::collect_unrecognized(parsed.options, po::include_positional); if (!unrecognized.empty()) { - std::wcerr << "error: unrecognized argument(s) '" - << boost::join(unrecognized, " ") << "'" << std::endl; + err_out << "error: unrecognized argument(s) '" + << boost::join(unrecognized, " ") << "'" << std::endl; return 1; } } catch (po::error const& e) { @@ -663,6 +666,7 @@ int mkdwarfs_main(int argc, sys_char** argv) { return 1; } + std::filesystem::path path(path_str); std::optional> input_list; if (vm.count("input-list")) { @@ -676,7 +680,7 @@ int mkdwarfs_main(int argc, sys_char** argv) { options.with_specials = true; if (!vm.count("input")) { - path = std::filesystem::current_path().string(); + path = std::filesystem::current_path(); } std::unique_ptr ifs; @@ -1046,6 +1050,8 @@ int mkdwarfs_main(int argc, sys_char** argv) { << " blocks with " << num_workers << " threads"; } + std::filesystem::path output(output_str); + std::unique_ptr os; if (!options.debug_filter_function) { @@ -1059,8 +1065,8 @@ int mkdwarfs_main(int argc, sys_char** argv) { std::ios::trunc); if (ofs->bad() || !ofs->is_open()) { - std::cerr << "error: cannot open output file '" << output - << "': " << strerror(errno) << std::endl; + err_out << "error: cannot open output file '" << output + << "': " << strerror(errno) << std::endl; return 1; }