error.cpp (5655B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "error.h" 5 #include "string_util.h" 6 7 #include <cstdlib> 8 #include <cstring> 9 #include <cwctype> 10 #include <type_traits> 11 12 #include "fmt/format.h" 13 14 #if defined(_WIN32) 15 #include "windows_headers.h" 16 #endif 17 18 Error::Error() = default; 19 20 Error::Error(const Error& c) = default; 21 22 Error::Error(Error&& e) = default; 23 24 Error::~Error() = default; 25 26 void Error::Clear() 27 { 28 m_description = {}; 29 } 30 31 void Error::Clear(Error* errptr) 32 { 33 if (errptr) 34 errptr->Clear(); 35 } 36 37 void Error::SetErrno(int err) 38 { 39 SetErrno(std::string_view(), err); 40 } 41 42 void Error::SetErrno(std::string_view prefix, int err) 43 { 44 m_type = Type::Errno; 45 46 #ifdef _MSC_VER 47 char buf[128]; 48 if (strerror_s(buf, sizeof(buf), err) == 0) 49 m_description = fmt::format("{}errno {}: {}", prefix, err, buf); 50 else 51 m_description = fmt::format("{}errno {}: <Could not get error message>", prefix, err); 52 #else 53 const char* buf = std::strerror(err); 54 if (buf) 55 m_description = fmt::format("{}errno {}: {}", prefix, err, buf); 56 else 57 m_description = fmt::format("{}errno {}: <Could not get error message>", prefix, err); 58 #endif 59 } 60 61 void Error::SetErrno(Error* errptr, int err) 62 { 63 if (errptr) 64 errptr->SetErrno(err); 65 } 66 67 void Error::SetErrno(Error* errptr, std::string_view prefix, int err) 68 { 69 if (errptr) 70 errptr->SetErrno(prefix, err); 71 } 72 73 void Error::SetString(std::string description) 74 { 75 m_type = Type::User; 76 m_description = std::move(description); 77 } 78 79 void Error::SetStringView(std::string_view description) 80 { 81 m_type = Type::User; 82 m_description = std::string(description); 83 } 84 85 void Error::SetString(Error* errptr, std::string description) 86 { 87 if (errptr) 88 errptr->SetString(std::move(description)); 89 } 90 91 void Error::SetStringView(Error* errptr, std::string_view description) 92 { 93 if (errptr) 94 errptr->SetStringView(std::move(description)); 95 } 96 97 #ifdef _WIN32 98 99 void Error::SetWin32(unsigned long err) 100 { 101 SetWin32(std::string_view(), err); 102 } 103 104 void Error::SetWin32(std::string_view prefix, unsigned long err) 105 { 106 m_type = Type::Win32; 107 108 WCHAR buf[128]; 109 DWORD r = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_USER_DEFAULT, buf, 110 static_cast<DWORD>(std::size(buf)), nullptr); 111 while (r > 0 && std::iswspace(buf[r - 1])) 112 r--; 113 114 if (r > 0) 115 { 116 m_description = 117 fmt::format("{}Win32 Error {}: {}", prefix, err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r))); 118 } 119 else 120 { 121 m_description = fmt::format("{}Win32 Error {}: <Could not resolve system error ID>", prefix, err); 122 } 123 } 124 125 void Error::SetWin32(Error* errptr, unsigned long err) 126 { 127 if (errptr) 128 errptr->SetWin32(err); 129 } 130 131 void Error::SetWin32(Error* errptr, std::string_view prefix, unsigned long err) 132 { 133 if (errptr) 134 errptr->SetWin32(prefix, err); 135 } 136 137 void Error::SetHResult(long err) 138 { 139 SetHResult(std::string_view(), err); 140 } 141 142 void Error::SetHResult(std::string_view prefix, long err) 143 { 144 m_type = Type::HResult; 145 146 WCHAR buf[128]; 147 DWORD r = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_USER_DEFAULT, buf, 148 static_cast<DWORD>(std::size(buf)), nullptr); 149 while (r > 0 && std::iswspace(buf[r - 1])) 150 r--; 151 152 if (r > 0) 153 { 154 m_description = fmt::format("{}HRESULT {:08X}: {}", prefix, static_cast<unsigned>(err), 155 StringUtil::WideStringToUTF8String(std::wstring_view(buf, r))); 156 } 157 else 158 { 159 m_description = fmt::format("{}HRESULT {:08X}: <Could not resolve system error ID>", prefix, err); 160 } 161 } 162 163 void Error::SetHResult(Error* errptr, long err) 164 { 165 if (errptr) 166 errptr->SetHResult(err); 167 } 168 169 void Error::SetHResult(Error* errptr, std::string_view prefix, long err) 170 { 171 if (errptr) 172 errptr->SetHResult(prefix, err); 173 } 174 175 #endif 176 177 void Error::SetSocket(int err) 178 { 179 SetSocket(std::string_view(), err); 180 } 181 182 void Error::SetSocket(std::string_view prefix, int err) 183 { 184 // Socket errors are win32 errors on windows 185 #ifdef _WIN32 186 SetWin32(prefix, err); 187 #else 188 SetErrno(prefix, err); 189 #endif 190 m_type = Type::Socket; 191 } 192 193 void Error::SetSocket(Error* errptr, int err) 194 { 195 if (errptr) 196 errptr->SetSocket(err); 197 } 198 199 void Error::SetSocket(Error* errptr, std::string_view prefix, int err) 200 { 201 if (errptr) 202 errptr->SetSocket(prefix, err); 203 } 204 205 Error Error::CreateNone() 206 { 207 return Error(); 208 } 209 210 Error Error::CreateErrno(int err) 211 { 212 Error ret; 213 ret.SetErrno(err); 214 return ret; 215 } 216 217 Error Error::CreateSocket(int err) 218 { 219 Error ret; 220 ret.SetSocket(err); 221 return ret; 222 } 223 224 Error Error::CreateString(std::string description) 225 { 226 Error ret; 227 ret.SetString(std::move(description)); 228 return ret; 229 } 230 231 #ifdef _WIN32 232 Error Error::CreateWin32(unsigned long err) 233 { 234 Error ret; 235 ret.SetWin32(err); 236 return ret; 237 } 238 239 Error Error::CreateHResult(long err) 240 { 241 Error ret; 242 ret.SetHResult(err); 243 return ret; 244 } 245 246 #endif 247 248 void Error::AddPrefix(std::string_view prefix) 249 { 250 m_description.insert(0, prefix); 251 } 252 253 void Error::AddSuffix(std::string_view suffix) 254 { 255 m_description.append(suffix); 256 } 257 258 void Error::AddPrefix(Error* errptr, std::string_view prefix) 259 { 260 if (errptr) 261 errptr->AddPrefix(prefix); 262 } 263 264 void Error::AddSuffix(Error* errptr, std::string_view prefix) 265 { 266 if (errptr) 267 errptr->AddSuffix(prefix); 268 } 269 270 Error& Error::operator=(const Error& e) = default; 271 272 Error& Error::operator=(Error&& e) = default; 273 274 bool Error::operator==(const Error& e) const 275 { 276 return (m_type == e.m_type && m_description == e.m_description); 277 } 278 279 bool Error::operator!=(const Error& e) const 280 { 281 return (m_type != e.m_type || m_description != e.m_description); 282 }