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-2024 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
73bool Term::Private::WindowsError::check_value() const noexcept { return m_check_value; }
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{
84 if(m_check_value) { throw Term::Private::WindowsException(m_error, str); }
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{
151 if(m_check_value) { throw Term::Private::ErrnoException(m_errno, str); }
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 message = _wcserror_s(&message[0], message.size(), static_cast<int>(error));
161#else
162 std::string message(m_maxSize, '\0');
163 message = ::strerror_r(static_cast<std::int32_t>(error), &message[0], message.size()); // NOLINT(readability-container-data-pointer)
165#endif
166}
167
169{
170 std::string what{"errno " + std::to_string(code()) + ": " + message()};
171 if(!context().empty()) { what += +" [" + context() + "]"; }
172 setWhat(what);
173}
174
176{
177 try
178 {
179 std::exception_ptr exception{std::current_exception()};
180 if(exception != nullptr) { std::rethrow_exception(exception); }
181 }
182 catch(const Term::Exception& exception)
183 {
184 switch(destination)
185 {
187#if defined(_WIN32)
188 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);
189 break;
190#endif
192#if defined(_WIN32)
193 (void)(fputws(Term::Private::to_wide(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n")).c_str(), stderr));
194#else
195 (void)(fputs(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n").c_str(), stderr));
196#endif
197 break;
198 default: break;
199 }
200 }
201 catch(const std::exception& exception)
202 {
203 switch(destination)
204 {
206#if defined(_WIN32)
207 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);
208 break;
209#endif
211#if defined(_WIN32)
212 (void)(fputws(Term::Private::to_wide(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n")).c_str(), stderr));
213#else
214 (void)(fputs(std::string("cpp-terminal v" + Term::Version::string() + "\n" + exception.what() + "\n").c_str(), stderr));
215#endif
216 break;
217 default: break;
218 }
219 }
220 catch(...)
221 {
222 switch(destination)
223 {
225#if defined(_WIN32)
226 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);
227 break;
228#endif
230#if defined(_WIN32)
231 (void)(fputws(Term::Private::to_wide("cpp-terminal v" + Term::Version::string() + ": Unknown error\n").c_str(), stderr));
232#else
233 (void)(fputs(("cpp-terminal v" + Term::Version::string() + ": Unknown error\n").c_str(), stderr));
234#endif
235 default: break;
236 }
237 }
238 (void)(std::fflush(stderr));
239 std::_Exit(Term::returnCode());
240}
const char * what() const noexcept override
Definition exception.cpp:43
virtual void build_what() const noexcept
Definition exception.cpp:57
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 context() const noexcept
Definition exception.cpp:53
std::int64_t code() const noexcept
Definition exception.cpp:49
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 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