diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7bef8bf..e032a90 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ PRIVATE yycc/carton/tabulate.cpp yycc/carton/ironpad.cpp yycc/carton/csconsole.cpp + #yycc/carton/clap/option.cpp ) target_sources(YYCCommonplace PUBLIC @@ -46,6 +47,7 @@ FILES yycc/macro/compiler_detector.hpp yycc/macro/ptr_size_detector.hpp yycc/macro/class_copy_move.hpp + yycc/macro/printf_checker.hpp yycc/flag_enum.hpp yycc/string/reinterpret.hpp yycc/string/op.hpp @@ -81,6 +83,9 @@ FILES yycc/carton/tabulate.hpp yycc/carton/ironpad.hpp yycc/carton/csconsole.hpp + yycc/carton/clap.hpp + yycc/carton/clap/types.hpp + yycc/carton/clap/option.hpp ) # Setup header infomations target_include_directories(YYCCommonplace diff --git a/src/yycc/carton/clap.hpp b/src/yycc/carton/clap.hpp new file mode 100644 index 0000000..32f766e --- /dev/null +++ b/src/yycc/carton/clap.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace yycc::carton::clap { + +} diff --git a/src/yycc/carton/clap/option.cpp b/src/yycc/carton/clap/option.cpp new file mode 100644 index 0000000..0f6f72e --- /dev/null +++ b/src/yycc/carton/clap/option.cpp @@ -0,0 +1,5 @@ +#include "option.hpp" + +namespace yycc::carton::clap::option { + +} diff --git a/src/yycc/carton/clap/option.hpp b/src/yycc/carton/clap/option.hpp new file mode 100644 index 0000000..bfbde59 --- /dev/null +++ b/src/yycc/carton/clap/option.hpp @@ -0,0 +1,85 @@ +#pragma once +#include "types.hpp" +#include "../../macro/class_copy_move.hpp" +#include "../../string/op.hpp" +#include +#include +#include +#include + +#define NS_YYCC_CLAP_TYPES ::yycc::carton::clap::types + +namespace yycc::carton::clap::option { + + class Option { + public: + Option(std::optional short_name, + std::optional long_name, + std::optional value_hint, + const std::u8string& description) : + short_name(short_name), long_name(long_name), value_hint(value_hint), description(description) { + if (!short_name.has_value() && !long_name.has_value()) { + throw std::logic_error("must have at least one name, short or long name"); + } + + if (short_name.has_value()) { + const auto& short_name_value = short_name.value(); + if (!legal_short_name(short_name_value)) { + throw std::logic_error(std::format("invalid short name {}", short_name_value)); + } + } + if (long_name.has_value()) { + const auto& long_name_value = long_name.value(); + if (!legal_long_name(long_name_value)) { + throw std::logic_error(std::format("invalid long name {}", long_name_value)); + } + } + } + ~Option() {} + YYCC_DEFAULT_COPY_MOVE(Option) + + public: + std::optional get_short_name() const { return this->short_name; } + std::optional get_long_name() const { return this->long_name; } + std::optional get_value_hint() const { return this->value_hint; } + std::u8string_view get_description() const { return this->description; } + + std::u8string to_showcase_name() { + namespace op = ::yycc::string::op; + + if (short_name.has_value()) { + if (long_name.has_value()) { + + } else { + + } + } else { + if (long_name.has_value()) { + op::printf + } else { + throw std::runtime_error("both long name and short name are empty"); + } + } + } + + private: + static bool legal_short_name(const std::u8string_view& name) { + if (name.empty()) return false; + if (name.starts_with(NS_YYCC_CLAP_TYPES::DASH)) return false; + return true; + } + static bool legal_long_name(const std::u8string_view& name) { + if (name.empty()) return false; + return true; + } + + private: + std::optional short_name; + std::optional long_name; + std::optional value_hint; + std::u8string description; + }; + +} // namespace yycc::carton::clap::option + +#undef NS_YYCC_CLAP_TYPES diff --git a/src/yycc/carton/clap/types.hpp b/src/yycc/carton/clap/types.hpp new file mode 100644 index 0000000..0f790d5 --- /dev/null +++ b/src/yycc/carton/clap/types.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace yycc::carton::clap::types { + + enum class ClapError { + + }; + + template + using ClapResult = std::expected; + + inline constexpr std::u8string_view DASH = u8"-"; + inline constexpr std::u8string_view DOUBLE_DASH = u8"--"; + + using Token = size_t; + +} // namespace yycc::carton::clap::types diff --git a/src/yycc/carton/csconsole.cpp b/src/yycc/carton/csconsole.cpp index f911a10..e3f6c3c 100644 --- a/src/yycc/carton/csconsole.cpp +++ b/src/yycc/carton/csconsole.cpp @@ -108,9 +108,7 @@ namespace yycc::carton::csconsole { if (GetConsoleMode(hStdOut, &dwConsoleMode)) { // console handle, use WriteConsoleW. // convert utf8 string to wide char first - auto rv = ENC::to_wchar(strl); - if (!rv.has_value()) return; - std::wstring wstrl(std::move(rv.value())); + std::wstring wstrl = ENC::to_wchar(strl).value(); size_t wstrl_size = wstrl.size(); // write string with size check if (wstrl_size <= std::numeric_limits::max()) { @@ -171,11 +169,8 @@ namespace yycc::carton::csconsole { // treat as format string va_list argcpy; va_copy(argcpy, argptr); - auto rv = OP::vprintf(u8_fmt, argcpy); + strl = OP::vprintf(u8_fmt, argcpy); va_end(argcpy); - // check format result - if (!rv.has_value()) return; - else strl = std::move(rv.value()); } else { // treat as plain string strl = u8_fmt; diff --git a/src/yycc/carton/ironpad.cpp b/src/yycc/carton/ironpad.cpp index 3077aca..c9403ec 100644 --- a/src/yycc/carton/ironpad.cpp +++ b/src/yycc/carton/ironpad.cpp @@ -63,11 +63,9 @@ namespace yycc::carton::ironpad { // check singleton // build mutex string first auto mutex_name = OP::printf(u8"Global\\%" PRIu32 ".{61634294-d23c-43f9-8490-b5e09837eede}", GetCurrentProcessId()); - if (!mutex_name.has_value()) return false; - auto w_mutex_name = ENC::to_wchar(mutex_name.value()); - if (!w_mutex_name.has_value()) return false; + auto wmutex_name = ENC::to_wchar(mutex_name).value(); // create mutex - m_SingletonMutex = CreateMutexW(NULL, FALSE, w_mutex_name.value().c_str()); + m_SingletonMutex = CreateMutexW(NULL, FALSE, wmutex_name.c_str()); DWORD errcode = GetLastError(); // check whether be created if (m_SingletonMutex == NULL) return false; @@ -303,18 +301,17 @@ namespace yycc::carton::ironpad { DWORD process_id = GetCurrentProcessId(); // conbine them as a file name prefix auto u8_filename_prefix = OP::printf(u8"%s.%" PRIu32, u8_process_name.c_str(), process_id); - if (!u8_filename_prefix.has_value()) return std::nullopt; // then get file name for log and minidump std::u8string u8_filename; switch (kind) { case FileKind::LogFile: - u8_filename = u8_filename_prefix.value() + u8".log"; + u8_filename = u8_filename_prefix + u8".log"; break; case FileKind::CoredumpFile: - u8_filename = u8_filename_prefix.value() + u8".dmp"; + u8_filename = u8_filename_prefix + u8".dmp"; break; default: - u8_filename = u8_filename_prefix.value(); + u8_filename = u8_filename_prefix; break; } @@ -451,11 +448,9 @@ namespace yycc::carton::ironpad { * @details This function will write coredump of given exception into given file path. */ void do_coredump(const std::u8string_view& u8_filename, LPEXCEPTION_POINTERS info) { - // convert file encoding - // if convertion failed, return - auto filename_rv = ENC::to_wchar(u8_filename); - if (!filename_rv.has_value()) return; - std::wstring filename = filename_rv.value(); + // convert file encoding. + // it must be okey. + auto filename = ENC::to_wchar(u8_filename).value(); // open file and write HANDLE hFile = CreateFileW(filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); @@ -554,15 +549,11 @@ namespace yycc::carton::ironpad { * @param[in] ... The argument to be formatted. */ void log_format_line(std::FILE* fs, const char8_t* fmt, ...) { - // do format first + // write to file and console va_list arg; va_start(arg, fmt); - auto fmt_rv = OP::vprintf(fmt, arg); + log_write_line(fs, OP::vprintf(fmt, arg).c_str()); va_end(arg); - // write to file and console - if (fmt_rv.has_value()) { - log_write_line(fs, fmt_rv.value().c_str()); - } } }; diff --git a/src/yycc/carton/wcwidth.cpp b/src/yycc/carton/wcwidth.cpp index 05188f0..c810d0a 100644 --- a/src/yycc/carton/wcwidth.cpp +++ b/src/yycc/carton/wcwidth.cpp @@ -468,11 +468,8 @@ namespace yycc::carton::wcwidth { } Result wcswidth(const std::u8string_view& rhs) { - // Cast encoding - auto u32str = ENC::to_utf32(rhs); - if (!u32str.has_value()) return std::unexpected(Error::BadEncoding); - // Call underlying function - return wcswidth(u32str.value()); + // Cast encoding and call underlying function + return wcswidth(ENC::to_utf32(rhs).value()); } } // namespace yycc::carton::wcwidth diff --git a/src/yycc/carton/wcwidth.hpp b/src/yycc/carton/wcwidth.hpp index 2b1520c..a879a48 100644 --- a/src/yycc/carton/wcwidth.hpp +++ b/src/yycc/carton/wcwidth.hpp @@ -31,7 +31,6 @@ namespace yycc::carton::wcwidth { /// @brief Error occurs in this module enum class Error { - BadEncoding, ///< Given BadAnsiEscSeq, ///< Bad char when processing ANSI Escape Sequence BadCsiSeq, ///< Bad char when processing CSI Sequence. }; diff --git a/src/yycc/macro/printf_checker.hpp b/src/yycc/macro/printf_checker.hpp new file mode 100644 index 0000000..7ba7758 --- /dev/null +++ b/src/yycc/macro/printf_checker.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "compiler_detector.hpp" +#include "stl_detector.hpp" + +// YYC MARK: +// This code is copied from Qt project. + +#if defined(YYCC_CC_GCC) +// GCC has its special attribute +#define YYCC_PRINTF_CHECK_ATTR(A, B) __attribute__((format(gnu_printf, (A), (B)))) +#elif defined(YYCC_CC_CLANG) +// Clang use its own attribute +#define YYCC_PRINTF_CHECK_ATTR(A, B) __attribute__((format(printf, (A), (B)))) +#else +// Other CC do not support this (like MSVC), skip it +#define YYCC_PRINTF_CHECK_ATTR(A, B) +#endif + +#if defined(YYCC_STL_MSSTL) +// On Microsoft STL, we can use some mechanisms to check it. +#include "../windows/import_guard_head.hpp" +#include +#include "../windows/import_guard_tail.hpp" +#define YYCC_PRINTF_CHECK_FMTSTR _Printf_format_string_ +#else +// Other STL do not have this. +#define YYCC_PRINTF_CHECK_FMTSTR +#endif diff --git a/src/yycc/patch/fopen.cpp b/src/yycc/patch/fopen.cpp index 8bf3470..a10cf5d 100644 --- a/src/yycc/patch/fopen.cpp +++ b/src/yycc/patch/fopen.cpp @@ -18,19 +18,9 @@ namespace yycc::patch::fopen { std::FILE* fopen(const char8_t* u8_filepath, const char8_t* u8_mode) { #if defined(YYCC_OS_WINDOWS) - // convert mode and file path to wchar - auto wmode = ENC::to_wchar(u8_mode); - auto wpath = ENC::to_wchar(u8_filepath); - - // check convertion success - if (wmode.has_value() && wpath.has_value()) { - // Call MSVCRT specified fopen which support wchar as argument. - // Reference: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 - return _wfopen(wpath.value().c_str(), wmode.value().c_str()); - } else { - // fail to convert encoding - return nullptr; - } + // Convert encoding first, and call MSVCRT specified fopen which support wchar as argument. + // Reference: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 + return _wfopen(ENC::to_wchar(u8_filepath).value().c_str(), ENC::to_wchar(u8_mode).value().c_str()); #else return std::fopen(REINTERPRET::as_ordinary(u8_filepath), REINTERPRET::as_ordinary(u8_mode)); #endif diff --git a/src/yycc/rust/env.cpp b/src/yycc/rust/env.cpp index d25247f..65a592d 100644 --- a/src/yycc/rust/env.cpp +++ b/src/yycc/rust/env.cpp @@ -25,10 +25,7 @@ namespace yycc::rust::env { #if defined(YYCC_OS_WINDOWS) // Reference: https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentvariablew // Convert to wchar - auto wname = ENC::to_wchar(name); - if (!wname.has_value()) { - return std::unexpected(EnvError::BadEncoding); - } + auto wname = ENC::to_wchar(name).value(); // Prepare a variable with proper init size for holding value. std::wstring wvalue; @@ -42,7 +39,7 @@ namespace yycc::rust::env { // So we forcely use checked add and sub for this bad behavior. auto fct_size = SAFEOP::checked_add(wvalue.size(), 1); if (!fct_size.has_value()) return std::unexpected(EnvError::BadArithmetic); - auto rv = ::GetEnvironmentVariableW(wname.value().c_str(), wvalue.data(), fct_size.value()); + auto rv = ::GetEnvironmentVariableW(wname.c_str(), wvalue.data(), fct_size.value()); // Check the return value if (rv == 0) { @@ -95,20 +92,10 @@ namespace yycc::rust::env { #if defined(YYCC_OS_WINDOWS) // Reference: https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew - // Convert to wchar - auto wname = ENC::to_wchar(name); - auto wvalue = ENC::to_wchar(value); - if (!(wname.has_value() && wvalue.has_value())) { - return std::unexpected(EnvError::BadEncoding); - } - - // Delete variable and check result. - auto rv = ::SetEnvironmentVariableW(wname.value().c_str(), wvalue.value().c_str()); - if (!rv) { - return std::unexpected(EnvError::BadCall); - } - - return {}; + // Convert to wchar, set variable, and check result. + auto rv = ::SetEnvironmentVariableW(ENC::to_wchar(name).value().c_str(), ENC::to_wchar(value).value().c_str()); + if (!rv) return std::unexpected(EnvError::BadCall); + else return {}; #else // Reference: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setenv.html @@ -129,19 +116,10 @@ namespace yycc::rust::env { #if defined(YYCC_OS_WINDOWS) // Reference: https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-setenvironmentvariablew - // Convert to wchar - auto wname = ENC::to_wchar(name); - if (!wname.has_value()) { - return std::unexpected(EnvError::BadEncoding); - } - - // Delete variable and check result. - auto rv = ::SetEnvironmentVariableW(wname.value().c_str(), NULL); - if (!rv) { - return std::unexpected(EnvError::BadCall); - } - - return {}; + // Convert to wchar, delete variable, and check result. + auto rv = ::SetEnvironmentVariableW(ENC::to_wchar(name).value().c_str(), NULL); + if (!rv) return std::unexpected(EnvError::BadCall); + else return {}; #else // Reference: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unsetenv.html diff --git a/src/yycc/string/op.cpp b/src/yycc/string/op.cpp index 357149e..48efdac 100644 --- a/src/yycc/string/op.cpp +++ b/src/yycc/string/op.cpp @@ -1,19 +1,21 @@ #include "op.hpp" +#include #include +#include namespace yycc::string::op { #pragma region Printf VPrintf + /// @brief The concept for all viable char type in printf function family template - requires(sizeof(TChar) == sizeof(char)) - static FormatResult> generic_printf(const TChar* format, va_list argptr) { + concept PrintfSupportedChar = std::is_same_v || std::is_same_v; + + template + static std::basic_string generic_printf(const TChar* format, va_list argptr) { // Prepare result std::basic_string rv; - // Check format - if (format == nullptr) return std::unexpected(FormatError::NullFormat); - // Prepare variable arguments va_list args1; va_copy(args1, argptr); @@ -21,12 +23,13 @@ namespace yycc::string::op { va_copy(args2, argptr); // The return value is desired char count without NULL terminal. - // Minus number means error. + // Negative number means error. int count = std::vsnprintf(nullptr, 0, reinterpret_cast(format), args1); // Check expected size. if (count < 0) { // Invalid length returned by vsnprintf. - return std::unexpected(FormatError::NoDesiredSize); + // This may be caused by invalid format string + throw std::logic_error("fail to determine the size of formatted string"); } va_end(args1); @@ -39,14 +42,15 @@ namespace yycc::string::op { // Check written size. if (write_result < 0 || write_result > count) { // Invalid write result in vsnprintf. - return std::unexpected(FormatError::BadWrittenSize); + // Idk why this can happen. + throw std::logic_error("the size of written formatted string is not expected"); } // Return value return rv; } - FormatResult printf(const char8_t* format, ...) { + std::u8string printf(const char8_t* format, ...) { va_list argptr; va_start(argptr, format); auto rv = vprintf(format, argptr); @@ -54,11 +58,11 @@ namespace yycc::string::op { return rv; } - FormatResult vprintf(const char8_t* format, va_list argptr) { + std::u8string vprintf(const char8_t* format, va_list argptr) { return generic_printf(format, argptr); } - FormatResult printf(const char* format, ...) { + std::string printf(const char* format, ...) { va_list argptr; va_start(argptr, format); auto rv = vprintf(format, argptr); @@ -66,7 +70,7 @@ namespace yycc::string::op { return rv; } - FormatResult vprintf(const char* format, va_list argptr) { + std::string vprintf(const char* format, va_list argptr) { return generic_printf(format, argptr); } diff --git a/src/yycc/string/op.hpp b/src/yycc/string/op.hpp index 53e37fb..54b6055 100644 --- a/src/yycc/string/op.hpp +++ b/src/yycc/string/op.hpp @@ -1,50 +1,41 @@ #pragma once +#include "../macro/printf_checker.hpp" #include #include #include #include #include -#include namespace yycc::string::op { - enum class FormatError { - NullFormat, ///< Given format string is nullptr. - NoDesiredSize, ///< Fail to fetch the expected size of result. - BadWrittenSize, ///< The written size is different with expected size. - }; - - template - using FormatResult = std::expected; - /** * @brief Perform an UTF8 string formatting operation. * @param[in] format The format string. * @param[in] ... Argument list of format string. - * @return The formatted result, or the fail reason. + * @return The formatted result. */ - FormatResult printf(const char8_t* format, ...); + std::u8string printf(YYCC_PRINTF_CHECK_FMTSTR const char8_t* format, ...) YYCC_PRINTF_CHECK_ATTR(1, 2); /** * @brief Perform an UTF8 string formatting operation. * @param[in] format The format string. * @param[in] argptr Argument list of format string. - * @return The formatted result, or the fail reason. + * @return The formatted result. */ - FormatResult vprintf(const char8_t* format, va_list argptr); + std::u8string vprintf(const char8_t* format, va_list argptr); /** * @brief Perform an ordinary string formatting operation. * @param[in] format The format string. * @param[in] ... Argument list of format string. - * @return The formatted result, or the fail reason. + * @return The formatted result. */ - FormatResult printf(const char* format, ...); + std::string printf(YYCC_PRINTF_CHECK_FMTSTR const char* format, ...) YYCC_PRINTF_CHECK_ATTR(1, 2); /** * @brief Perform an ordinary string formatting operation. * @param[in] format The format string. * @param[in] argptr Argument list of format string. - * @return The formatted result, or the fail reason. + * @return The formatted result. */ - FormatResult vprintf(const char* format, va_list argptr); + std::string vprintf(const char* format, va_list argptr); /** * @brief Modify given string with all occurrences of substring \e old replaced by \e new. diff --git a/src/yycc/windows/dialog.cpp b/src/yycc/windows/dialog.cpp index b9c0a57..2ab219b 100644 --- a/src/yycc/windows/dialog.cpp +++ b/src/yycc/windows/dialog.cpp @@ -130,21 +130,15 @@ namespace yycc::windows::dialog { // build new Windows oriented string vector for (const auto& item : m_Filters) { // convert name to wchar - auto win_name = ENC::to_wchar(item.first); - if (!win_name.has_value()) { - return std::unexpected(DialogError::BadEncoding); - } + auto win_name = ENC::to_wchar(item.first).value(); // join pattern string and convert to wchar const auto& modes = item.second; auto joined_modes = OP::join(modes.begin(), modes.end(), u8";"); - auto win_modes = ENC::to_wchar(joined_modes); - if (!win_modes.has_value()) { - return std::unexpected(DialogError::BadEncoding); - } + auto win_modes = ENC::to_wchar(joined_modes).value(); // append this pair - rv.m_WinFilters.emplace_back(std::make_pair(win_name.value(), win_modes.value())); + rv.m_WinFilters.emplace_back(std::make_pair(win_name, win_modes)); } // update data struct @@ -305,28 +299,21 @@ namespace yycc::windows::dialog { // build title and init file name if (m_Title.has_value()) { - auto win_title = ENC::to_wchar(m_Title.value()); - if (!win_title.has_value()) return std::unexpected(DialogError::BadEncoding); - else rv.m_WinTitle = win_title.value(); + rv.m_WinTitle = ENC::to_wchar(m_Title.value()).value(); } else rv.m_WinTitle = std::nullopt; if (m_InitFileName.has_value()) { - auto win_init_file_name = ENC::to_wchar(m_InitFileName.value()); - if (!win_init_file_name.has_value()) return std::unexpected(DialogError::BadEncoding); - else rv.m_WinInitFileName = win_init_file_name.value(); + rv.m_WinInitFileName = ENC::to_wchar(m_InitFileName.value()).value(); } else rv.m_WinInitFileName = std::nullopt; // fetch init directory if (m_InitDirectory.has_value()) { // convert to wchar path - auto w_init_dir = ENC::to_wchar(m_InitDirectory.value()); - if (!w_init_dir.has_value()) { - return std::unexpected(DialogError::BadEncoding); - } + auto w_init_dir = ENC::to_wchar(m_InitDirectory.value()).value(); // fetch IShellItem* // Ref: https://stackoverflow.com/questions/76306324/how-to-set-default-folder-for-ifileopendialog-interface IShellItem* init_directory = NULL; - HRESULT hr = SHCreateItemFromParsingName(w_init_dir.value().c_str(), NULL, IID_PPV_ARGS(&init_directory)); + HRESULT hr = SHCreateItemFromParsingName(w_init_dir.c_str(), NULL, IID_PPV_ARGS(&init_directory)); if (FAILED(hr)) return std::unexpected(DialogError::NoSuchDir); // assign IShellItem* @@ -378,7 +365,7 @@ namespace yycc::windows::dialog { WINCOM::SmartLPWSTR display_name(display_name_ptr); // convert result and return - return ENC::to_utf8(display_name.get()).transform_error([](auto err) { return DialogError::BadEncoding; }); + return ENC::to_utf8(display_name.get()).value(); } /** diff --git a/src/yycc/windows/dialog.hpp b/src/yycc/windows/dialog.hpp index e3570a6..0fe3459 100644 --- a/src/yycc/windows/dialog.hpp +++ b/src/yycc/windows/dialog.hpp @@ -29,7 +29,6 @@ namespace yycc::windows::dialog { /// @brief The error occurs in this module. enum class DialogError { - BadEncoding, ///< Error occurs when perform encoding convertion. TooManyFilters, ///< The size of file filters list is too large for Windows. IndexOverflow, ///< Default filter index is too large for Windows. EmptyFilters, ///< File filters is empty when picking file. @@ -310,7 +309,7 @@ namespace yycc::windows::dialog { */ DialogResult> open_folder(const FileDialog& params); -} +} // namespace yycc::windows::dialog #undef NS_YYCC_WINDOWS_COM diff --git a/src/yycc/windows/winfct.cpp b/src/yycc/windows/winfct.cpp index 3235d0e..d16e89d 100644 --- a/src/yycc/windows/winfct.cpp +++ b/src/yycc/windows/winfct.cpp @@ -21,7 +21,7 @@ namespace yycc::windows::winfct { (LPCWSTR) get_current_module, &hModule); if (rv) return hModule; - else return std::unexpected(WinFctError::Backend); + else return std::unexpected(WinFctError::Win32); } WinFctResult get_temp_directory() { @@ -33,7 +33,7 @@ namespace yycc::windows::winfct { while (true) { if ((expected_size = ::GetTempPathW(static_cast(wpath.size()), wpath.data())) == 0) { // failed, return - return std::unexpected(WinFctError::Backend); + return std::unexpected(WinFctError::Win32); } if (expected_size > static_cast(wpath.size())) { @@ -47,7 +47,7 @@ namespace yycc::windows::winfct { } // convert to utf8 and return - return ENC::to_utf8(wpath).transform_error([](auto err) { return WinFctError::Encoding; }); + return ENC::to_utf8(wpath).value(); } WinFctResult get_module_file_name(HINSTANCE hModule) { @@ -58,7 +58,7 @@ namespace yycc::windows::winfct { while (true) { if ((copied_size = ::GetModuleFileNameW(hModule, wpath.data(), static_cast(wpath.size()))) == 0) { // failed, return - return std::unexpected(WinFctError::Backend); + return std::unexpected(WinFctError::Win32); } // check insufficient buffer @@ -73,7 +73,7 @@ namespace yycc::windows::winfct { } // convert to utf8 and return - return ENC::to_utf8(wpath).transform_error([](auto err) { return WinFctError::Encoding; }); + return ENC::to_utf8(wpath).value(); } bool is_valid_code_page(UINT code_page) { @@ -82,41 +82,32 @@ namespace yycc::windows::winfct { } WinFctResult copy_file(const std::u8string_view& lpExistingFileName, const std::u8string_view& lpNewFileName, BOOL bFailIfExists) { - auto wExistingFileName = ENC::to_wchar(lpExistingFileName); - auto wNewFileName = ENC::to_wchar(lpNewFileName); - if (!(wExistingFileName.has_value() && wNewFileName.has_value())) { - return std::unexpected(WinFctError::Encoding); - } + auto wExistingFileName = ENC::to_wchar(lpExistingFileName).value(); + auto wNewFileName = ENC::to_wchar(lpNewFileName).value(); - if (!::CopyFileW(wExistingFileName.value().c_str(), wNewFileName.value().c_str(), bFailIfExists)) { - return std::unexpected(WinFctError::Backend); + if (!::CopyFileW(wExistingFileName.c_str(), wNewFileName.c_str(), bFailIfExists)) { + return std::unexpected(WinFctError::Win32); } return {}; } WinFctResult move_file(const std::u8string_view& lpExistingFileName, const std::u8string_view& lpNewFileName) { - auto wExistingFileName = ENC::to_wchar(lpExistingFileName); - auto wNewFileName = ENC::to_wchar(lpNewFileName); - if (!(wExistingFileName.has_value() && wNewFileName.has_value())) { - return std::unexpected(WinFctError::Encoding); - } + auto wExistingFileName = ENC::to_wchar(lpExistingFileName).value(); + auto wNewFileName = ENC::to_wchar(lpNewFileName).value(); - if (!::MoveFileW(wExistingFileName.value().c_str(), wNewFileName.value().c_str())) { - return std::unexpected(WinFctError::Backend); + if (!::MoveFileW(wExistingFileName.c_str(), wNewFileName.c_str())) { + return std::unexpected(WinFctError::Win32); } return {}; } WinFctResult delete_file(const std::u8string_view& lpFileName) { - auto wFileName = ENC::to_wchar(lpFileName); - if (!wFileName.has_value()) { - return std::unexpected(WinFctError::Encoding); - } + auto wFileName = ENC::to_wchar(lpFileName).value(); - if (!::DeleteFileW(wFileName.value().c_str())) { - return std::unexpected(WinFctError::Backend); + if (!::DeleteFileW(wFileName.c_str())) { + return std::unexpected(WinFctError::Win32); } return {}; @@ -144,11 +135,11 @@ namespace yycc::windows::winfct { // fetch path LPWSTR raw_known_path; HRESULT hr = SHGetKnownFolderPath(*pId, KF_FLAG_CREATE, NULL, &raw_known_path); - if (FAILED(hr)) return std::unexpected(WinFctError::Backend); + if (FAILED(hr)) return std::unexpected(WinFctError::Win32); COM::SmartLPWSTR known_path(raw_known_path); // convert to utf8 and return - return ENC::to_utf8(known_path.get()).transform_error([](auto err) { return WinFctError::Encoding; }); + return ENC::to_utf8(known_path.get()).value(); } #endif diff --git a/src/yycc/windows/winfct.hpp b/src/yycc/windows/winfct.hpp index 06415da..f0b46f6 100644 --- a/src/yycc/windows/winfct.hpp +++ b/src/yycc/windows/winfct.hpp @@ -15,8 +15,7 @@ namespace yycc::windows::winfct { /// @brief All errors occur in this module. enum class WinFctError { - Backend, ///< Error occurs when calling Win32 functions. - Encoding, ///< Can not perform encoding convertion. + Win32, ///< Error occurs when calling Win32 functions. NoCom, ///< No COM environment. }; diff --git a/testbench/CMakeLists.txt b/testbench/CMakeLists.txt index 731f700..167b75e 100644 --- a/testbench/CMakeLists.txt +++ b/testbench/CMakeLists.txt @@ -39,6 +39,7 @@ PRIVATE yycc/carton/termcolor.cpp yycc/carton/wcwidth.cpp yycc/carton/tabulate.cpp + yycc/carton/clap.cpp ) target_sources(YYCCTestbench PRIVATE diff --git a/src/yycc/carton/clap/kernel.hpp b/testbench/yycc/carton/clap.cpp similarity index 100% rename from src/yycc/carton/clap/kernel.hpp rename to testbench/yycc/carton/clap.cpp diff --git a/testbench/yycc/patch/ptr_pad.cpp b/testbench/yycc/patch/ptr_pad.cpp index 0bc88aa..8d8f420 100644 --- a/testbench/yycc/patch/ptr_pad.cpp +++ b/testbench/yycc/patch/ptr_pad.cpp @@ -10,12 +10,11 @@ namespace yycctest::patch::ptr_pad { TEST(PatchPtrPad, Normal) { auto rv = OP::printf(u8"0x%" PRIXPTR_LPAD PRIXPTR, nullptr); - EXPECT_TRUE(rv.has_value()); #if defined(YYCC_PTRSIZE_32) - EXPECT_EQ(rv.value(), u8"0x00000000"); + EXPECT_EQ(rv, u8"0x00000000"); #else - EXPECT_EQ(rv.value(), u8"0x0000000000000000"); + EXPECT_EQ(rv, u8"0x0000000000000000"); #endif } diff --git a/testbench/yycc/string/op.cpp b/testbench/yycc/string/op.cpp index f7ed3ba..c1102f8 100644 --- a/testbench/yycc/string/op.cpp +++ b/testbench/yycc/string/op.cpp @@ -10,8 +10,16 @@ using namespace std::literals::string_view_literals; namespace yycctest::string::op { TEST(StringOp, Printf) { - auto rv = OP::printf(u8"%s == %s", u8"Hello World", u8"Hello, world"); - EXPECT_EQ(rv, u8"Hello World == Hello, world"); + // UTF8 string + { + auto rv = OP::printf(u8"%s == %s", u8"Hello World", u8"Hello, world"); + EXPECT_EQ(rv, u8"Hello World == Hello, world"); + } + // Ordinary string + { + auto rv = OP::printf("%s == %s", "Hello World", "Hello, world"); + EXPECT_EQ(rv, "Hello World == Hello, world"); + } } TEST(StringOp, Replace) {