Compare commits
16 Commits
546acf24bb
...
215220f98b
Author | SHA1 | Date |
---|---|---|
Brett | 215220f98b | |
Brett | 465f1a4fc8 | |
Brett | 650af9877f | |
Brett | d3ed46686e | |
Brett | 1b4e36416a | |
Brett | 9348207ffb | |
Brett | 34536e2a63 | |
Brett | bbbf0ba2e5 | |
Brett | 0e17dff862 | |
Brett | 1d03938f95 | |
Brett | 6579a3f5cb | |
Brett | ea986bbc95 | |
Brett | 1e8f431f9e | |
Brett | a3f6757146 | |
Brett | d1e9d5daef | |
Brett | 7f9d9bf241 |
|
@ -15,6 +15,7 @@
|
|||
#include <blt/std/hashmap.h>
|
||||
#include <variant>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
|
||||
namespace blt
|
||||
{
|
||||
|
@ -329,6 +330,7 @@ namespace blt
|
|||
return std::holds_alternative<arg_data_internal_t>(v) && std::holds_alternative<T>(std::get<arg_data_internal_t>(v));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static inline T& get(arg_data_t& v)
|
||||
{
|
||||
|
@ -338,6 +340,33 @@ namespace blt
|
|||
return std::get<T>(std::get<arg_data_internal_t>(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to cast the variant stored in the arg results to the requested type
|
||||
* if user is requesting an int, but holds a string, we are going to make the assumption the data can be converted
|
||||
* it is up to the user to deal with the variant if they do not want this behaviour!
|
||||
* @tparam T type to convert to
|
||||
* @param v
|
||||
* @return
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T get_cast(arg_data_t& v)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, arg_data_vec_t>)
|
||||
return std::get<arg_data_vec_t>(v);
|
||||
else
|
||||
{
|
||||
auto t = std::get<arg_data_internal_t>(v);
|
||||
// user is requesting an int, but holds a string, we are going to make the assumption the data can be converted
|
||||
// it is up to the user to deal with the variant if they do not want this behaviour!
|
||||
if constexpr (std::is_same_v<int32_t, T>)
|
||||
{
|
||||
if (std::holds_alternative<std::string>(t))
|
||||
return std::stoi(std::get<std::string>(t));
|
||||
}
|
||||
return std::get<T>(t);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
arg_parse(const std::string& helpMessage = "show this help menu and exit")
|
||||
{
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// Created by brett on 21/08/23.
|
||||
//
|
||||
|
||||
#ifndef BLT_MUSTACHE_H
|
||||
#define BLT_MUSTACHE_H
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <blt/std/hashmap.h>
|
||||
|
||||
namespace blt
|
||||
{
|
||||
|
||||
class mustache_syntax_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit mustache_syntax_error(): std::runtime_error("mustache syntax is invalid!")
|
||||
{}
|
||||
|
||||
explicit mustache_syntax_error(const std::string& str): std::runtime_error(str)
|
||||
{}
|
||||
};
|
||||
|
||||
class mustache_lexer
|
||||
{
|
||||
private:
|
||||
std::string str;
|
||||
size_t index = 0;
|
||||
public:
|
||||
explicit mustache_lexer(std::string str): str(std::move(str))
|
||||
{}
|
||||
|
||||
inline bool hasNext()
|
||||
{
|
||||
if (index >= str.size())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline char peek()
|
||||
{
|
||||
return str[index];
|
||||
}
|
||||
|
||||
inline bool hasTemplatePrefix()
|
||||
{
|
||||
if (index + 1 >= str.size())
|
||||
return false;
|
||||
return str[index] == '{' && str[index + 1] == '{';
|
||||
}
|
||||
|
||||
inline bool hasTemplateSuffix()
|
||||
{
|
||||
if (index + 1 >= str.size())
|
||||
return false;
|
||||
return str[index] == '}' && str[index + 1] == '}';
|
||||
}
|
||||
|
||||
inline void consumeTemplatePrefix()
|
||||
{
|
||||
index += 2;
|
||||
}
|
||||
|
||||
inline void consumeTemplateSuffix()
|
||||
{
|
||||
index += 2;
|
||||
}
|
||||
|
||||
inline std::string consumeToken()
|
||||
{
|
||||
std::string token;
|
||||
while (!hasTemplateSuffix())
|
||||
{
|
||||
if (!hasNext())
|
||||
throw mustache_syntax_error("Error processing token. Mustache template incomplete.");
|
||||
token += consume();
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
inline char consume()
|
||||
{
|
||||
return str[index++];
|
||||
}
|
||||
};
|
||||
|
||||
class mustache
|
||||
{
|
||||
private:
|
||||
mustache_lexer lexer;
|
||||
|
||||
std::string assemble(){
|
||||
std::string buffer;
|
||||
|
||||
while (lexer.hasNext()){
|
||||
if (lexer.hasTemplatePrefix()){
|
||||
lexer.consumeTemplatePrefix();
|
||||
if (!lexer.hasNext())
|
||||
throw mustache_syntax_error("template incomplete, found '{{' missing '}}'");
|
||||
auto c = lexer.peek();
|
||||
switch (c) {
|
||||
case '%':
|
||||
break;
|
||||
case '$':
|
||||
break;
|
||||
case '#':
|
||||
break;
|
||||
case '@':
|
||||
break;
|
||||
case '/':
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} else
|
||||
buffer += lexer.consume();
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit mustache(std::string str): lexer(std::move(str))
|
||||
{}
|
||||
|
||||
static std::string compile(std::string input) {
|
||||
mustache compiler(std::move(input));
|
||||
return compiler.assemble();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //BLT_MUSTACHE_H
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Created by Brett on 23/08/23.
|
||||
* Licensed under GNU General Public License V3.0
|
||||
* See LICENSE file for license detail
|
||||
*/
|
||||
|
||||
#ifndef BLT_ASSERT_H
|
||||
#define BLT_ASSERT_H
|
||||
|
||||
namespace blt
|
||||
{
|
||||
void printStacktrace(char** messages, int size, const char* path, int line);
|
||||
|
||||
void b_assert_failed(const char* expression, const char* path, int line);
|
||||
|
||||
void b_throw(const char* what, const char* path, int line);
|
||||
}
|
||||
|
||||
// prints error with stack trace if assertion fails. Does not stop execution.
|
||||
#define blt_assert(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__) } while (0)
|
||||
// prints error with stack trace then exits with failure.
|
||||
#define BLT_ASSERT(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__); std::exit(EXIT_FAILURE); } while (0)
|
||||
// prints as error but does not throw the exception.
|
||||
#define blt_throw(throwable) do {blt::b_throw(throwable.what(), __FILE__, __LINE__);} while (0)
|
||||
// prints as error with stack trace and throws the exception.
|
||||
#define BLT_THROW(throwable) do {blt::b_throw(throwable.what(), __FILE__, __LINE__); throw throwable;} while(0)
|
||||
|
||||
|
||||
#endif //BLT_ASSERT_H
|
|
@ -11,7 +11,8 @@
|
|||
#include <ios>
|
||||
#include "memory.h"
|
||||
|
||||
namespace blt::fs {
|
||||
namespace blt::fs
|
||||
{
|
||||
|
||||
/**
|
||||
* A simple interface which provides a way of reading the next block of data from a resource.
|
||||
|
@ -20,12 +21,14 @@ namespace blt::fs {
|
|||
* Reading of a large number of bytes ( > block size) is guaranteed to not significantly increase the read time and will likely result in a
|
||||
* direct passthrough to the underlying system. Small reads will be buffered, hence the name "block" reader.
|
||||
*/
|
||||
class block_reader {
|
||||
class block_reader
|
||||
{
|
||||
protected:
|
||||
// 32768 block size seems the fastest on my system
|
||||
unsigned long m_bufferSize;
|
||||
public:
|
||||
explicit block_reader(size_t bufferSize): m_bufferSize(bufferSize) {}
|
||||
explicit block_reader(size_t bufferSize): m_bufferSize(bufferSize)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Reads bytes from the internal filesystem implementation
|
||||
|
@ -34,7 +37,11 @@ namespace blt::fs {
|
|||
* @return status code. non-zero return codes indicates a failure has occurred.
|
||||
*/
|
||||
virtual int read(char* buffer, size_t bytes) = 0;
|
||||
virtual char get(){
|
||||
|
||||
virtual size_t gcount() = 0;
|
||||
|
||||
virtual char get()
|
||||
{
|
||||
char c[1];
|
||||
read(c, 1);
|
||||
return c[0];
|
||||
|
@ -44,11 +51,13 @@ namespace blt::fs {
|
|||
/**
|
||||
* A buffered block writer without a definite backend implementation. Exactly the same as a block_reader but for writing to the filesystem.
|
||||
*/
|
||||
class block_writer {
|
||||
class block_writer
|
||||
{
|
||||
protected:
|
||||
unsigned long m_bufferSize;
|
||||
public:
|
||||
explicit block_writer(unsigned long bufferSize): m_bufferSize(bufferSize) {}
|
||||
explicit block_writer(unsigned long bufferSize): m_bufferSize(bufferSize)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Writes the bytes to the filesystem backend implementation
|
||||
|
@ -57,7 +66,9 @@ namespace blt::fs {
|
|||
* @return non-zero code if failure
|
||||
*/
|
||||
virtual int write(char* buffer, size_t bytes) = 0;
|
||||
virtual int put(char c){
|
||||
|
||||
virtual int put(char c)
|
||||
{
|
||||
char a[1];
|
||||
a[0] = c;
|
||||
return write(a, 1);
|
||||
|
@ -72,7 +83,8 @@ namespace blt::fs {
|
|||
/**
|
||||
* fstream implementation of the block reader.
|
||||
*/
|
||||
class fstream_block_reader : public block_reader {
|
||||
class fstream_block_reader : public block_reader
|
||||
{
|
||||
private:
|
||||
std::fstream& m_stream;
|
||||
char* m_buffer = nullptr;
|
||||
|
@ -90,20 +102,29 @@ namespace blt::fs {
|
|||
|
||||
int read(char* buffer, size_t bytes) override;
|
||||
|
||||
~fstream_block_reader() {
|
||||
size_t gcount() final {
|
||||
return m_stream.gcount();
|
||||
}
|
||||
|
||||
~fstream_block_reader()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
};
|
||||
|
||||
class fstream_block_writer : public block_writer {
|
||||
class fstream_block_writer : public block_writer
|
||||
{
|
||||
private:
|
||||
std::fstream& m_stream;
|
||||
char* m_buffer;
|
||||
size_t writeIndex = 0;
|
||||
|
||||
void flush_internal();
|
||||
|
||||
public:
|
||||
explicit fstream_block_writer(std::fstream& stream, size_t bufferSize = 131072):
|
||||
block_writer(bufferSize), m_stream(stream), m_buffer(new char[bufferSize]) {}
|
||||
block_writer(bufferSize), m_stream(stream), m_buffer(new char[bufferSize])
|
||||
{}
|
||||
|
||||
explicit fstream_block_writer(fstream_block_writer& copy) = delete;
|
||||
|
||||
|
@ -114,11 +135,14 @@ namespace blt::fs {
|
|||
fstream_block_writer& operator=(const fstream_block_writer&& move) = delete;
|
||||
|
||||
int write(char* buffer, size_t bytes) override;
|
||||
inline void flush() override {
|
||||
|
||||
inline void flush() override
|
||||
{
|
||||
flush_internal();
|
||||
}
|
||||
|
||||
~fstream_block_writer() {
|
||||
~fstream_block_writer()
|
||||
{
|
||||
flush_internal();
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
|
|
@ -454,7 +454,7 @@ namespace blt::logging {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks if the next character in the parser is a tag opening, if not output the chars to the out string
|
||||
* Checks if the next character in the parser is a tag opening, if not output the buffer to the out string
|
||||
*/
|
||||
inline bool tagOpening(string_parser& parser, std::string& out){
|
||||
char c = ' ';
|
||||
|
@ -649,7 +649,7 @@ namespace blt::logging {
|
|||
#define BLT_ERROR(format, ...)
|
||||
#define BLT_FATAL(format, ...)
|
||||
#else
|
||||
#define BLT_LOG(format, level, ...) log(format, level, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#define BLT_LOG(format, level, ...) blt::logging::log(format, level, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#define BLT_LOG_STREAM(level) blt::logging::logger{level, __FILE__, __LINE__}
|
||||
#ifdef BLT_DISABLE_TRACE
|
||||
#define BLT_TRACE(format, ...)
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace blt::string {
|
|||
}
|
||||
|
||||
// https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
|
||||
static bool replace(std::string& str, const std::string& from, const std::string& to) {
|
||||
static inline bool replace(std::string& str, const std::string& from, const std::string& to) {
|
||||
size_t start_pos = str.find(from);
|
||||
if(start_pos == std::string::npos)
|
||||
return false;
|
||||
|
@ -148,7 +148,7 @@ namespace blt::string {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void replaceAll(std::string& str, const std::string& from, const std::string& to) {
|
||||
static inline void replaceAll(std::string& str, const std::string& from, const std::string& to) {
|
||||
if(from.empty())
|
||||
return;
|
||||
size_t start_pos = 0;
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
//
|
||||
// Created by brett on 15/08/23.
|
||||
//
|
||||
|
||||
#if !defined(BLT_UUID_H) && defined(__has_include) && __has_include(<openssl/sha.h>)
|
||||
#define BLT_UUID_H
|
||||
|
||||
#include <string>
|
||||
#include <openssl/sha.h>
|
||||
#include <random>
|
||||
#include <exception>
|
||||
#include <blt/std/string.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace blt::uuid
|
||||
{
|
||||
|
||||
// from https://www.rfc-editor.org/rfc/rfc4122#section-4.3
|
||||
|
||||
union uuid_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
u_int32_t time_low;
|
||||
u_int16_t time_mid;
|
||||
u_int16_t time_hi_and_version;
|
||||
u_int8_t clock_seq_hi_and_reserved;
|
||||
u_int8_t clock_seq_low;
|
||||
u_int8_t node[6];
|
||||
} uuid;
|
||||
u_int8_t str[16];
|
||||
};
|
||||
|
||||
/* Name string is a fully-qualified domain name */
|
||||
constexpr static uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b810,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
/* Name string is a URL */
|
||||
constexpr static uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b811,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
/* Name string is an ISO OID */
|
||||
constexpr static uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b812,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
/* Name string is an X.500 DN (in DER or a text output format) */
|
||||
constexpr static uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b814,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
class malformed_uuid_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit malformed_uuid_exception(const std::string& error = ""): std::runtime_error(error)
|
||||
{}
|
||||
};
|
||||
|
||||
static unsigned char hex2byte(const char* hex)
|
||||
{
|
||||
unsigned short byte = 0;
|
||||
std::istringstream iss(hex);
|
||||
iss >> std::hex >> byte;
|
||||
return byte % 0x100;
|
||||
}
|
||||
|
||||
static std::string byte2hex(const uint8_t* data, int len)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex;
|
||||
|
||||
const char dash[] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
if (dash[i])
|
||||
ss << std::dec << '-';
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (int) data[i];
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static uuid_t genV5(const std::string& objectName, uuid_t namespaceUUID = NameSpace_OID)
|
||||
{
|
||||
auto new_str = std::string(reinterpret_cast<const char*>(namespaceUUID.str)) + objectName;
|
||||
const auto* c_str = reinterpret_cast<const unsigned char*>(new_str.c_str());
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
uuid_t result{};
|
||||
|
||||
SHA1(c_str, strlen(new_str.c_str()), hash);
|
||||
|
||||
memcpy(result.str, hash, 16);
|
||||
|
||||
//set high-nibble to 5 to indicate type 5
|
||||
result.str[6] &= 0x0F;
|
||||
result.str[6] |= 0x50;
|
||||
|
||||
//set upper two bits to "10"
|
||||
result.str[8] &= 0x3F;
|
||||
result.str[8] |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string toString(uuid_t uuid)
|
||||
{
|
||||
return byte2hex(uuid.str, 16);
|
||||
}
|
||||
|
||||
static uuid_t toUUID(const std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
throw malformed_uuid_exception("expected at least 32 characters!");
|
||||
if (str.size() > 36)
|
||||
throw malformed_uuid_exception("UUID cannot contain more then 128 bits of information!");
|
||||
|
||||
uuid_t uuid{};
|
||||
|
||||
std::string data = str;
|
||||
|
||||
if (data.size() == 36)
|
||||
blt::string::replaceAll(data, "-", "");
|
||||
|
||||
if (data.size() == 32)
|
||||
{
|
||||
char cpy[2];
|
||||
for (size_t i = 0; i < data.size(); i += 2)
|
||||
{
|
||||
cpy[0] = data[i];
|
||||
cpy[1] = data[i + 1];
|
||||
uuid.str[i / 2] = hex2byte(cpy);
|
||||
}
|
||||
} else
|
||||
throw malformed_uuid_exception("UUID is expected as a string of bytes xxxxxxxx or in uuid format 8-4-4-4-12");
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
static uuid_t genV4()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::seed_seq seed{ rd(), rd(), rd(), rd() };
|
||||
std::mt19937_64 gen(seed);
|
||||
std::uniform_int_distribution<int> dis(0, 15);
|
||||
std::uniform_int_distribution<> dis2(8, 11);
|
||||
|
||||
std::stringstream ss;
|
||||
int i;
|
||||
ss << std::hex;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 4; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-4";
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
ss << dis2(gen);
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 12; i++) {
|
||||
ss << dis(gen);
|
||||
};
|
||||
|
||||
return toUUID(ss.str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif //BLT_UUID_H
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Created by Brett on 23/08/23.
|
||||
* Licensed under GNU General Public License V3.0
|
||||
* See LICENSE file for license detail
|
||||
*/
|
||||
#include <blt/std/assert.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/std/string.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define BLT_STACK_TRACE(number) void* ptrs[number]; \
|
||||
int size = backtrace(ptrs, number); \
|
||||
char** messages = backtrace_symbols(ptrs, size);
|
||||
|
||||
#define BLT_FREE_STACK_TRACE() free(messages);
|
||||
#else
|
||||
#define BLT_STACK_TRACE(number) void();
|
||||
#define BLT_FREE_STACK_TRACE() void();
|
||||
#endif
|
||||
|
||||
namespace blt {
|
||||
|
||||
static inline std::string _macro_filename(const std::string& path){
|
||||
auto paths = blt::string::split(path, "/");
|
||||
auto final = paths[paths.size()-1];
|
||||
if (final == "/")
|
||||
return paths[paths.size()-2];
|
||||
return final;
|
||||
}
|
||||
|
||||
void b_throw(const char* what, const char* path, int line)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
BLT_STACK_TRACE(50);
|
||||
|
||||
BLT_ERROR("An exception '%s' has occurred in file '%s:%d'", what, path, line);
|
||||
BLT_ERROR("Stack Trace:");
|
||||
printStacktrace(messages, size, path, line);
|
||||
|
||||
BLT_FREE_STACK_TRACE();
|
||||
#endif
|
||||
}
|
||||
|
||||
void b_assert_failed(const char* expression, const char* path, int line)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
BLT_STACK_TRACE(50);
|
||||
|
||||
BLT_ERROR("The assertion '%s' has failed in file '%s:%d'", expression, path, line);
|
||||
BLT_ERROR("Stack Trace:");
|
||||
|
||||
backtrace_symbols(ptrs, size);
|
||||
|
||||
printStacktrace(messages, size, path, line);
|
||||
|
||||
BLT_FREE_STACK_TRACE();
|
||||
#endif
|
||||
}
|
||||
|
||||
void printStacktrace(char** messages, int size, const char* path, int line)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
for (int i = 1; i < size; i++){
|
||||
int tabs = i - 1;
|
||||
std::string buffer;
|
||||
for (int j = 0; j < tabs; j++)
|
||||
buffer += '\t';
|
||||
if (i != 1)
|
||||
buffer += "⮡";
|
||||
|
||||
std::string message(messages[i]);
|
||||
|
||||
auto f = message.find('(');
|
||||
|
||||
auto mes = message.substr(f + 1, message.size());
|
||||
std::string loc;
|
||||
|
||||
buffer += message.substr(0, f);
|
||||
if (i == 1)
|
||||
{
|
||||
loc = '\'';
|
||||
loc += _macro_filename(path);
|
||||
loc += ':';
|
||||
loc += std::to_string(line);
|
||||
loc += '\'';
|
||||
} else
|
||||
loc = mes.substr(0, mes.find('+'));
|
||||
|
||||
if (!loc.empty())
|
||||
buffer += " in ";
|
||||
buffer += loc;
|
||||
|
||||
|
||||
BLT_ERROR(buffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue