1
0

fix: change the behavior of printf in string op.

- add compiler hint for checking the arguments of printf.
- change the return value of printf. from std::expected to normal value. use C++ exception to indicate error.
	* the error of printf usually caused by programmer. so it can be found when testing program.
	* so i use std::logic_error to indicate this and programmer should fix this before releasing program.
- change the use of encoding convertion. for those cases that convertion must be safe, we unwrap it directly.
This commit is contained in:
2025-09-22 22:14:36 +08:00
parent 45e4031b5c
commit c85830902b
22 changed files with 240 additions and 164 deletions

5
src/yycc/carton/clap.hpp Normal file
View File

@ -0,0 +1,5 @@
#pragma once
namespace yycc::carton::clap {
}

View File

@ -0,0 +1,5 @@
#include "option.hpp"
namespace yycc::carton::clap::option {
}

View File

@ -0,0 +1,85 @@
#pragma once
#include "types.hpp"
#include "../../macro/class_copy_move.hpp"
#include "../../string/op.hpp"
#include <optional>
#include <stdexcept>
#include <format>
#include <string>
#define NS_YYCC_CLAP_TYPES ::yycc::carton::clap::types
namespace yycc::carton::clap::option {
class Option {
public:
Option(std::optional<std::u8string_view> short_name,
std::optional<std::u8string_view> long_name,
std::optional<std::u8string_view> 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<std::u8string_view> get_short_name() const { return this->short_name; }
std::optional<std::u8string_view> get_long_name() const { return this->long_name; }
std::optional<std::u8string_view> 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<std::u8string> short_name;
std::optional<std::u8string> long_name;
std::optional<std::u8string> value_hint;
std::u8string description;
};
} // namespace yycc::carton::clap::option
#undef NS_YYCC_CLAP_TYPES

View File

@ -0,0 +1,19 @@
#pragma once
#include <expected>
#include <string_view>
namespace yycc::carton::clap::types {
enum class ClapError {
};
template<typename T>
using ClapResult = std::expected<T, ClapError>;
inline constexpr std::u8string_view DASH = u8"-";
inline constexpr std::u8string_view DOUBLE_DASH = u8"--";
using Token = size_t;
} // namespace yycc::carton::clap::types

View File

@ -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<DWORD>::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;

View File

@ -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());
}
}
};

View File

@ -468,11 +468,8 @@ namespace yycc::carton::wcwidth {
}
Result<size_t> 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

View File

@ -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.
};