From 19086f44e203669fec214feaeeb1079133c22b18 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Fri, 12 Dec 2025 13:45:13 +0800 Subject: [PATCH] refactor: add result wrapper for env vars and args --- src/yycc/carton/clap/parser.cpp | 5 ++++- src/yycc/carton/clap/resolver.cpp | 5 ++++- src/yycc/carton/clap/types.hpp | 3 ++- src/yycc/env.cpp | 34 +++++++++++++++---------------- src/yycc/env.hpp | 23 ++++++++++++--------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/yycc/carton/clap/parser.cpp b/src/yycc/carton/clap/parser.cpp index 8202c79..8f01379 100644 --- a/src/yycc/carton/clap/parser.cpp +++ b/src/yycc/carton/clap/parser.cpp @@ -177,7 +177,10 @@ namespace yycc::carton::clap::parser { } TYPES::ClapResult Parser::from_system(const APPLICATION::Application& app) { - auto args = ENV::get_args(); + auto rv_args = ENV::get_args(); + if (!rv_args.has_value()) return std::unexpected(TYPES::ClapError::Others); + auto args = std::move(rv_args.value()); + auto rv = capture(app, args | std::views::transform([](const auto& s) { return std::u8string_view(s); })); diff --git a/src/yycc/carton/clap/resolver.cpp b/src/yycc/carton/clap/resolver.cpp index 38e9dc9..fe413a2 100644 --- a/src/yycc/carton/clap/resolver.cpp +++ b/src/yycc/carton/clap/resolver.cpp @@ -54,7 +54,10 @@ namespace yycc::carton::clap::resolver { } TYPES::ClapResult Resolver::from_system(const APPLICATION::Application& app) { - auto vars = ENV::get_vars(); + auto rv_vars = ENV::get_vars(); + if (!rv_vars.has_value()) return std::unexpected(TYPES::ClapError::Others); + auto vars = std::move(rv_vars.value()); + auto rv = capture(app, vars | std::views::transform([](const auto& p) { return std::make_pair(p.first, p.second); })); diff --git a/src/yycc/carton/clap/types.hpp b/src/yycc/carton/clap/types.hpp index edaa891..abc6990 100644 --- a/src/yycc/carton/clap/types.hpp +++ b/src/yycc/carton/clap/types.hpp @@ -11,7 +11,8 @@ namespace yycc::carton::clap::types { UnexpectedValue, ///< When parsing commandline argument, reach associated value unexpected. LostValue, ///< When parsing commandline argument, fail to find associated value. NotCaptured, ///< When fetching option or variable, given option or variable is not captured. - BadCast ///< When fetching option or variable, the content of given option or variable can not be cast into expected type. + BadCast, ///< When fetching option or variable, the content of given option or variable can not be cast into expected type. + Others, ///< Any other errors. }; /// @brief The result type used in this module. diff --git a/src/yycc/env.cpp b/src/yycc/env.cpp index 5dca976..d48999b 100644 --- a/src/yycc/env.cpp +++ b/src/yycc/env.cpp @@ -173,7 +173,7 @@ namespace yycc::env { using SmartEnvironmentStrings = std::unique_ptr, EnvironmentStringsDeleter>; #endif - std::vector get_vars() { + VarResult> get_vars() { // TODO: Considering whether replace return value with an iterator. std::vector rv; @@ -181,7 +181,7 @@ namespace yycc::env { // Reference: https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentstringsw SmartEnvironmentStrings env_block(GetEnvironmentStringsW()); - if (env_block == nullptr) throw std::runtime_error("GetEnvironmentStringsW call failed"); + if (env_block == nullptr) return std::unexpected(VarError::SysCall); wchar_t *current = env_block.get(); while (*current != L'\0') { @@ -193,17 +193,17 @@ namespace yycc::env { if (pos != std::string::npos) { auto key = entry.substr(0, pos); auto value = entry.substr(pos + 1); - if (key.empty()) throw std::runtime_error("unexpected empty variable name"); + if (key.empty()) return std::unexpected(VarError::NullPointer); auto u8key = ENC::to_utf8(key); auto u8value = ENC::to_utf8(value); if (u8key.has_value() && u8value.has_value()) { rv.emplace_back(std::make_pair(std::move(u8key.value()), std::move(u8value.value()))); } else { - throw std::runtime_error("bad encoding of variable"); + return std::unexpected(VarError::BadEncoding); } } else { - throw std::runtime_error("bad variable syntax"); + return std::unexpected(VarError::Others); } // Increase the pointer @@ -221,10 +221,10 @@ namespace yycc::env { if (pos != std::string::npos) { auto key = entry.substr(0, pos); auto value = entry.substr(pos + 1); - if (key.empty()) throw std::runtime_error("unexpected empty variable name"); + if (key.empty()) return std::unexpected(VarError::NullPointer); rv.emplace_back(std::make_pair(REINTERPRET::as_utf8(key), REINTERPRET::as_utf8(value))); } else { - throw std::runtime_error("bad variable syntax"); + return std::unexpected(VarError::Others); } } #endif @@ -362,7 +362,7 @@ namespace yycc::env { else return std::unexpected(PathError::SysCall); #else // Reference: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html - + // HOME is an environment variable in POSIX standard. auto home = get_var(u8"HOME"); if (home.has_value()) rv = std::move(home.value()); @@ -385,7 +385,7 @@ namespace yycc::env { class CommandLineArgvDeleter { public: CommandLineArgvDeleter() {} - void operator()(LPWCH ptr) { + void operator()(LPWSTR* ptr) { if (ptr != nullptr) { LocalFree(ptr); } @@ -395,7 +395,7 @@ namespace yycc::env { #endif - std::vector get_args() { + ArgResult> get_args() { // TODO: Considering whether use iterator as return value. std::vector rv; @@ -405,18 +405,18 @@ namespace yycc::env { // Fetch args from Win32 functions int argc; SmartCommandLineArgv argv(CommandLineToArgvW(GetCommandLineW(), &argc)); - if (argv == nullptr) throw std::runtime_error("unexpected blank command line tuple"); + if (argv == nullptr) return std::unexpected(ArgError::NullPointer); // Analyse it for (int i = 1; i < argc; ++i) { // starts with 1 to remove first part (executable self) auto arg = argv.get()[i]; - if (arg == nullptr) throw std::runtime_error("unexpected nullptr argument"); + if (arg == nullptr) return std::unexpected(ArgError::NullPointer); auto u8arg = ENC::to_utf8(arg); if (u8arg.has_value()) { rv.emplace_back(std::move(u8arg.value())); } else { - throw std::runtime_error("bad encoding of argument"); + return std::unexpected(ArgError::BadEncoding); } } @@ -437,7 +437,7 @@ namespace yycc::env { // We use NUL as delimiter std::getline(cmdline, arg, '\0'); // Check whether reading is okey. - if (!cmdline.good()) throw std::runtime_error("bad reading"); + if (!cmdline.good()) return std::unexpected(ArgError::Others); // If return string is empty, it means that we reach the tail. if (arg.empty()) break; @@ -447,7 +447,7 @@ namespace yycc::env { // Close file cmdline.close(); } else { - throw std::runtime_error("fail to open cmdline file"); + return std::unexpected(ArgError::Others); } #elif defined(YYCC_OS_MACOS) @@ -457,11 +457,11 @@ namespace yycc::env { if (apple_argv && apple_argc) { for (int i = 0; i < *apple_argc; ++i) { auto ptr = (*apple_argv)[i]; - if (ptr == nullptr) throw std::runtime_error("unexpected nullptr argument"); + if (ptr == nullptr) return std::unexpected(ArgError::NullPointer); else rv.emplace_back(REINTERPRET::as_utf8(ptr)); } } else { - throw std::runtime_error("fail to get pointer to argument data"); + return std::unexpected(ArgError::SysCall); } #else #error "Not supported OS" diff --git a/src/yycc/env.hpp b/src/yycc/env.hpp index b2f6d75..2716be5 100644 --- a/src/yycc/env.hpp +++ b/src/yycc/env.hpp @@ -21,12 +21,13 @@ namespace yycc::env { /// @brief The error occurs in environment variable operations. enum class VarError { - SysCall, ///< Error occurs when calling backend functions. - NoSuchName, ///< The variable with given name is not presented. - BadName, ///< Given name is ill-formated (empty string or has "=" character). - BadEncoding, ///< Error when performing encoding convertion. - NoMemory, ///< No enough memory to finish this operation. - Others, ///< Any other error types. + SysCall, ///< Error occurs when calling backend functions. + NoSuchName, ///< The variable with given name is not presented. + BadName, ///< Given name is ill-formated (empty string or has "=" character). + BadEncoding, ///< Error when performing encoding convertion. + NoMemory, ///< No enough memory to finish this operation. + NullPointer, ///< Unexpected null pointer occurs during operation. + Others, ///< Any other error types. }; /// @brief The result type in environment variable operations. @@ -74,7 +75,7 @@ namespace yycc::env { * @return The list holding all variables. * @exception std::runtime_error Error occurs when getting variables. */ - std::vector get_vars(); + VarResult> get_vars(); #pragma endregion @@ -121,8 +122,10 @@ namespace yycc::env { /// @brief Error occurs when operating argument related functions. enum class ArgError { - SysCall, ///< Underlying system calling error. - Others, ///< Any other error types. + SysCall, ///< Underlying system calling error. + BadEncoding, ///< Error when performing encoding convertion. + NullPointer, ///< Unexpected null pointer occurs during operation. + Others, ///< Any other error types. }; /// @brief The result type used for argument related functions; @@ -134,7 +137,7 @@ namespace yycc::env { * @return The list holding all argument one by one. * @exception std::runtime_error Error occurs when getting arguments. */ - std::vector get_args(); + ArgResult> get_args(); #pragma endregion