feat: add lost functions for env namespace.
- add some lost functions for env namespace according to Rust std library. hiwever some functions are not implemented. - change some function's signatures located in env namespace. - reduce some useless error kine in env namespace.
This commit is contained in:
@ -113,7 +113,7 @@ namespace yycc::carton::clap::manual {
|
|||||||
auto executable = ENV::current_exe();
|
auto executable = ENV::current_exe();
|
||||||
if (executable.has_value()) {
|
if (executable.has_value()) {
|
||||||
TERMCOLOR::cprintln(trctx.usage_title, TERMCOLOR::Color::Yellow, TERMCOLOR::Color::Default, TERMCOLOR::Attribute::Default, dst);
|
TERMCOLOR::cprintln(trctx.usage_title, TERMCOLOR::Color::Yellow, TERMCOLOR::Color::Default, TERMCOLOR::Attribute::Default, dst);
|
||||||
dst << INDENT << FORMAT::format(trctx.usage_body, executable.value()) << std::endl;
|
dst << INDENT << FORMAT::format(trctx.usage_body, executable.value().u8string()) << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &variables = app.get_variables();
|
const auto &variables = app.get_variables();
|
||||||
|
|||||||
@ -50,7 +50,7 @@ namespace yycc::env {
|
|||||||
// the size passed to this function must include NULL terminal.
|
// the size passed to this function must include NULL terminal.
|
||||||
// So we forcely use checked add and sub for this bad behavior.
|
// So we forcely use checked add and sub for this bad behavior.
|
||||||
auto fct_size = SAFEOP::checked_add<size_t>(wvalue.size(), 1);
|
auto fct_size = SAFEOP::checked_add<size_t>(wvalue.size(), 1);
|
||||||
if (!fct_size.has_value()) return std::unexpected(VarError::BadArithmetic);
|
if (!fct_size.has_value()) return std::unexpected(VarError::Others);
|
||||||
auto rv = ::GetEnvironmentVariableW(wname.c_str(), wvalue.data(), fct_size.value());
|
auto rv = ::GetEnvironmentVariableW(wname.c_str(), wvalue.data(), fct_size.value());
|
||||||
|
|
||||||
// Check the return value
|
// Check the return value
|
||||||
@ -58,14 +58,14 @@ namespace yycc::env {
|
|||||||
// Function failed. Extract error reason.
|
// Function failed. Extract error reason.
|
||||||
auto ec = GetLastError();
|
auto ec = GetLastError();
|
||||||
if (ec == ERROR_ENVVAR_NOT_FOUND) return std::unexpected(VarError::NoSuchName);
|
if (ec == ERROR_ENVVAR_NOT_FOUND) return std::unexpected(VarError::NoSuchName);
|
||||||
else return std::unexpected(VarError::BadCall);
|
else return std::unexpected(VarError::SysCall);
|
||||||
} else {
|
} else {
|
||||||
// Function okey. Check the size.
|
// Function okey. Check the size.
|
||||||
// Fetch function expected size.
|
// Fetch function expected size.
|
||||||
auto rv_size = SAFECAST::try_to<size_t>(rv);
|
auto rv_size = SAFECAST::try_to<size_t>(rv);
|
||||||
if (!rv_size.has_value()) return std::unexpected(VarError::BadArithmetic);
|
if (!rv_size.has_value()) return std::unexpected(VarError::Others);
|
||||||
auto exp_size = SAFEOP::checked_sub<size_t>(rv_size.value(), 1);
|
auto exp_size = SAFEOP::checked_sub<size_t>(rv_size.value(), 1);
|
||||||
if (!exp_size.has_value()) return std::unexpected(VarError::BadArithmetic);
|
if (!exp_size.has_value()) return std::unexpected(VarError::Others);
|
||||||
|
|
||||||
// YYC MARK:
|
// YYC MARK:
|
||||||
// According to Microsoft, the return value of this function is just a bullshit.
|
// According to Microsoft, the return value of this function is just a bullshit.
|
||||||
@ -106,7 +106,7 @@ namespace yycc::env {
|
|||||||
|
|
||||||
// Convert to wchar, set variable, and check result.
|
// 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());
|
auto rv = ::SetEnvironmentVariableW(ENC::to_wchar(name).value().c_str(), ENC::to_wchar(value).value().c_str());
|
||||||
if (!rv) return std::unexpected(VarError::BadCall);
|
if (!rv) return std::unexpected(VarError::SysCall);
|
||||||
else return {};
|
else return {};
|
||||||
#else
|
#else
|
||||||
// Reference: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setenv.html
|
// Reference: https://pubs.opengroup.org/onlinepubs/9699919799/functions/setenv.html
|
||||||
@ -130,7 +130,7 @@ namespace yycc::env {
|
|||||||
|
|
||||||
// Convert to wchar, delete variable, and check result.
|
// Convert to wchar, delete variable, and check result.
|
||||||
auto rv = ::SetEnvironmentVariableW(ENC::to_wchar(name).value().c_str(), NULL);
|
auto rv = ::SetEnvironmentVariableW(ENC::to_wchar(name).value().c_str(), NULL);
|
||||||
if (!rv) return std::unexpected(VarError::BadCall);
|
if (!rv) return std::unexpected(VarError::SysCall);
|
||||||
else return {};
|
else return {};
|
||||||
#else
|
#else
|
||||||
// Reference: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unsetenv.html
|
// Reference: https://pubs.opengroup.org/onlinepubs/9699919799/functions/unsetenv.html
|
||||||
@ -146,18 +146,26 @@ namespace yycc::env {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VarResult<std::vector<VarPair>> get_vars() {
|
||||||
|
// TODO: finish this function according to Rust implementation.
|
||||||
|
// Considering whether replace return value with an iterator.
|
||||||
|
throw std::logic_error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Environment
|
#pragma region Environment Path
|
||||||
|
|
||||||
PathResult<std::u8string> current_exe() {
|
PathResult<std::filesystem::path> current_dir() {
|
||||||
|
return std::filesystem::current_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
PathResult<std::filesystem::path> current_exe() {
|
||||||
#if defined(YYCC_OS_WINDOWS)
|
#if defined(YYCC_OS_WINDOWS)
|
||||||
return WINFCT::get_module_file_name(NULL).transform_error([](auto e) { return PathError::Win32; });
|
return WINFCT::get_module_file_name(NULL).transform_error([](auto e) { return PathError::SysCall; }).transform([](auto v) {
|
||||||
#else
|
return std::filesystem::path(v);
|
||||||
// TODO:
|
});
|
||||||
// "/proc/self/exe" is Linux specific, not in POSIX standard.
|
#elif defined(YYCC_OS_LINUX)
|
||||||
// This method may need further patch when running on macOS.
|
|
||||||
|
|
||||||
// Reference: https://www.man7.org/linux/man-pages/man2/readlink.2.html
|
// Reference: https://www.man7.org/linux/man-pages/man2/readlink.2.html
|
||||||
|
|
||||||
// specify the path
|
// specify the path
|
||||||
@ -169,7 +177,7 @@ namespace yycc::env {
|
|||||||
}
|
}
|
||||||
auto expected_size = SAFECAST::try_to<size_t>(sb.st_size);
|
auto expected_size = SAFECAST::try_to<size_t>(sb.st_size);
|
||||||
if (!expected_size.has_value()) {
|
if (!expected_size.has_value()) {
|
||||||
return std::unexpected(PathError::BadCast);
|
return std::unexpected(PathError::Others);
|
||||||
}
|
}
|
||||||
auto buf_size = expected_size.value();
|
auto buf_size = expected_size.value();
|
||||||
// Some magic symlinks under (for example) /proc and /sys report 'st_size' as zero.
|
// Some magic symlinks under (for example) /proc and /sys report 'st_size' as zero.
|
||||||
@ -184,27 +192,50 @@ namespace yycc::env {
|
|||||||
// write data
|
// write data
|
||||||
auto passed_size = SAFEOP::checked_add<size_t>(buf_size, 1);
|
auto passed_size = SAFEOP::checked_add<size_t>(buf_size, 1);
|
||||||
if (!passed_size.has_value()) {
|
if (!passed_size.has_value()) {
|
||||||
return std::unexpected(PathError::Overflow);
|
return std::unexpected(PathError::Others);
|
||||||
}
|
}
|
||||||
ssize_t nbytes = readlink(path, REINTERPRET::as_ordinary(rv.data()), passed_size.value());
|
ssize_t nbytes = readlink(path, REINTERPRET::as_ordinary(rv.data()), passed_size.value());
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
return std::unexpected(PathError::Posix);
|
return std::unexpected(PathError::Others);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check written size
|
// check written size
|
||||||
auto written_size = SAFECAST::try_to<size_t>(nbytes);
|
auto written_size = SAFECAST::try_to<size_t>(nbytes);
|
||||||
if (!written_size.has_value()) {
|
if (!written_size.has_value()) {
|
||||||
return std::unexpected(PathError::BadCast);
|
return std::unexpected(PathError::Others);
|
||||||
}
|
}
|
||||||
if (written_size.value() != buf_size) {
|
if (written_size.value() != buf_size) {
|
||||||
return std::unexpected(PathError::BadSize);
|
return std::unexpected(PathError::Others);
|
||||||
}
|
}
|
||||||
|
|
||||||
// okey
|
// okey
|
||||||
return rv;
|
return std::filesystem::path(rv);
|
||||||
|
#else
|
||||||
|
// TODO: Implement this in other OS.
|
||||||
|
// "/proc/self/exe" is Linux specific, not in POSIX standard.
|
||||||
|
// This method may need further patch when running on macOS.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathResult<std::filesystem::path> home_dir() {
|
||||||
|
// TODO: finish this function according to Rust implementation.
|
||||||
|
throw std::logic_error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
PathResult<std::filesystem::path> temp_dir() {
|
||||||
|
return std::filesystem::temp_directory_path();
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Environment Argument
|
||||||
|
|
||||||
|
ArgResult<std::vector<std::u8string>> get_args() {
|
||||||
|
// TODO: finish this function according to Rust implementation.
|
||||||
|
// Considering whether use iterator as return value.
|
||||||
|
throw std::logic_error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
} // namespace yycc::env
|
} // namespace yycc::env
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <filesystem>
|
||||||
#include <expected>
|
#include <expected>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The namespace providing runtime environment operations.
|
* @brief The namespace providing runtime environment operations.
|
||||||
|
|
||||||
* @details
|
* @details
|
||||||
* When I programming with Rust, I was astonished that
|
* When I programming with Rust, I was astonished that
|
||||||
* Rust standard library have so much robust environment-related operations,
|
* Rust standard library have so much robust environment-related operations,
|
||||||
@ -20,18 +20,24 @@ namespace yycc::env {
|
|||||||
|
|
||||||
/// @brief The error occurs in environment variable operations.
|
/// @brief The error occurs in environment variable operations.
|
||||||
enum class VarError {
|
enum class VarError {
|
||||||
|
SysCall, ///< Error occurs when calling backend functions.
|
||||||
NoSuchName, ///< The variable with given name is not presented.
|
NoSuchName, ///< The variable with given name is not presented.
|
||||||
BadEncoding, ///< Error when performing encoding convertion.
|
|
||||||
BadArithmetic, ///< Error when performing arithmetic operations.
|
|
||||||
BadCall, ///< Error occurs when calling backend functions.
|
|
||||||
BadName, ///< Given name is ill-formated (empty string or has "=" character).
|
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.
|
NoMemory, ///< No enough memory to finish this operation.
|
||||||
|
Others, ///< Any other error types.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief The result type in environment variable operations.
|
/// @brief The result type in environment variable operations.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using VarResult = std::expected<T, VarError>;
|
using VarResult = std::expected<T, VarError>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The pair representing an environment variable.
|
||||||
|
* @details The left side is the name of variable. The right side is the content of variable.
|
||||||
|
*/
|
||||||
|
using VarPair = std::pair<std::u8string, std::u8string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the value of given environment variable name.
|
* @brief Get the value of given environment variable name.
|
||||||
* @param[in] name The name of environment variable
|
* @param[in] name The name of environment variable
|
||||||
@ -61,17 +67,21 @@ namespace yycc::env {
|
|||||||
*/
|
*/
|
||||||
VarResult<void> del_var(const std::u8string_view& name);
|
VarResult<void> del_var(const std::u8string_view& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns an list of (variable, value) pairs of strings,
|
||||||
|
* for all the environment variables of the current process.
|
||||||
|
* @return The list holding all variables.
|
||||||
|
*/
|
||||||
|
VarResult<std::vector<VarPair>> get_vars();
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Environment Path
|
#pragma region Environment Path
|
||||||
|
|
||||||
/// @brief Error occurs when operating path related functions.
|
/// @brief Error occurs when operating path related functions.
|
||||||
enum class PathError {
|
enum class PathError {
|
||||||
Win32, ///< Underlying Win32 function error.
|
SysCall, ///< Underlying system calling error.
|
||||||
Posix, ///< Underlying POSIX failed.
|
Others, ///< Any other error types.
|
||||||
BadSize, ///< Written size if not matched with expected size.
|
|
||||||
BadCast, ///< Error occurs when casting values.
|
|
||||||
Overflow, ///< Some arithmetic operation overflow.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief The result type used for path related functions;
|
/// @brief The result type used for path related functions;
|
||||||
@ -79,10 +89,49 @@ namespace yycc::env {
|
|||||||
using PathResult = std::expected<T, PathError>;
|
using PathResult = std::expected<T, PathError>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the path of the current running executable.
|
* @brief Returns the current working directory.
|
||||||
* @return Gotten path (no absolute path guaranteed) or error occurs.
|
* @return Current working directory path or error occurs.
|
||||||
*/
|
*/
|
||||||
PathResult<std::u8string> current_exe();
|
PathResult<std::filesystem::path> current_dir();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the path of the current running executable.
|
||||||
|
* @return Current running executable path or error occurs.
|
||||||
|
* Please note that there is no guarantee that return path is absolute path.
|
||||||
|
*/
|
||||||
|
PathResult<std::filesystem::path> current_exe();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the path of the current user's home directory if known.
|
||||||
|
* @return Current user's home directory path or error occurs.
|
||||||
|
*/
|
||||||
|
PathResult<std::filesystem::path> home_dir();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the path of a temporary directory.
|
||||||
|
* @return The path of a temporary directory.
|
||||||
|
*/
|
||||||
|
PathResult<std::filesystem::path> temp_dir();
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Environment Argument
|
||||||
|
|
||||||
|
/// @brief Error occurs when operating argument related functions.
|
||||||
|
enum class ArgError {
|
||||||
|
SysCall, ///< Underlying system calling error.
|
||||||
|
Others, ///< Any other error types.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief The result type used for argument related functions;
|
||||||
|
template<typename T>
|
||||||
|
using ArgResult = std::expected<T, ArgError>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the arguments that this program was started with (normally passed via the command line).
|
||||||
|
* @return The list holding all argument one by one.
|
||||||
|
*/
|
||||||
|
ArgResult<std::vector<std::u8string>> get_args();
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|||||||
@ -48,8 +48,7 @@ namespace yycctest::env {
|
|||||||
auto rv = ENV::current_exe();
|
auto rv = ENV::current_exe();
|
||||||
ASSERT_TRUE(rv.has_value());
|
ASSERT_TRUE(rv.has_value());
|
||||||
|
|
||||||
std::filesystem::path p(rv.value());
|
auto filename = rv.value().filename().u8string();
|
||||||
auto filename = p.filename().u8string();
|
|
||||||
#if defined(YYCC_OS_WINDOWS)
|
#if defined(YYCC_OS_WINDOWS)
|
||||||
// Only Windows has special ext.
|
// Only Windows has special ext.
|
||||||
EXPECT_EQ(filename, u8"YYCCTest.exe");
|
EXPECT_EQ(filename, u8"YYCCTest.exe");
|
||||||
|
|||||||
Reference in New Issue
Block a user