CLI11
C++11 Command Line Interface Parser
Loading...
Searching...
No Matches
Encoding_inl.hpp
1// Copyright (c) 2017-2024, University of Cincinnati, developed by Henry Schreiner
2// under NSF AWARD 1414736 and by the respective contributors.
3// All rights reserved.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6
7#pragma once
8
9// IWYU pragma: private, include "CLI/CLI.hpp"
10
11// This include is only needed for IDEs to discover symbols
12#include "../Encoding.hpp"
13#include "../Macros.hpp"
14
15// [CLI11:public_includes:set]
16#include <array>
17#include <clocale>
18#include <cstdlib>
19#include <cstring>
20#include <cwchar>
21#include <locale>
22#include <stdexcept>
23#include <string>
24#include <type_traits>
25#include <utility>
26// [CLI11:public_includes:end]
27
28namespace CLI {
29// [CLI11:encoding_inl_hpp:verbatim]
30
31namespace detail {
32
33#if !CLI11_HAS_CODECVT
35CLI11_INLINE void set_unicode_locale() {
36 static const std::array<const char *, 3> unicode_locales{{"C.UTF-8", "en_US.UTF-8", ".UTF-8"}};
37
38 for(const auto &locale_name : unicode_locales) {
39 if(std::setlocale(LC_ALL, locale_name) != nullptr) {
40 return;
41 }
42 }
43 throw std::runtime_error("CLI::narrow: could not set locale to C.UTF-8");
44}
45
46template <typename F> struct scope_guard_t {
47 F closure;
48
49 explicit scope_guard_t(F closure_) : closure(closure_) {}
50 ~scope_guard_t() { closure(); }
51};
52
53template <typename F> CLI11_NODISCARD CLI11_INLINE scope_guard_t<F> scope_guard(F &&closure) {
54 return scope_guard_t<F>{std::forward<F>(closure)};
55}
56
57#endif // !CLI11_HAS_CODECVT
58
59CLI11_DIAGNOSTIC_PUSH
60CLI11_DIAGNOSTIC_IGNORE_DEPRECATED
61
62CLI11_INLINE std::string narrow_impl(const wchar_t *str, std::size_t str_size) {
63#if CLI11_HAS_CODECVT
64#ifdef _WIN32
65 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(str, str + str_size);
66
67#else
68 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(str, str + str_size);
69
70#endif // _WIN32
71#else // CLI11_HAS_CODECVT
72 (void)str_size;
73 std::mbstate_t state = std::mbstate_t();
74 const wchar_t *it = str;
75
76 std::string old_locale = std::setlocale(LC_ALL, nullptr);
77 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
78 set_unicode_locale();
79
80 std::size_t new_size = std::wcsrtombs(nullptr, &it, 0, &state);
81 if(new_size == static_cast<std::size_t>(-1)) {
82 throw std::runtime_error("CLI::narrow: conversion error in std::wcsrtombs at offset " +
83 std::to_string(it - str));
84 }
85 std::string result(new_size, '\0');
86 std::wcsrtombs(const_cast<char *>(result.data()), &str, new_size, &state);
87
88 return result;
89
90#endif // CLI11_HAS_CODECVT
91}
92
93CLI11_INLINE std::wstring widen_impl(const char *str, std::size_t str_size) {
94#if CLI11_HAS_CODECVT
95#ifdef _WIN32
96 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(str, str + str_size);
97
98#else
99 return std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(str, str + str_size);
100
101#endif // _WIN32
102#else // CLI11_HAS_CODECVT
103 (void)str_size;
104 std::mbstate_t state = std::mbstate_t();
105 const char *it = str;
106
107 std::string old_locale = std::setlocale(LC_ALL, nullptr);
108 auto sg = scope_guard([&] { std::setlocale(LC_ALL, old_locale.c_str()); });
109 set_unicode_locale();
110
111 std::size_t new_size = std::mbsrtowcs(nullptr, &it, 0, &state);
112 if(new_size == static_cast<std::size_t>(-1)) {
113 throw std::runtime_error("CLI::widen: conversion error in std::mbsrtowcs at offset " +
114 std::to_string(it - str));
115 }
116 std::wstring result(new_size, L'\0');
117 std::mbsrtowcs(const_cast<wchar_t *>(result.data()), &str, new_size, &state);
118
119 return result;
120
121#endif // CLI11_HAS_CODECVT
122}
123
124CLI11_DIAGNOSTIC_POP
125
126} // namespace detail
127
128CLI11_INLINE std::string narrow(const wchar_t *str, std::size_t str_size) { return detail::narrow_impl(str, str_size); }
129CLI11_INLINE std::string narrow(const std::wstring &str) { return detail::narrow_impl(str.data(), str.size()); }
130// Flawfinder: ignore
131CLI11_INLINE std::string narrow(const wchar_t *str) { return detail::narrow_impl(str, std::wcslen(str)); }
132
133CLI11_INLINE std::wstring widen(const char *str, std::size_t str_size) { return detail::widen_impl(str, str_size); }
134CLI11_INLINE std::wstring widen(const std::string &str) { return detail::widen_impl(str.data(), str.size()); }
135// Flawfinder: ignore
136CLI11_INLINE std::wstring widen(const char *str) { return detail::widen_impl(str, std::strlen(str)); }
137
138#ifdef CLI11_CPP17
139CLI11_INLINE std::string narrow(std::wstring_view str) { return detail::narrow_impl(str.data(), str.size()); }
140CLI11_INLINE std::wstring widen(std::string_view str) { return detail::widen_impl(str.data(), str.size()); }
141#endif // CLI11_CPP17
142
143#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0
144CLI11_INLINE std::filesystem::path to_path(std::string_view str) {
145 return std::filesystem::path{
146#ifdef _WIN32
147 widen(str)
148#else
149 str
150#endif // _WIN32
151 };
152}
153#endif // CLI11_HAS_FILESYSTEM
154
155// [CLI11:encoding_inl_hpp:end]
156} // namespace CLI