cpp-terminal 1.0.0
Small C++ library for writing multiplatform terminal applications
Loading...
Searching...
No Matches
exception.cpp
Go to the documentation of this file.
1/*
2* cpp-terminal
3* C++ library for writing multi-platform terminal applications.
4*
5* SPDX-FileCopyrightText: 2019-2025 cpp-terminal
6*
7* SPDX-License-Identifier: MIT
8*/
9
11
14#include "return_code.hpp"
15
16#include <atomic>
17#include <exception>
18
19#if defined(_WIN32)
21
22 #include <memory>
23 #pragma warning(push)
24 #pragma warning(disable : 4668)
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h>
27 #pragma warning(pop)
28 #if defined(MessageBox)
29 #undef MessageBox
30 #endif
31#else
32 #include <cstring>
33#endif
34
35#include <cerrno>
36#include <cstdio>
37#include <string>
38
39Term::Exception::Exception(const std::string& message) noexcept : m_message(message) {}
40
41Term::Exception::Exception(const std::int64_t& code, const std::string& message) noexcept : m_code(code), m_message(message) {}
42
43const char* Term::Exception::what() const noexcept
44{
45 build_what();
46 return m_what.c_str();
47}
48
49std::int64_t Term::Exception::code() const noexcept { return m_code; }
50
51std::string Term::Exception::message() const noexcept { return m_message; }
52
53std::string Term::Exception::context() const noexcept { return m_context; }
54
55Term::Exception::Exception(const std::int64_t& code) noexcept : m_code(code) {}
56
57void Term::Exception::build_what() const noexcept
58{
59 if(0 == m_code) { m_what = m_message; }
60 else { m_what = "error " + std::to_string(m_code) + ": " + m_message; }
61}
62
63void Term::Exception::setMessage(const std::string& message) noexcept { m_message = message; }
64
65void Term::Exception::setContext(const std::string& context) noexcept { m_context = context; }
66
67void Term::Exception::setWhat(const std::string& what) const noexcept { m_what = what; }
68
69#if defined(_WIN32)
70
71std::int64_t Term::Private::WindowsError::error() const noexcept { return m_error; }
72
74
76{
77 m_error = static_cast<std::int64_t>(GetLastError());
78 m_check_value = ret;
79 return *this;
80}
81
82void Term::Private::WindowsError::throw_exception(const std::string& str) const
83{
85}
86
87Term::Private::WindowsException::WindowsException(const std::int64_t& error, const std::string& context) : Term::Exception(static_cast<std::int64_t>(error))
88{
90 wchar_t* ptr{nullptr};
91 const DWORD cchMsg{FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, static_cast<uint32_t>(code()), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), reinterpret_cast<wchar_t*>(&ptr), 0, nullptr)};
92 if(cchMsg > 0)
93 {
94 auto deleter = [](void* p)
95 {
96 if(p != nullptr) { ::LocalFree(p); }
97 };
98 std::unique_ptr<wchar_t, decltype(deleter)> ptrBuffer(ptr, deleter);
99 std::string ret{Term::Private::to_narrow(ptrBuffer.get())};
100 if(ret.size() >= 2 && ret[ret.size() - 1] == '\n' && ret[ret.size() - 2] == '\r') ret.erase(ret.size() - 2);
101 setMessage(ret);
102 }
103 else { throw Term::Exception(::GetLastError(), "Error in FormatMessageW"); }
104}
105
107{
108 std::string what{std::string("windows error ") + std::to_string(code()) + std::string(": ") + message().c_str()};
109 if(!context().empty()) what += " [" + context() + "]";
110 setWhat(what);
111}
112
113#endif
114
116{
117#if defined(_WIN32)
118 _set_errno(0);
119#else
120 errno = {0}; //NOSONAR
121#endif
122}
123
125{
126#if defined(_WIN32)
127 _set_errno(0);
128#else
129 errno = {0}; //NOSONAR
130#endif
131}
132
133std::int64_t Term::Private::Errno::error() const noexcept { return m_errno; }
134
135bool Term::Private::Errno::check_value() const noexcept { return m_check_value; }
136
138{
139#if defined(_WIN32)
140 int err{static_cast<int>(m_errno)};
141 _get_errno(&err);
142#else
143 m_errno = static_cast<std::uint32_t>(errno); //NOSONAR
144#endif
145 m_check_value = {ret};
146 return *this;
147}
148
149void Term::Private::Errno::throw_exception(const std::string& str) const
150{
152}
153
154Term::Private::ErrnoException::ErrnoException(const std::int64_t& error, const std::string& context) : Term::Exception(error)
155{
157#if defined(_WIN32)
158 std::wstring message(m_maxSize, L'\0');
159 const errno_t result = _wcserror_s(&message[0], message.size(), static_cast<int>(error));
160 if(result == 0) setMessage(Term::Private::to_narrow(message.c_str()));
161 else
162 setMessage("_wcserror_s failed");
163#else
164 std::string message(m_maxSize, '\0');
165 message = ::strerror_r(static_cast<std::int32_t>(error), &message[0], message.size()); // NOLINT(readability-container-data-pointer)
167#endif
168}
169
171{
172 std::string what{"errno " + std::to_string(code()) + ": " + message()};
173 if(!context().empty()) { what += +" [" + context() + "]"; }
174 setWhat(what);
175}
176
178{
179 try
180 {
181 std::exception_ptr exception{std::current_exception()};
182 if(exception != nullptr) { std::rethrow_exception(exception); }
183 }
184 catch(const Term::Exception& exception)
185 {
186 switch(destination)
187 {
189#if defined(_WIN32)
190 MessageBoxW(nullptr, Term::Private::to_wide(exception.what()).c_str(), Term::Private::to_wide("cpp-terminal v" + Term::Version::string()).c_str(), MB_OK | MB_ICONERROR);
191 break;
192#endif
194#if defined(_WIN32)
195 (void)(fputws(Term::Private::to_wide(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n")).c_str(), stderr));
196#else
197 (void)(fputs(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n").c_str(), stderr));
198#endif
199 break;
200 default: break;
201 }
202 }
203 catch(const std::exception& exception)
204 {
205 switch(destination)
206 {
208#if defined(_WIN32)
209 MessageBoxW(nullptr, Term::Private::to_wide(exception.what()).c_str(), Term::Private::to_wide("cpp-terminal v" + Term::Version::string()).c_str(), MB_OK | MB_ICONERROR);
210 break;
211#endif
213#if defined(_WIN32)
214 (void)(fputws(Term::Private::to_wide(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n")).c_str(), stderr));
215#else
216 (void)(fputs(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n").c_str(), stderr));
217#endif
218 break;
219 default: break;
220 }
221 }
222 catch(...)
223 {
224 switch(destination)
225 {
227#if defined(_WIN32)
228 MessageBoxW(nullptr, Term::Private::to_wide("cpp-terminal v" + Term::Version::string() + "Unknown error").c_str(), Term::Private::to_wide("cpp-terminal v" + Term::Version::string()).c_str(), MB_OK | MB_ICONERROR);
229 break;
230#endif
232#if defined(_WIN32)
233 (void)(fputws(Term::Private::to_wide("cpp-terminal v" + Term::Version::string() + ": Unknown error\n").c_str(), stderr));
234#else
235 (void)(fputs(("cpp-terminal v" + Term::Version::string() + ": Unknown error\n").c_str(), stderr));
236#endif
237 default: break;
238 }
239 }
240 (void)(std::fflush(stderr));
241 std::_Exit(Term::returnCode());
242}
const char * what() const noexcept override
Definition exception.cpp:43
virtual void build_what() const noexcept
Definition exception.cpp:57
std::int64_t m_code
Definition exception.hpp:44
void setContext(const std::string &context) noexcept
Definition exception.cpp:65
void setWhat(const std::string &what) const noexcept
Definition exception.cpp:67
static const constexpr std::size_t m_maxSize
Definition exception.hpp:41
Exception(const std::string &message) noexcept
Definition exception.cpp:39
void setMessage(const std::string &message) noexcept
Definition exception.cpp:63
std::string message() const noexcept
Definition exception.cpp:51
std::string m_context
Definition exception.hpp:46
std::string context() const noexcept
Definition exception.cpp:53
std::int64_t code() const noexcept
Definition exception.cpp:49
std::string m_message
Definition exception.hpp:45
std::string m_what
Definition exception.hpp:47
void build_what() const noexcept final
ErrnoException(const ErrnoException &)=default
void throw_exception(const std::string &str={}) const
bool check_value() const noexcept
std::int64_t m_errno
Definition exception.hpp:69
std::int64_t error() const noexcept
virtual ~Errno() noexcept
Errno & check_if(const bool &ret) noexcept
bool check_value() const noexcept
Definition exception.cpp:73
WindowsError & check_if(const bool &ret) noexcept
Definition exception.cpp:75
std::int64_t error() const noexcept
Definition exception.cpp:71
void throw_exception(const std::string &str=std::string()) const
Definition exception.cpp:82
WindowsException(const std::int64_t &error, const std::string &context=std::string())
Definition exception.cpp:87
void build_what() const noexcept final
std::wstring to_wide(const std::string &str)
Definition unicode.cpp:40
std::string to_narrow(const std::wstring &wstr)
Definition unicode.cpp:26
void ExceptionHandler(const ExceptionDestination &destination=ExceptionDestination::StdErr) noexcept
std::string string() noexcept
String version of cpp-terminal.
Definition args.cpp:13
std::uint16_t returnCode() noexcept