Commits (7)
#include "buffer.h"
#ifdef NO_ERR_OUT
#include <iostream>
#endif
#include <cstring>
#include <inttypes.h>
#include "err_out.h"
int get_socket_id(const std::string &ip, int max_count) {
char LOCAL_BUFFER[LOCAL_BUFFER_SIZE];
int get_socket_id(const std::string &ip, int32_t max_count) {
if (ip.find("2::") != 0) {
#ifdef NO_ERR_OUT
std::cerr << "Unsupported IP: '"<< ip << "' (only supports 'N-to-N' IPs with '2::' prefix)" << std::endl;
#else
print_cerr("Unsupported IP: '%s' (only supports 'N-to-N' IPs with '2::' prefix)", ip.c_str());
#endif
}
int id = strtol(ip.c_str()+3, nullptr, 10)-1;
int32_t id = strtol(ip.c_str()+3, nullptr, 10)-1;
if (id >= max_count) {
#ifdef NO_ERR_OUT
std::cerr << "'N-to-N' IP '" << ip << "' outside of range [1:"<< (max_count) << "]. Ignoring packet." << std::endl;
#else
print_cerr("Id '%" PRIi32 "' of 'N-to-N' IP '%s' outside of range [1:%" PRIi32 "]. Ignoring packet.", ip.c_str(), max_count);
#endif
return -1;
}
return id;
......@@ -62,7 +77,13 @@ double BinaryReader::read_f64() {
return *((double*)&t);
}
std::string BinaryReader::read_str() {
if (pos >= end) throw BufferException("str read past buffer content.");
if (pos >= end) {
#ifdef NO_ERR_OUT
throw BufferException("str read past buffer content.");
#else
throw_error("BinaryReader", "str read past buffer content.");
#endif
}
auto start = pos;
while (pos < end && *pos != '\0') ++pos;
++pos; // Go after '\0'
......@@ -70,7 +91,13 @@ std::string BinaryReader::read_str() {
}
void BinaryReader::check_range(int bytes, const char* type) {
if (pos + bytes > end) throw BufferException(std::string(type) + " read past buffer content.");
if (pos + bytes > end) {
#ifdef NO_ERR_OUT
throw BufferException(std::string(type) + " read past buffer content.");
#else
throw_error("BinaryReader", "%s read past buffer content.", type);
#endif
}
}
......
#pragma once
#include <stdint.h>
#include <string>
#include <exception>
// Used for "snprintf" target
constexpr int32_t LOCAL_BUFFER_SIZE = 4096;
extern char LOCAL_BUFFER[LOCAL_BUFFER_SIZE];
struct DynamicBuffer {
......@@ -107,6 +112,7 @@ struct BinaryWriter {
void write_str(const std::string &str);
};
#ifdef NO_ERR_OUT
class BufferException : public std::exception {
std::string description;
......@@ -119,4 +125,6 @@ public:
}
};
int get_socket_id(const std::string &ip, int max_count);
\ No newline at end of file
#endif
int get_socket_id(const std::string &ip, int32_t max_count);
\ No newline at end of file
#include "err_out.h"
#include "buffer.h"
#include <stdarg.h>
#include "printf.h"
throw_func ERR_OUT_throw_error = nullptr;
print_func ERR_OUT_print_cout = nullptr;
print_func ERR_OUT_print_cerr = nullptr;
void ERR_OUT_set_functions(throw_func throw_error_ptr, print_func print_cout_ptr, print_func print_cerr_ptr) {
ERR_OUT_throw_error = throw_error_ptr;
ERR_OUT_print_cout = print_cout_ptr;
ERR_OUT_print_cerr = print_cerr_ptr;
}
void throw_error(const char *type, const char *msg_format, ...) {
va_list args;
va_start(args, msg_format);
vsnprintf(LOCAL_BUFFER, LOCAL_BUFFER_SIZE, msg_format, args);
va_end(args);
ERR_OUT_throw_error(type, LOCAL_BUFFER);
}
void print_cout(const char *format, ...) {
va_list args;
va_start(args, format);
vsnprintf(LOCAL_BUFFER, LOCAL_BUFFER_SIZE, format, args);
va_end(args);
ERR_OUT_print_cout(LOCAL_BUFFER);
}
void print_cerr(const char *format, ...) {
va_list args;
va_start(args, format);
vsnprintf(LOCAL_BUFFER, LOCAL_BUFFER_SIZE, format, args);
va_end(args);
ERR_OUT_print_cerr(LOCAL_BUFFER);
}
\ No newline at end of file
#pragma once
/*
This header should be used as an abstraction in an autopilot in order to:
This header should be used as an interface in an autopilot in order to:
- throw errors
- print error messages (cerr)
- print information messages (cout)
The correct function pointers must be provided to the autopilot through the ERR_OUT_set_functions() function
The goal is that the hardware_emulator can substitute its own function calls (dynamically loaded)
in order to properly transmit messages and errors from the autopilot.
In order to use the different implementations (standalone_err_out.cpp, ...) the correct file has to be compiled into the autopilot.
*/
#ifdef __cplusplus
extern "C" {
#endif
using throw_func = void (*)(const char* type, const char* message);
using print_func = void (*)(const char* message);
using set_functions_func = void (*)(throw_func throw_error_ptr, print_func print_cout_ptr, print_func print_cerr_ptr);
extern throw_func ERR_OUT_throw_error;
extern print_func ERR_OUT_print_cout;
extern print_func ERR_OUT_print_cerr;
void throw_error(const char* type, const char* message);
void print_cout(const char *message);
void print_cerr(const char *message);
void ERR_OUT_set_functions(throw_func throw_error_ptr, print_func print_cout_ptr, print_func print_cerr_ptr);
#ifndef NO_ERR_OUT
void throw_error(const char *type, const char *msg_format, ...);
void print_cout(const char *msg_format, ...);
void print_cerr(const char *msg_format, ...);
#endif
#ifdef __cplusplus
}
......
......@@ -3,14 +3,29 @@
*/
#include "json.h"
#include <stdarg.h>
#include <math.h>
#include <cctype>
#include <limits>
#include <sstream>
#include <inttypes.h>
#include "printf.h"
#include "err_out.h"
char JsonWriter::LOCAL_BUFFER[JsonWriter::LOCAL_BUFFER_SIZE];
const char* get_type_name(ValueType type) {
switch(type) {
case ValueType::OBJECT: return "Object";
case ValueType::ARRAY: return "Array";
case ValueType::STRING: return "String";
case ValueType::NUMBER: return "Number";
case ValueType::BOOLEAN: return "Boolean";
case ValueType::UNKNOWN: return "Unknown";
}
return "";
}
void JsonWriter::start_object() {
separate();
......@@ -194,7 +209,9 @@ ObjectIterator& ObjectIterator::operator++() {
}
StringRef ObjectIterator::operator*() {
// Get key
if (traverser.current_type != ValueType::STRING) throw ParsingException("Parsing exception: Expected a string as key");
if (traverser.current_type != ValueType::STRING) {
traverser.parsing_exception("Expected a string as key when iterating object entries.");
}
auto key = traverser.get_string();
last_elem_pos = traverser.pos; // Track traversal
return key;
......@@ -236,7 +253,36 @@ bool ArrayIterator::operator!=( const ArrayIterator& other ) {
void JsonTraverser::parsing_exception(const char *msg_format, ...) {
va_list args;
va_start(args, msg_format);
auto written = vsnprintf(LOCAL_BUFFER, LOCAL_BUFFER_SIZE, msg_format, args);
va_end(args);
if (written > LOCAL_BUFFER_SIZE) written = LOCAL_BUFFER_SIZE;
// Print " at [Line 6] ... some_json ..."
int32_t pos_in_line = pos - line_start;
const char *dots_before = "";
const char *dots_after = "";
int32_t before_length = pos_in_line;
auto context_before = line_start;
if (pos_in_line > 30) {
dots_before = "...";
before_length = 30;
context_before = pos - 30;
}
int32_t after_length = 0;
auto test = pos;
while (*test != '\0' && *test != '\n') {
++after_length;
++test;
if (after_length >= 50) {
dots_after = "...";
break;
}
}
snprintf(LOCAL_BUFFER+written, LOCAL_BUFFER_SIZE-written, "\n at [Line %" PRIi32 "] %s %.*s[>]%.*s %s", line, dots_before, before_length, context_before, after_length, pos, dots_after);
ERR_OUT_throw_error("JsonParsingException",LOCAL_BUFFER);
}
......@@ -247,6 +293,8 @@ JsonTraverser::JsonTraverser(const char *data) {
pos = data;
c = *pos;
depth = 0;
line = 1;
line_start = data;
goto_next_value();
}
......@@ -259,8 +307,9 @@ bool JsonTraverser::is_empty(){
}
ObjectStream JsonTraverser::stream_object() {
// TODO
if (current_type != ValueType::OBJECT) throw ParsingException("Parsing exception: tried to read object but got wrong type.");
if (current_type != ValueType::OBJECT) {
parsing_exception("Tried to stream an Object but got type %s.", get_type_name(current_type));
}
next_char(); // Move after '{'
depth++;
int32_t iteration_depth = depth;
......@@ -270,7 +319,9 @@ ObjectStream JsonTraverser::stream_object() {
ArrayStream JsonTraverser::stream_array() {
// TODO
if (current_type != ValueType::ARRAY) throw ParsingException("Parsing exception: tried to read array but got wrong type.");
if (current_type != ValueType::ARRAY) {
parsing_exception("Tried to stream an Array but got type %s.", get_type_name(current_type));
}
next_char(); // Move after '['
depth++;
int32_t iteration_depth = depth;
......@@ -279,7 +330,9 @@ ArrayStream JsonTraverser::stream_array() {
}
bool JsonTraverser::get_bool() {
if (current_type != ValueType::BOOLEAN) throw ParsingException("Parsing exception: tried to read bool but got wrong type.");
if (current_type != ValueType::BOOLEAN) {
parsing_exception("Tried to read a Boolean but got type %s.", get_type_name(current_type));
}
skip_bool();
goto_next_value();
return last_bool;
......@@ -287,7 +340,9 @@ bool JsonTraverser::get_bool() {
StringRef JsonTraverser::get_string() {
if (current_type != ValueType::STRING) throw ParsingException("Parsing exception: tried to read string but got wrong type.");
if (current_type != ValueType::STRING) {
parsing_exception("Tried to read a String but got type %s.", get_type_name(current_type));
}
auto start = pos +1;
skip_string();
auto end = pos - 1;
......@@ -312,13 +367,15 @@ double JsonTraverser::get_double() {
if (s.equals("Infinity"))
return std::numeric_limits<double>::infinity();
}
throw ParsingException("Parsing exception: tried to read double but got wrong type.");
parsing_exception("Tried to read a Double but got type %s.", get_type_name(current_type));
}
int64_t JsonTraverser::get_long() {
if (current_type != ValueType::NUMBER) throw ParsingException("Parsing exception: tried to read int64_t but got wrong type.");
if (current_type != ValueType::NUMBER) {
parsing_exception("Tried to read a Long but got type %s.", get_type_name(current_type));
}
char *end;
auto res = strtoll(pos, &end, 10);
goto_char(end);
......@@ -328,7 +385,7 @@ int64_t JsonTraverser::get_long() {
void JsonTraverser::expect_valid_integer(int64_t l) {
if (l > (int64_t) INT32_MAX || l < (int64_t) INT32_MIN)
throw ParsingException("Parsing exception: The int64_t doesn't fit in an int32_t");
parsing_exception("The int64_t '%" PRIi64 "' doesn't fit in an int32_t", l);
}
void JsonTraverser::get_value_type() {
......@@ -415,12 +472,12 @@ void JsonTraverser::skip_long() {
if (c == '-')
next_char();
if (c < '0' || c > '9')
throw ParsingException("Parsing exception: Expected digit in long");
parsing_exception("Expected digit in long (got '%c').", c);
do {
next_char();
} while (c >= '0' && c <= '9');
if (!is_next_whitespace() && c != ',' && c != ']' && c != '}')
throw ParsingException("Parsing exception: Unexpected character in long");
parsing_exception("Unexpected character in Long: '%c'.", c);
current_type = ValueType::UNKNOWN;
}
......@@ -438,7 +495,7 @@ void JsonTraverser::skip_string() {
next_char();
}
if (c == '\0')
throw ParsingException("Parsing exception: Missing closing string delimiter");
parsing_exception("Missing closing string delimiter");
next_char();
current_type = ValueType::UNKNOWN;
}
......@@ -447,11 +504,11 @@ void JsonTraverser::skip_bool() {
if (c == 't' || c == 'T') {
last_bool = true;
if (!is_true())
throw ParsingException("Parsing exception: Unexpected value for boolean");
parsing_exception("Unexpected value for boolean");
} else {
last_bool = false;
if (!is_false())
throw ParsingException("Parsing exception: Unexpected value for boolean");
parsing_exception("Unexpected value for boolean");
}
current_type = ValueType::UNKNOWN;
}
......
......@@ -4,15 +4,12 @@
#pragma once
#include <string>
#include <exception>
//#include <exception>
#include <stdint.h>
#include "buffer.h"
struct JsonWriter {
// Used for "snprintf" target
static constexpr int32_t LOCAL_BUFFER_SIZE = 1024;
static char LOCAL_BUFFER[LOCAL_BUFFER_SIZE];
static constexpr int32_t TAB = 2;
......@@ -126,15 +123,15 @@ struct StringRef {
}
};
class ParsingException : public std::exception {
const char *msg;
public:
ParsingException(const char *msg) : msg(msg) {}
virtual const char* what() const throw()
{
return msg;
}
};
// class ParsingException : public std::exception {
// const char *msg;
// public:
// ParsingException(const char *msg) : msg(msg) {}
// virtual const char* what() const throw()
// {
// return msg;
// }
// };
enum class ValueType {
OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, UNKNOWN
......@@ -216,6 +213,8 @@ struct JsonTraverser {
void expect_valid_integer(int64_t l);
void parsing_exception(const char *msg_format, ...);
private:
//const char *data;
......@@ -224,6 +223,8 @@ private:
ValueType current_type;
char c;
bool last_bool;
int32_t line;
const char* line_start;
void get_value_type();
......@@ -259,7 +260,14 @@ private:
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
}
void next_char() {
if (c != '\0') c = *(++pos);
if (c == '\0') return;
if (c != '\n') {
c = *(++pos);
} else {
++line;
c = *(++pos);
line_start = pos;
}
}
// Must make sure it is in range
void goto_char(const char *target) {
......
#include "err_out.h"
#include "standard_err_out.h"
#include <exception>
#include <string>
#include <iostream>
/*
This "backend" for err_out.h just uses the standard outputs and throws a standard c++ exception.
*/
class StandaloneException : public std::exception {
std::string msg;
public:
......@@ -17,12 +13,12 @@ public:
}
};
void throw_error(const char* type, const char* message) {
void ERR_OUT_standard_throw_error(const char* type, const char* message) {
throw StandaloneException(type, message);
}
void print_cout(const char *message) {
std::cout << message;
void ERR_OUT_standard_print_cout(const char *message) {
std::cout << message << std::endl;
}
void print_cerr(const char *message) {
std::cerr << message;
void ERR_OUT_standard_print_cerr(const char *message) {
std::cerr << message << std::endl;
}
\ No newline at end of file
#pragma once
/*
A set of functions that can be given to the ERR_OUT_set_functions() call of an autopilot.
These functions redirect the calls to cout and cerr and throw a C++ exception.
*/
#ifdef __cplusplus
extern "C" {
#endif
void ERR_OUT_standard_throw_error(const char* type, const char* message);
void ERR_OUT_standard_print_cout(const char *message);
void ERR_OUT_standard_print_cerr(const char *message);
#ifdef __cplusplus
}
#endif
......@@ -87,6 +87,11 @@ struct vec2 {
explicit operator vec2<A>() const {
return vec2<A>( ( A )x, ( A )y );
}
T &operator[](size_t i) {
if (i == 1) return y;
return x;
}
};
using vec2i8 = vec2<i8>;
......