carb/extras/Errors.h
File members: carb/extras/Errors.h
// Copyright (c) 2019-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "../Defines.h"
#include "../logging/Log.h"
#if CARB_PLATFORM_WINDOWS
# include "../CarbWindows.h"
# include "Unicode.h"
# include <memory>
#elif CARB_POSIX
// Nothing needed for now
#else
CARB_UNSUPPORTED_PLATFORM();
#endif
#include <cerrno>
#include <string.h>
#include <string>
namespace carb
{
namespace extras
{
using ErrnoType = std::decay_t<decltype(errno)>;
#if defined(DOXYGEN_BUILD) || CARB_PLATFORM_WINDOWS
using WinApiErrorType = unsigned long;
#endif
inline ErrnoType getLastErrno() noexcept
{
return errno;
}
inline std::string convertErrnoToMessage(ErrnoType errorCode)
{
if (errorCode == 0)
return {};
char buffer[1024];
constexpr size_t bufferSize = carb::countOf(buffer);
#if CARB_PLATFORM_WINDOWS
if (CARB_LIKELY(strerror_s(buffer, bufferSize, errorCode) == 0))
return buffer;
return ("Error code " + std::to_string(errorCode)) + " failed to format";
#elif CARB_PLATFORM_MACOS || CARB_PLATFORM_LINUX
// strerror_r implementation switch
# if CARB_PLATFORM_MACOS || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
// XSI-compliant strerror_r
if (CARB_LIKELY(strerror_r(errorCode, buffer, bufferSize) == 0))
return buffer;
return ("Error code " + std::to_string(errorCode)) + " failed to format";
# else
// GNU-specific strerror_r
// We always get some result in this implementation for a valid buffer
return strerror_r(errorCode, buffer, bufferSize);
# endif // end of strerror_r implementation switch
#else
CARB_UNSUPPORTED_PLATFORM();
#endif // end of platform switch
}
inline std::string getLastErrnoMessage(ErrnoType* out = nullptr)
{
const ErrnoType errorCode = getLastErrno();
if (out)
*out = errorCode;
auto str = convertErrnoToMessage(errorCode);
errno = errorCode;
return str;
}
#if CARB_PLATFORM_WINDOWS || defined(DOXYGEN_BUILD)
inline WinApiErrorType getLastWinApiErrorCode() noexcept
{
return ::GetLastError();
}
inline std::string convertWinApiErrorCodeToMessage(WinApiErrorType errorCode)
{
if (errorCode == CARBWIN_ERROR_SUCCESS)
{
return {};
}
LPWSTR resultMessageBuffer = nullptr;
const DWORD kFormatFlags = CARBWIN_FORMAT_MESSAGE_ALLOCATE_BUFFER | CARBWIN_FORMAT_MESSAGE_FROM_SYSTEM |
CARBWIN_FORMAT_MESSAGE_IGNORE_INSERTS;
const DWORD dwFormatResultCode = FormatMessageW(kFormatFlags, nullptr, errorCode,
CARBWIN_MAKELANGID(CARBWIN_LANG_NEUTRAL, CARBWIN_SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&resultMessageBuffer), 0, nullptr);
if (dwFormatResultCode == 0 || !resultMessageBuffer)
{
return ("Error code " + std::to_string(errorCode)) + " failed to format";
}
struct Deleter
{
void operator()(LPWSTR str)
{
::LocalFree(str);
}
};
std::unique_ptr<WCHAR, Deleter> systemBuffKeeper(resultMessageBuffer);
return carb::extras::convertWideToUtf8(resultMessageBuffer);
}
inline std::string getLastWinApiErrorMessage()
{
const WinApiErrorType errorCode = getLastWinApiErrorCode();
auto str = convertWinApiErrorCodeToMessage(errorCode);
SetLastError(errorCode);
return str;
}
#endif // #if CARB_PLATFORM_WINDOWS
} // namespace extras
} // namespace carb