Commit 87d964d7 authored by Gallacchi Mattia's avatar Gallacchi Mattia
Browse files

Fix segfault bug

parent 54a93a2d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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")
+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
+121 −32
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
    }

@@ -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;
    }

@@ -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)
@@ -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);
@@ -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;
@@ -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);
@@ -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;
    }

@@ -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]);
@@ -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;
    }
@@ -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;
}
@@ -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;
    }

@@ -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)
@@ -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;
    }

@@ -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;
    }

@@ -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
+174 −25
Original line number Diff line number Diff line
@@ -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,
@@ -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",
@@ -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;
@@ -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;
@@ -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
+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()
    {
@@ -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);
    }
@@ -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