metayeti/mINI

mIni doesn't parse properly strings

Closed this issue · 4 comments

Hi !
I realised a problem in mIni as it doesn't parse strings properly, the string should be parsed as A MineServer ! but is instead parsed as A.

Config :

[network]
port = 25565

[display]
motd = A MineServer !

[other]
max-players = 100

Using logging here is what I get :

[DEBUG] 10:34:32 - Parsed port as 25565
[DEBUG] 10:34:32 - Parsed motd as A
[DEBUG] 10:34:32 - Parsed max-players as 100
[INFO]  10:34:32 - Motd : A

Hi. I tried it on my end and it works for me. Can you share your code - preferably a small testcase that reproduces the problem? Which library version are you using? Thanks.

Hi there !

I am using the latest version that you uploaded yesterday ! And for the config, I wrote my own wrapper around it, here is the code :
Config.h

//
// Created by Lygaen on 22/02/2022.
//

#ifndef MINESERVER_CONFIG_H
#define MINESERVER_CONFIG_H

#include <unordered_map>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include "../vendor/ini.h"

#define MINESERVER_VERSION_NAME "1.8.9 MineServer"
#define MINESERVER_PROTOCOL_VERSION 47

template<typename T>
std::enable_if_t<std::is_arithmetic<T>::value, std::string> stringify(T t) {
    return std::to_string(t);
}

template<typename T>
std::enable_if_t<!std::is_arithmetic<T>::value, std::string> stringify(T t) {
    return static_cast<std::ostringstream &>(std::ostringstream() << t).str();
}

inline std::string stringify(std::string t) {
    return t;
}

template<typename T>
T getStringAs(std::string &s) {
    std::stringstream convert(s);

    T value;
    convert >> value;
    return value;
}

inline std::string getStringAs(std::string &s) {
    return s;
}

template<typename T>
class Field {
private:
    T value;
    const char* fieldName;
    const char* section;

public:
    Field(const char* section, const char* fieldName, T defaultValue) : section(section), value(defaultValue),
                                                                        fieldName(fieldName) {}

    void parseFromMap(const mINI::INIStructure &structure) {
        if (structure.has(section) && structure.get(section).has(fieldName)) {
            auto val = structure.get(section).get(fieldName);
            value = getStringAs<T>(val);
        }
    }

    void parseFromArgs(std::vector<std::string> &args) {
        auto loc = std::find(args.begin(), args.end(), "--" + std::string(fieldName));
        if (loc != args.end() && std::next(loc) != args.end()) {
            auto index = std::distance(args.begin(), std::next(loc));

            auto val = args[index];

            value = getStringAs<T>(val);
        }
    }

    void saveToMap(mINI::INIStructure &structure) {
        if (!structure.has(section) || !structure.get(section).has(fieldName)) {
            structure[section][fieldName] = stringify(value);
        }
    }

    void set(T v) { value = v; }

    [[nodiscard]] T get() const { return value; }
};

class Config {
private:
    mINI::INIFile file = mINI::INIFile("config.ini");
    mINI::INIStructure data;

    static Config* instance;
public:
    Config(int argc, char* argv[]);

    bool loadFromFile();

    bool save();

    static Config* getInstance() {
        return instance;
    }

    Field<unsigned short> port = Field<unsigned short>("network", "port", 25565);
    Field<unsigned int> maxPlayers = Field<unsigned int>("other", "max-players", 100);
    Field<std::string> motd = Field<std::string>("display", "motd", "A MineServer !");
};


#endif //MINESERVER_CONFIG_H

Config.cpp

//
// Created by Lygaen on 22/02/2022.
//

#include "config.h"

#include <iostream>
#include <filesystem>
#include "logger.h"

Config* Config::instance;

bool Config::loadFromFile() {
    bool success = file.read(data);

    if (!success) {
        return false;
    }

    port.parseFromMap(data);
    motd.parseFromMap(data);
    maxPlayers.parseFromMap(data);

    return true;
}

bool Config::save() {
    port.saveToMap(data);
    motd.saveToMap(data);
    maxPlayers.saveToMap(data);

    return file.write(data, false);
}

Config::Config(int argc, char** argv) {
    if (!std::filesystem::exists("./config.ini")) {
        std::ofstream ofs("./config.ini");
        ofs.close();
    }

    bool success = loadFromFile();

    if (!success) {
        logger::critical("Cannot load data from config !");
        exit(1);
    }

    std::vector<std::string> args{argv + 1, argv + argc};

    port.parseFromArgs(args);
    motd.parseFromArgs(args);
    maxPlayers.parseFromArgs(args);

    success = save();

    if (!success) {
        logger::critical("Cannot save data to the config !");
        exit(1);
    }

    instance = this;
}

While you checkout the code, I'll be writing a test case !

Sorry for the bother, after some extensive search I found out that the error was on my side...
I'm deeply sorry...

Thank you for your time !

No problem - glad you found the issue!