File indexing completed on 2026-01-08 10:09:17
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009
0010
0011
0012 #include "../Encoding.hpp"
0013 #include "../Macros.hpp"
0014
0015
0016 #include <array>
0017 #include <clocale>
0018 #include <cstdlib>
0019 #include <cstring>
0020 #include <cwchar>
0021 #include <locale>
0022 #include <stdexcept>
0023 #include <string>
0024 #include <type_traits>
0025 #include <utility>
0026
0027
0028 namespace CLI {
0029
0030
0031 namespace detail {
0032
0033 #if !CLI11_HAS_CODECVT
0034
0035 CLI11_INLINE void set_unicode_locale() {
0036 static const std::array<const char *, 3> unicode_locales{{"C.UTF-8", "en_US.UTF-8", ".UTF-8"}};
0037
0038 for(const auto &locale_name : unicode_locales) {
0039 if(std::setlocale(LC_ALL, locale_name) != nullptr) {
0040 return;
0041 }
0042 }
0043 throw std::runtime_error("CLI::narrow: could not set locale to C.UTF-8");
0044 }
0045
0046 template <typename F> struct scope_guard_t {
0047 F closure;
0048
0049 explicit scope_guard_t(F closure_) : closure(closure_) {}
0050 ~scope_guard_t() { closure(); }
0051 };
0052
0053 template <typename F> CLI11_NODISCARD CLI11_INLINE scope_guard_t<F> scope_guard(F &&closure) {
0054 return scope_guard_t<F>{std::forward<F>(closure)};
0055 }
0056
0057 #endif
0058
0059 CLI11_DIAGNOSTIC_PUSH
0060 CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
0061
0062 CLI11_INLINE std::string narrow_impl(const wchar_t *str, std::size_t str_size) {
0063 #if CLI11_HAS_CODECVT
0064 #ifdef _WIN32
0065 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(str, str + str_size);
0066
0067 #else
0068 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(str, str + str_size);
0069
0070 #endif
0071 #else
0072 (void)str_size;
0073 std::mbstate_t state = std::mbstate_t();
0074 const wchar_t *it = str;
0075
0076 std::string old_locale = std::setlocale(LC_ALL, nullptr);
0077 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
0078 set_unicode_locale();
0079
0080 std::size_t new_size = std::wcsrtombs(nullptr, &it, 0, &state);
0081 if(new_size == static_cast<std::size_t>(-1)) {
0082 throw std::runtime_error("CLI::narrow: conversion error in std::wcsrtombs at offset " +
0083 std::to_string(it - str));
0084 }
0085 std::string result(new_size, '\0');
0086 std::wcsrtombs(const_cast<char *>(result.data()), &str, new_size, &state);
0087
0088 return result;
0089
0090 #endif
0091 }
0092
0093 CLI11_INLINE std::wstring widen_impl(const char *str, std::size_t str_size) {
0094 #if CLI11_HAS_CODECVT
0095 #ifdef _WIN32
0096 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(str, str + str_size);
0097
0098 #else
0099 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(str, str + str_size);
0100
0101 #endif
0102 #else
0103 (void)str_size;
0104 std::mbstate_t state = std::mbstate_t();
0105 const char *it = str;
0106
0107 std::string old_locale = std::setlocale(LC_ALL, nullptr);
0108 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
0109 set_unicode_locale();
0110
0111 std::size_t new_size = std::mbsrtowcs(nullptr, &it, 0, &state);
0112 if(new_size == static_cast<std::size_t>(-1)) {
0113 throw std::runtime_error("CLI::widen: conversion error in std::mbsrtowcs at offset " +
0114 std::to_string(it - str));
0115 }
0116 std::wstring result(new_size, L'\0');
0117 std::mbsrtowcs(const_cast<wchar_t *>(result.data()), &str, new_size, &state);
0118
0119 return result;
0120
0121 #endif
0122 }
0123
0124 CLI11_DIAGNOSTIC_POP
0125
0126 }
0127
0128 CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t str_size) { return detail::narrow_impl(str, str_size); }
0129 CLI11_INLINE std::string narrow(const std::wstring &str) { return detail::narrow_impl(str.data(), str.size()); }
0130
0131 CLI11_INLINE std::string narrow(const wchar_t *str) { return detail::narrow_impl(str, std::wcslen(str)); }
0132
0133 CLI11_INLINE std::wstring widen(const char *str, std::size_t str_size) { return detail::widen_impl(str, str_size); }
0134 CLI11_INLINE std::wstring widen(const std::string &str) { return detail::widen_impl(str.data(), str.size()); }
0135
0136 CLI11_INLINE std::wstring widen(const char *str) { return detail::widen_impl(str, std::strlen(str)); }
0137
0138 #ifdef CLI11_CPP17
0139 CLI11_INLINE std::string narrow(std::wstring_view str) { return detail::narrow_impl(str.data(), str.size()); }
0140 CLI11_INLINE std::wstring widen(std::string_view str) { return detail::widen_impl(str.data(), str.size()); }
0141 #endif
0142
0143 #if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
0144 CLI11_INLINE std::filesystem::path to_path(std::string_view str) {
0145 return std::filesystem::path{
0146 #ifdef _WIN32
0147 widen(str)
0148 #else
0149 str
0150 #endif
0151 };
0152 }
0153 #endif
0154
0155
0156 }