Loading CMakeLists.txt +9 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,15 @@ cmake_minimum_required(VERSION 3.20) project(rsvp-c-cpp LANGUAGES C CXX) include(FetchContent) FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip ) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) include_directories(src) add_compile_options("-Wall") Loading check_mem.sh +20 −7 Original line number Diff line number Diff line #!/bin/bash SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" cd $SCRIPTPATH/build make CEXE="test" CPPEXE="testpp" run_valgrind() { valgrind --leak-check=full \ --show-leak-kinds=all \ --track-origins=yes \ --log-file=valgrind-out.txt \ ./tests/testpp No newline at end of file --log-file=$1-valgrind-out.txt \ ./$1 } cmake --build build/debug cmake --build build/release cd $SCRIPTPATH/build/debug/tests run_valgrind $CEXE run_valgrind $CPPEXE cd $SCRIPTPATH/build/release/tests run_valgrind $CEXE run_valgrind $CPPEXE src/rsvp.c +121 −32 Original line number Diff line number Diff line Loading @@ -4,6 +4,9 @@ #include <stdarg.h> #include "rsvp.h" #define ERR_STR_SIZE 256 static char error_str[ERR_STR_SIZE] = {0}; RSVP_TYPE get_type(char *type) { RSVP_TYPE type_ = STR; Loading Loading @@ -32,6 +35,15 @@ int count_tokens(char *str, char delimiter) return counter; } void set_error_string(char* format, ...) { memset(error_str, 0, ERR_STR_SIZE); va_list ap; va_start(ap, format); vsnprintf(error_str, ERR_STR_SIZE, format, ap); va_end(ap); } rsvp_vecd_elem_t* get_vecd_elem(char *token) { char *value = NULL, *begin = token; Loading @@ -54,14 +66,12 @@ rsvp_vecd_elem_t* get_vecd_elem(char *token) elem = (rsvp_vecd_elem_t*)malloc(sizeof(rsvp_vecd_elem_t)); if (!elem) { error_code = ALLOCATION_FAILED; goto exit; } name_len = index + 1; elem->name = (char*)malloc(name_len); if (!elem->name) { error_code = ALLOCATION_FAILED; goto free_elem; } Loading @@ -69,8 +79,7 @@ rsvp_vecd_elem_t* get_vecd_elem(char *token) memcpy(elem->name, begin, name_len - 1); if ((elem->value = strtod(value, NULL)) == 0.0) { error_code = DBL_CONVERSION_FAILED; sprintf(error_str, "Failed to convert %s to double", value); set_error_string("Failed to convert %s to double", value); goto free_name; } Loading @@ -84,12 +93,13 @@ exit: return NULL; } rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* var, int index) rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* vecd, int index) { if (index >= var->len) { if (index >= vecd->len) { rsvp_error_str("Index out of range for value %s", vecd->name); return NULL; } return (rsvp_vecd_elem_t*)var->value.vecd + index; return (rsvp_vecd_elem_t*)vecd->value.vecd + index; } rsvp_var_t* process_args(char *arg) Loading Loading @@ -181,7 +191,7 @@ rsvp_var_t* process_args(char *arg) printf("Error: %s\n", error_str); continue; } rsvp_vecd_add_elem(var, elem->name, elem->value); rsvp_var_vecd_add_elem(var, elem->name, elem->value); free(elem->name); free(elem); token = strtok(NULL, &delimiter); Loading @@ -198,7 +208,7 @@ rsvp_var_t* process_args(char *arg) token = strtok(value, &delimiter); for (int i = 0; i < elem_count; i++) { rsvp_vecs_add_elem(var, token); rsvp_var_vecs_add_elem(var, token); token = strtok(NULL, &delimiter); } break; Loading @@ -215,36 +225,39 @@ rsvp_var_t* process_args(char *arg) rsvp_var_print(var); #endif free(name); if (!var) { error_code = VAR_CREATION_FAILED; printf("Failed to add arg\n"); set_error_string("Failed to add arg %s\n", name); free(name); return NULL; } free(name); return var; } rsvp_data_t *rsvp_data_parse(char* data) { char *token = NULL; char *token = NULL, *raw_data = NULL; char **args = NULL; char delimiter = ';'; size_t index = 0, token_len = 0; rsvp_data_t *rsvp_data = (rsvp_data_t*)malloc(sizeof(rsvp_data_t)); if (!rsvp_data) { error_code = ALLOCATION_FAILED; return NULL; } raw_data = malloc(strlen(data) + 1); memset(raw_data, 0, strlen(data) + 1); memcpy(raw_data, data, strlen(data)); memset(rsvp_data, 0, sizeof(rsvp_data_t)); rsvp_data->args_count = count_tokens(data, delimiter); rsvp_data->args_count = count_tokens(raw_data, delimiter); args = (char**)malloc(rsvp_data->args_count * sizeof(char*)); // Get command string token = strtok(data, &delimiter); token = strtok(raw_data, &delimiter); token_len = strlen(token) + 1; rsvp_data->cmd = (char*)malloc(token_len); memset(rsvp_data->cmd, 0, token_len); Loading @@ -270,7 +283,6 @@ rsvp_data_t *rsvp_data_parse(char* data) rsvp_data->args = (rsvp_var_t**)malloc(rsvp_data->args_count * sizeof(rsvp_var_t*)); if (!rsvp_data->args) { error_code = ALLOCATION_FAILED; return NULL; } Loading @@ -290,10 +302,68 @@ rsvp_data_t *rsvp_data_parse(char* data) } free(args); free(raw_data); return rsvp_data; } rsvp_data_t* rsvp_data_create(char* cmd) { rsvp_data_t *data = NULL; size_t len = strlen(cmd) + 1; data = (rsvp_data_t*)malloc(sizeof(rsvp_data_t)); if (!data) { set_error_string("Failed to allocate memory for data %s\n", cmd); return NULL; } memset(data, 0, sizeof(rsvp_data_t)); data->cmd = (char*)malloc(len); if (!data->cmd) { set_error_string("Failed to allocate memory for data command %s\n", cmd); free(data); return NULL; } memset(data->cmd, 0, len); memcpy(data->cmd, cmd, len - 1); return data; } int rsvp_data_add_var(rsvp_data_t* data, rsvp_var_t* var) { data->args_count += 1; data->args = (rsvp_var_t**)realloc(data->args, sizeof(rsvp_data_t*) * data->args_count); if (!data->args) { set_error_string("Failed to allocate memory for new variable %s\n", var->name); data->args_count -= 1; return -1; } data->args[data->args_count - 1] = var; return NO_ERROR; } int rsvp_data_add_vars(rsvp_data_t* data, unsigned int count, ...) { va_list args; va_start(args, count); for (unsigned int i = 0; i < count; i++) { rsvp_var_t* var = va_arg(args, rsvp_var_t*); if (rsvp_data_add_var(data, var) < 0) { return -1; } } va_end(args); return NO_ERROR; } void rsvp_var_print(rsvp_var_t *var) { printf("Name: %s, type: %s, value: ", var->name, rsvp_type_str[var->type]); Loading Loading @@ -401,14 +471,14 @@ rsvp_var_t* rsvp_var_init(char *name) size_t len = strlen(name) + 1; rsvp_var_t *var = (rsvp_var_t*)malloc(sizeof(rsvp_var_t)); if (!var) { error_code = ALLOCATION_FAILED; set_error_string("Allocation of variable %s failed", name); return NULL; } memset(var, 0, sizeof(rsvp_var_t)); var->name = (char*)malloc(len); if (!var->name) { error_code = ALLOCATION_FAILED; set_error_string("Allocation of variable %s name's failed", name); free(var); return NULL; } Loading Loading @@ -456,17 +526,18 @@ rsvp_var_t* rsvp_var_create_bool(char *name, int value) rsvp_var_t* rsvp_var_create_string(char *name, char* value) { size_t len = strlen(name) + 1; rsvp_var_t *var = rsvp_var_init(name); if (!var) return NULL; var->type = STR; var->value.s = (char*)malloc(strlen(value)); var->value.s = (char*)malloc(len); if (!var->value.s) { error_code = ALLOCATION_FAILED; return NULL; } memcpy(var->value.s, value, strlen(value)); memset(var->value.s, 0, len); memcpy(var->value.s, value, len - 1); return var; } Loading @@ -482,12 +553,12 @@ rsvp_var_t* rsvp_var_create_vecd(char *name) return var; } int rsvp_vecd_add_elem(rsvp_var_t* vecd, char* name, double value) int rsvp_var_vecd_add_elem(rsvp_var_t* vecd, char* name, double value) { size_t name_len = strlen(name) + 1; if (vecd->type != VECD) { error_code = WRONG_VARIABLE_TYPE; set_error_string("Failed to add element to variable %s because is of type %s instead of VECD.", vecd->name, rsvp_type_str[vecd->type]); return -1; } Loading @@ -495,20 +566,24 @@ int rsvp_vecd_add_elem(rsvp_var_t* vecd, char* name, double value) vecd->value.vecd = (rsvp_vecd_elem_t*)realloc(vecd->value.vecd, vecd->len * sizeof(rsvp_vecd_elem_t)); if (!vecd->value.vecd) { error_code = ALLOCATION_FAILED; set_error_string("Failed to augment the size of %s", vecd->name); vecd->len -= 1; return -1; } vecd->value.vecd[vecd->len - 1].name = (char*)malloc(name_len); if (!vecd->value.vecd[vecd->len - 1].name) { set_error_string("Failed to allocate name for element %s", name); vecd->len -=1; vecd->value.vecd = (rsvp_vecd_elem_t*)realloc(vecd->value.vecd, vecd->len * sizeof(rsvp_vecd_elem_t)); return -1; } memset(vecd->value.vecd[vecd->len - 1].name, 0, name_len); memcpy(vecd->value.vecd[vecd->len - 1].name, name, name_len - 1); vecd->value.vecd[vecd->len - 1].value = value; return 0; return NO_ERROR; } rsvp_var_t* rsvp_var_create_vecs(char *name) Loading @@ -522,12 +597,12 @@ rsvp_var_t* rsvp_var_create_vecs(char *name) return var; } int rsvp_vecs_add_elem(rsvp_var_t* vecs, char *value) int rsvp_var_vecs_add_elem(rsvp_var_t* vecs, char *value) { size_t value_len = strlen(value) + 1; if (vecs->type != VECS) { error_code = WRONG_VARIABLE_TYPE; set_error_string("Failed to add element to variable %s because is of type %s instead of VECS.", vecs->name, rsvp_type_str[vecs->type]); return -1; } Loading @@ -535,13 +610,12 @@ int rsvp_vecs_add_elem(rsvp_var_t* vecs, char *value) vecs->value.vecs = (char**)realloc(vecs->value.vecs, vecs->len * sizeof(char*)); if (!vecs->value.vecs) { error_code = ALLOCATION_FAILED; vecs->len -= 1; return -1; } vecs->value.vecs[vecs->len - 1] = (char*)malloc(value_len); if (!vecs->value.vecs[vecs->len - 1]) { error_code = ALLOCATION_FAILED; return -1; } Loading @@ -550,3 +624,18 @@ int rsvp_vecs_add_elem(rsvp_var_t* vecs, char *value) return NO_ERROR; } char* rsvp_var_vecs_get_elem(rsvp_var_t* vecs, int index) { if (index >= vecs->len) { rsvp_error_str("Index out of range for value %s", vecs->name); return NULL; } return vecs->value.vecs[index]; } const char* rsvp_error_str() { return (const char*)&error_str; } No newline at end of file src/rsvp.h +174 −25 Original line number Diff line number Diff line Loading @@ -2,18 +2,7 @@ #define RSVP_H #define TYPE_COUNT 6 #define ERR_STR_SIZE 256 #define NO_ERROR 0 #define ALLOCATION_FAILED (NO_ERROR + 1) #define VAR_CREATION_FAILED (ALLOCATION_FAILED + 1) #define DBL_CONVERSION_FAILED (VAR_CREATION_FAILED + 1) #define INT_CONVERSION_FAILED 4 #define BOOL_CONVERSION_FAILED 5 #define WRONG_VARIABLE_TYPE 6 static int error_code = NO_ERROR; static char error_str[ERR_STR_SIZE] = {0}; typedef enum { STR = 0, Loading @@ -24,7 +13,11 @@ typedef enum { VECS, } RSVP_TYPE; static char rsvp_type_str [TYPE_COUNT][5] = { /** * @brief Conversion of the RSVP_TYPE enum to string * */ const static char rsvp_type_str [TYPE_COUNT][5] = { "STR\0", "INT\0", "DBL\0", Loading @@ -33,17 +26,20 @@ static char rsvp_type_str [TYPE_COUNT][5] = { "VECS" }; /** * @brief Array of double element struct * */ struct rsvp_vecd_elem { char *name; double value; }; typedef struct rsvp_vecd_elem rsvp_vecd_elem_t; struct rsvp_vecs_elem { char *value; }; typedef struct rsvp_vecs_elem rsvp_vecs_elem_t; /** * @brief Define the possible values of RSVP variable value * */ typedef union { int i; Loading @@ -55,17 +51,22 @@ typedef union } value_t; /** * @brief Generic RSVP variable structure * */ struct rsvp_var { char *name; int len; RSVP_TYPE type; value_t value; // void *value; }; typedef struct rsvp_var rsvp_var_t; /** * @brief RSVP data struct * */ struct rsvp_data { char *cmd; rsvp_var_t **args; Loading @@ -73,24 +74,172 @@ struct rsvp_data { }; typedef struct rsvp_data rsvp_data_t; /** * @brief Parse raw RSVP data. Remember to free the memory using rsvp_data_free * * @param data Data to parse * @return rsvp_data_t* Pointer to the parsed data */ extern rsvp_data_t* rsvp_data_parse(char* data); /** * @brief Create a new RSVP data struct. Remember to free the memory using rsvp_data_free * * @param cmd RSVP data command * @return rsvp_data_t* RSVP data struct */ extern rsvp_data_t* rsvp_data_create(char* cmd); /** * @brief Add an argument to the RSVP data struct * * @param data Pointer of the RSVP data struct to add the argument to * @param var RSVP argument to be added * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_data_add_var(rsvp_data_t* data, rsvp_var_t* var); /** * @brief Add multiple arguments to the RSVP data struct * * @param data Pointer of the RSVP data struct to add the argument to * @param count Number of arguments to be added * @param ... RSVP argument to be added (<= count). Type rsvp_var_t* * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_data_add_vars(rsvp_data_t* data, unsigned int count, ...); /** * @brief Convert rsvp_data_t to a string of raw RSVP data * * @param data Data to convert * @return char* String of raw RSVP data */ extern char* rsvp_data_to_string(rsvp_data_t* data); extern rsvp_data_t* rsvp_data_build(char *cmd, ...); /** * @brief Print the RSVP data struct to stdout * * @param data Data to print */ extern void rsvp_data_print(rsvp_data_t* data); /** * @brief Free allocated memory used by data * * @param data Data to free */ extern void rsvp_data_free(rsvp_data_t *data); // Variable creation /** * @brief Create a new RSVP integer variable * * @param name Variable name * @param value Variable integer value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_int(char *name, int value); /** * @brief Create a new RSVP double variable * * @param name Variable name * @param value Variable double value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_double(char *name, double value); /** * @brief Create a new RSVP boolean variable * * @param name Variable name * @param value Variable boolean value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_bool(char *name, int value); /** * @brief Create a new RSVP string variable * * @param name Variable name * @param value Variable string value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_string(char *name, char* value); /** * @brief Create a new empty array of double variable * * @param name Variable name * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_vecd(char *name); extern int rsvp_vecd_add_elem(rsvp_var_t* vecd, char* name, double value); /** * @brief Add an element to a array of double variable * * @param vecd Array of double variable to add the element to * @param name Element name * @param value Element value * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_var_vecd_add_elem(rsvp_var_t* vecd, char* name, double value); /** * @brief Get a specific element from an array of double variable * * @param var Array of double * @param index Element index * @return rsvp_vecd_elem_t* Element */ extern rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* vecd, int index); /** * @brief Create a new array of string variable * * @param name Variable name * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_vecs(char *name); extern int rsvp_vecs_add_elem(rsvp_var_t* vecs, char* value); extern rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* var, int index); /** * @brief Add a string to an array of strings * * @param vecs Array of strings * @param value String to add * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_var_vecs_add_elem(rsvp_var_t* vecs, char* value); /** * @brief Get a specific element from an array of string variable * * @param vecs Array of strings * @param index Element index * @return char* String */ extern char* rsvp_var_vecs_get_elem(rsvp_var_t* vecs, int index); /** * @brief Print a RSVP variable to stdout * * @param var Variable to print */ extern void rsvp_var_print(rsvp_var_t *var); /** * @brief Free an allocated RSVP variable * * @param var Variable to free */ extern void rsvp_var_free(rsvp_var_t *var); /** * @brief Get the current error string * * @return const char* Error string */ extern const char* rsvp_error_str(); #endif //RSVP_H No newline at end of file src/rsvppp.cpp +106 −30 Original line number Diff line number Diff line #include "rsvppp.h" #include <iostream> using namespace std; namespace RSVP { Packet::Packet(string command) { command_ = command; raw_data_ = nullptr; } Packet::Packet(rsvp_data_t* raw_data): raw_data_(raw_data) { command_ = string(raw_data_->cmd); for (unsigned int i = 0; i < raw_data_->args_count; i++) { args_.push_back(raw_data_->args[i]); } } Packet::Packet(string command) : command_(command) { } Packet::~Packet() { if (raw_data_ != nullptr) { rsvp_data_free(raw_data_); for (auto &arg: args_) delete arg; } else { for (auto &arg: args_) { for (size_t i = 0; i < args_.size(); i++) { rsvp_var_t *arg = args_[i]; rsvp_var_free(arg); } } } string Packet::to_string() { Loading Loading @@ -84,21 +66,67 @@ namespace RSVP { return data; } void Packet::print() Packet Packet::parse_data(std::string data) { rsvp_data_t *raw_data = rsvp_data_parse((char*)data.c_str()); string cmd(raw_data->cmd); Packet pkt(cmd); for (unsigned int i = 0; i < raw_data->args_count; i++) { rsvp_var_t *arg = raw_data->args[i]; switch (arg->type) { // rsvp_data_print(); case STR: pkt.add_arg(string(arg->name), string(arg->value.s)); break; case INT: pkt.add_arg(arg->name, arg->value.i); break; case BOOL: pkt.add_arg(arg->name, arg->value.b); break; case DBL: pkt.add_arg(arg->name, arg->value.d); break; case VECD: { vector<tuple<string, double>> vecd; for (int i = 0; i < arg->len; i++) { rsvp_vecd_elem_t* elem = rsvp_var_get_vecd_elem(arg, i); vecd.push_back({elem->name, elem->value}); } Packet Packet::parse_data(std::string data) pkt.add_arg(arg->name, vecd); break; } case VECS: { return Packet(rsvp_data_parse((char*)data.c_str())); vector<string> vecs; for (int i = 0; i < arg->len; i++) { vecs.push_back(arg->value.vecs[i]); } pkt.add_arg(arg->name, vecs); break; } default: break; } } rsvp_data_free(raw_data); return pkt; } void Packet::add_arg(std::string name, int value) { rsvp_var_t* var = rsvp_var_create_int((char*)name.c_str(), value); if (!var) { return; throw PacketException(rsvp_error_str()); } args_.push_back(var); } Loading @@ -106,9 +134,57 @@ namespace RSVP { void Packet::add_arg(std::string name, double value) { rsvp_var_t* var = rsvp_var_create_double((char*)name.c_str(), value); if (!var) { throw PacketException(rsvp_error_str()); } args_.push_back(var); } void Packet::add_arg(std::string name, bool value) { rsvp_var_t* var = rsvp_var_create_bool((char*)name.c_str(), value); if (!var) { throw PacketException(rsvp_error_str()); } args_.push_back(var); } void Packet::add_arg(std::string name, std::string value) { rsvp_var_t* var = rsvp_var_create_string((char*)name.c_str(), (char*)value.c_str()); if (!var) { throw PacketException(rsvp_error_str()); } args_.push_back(var); } void Packet::add_arg(std::string name, std::vector<std::tuple<string, double>> values) { rsvp_var_t* var = rsvp_var_create_vecd((char*)name.c_str()); if (!var) { throw PacketException(rsvp_error_str()); } for (auto &value: values) { if (rsvp_var_vecd_add_elem(var, (char*)get<0>(value).c_str(), get<1>(value)) < 0) { throw PacketException(rsvp_error_str()); } } args_.push_back(var); } void Packet::add_arg(std::string name, std::vector<std::string> values) { rsvp_var_t* var = rsvp_var_create_vecs((char*)name.c_str()); if (!var) { return; } for (auto &value: values) { if (rsvp_var_vecs_add_elem(var, (char*)value.c_str()) < 0) { break; } } args_.push_back(var); } } No newline at end of file Loading
CMakeLists.txt +9 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,15 @@ cmake_minimum_required(VERSION 3.20) project(rsvp-c-cpp LANGUAGES C CXX) include(FetchContent) FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip ) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) include_directories(src) add_compile_options("-Wall") Loading
check_mem.sh +20 −7 Original line number Diff line number Diff line #!/bin/bash SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" cd $SCRIPTPATH/build make CEXE="test" CPPEXE="testpp" run_valgrind() { valgrind --leak-check=full \ --show-leak-kinds=all \ --track-origins=yes \ --log-file=valgrind-out.txt \ ./tests/testpp No newline at end of file --log-file=$1-valgrind-out.txt \ ./$1 } cmake --build build/debug cmake --build build/release cd $SCRIPTPATH/build/debug/tests run_valgrind $CEXE run_valgrind $CPPEXE cd $SCRIPTPATH/build/release/tests run_valgrind $CEXE run_valgrind $CPPEXE
src/rsvp.c +121 −32 Original line number Diff line number Diff line Loading @@ -4,6 +4,9 @@ #include <stdarg.h> #include "rsvp.h" #define ERR_STR_SIZE 256 static char error_str[ERR_STR_SIZE] = {0}; RSVP_TYPE get_type(char *type) { RSVP_TYPE type_ = STR; Loading Loading @@ -32,6 +35,15 @@ int count_tokens(char *str, char delimiter) return counter; } void set_error_string(char* format, ...) { memset(error_str, 0, ERR_STR_SIZE); va_list ap; va_start(ap, format); vsnprintf(error_str, ERR_STR_SIZE, format, ap); va_end(ap); } rsvp_vecd_elem_t* get_vecd_elem(char *token) { char *value = NULL, *begin = token; Loading @@ -54,14 +66,12 @@ rsvp_vecd_elem_t* get_vecd_elem(char *token) elem = (rsvp_vecd_elem_t*)malloc(sizeof(rsvp_vecd_elem_t)); if (!elem) { error_code = ALLOCATION_FAILED; goto exit; } name_len = index + 1; elem->name = (char*)malloc(name_len); if (!elem->name) { error_code = ALLOCATION_FAILED; goto free_elem; } Loading @@ -69,8 +79,7 @@ rsvp_vecd_elem_t* get_vecd_elem(char *token) memcpy(elem->name, begin, name_len - 1); if ((elem->value = strtod(value, NULL)) == 0.0) { error_code = DBL_CONVERSION_FAILED; sprintf(error_str, "Failed to convert %s to double", value); set_error_string("Failed to convert %s to double", value); goto free_name; } Loading @@ -84,12 +93,13 @@ exit: return NULL; } rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* var, int index) rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* vecd, int index) { if (index >= var->len) { if (index >= vecd->len) { rsvp_error_str("Index out of range for value %s", vecd->name); return NULL; } return (rsvp_vecd_elem_t*)var->value.vecd + index; return (rsvp_vecd_elem_t*)vecd->value.vecd + index; } rsvp_var_t* process_args(char *arg) Loading Loading @@ -181,7 +191,7 @@ rsvp_var_t* process_args(char *arg) printf("Error: %s\n", error_str); continue; } rsvp_vecd_add_elem(var, elem->name, elem->value); rsvp_var_vecd_add_elem(var, elem->name, elem->value); free(elem->name); free(elem); token = strtok(NULL, &delimiter); Loading @@ -198,7 +208,7 @@ rsvp_var_t* process_args(char *arg) token = strtok(value, &delimiter); for (int i = 0; i < elem_count; i++) { rsvp_vecs_add_elem(var, token); rsvp_var_vecs_add_elem(var, token); token = strtok(NULL, &delimiter); } break; Loading @@ -215,36 +225,39 @@ rsvp_var_t* process_args(char *arg) rsvp_var_print(var); #endif free(name); if (!var) { error_code = VAR_CREATION_FAILED; printf("Failed to add arg\n"); set_error_string("Failed to add arg %s\n", name); free(name); return NULL; } free(name); return var; } rsvp_data_t *rsvp_data_parse(char* data) { char *token = NULL; char *token = NULL, *raw_data = NULL; char **args = NULL; char delimiter = ';'; size_t index = 0, token_len = 0; rsvp_data_t *rsvp_data = (rsvp_data_t*)malloc(sizeof(rsvp_data_t)); if (!rsvp_data) { error_code = ALLOCATION_FAILED; return NULL; } raw_data = malloc(strlen(data) + 1); memset(raw_data, 0, strlen(data) + 1); memcpy(raw_data, data, strlen(data)); memset(rsvp_data, 0, sizeof(rsvp_data_t)); rsvp_data->args_count = count_tokens(data, delimiter); rsvp_data->args_count = count_tokens(raw_data, delimiter); args = (char**)malloc(rsvp_data->args_count * sizeof(char*)); // Get command string token = strtok(data, &delimiter); token = strtok(raw_data, &delimiter); token_len = strlen(token) + 1; rsvp_data->cmd = (char*)malloc(token_len); memset(rsvp_data->cmd, 0, token_len); Loading @@ -270,7 +283,6 @@ rsvp_data_t *rsvp_data_parse(char* data) rsvp_data->args = (rsvp_var_t**)malloc(rsvp_data->args_count * sizeof(rsvp_var_t*)); if (!rsvp_data->args) { error_code = ALLOCATION_FAILED; return NULL; } Loading @@ -290,10 +302,68 @@ rsvp_data_t *rsvp_data_parse(char* data) } free(args); free(raw_data); return rsvp_data; } rsvp_data_t* rsvp_data_create(char* cmd) { rsvp_data_t *data = NULL; size_t len = strlen(cmd) + 1; data = (rsvp_data_t*)malloc(sizeof(rsvp_data_t)); if (!data) { set_error_string("Failed to allocate memory for data %s\n", cmd); return NULL; } memset(data, 0, sizeof(rsvp_data_t)); data->cmd = (char*)malloc(len); if (!data->cmd) { set_error_string("Failed to allocate memory for data command %s\n", cmd); free(data); return NULL; } memset(data->cmd, 0, len); memcpy(data->cmd, cmd, len - 1); return data; } int rsvp_data_add_var(rsvp_data_t* data, rsvp_var_t* var) { data->args_count += 1; data->args = (rsvp_var_t**)realloc(data->args, sizeof(rsvp_data_t*) * data->args_count); if (!data->args) { set_error_string("Failed to allocate memory for new variable %s\n", var->name); data->args_count -= 1; return -1; } data->args[data->args_count - 1] = var; return NO_ERROR; } int rsvp_data_add_vars(rsvp_data_t* data, unsigned int count, ...) { va_list args; va_start(args, count); for (unsigned int i = 0; i < count; i++) { rsvp_var_t* var = va_arg(args, rsvp_var_t*); if (rsvp_data_add_var(data, var) < 0) { return -1; } } va_end(args); return NO_ERROR; } void rsvp_var_print(rsvp_var_t *var) { printf("Name: %s, type: %s, value: ", var->name, rsvp_type_str[var->type]); Loading Loading @@ -401,14 +471,14 @@ rsvp_var_t* rsvp_var_init(char *name) size_t len = strlen(name) + 1; rsvp_var_t *var = (rsvp_var_t*)malloc(sizeof(rsvp_var_t)); if (!var) { error_code = ALLOCATION_FAILED; set_error_string("Allocation of variable %s failed", name); return NULL; } memset(var, 0, sizeof(rsvp_var_t)); var->name = (char*)malloc(len); if (!var->name) { error_code = ALLOCATION_FAILED; set_error_string("Allocation of variable %s name's failed", name); free(var); return NULL; } Loading Loading @@ -456,17 +526,18 @@ rsvp_var_t* rsvp_var_create_bool(char *name, int value) rsvp_var_t* rsvp_var_create_string(char *name, char* value) { size_t len = strlen(name) + 1; rsvp_var_t *var = rsvp_var_init(name); if (!var) return NULL; var->type = STR; var->value.s = (char*)malloc(strlen(value)); var->value.s = (char*)malloc(len); if (!var->value.s) { error_code = ALLOCATION_FAILED; return NULL; } memcpy(var->value.s, value, strlen(value)); memset(var->value.s, 0, len); memcpy(var->value.s, value, len - 1); return var; } Loading @@ -482,12 +553,12 @@ rsvp_var_t* rsvp_var_create_vecd(char *name) return var; } int rsvp_vecd_add_elem(rsvp_var_t* vecd, char* name, double value) int rsvp_var_vecd_add_elem(rsvp_var_t* vecd, char* name, double value) { size_t name_len = strlen(name) + 1; if (vecd->type != VECD) { error_code = WRONG_VARIABLE_TYPE; set_error_string("Failed to add element to variable %s because is of type %s instead of VECD.", vecd->name, rsvp_type_str[vecd->type]); return -1; } Loading @@ -495,20 +566,24 @@ int rsvp_vecd_add_elem(rsvp_var_t* vecd, char* name, double value) vecd->value.vecd = (rsvp_vecd_elem_t*)realloc(vecd->value.vecd, vecd->len * sizeof(rsvp_vecd_elem_t)); if (!vecd->value.vecd) { error_code = ALLOCATION_FAILED; set_error_string("Failed to augment the size of %s", vecd->name); vecd->len -= 1; return -1; } vecd->value.vecd[vecd->len - 1].name = (char*)malloc(name_len); if (!vecd->value.vecd[vecd->len - 1].name) { set_error_string("Failed to allocate name for element %s", name); vecd->len -=1; vecd->value.vecd = (rsvp_vecd_elem_t*)realloc(vecd->value.vecd, vecd->len * sizeof(rsvp_vecd_elem_t)); return -1; } memset(vecd->value.vecd[vecd->len - 1].name, 0, name_len); memcpy(vecd->value.vecd[vecd->len - 1].name, name, name_len - 1); vecd->value.vecd[vecd->len - 1].value = value; return 0; return NO_ERROR; } rsvp_var_t* rsvp_var_create_vecs(char *name) Loading @@ -522,12 +597,12 @@ rsvp_var_t* rsvp_var_create_vecs(char *name) return var; } int rsvp_vecs_add_elem(rsvp_var_t* vecs, char *value) int rsvp_var_vecs_add_elem(rsvp_var_t* vecs, char *value) { size_t value_len = strlen(value) + 1; if (vecs->type != VECS) { error_code = WRONG_VARIABLE_TYPE; set_error_string("Failed to add element to variable %s because is of type %s instead of VECS.", vecs->name, rsvp_type_str[vecs->type]); return -1; } Loading @@ -535,13 +610,12 @@ int rsvp_vecs_add_elem(rsvp_var_t* vecs, char *value) vecs->value.vecs = (char**)realloc(vecs->value.vecs, vecs->len * sizeof(char*)); if (!vecs->value.vecs) { error_code = ALLOCATION_FAILED; vecs->len -= 1; return -1; } vecs->value.vecs[vecs->len - 1] = (char*)malloc(value_len); if (!vecs->value.vecs[vecs->len - 1]) { error_code = ALLOCATION_FAILED; return -1; } Loading @@ -550,3 +624,18 @@ int rsvp_vecs_add_elem(rsvp_var_t* vecs, char *value) return NO_ERROR; } char* rsvp_var_vecs_get_elem(rsvp_var_t* vecs, int index) { if (index >= vecs->len) { rsvp_error_str("Index out of range for value %s", vecs->name); return NULL; } return vecs->value.vecs[index]; } const char* rsvp_error_str() { return (const char*)&error_str; } No newline at end of file
src/rsvp.h +174 −25 Original line number Diff line number Diff line Loading @@ -2,18 +2,7 @@ #define RSVP_H #define TYPE_COUNT 6 #define ERR_STR_SIZE 256 #define NO_ERROR 0 #define ALLOCATION_FAILED (NO_ERROR + 1) #define VAR_CREATION_FAILED (ALLOCATION_FAILED + 1) #define DBL_CONVERSION_FAILED (VAR_CREATION_FAILED + 1) #define INT_CONVERSION_FAILED 4 #define BOOL_CONVERSION_FAILED 5 #define WRONG_VARIABLE_TYPE 6 static int error_code = NO_ERROR; static char error_str[ERR_STR_SIZE] = {0}; typedef enum { STR = 0, Loading @@ -24,7 +13,11 @@ typedef enum { VECS, } RSVP_TYPE; static char rsvp_type_str [TYPE_COUNT][5] = { /** * @brief Conversion of the RSVP_TYPE enum to string * */ const static char rsvp_type_str [TYPE_COUNT][5] = { "STR\0", "INT\0", "DBL\0", Loading @@ -33,17 +26,20 @@ static char rsvp_type_str [TYPE_COUNT][5] = { "VECS" }; /** * @brief Array of double element struct * */ struct rsvp_vecd_elem { char *name; double value; }; typedef struct rsvp_vecd_elem rsvp_vecd_elem_t; struct rsvp_vecs_elem { char *value; }; typedef struct rsvp_vecs_elem rsvp_vecs_elem_t; /** * @brief Define the possible values of RSVP variable value * */ typedef union { int i; Loading @@ -55,17 +51,22 @@ typedef union } value_t; /** * @brief Generic RSVP variable structure * */ struct rsvp_var { char *name; int len; RSVP_TYPE type; value_t value; // void *value; }; typedef struct rsvp_var rsvp_var_t; /** * @brief RSVP data struct * */ struct rsvp_data { char *cmd; rsvp_var_t **args; Loading @@ -73,24 +74,172 @@ struct rsvp_data { }; typedef struct rsvp_data rsvp_data_t; /** * @brief Parse raw RSVP data. Remember to free the memory using rsvp_data_free * * @param data Data to parse * @return rsvp_data_t* Pointer to the parsed data */ extern rsvp_data_t* rsvp_data_parse(char* data); /** * @brief Create a new RSVP data struct. Remember to free the memory using rsvp_data_free * * @param cmd RSVP data command * @return rsvp_data_t* RSVP data struct */ extern rsvp_data_t* rsvp_data_create(char* cmd); /** * @brief Add an argument to the RSVP data struct * * @param data Pointer of the RSVP data struct to add the argument to * @param var RSVP argument to be added * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_data_add_var(rsvp_data_t* data, rsvp_var_t* var); /** * @brief Add multiple arguments to the RSVP data struct * * @param data Pointer of the RSVP data struct to add the argument to * @param count Number of arguments to be added * @param ... RSVP argument to be added (<= count). Type rsvp_var_t* * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_data_add_vars(rsvp_data_t* data, unsigned int count, ...); /** * @brief Convert rsvp_data_t to a string of raw RSVP data * * @param data Data to convert * @return char* String of raw RSVP data */ extern char* rsvp_data_to_string(rsvp_data_t* data); extern rsvp_data_t* rsvp_data_build(char *cmd, ...); /** * @brief Print the RSVP data struct to stdout * * @param data Data to print */ extern void rsvp_data_print(rsvp_data_t* data); /** * @brief Free allocated memory used by data * * @param data Data to free */ extern void rsvp_data_free(rsvp_data_t *data); // Variable creation /** * @brief Create a new RSVP integer variable * * @param name Variable name * @param value Variable integer value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_int(char *name, int value); /** * @brief Create a new RSVP double variable * * @param name Variable name * @param value Variable double value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_double(char *name, double value); /** * @brief Create a new RSVP boolean variable * * @param name Variable name * @param value Variable boolean value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_bool(char *name, int value); /** * @brief Create a new RSVP string variable * * @param name Variable name * @param value Variable string value * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_string(char *name, char* value); /** * @brief Create a new empty array of double variable * * @param name Variable name * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_vecd(char *name); extern int rsvp_vecd_add_elem(rsvp_var_t* vecd, char* name, double value); /** * @brief Add an element to a array of double variable * * @param vecd Array of double variable to add the element to * @param name Element name * @param value Element value * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_var_vecd_add_elem(rsvp_var_t* vecd, char* name, double value); /** * @brief Get a specific element from an array of double variable * * @param var Array of double * @param index Element index * @return rsvp_vecd_elem_t* Element */ extern rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* vecd, int index); /** * @brief Create a new array of string variable * * @param name Variable name * @return rsvp_var_t* Pointer to the created variable */ extern rsvp_var_t* rsvp_var_create_vecs(char *name); extern int rsvp_vecs_add_elem(rsvp_var_t* vecs, char* value); extern rsvp_vecd_elem_t* rsvp_var_get_vecd_elem(rsvp_var_t* var, int index); /** * @brief Add a string to an array of strings * * @param vecs Array of strings * @param value String to add * @return int 0 on success, -1 on failure. Use rsvp_error_string to get more information */ extern int rsvp_var_vecs_add_elem(rsvp_var_t* vecs, char* value); /** * @brief Get a specific element from an array of string variable * * @param vecs Array of strings * @param index Element index * @return char* String */ extern char* rsvp_var_vecs_get_elem(rsvp_var_t* vecs, int index); /** * @brief Print a RSVP variable to stdout * * @param var Variable to print */ extern void rsvp_var_print(rsvp_var_t *var); /** * @brief Free an allocated RSVP variable * * @param var Variable to free */ extern void rsvp_var_free(rsvp_var_t *var); /** * @brief Get the current error string * * @return const char* Error string */ extern const char* rsvp_error_str(); #endif //RSVP_H No newline at end of file
src/rsvppp.cpp +106 −30 Original line number Diff line number Diff line #include "rsvppp.h" #include <iostream> using namespace std; namespace RSVP { Packet::Packet(string command) { command_ = command; raw_data_ = nullptr; } Packet::Packet(rsvp_data_t* raw_data): raw_data_(raw_data) { command_ = string(raw_data_->cmd); for (unsigned int i = 0; i < raw_data_->args_count; i++) { args_.push_back(raw_data_->args[i]); } } Packet::Packet(string command) : command_(command) { } Packet::~Packet() { if (raw_data_ != nullptr) { rsvp_data_free(raw_data_); for (auto &arg: args_) delete arg; } else { for (auto &arg: args_) { for (size_t i = 0; i < args_.size(); i++) { rsvp_var_t *arg = args_[i]; rsvp_var_free(arg); } } } string Packet::to_string() { Loading Loading @@ -84,21 +66,67 @@ namespace RSVP { return data; } void Packet::print() Packet Packet::parse_data(std::string data) { rsvp_data_t *raw_data = rsvp_data_parse((char*)data.c_str()); string cmd(raw_data->cmd); Packet pkt(cmd); for (unsigned int i = 0; i < raw_data->args_count; i++) { rsvp_var_t *arg = raw_data->args[i]; switch (arg->type) { // rsvp_data_print(); case STR: pkt.add_arg(string(arg->name), string(arg->value.s)); break; case INT: pkt.add_arg(arg->name, arg->value.i); break; case BOOL: pkt.add_arg(arg->name, arg->value.b); break; case DBL: pkt.add_arg(arg->name, arg->value.d); break; case VECD: { vector<tuple<string, double>> vecd; for (int i = 0; i < arg->len; i++) { rsvp_vecd_elem_t* elem = rsvp_var_get_vecd_elem(arg, i); vecd.push_back({elem->name, elem->value}); } Packet Packet::parse_data(std::string data) pkt.add_arg(arg->name, vecd); break; } case VECS: { return Packet(rsvp_data_parse((char*)data.c_str())); vector<string> vecs; for (int i = 0; i < arg->len; i++) { vecs.push_back(arg->value.vecs[i]); } pkt.add_arg(arg->name, vecs); break; } default: break; } } rsvp_data_free(raw_data); return pkt; } void Packet::add_arg(std::string name, int value) { rsvp_var_t* var = rsvp_var_create_int((char*)name.c_str(), value); if (!var) { return; throw PacketException(rsvp_error_str()); } args_.push_back(var); } Loading @@ -106,9 +134,57 @@ namespace RSVP { void Packet::add_arg(std::string name, double value) { rsvp_var_t* var = rsvp_var_create_double((char*)name.c_str(), value); if (!var) { throw PacketException(rsvp_error_str()); } args_.push_back(var); } void Packet::add_arg(std::string name, bool value) { rsvp_var_t* var = rsvp_var_create_bool((char*)name.c_str(), value); if (!var) { throw PacketException(rsvp_error_str()); } args_.push_back(var); } void Packet::add_arg(std::string name, std::string value) { rsvp_var_t* var = rsvp_var_create_string((char*)name.c_str(), (char*)value.c_str()); if (!var) { throw PacketException(rsvp_error_str()); } args_.push_back(var); } void Packet::add_arg(std::string name, std::vector<std::tuple<string, double>> values) { rsvp_var_t* var = rsvp_var_create_vecd((char*)name.c_str()); if (!var) { throw PacketException(rsvp_error_str()); } for (auto &value: values) { if (rsvp_var_vecd_add_elem(var, (char*)get<0>(value).c_str(), get<1>(value)) < 0) { throw PacketException(rsvp_error_str()); } } args_.push_back(var); } void Packet::add_arg(std::string name, std::vector<std::string> values) { rsvp_var_t* var = rsvp_var_create_vecs((char*)name.c_str()); if (!var) { return; } for (auto &value: values) { if (rsvp_var_vecs_add_elem(var, (char*)value.c_str()) < 0) { break; } } args_.push_back(var); } } No newline at end of file