Commit 3bee2a83 authored by jan.koester's avatar jan.koester
Browse files

test

parent 502d61a1
Loading
Loading
Loading
Loading
+26 −46
Original line number Diff line number Diff line
@@ -60,12 +60,11 @@ const char* confplus::Yaml::getAuthor(){
void confplus::Yaml::saveConfig(const char *path, const Config *conf){
    std::ofstream f(path);
    if (!f.is_open()) {
        throw "Failed to open file for writing!";
        confplus::ConfException err;
        err[confplus::ConfException::Critical] << "Failed to open file for writing: " << path;
        throw err;
    }

    // A path node whose children are ALL numeric ("0","1",...) represents a
    // YAML sequence. Sequence-of-mappings and nested sequences are stored this
    // way by the stack-based loader.
    auto isNumber = [](const std::string &s) -> bool {
        if (s.empty()) return false;
        for (char c : s) if (c < '0' || c > '9') return false;
@@ -79,7 +78,6 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
        return true;
    };

    // Get value at position from a ConfigData node
    auto getValueAt = [&conf](const Config::ConfigData *node, size_t pos) -> std::string {
        try {
            return conf->getValue(node, pos);
@@ -88,12 +86,10 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
        }
    };

    // Check if a string needs quoting in YAML
    auto needsQuote = [](const std::string &s) -> bool {
        if (s.empty()) return true;
        if (s == "true" || s == "false" || s == "yes" || s == "no" ||
            s == "null" || s == "~") return true;
        // Check if it's a number
        bool isNum = true;
        for (size_t i = 0; i < s.size(); ++i) {
            char c = s[i];
@@ -101,8 +97,7 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
            if (c == '.') continue;
            if (c < '0' || c > '9') { isNum = false; break; }
        }
        if (isNum && !s.empty() && s != "-" && s != "+") return false; // numbers don't need quotes
        // Check for special characters
        if (isNum && !s.empty() && s != "-" && s != "+") return false;
        for (char c : s) {
            if (c == ':' || c == '#' || c == '[' || c == ']' ||
                c == '{' || c == '}' || c == ',' || c == '&' ||
@@ -123,7 +118,6 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
    std::function<void(const Config::ConfigData*, const std::string&)> emitSequence;
    std::function<void(const Config::ConfigData*, const std::string&)> emitSeqElement;

    // Emit a chain of sibling nodes as a YAML mapping at indent `pad`.
    emitMapping = [&](const Config::ConfigData *first, const std::string &pad) {
        for (const Config::ConfigData *n = first; n; n = n->next()) {
            if (n->childs()) {
@@ -133,7 +127,6 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
                else
                    emitMapping(n->getChild(), pad + "  ");
            } else if (n->getElements() > 1) {
                // simple sequence of scalars
                f << pad << n->getKey() << ":\n";
                for (size_t i = 0; i < n->getElements(); ++i)
                    f << pad << "  - " << quoteValue(getValueAt(n, i)) << "\n";
@@ -143,7 +136,6 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
        }
    };

    // Emit a path node whose children are numeric indices as a YAML sequence.
    emitSequence = [&](const Config::ConfigData *node, const std::string &pad) {
        std::string ipad = pad + "  ";
        for (const Config::ConfigData *el = node->getChild(); el; el = el->next()) {
@@ -163,8 +155,6 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
        }
    };

    // Emit a mapping that is one element of a sequence: the first key line is
    // prefixed with "- ", subsequent keys align with two spaces.
    emitSeqElement = [&](const Config::ConfigData *first, const std::string &pad) {
        bool firstKey = true;
        for (const Config::ConfigData *n = first; n; n = n->next()) {
@@ -186,7 +176,6 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){
        }
    };

    // Top-level: blank lines between sections for readability
    const Config::ConfigData *top = conf->first();
    bool firstTop = true;
    for (const Config::ConfigData *n = top; n; n = n->next()) {
@@ -213,37 +202,33 @@ void confplus::Yaml::saveConfig(const char *path,const Config *conf){

void confplus::Yaml::loadConfig(const char* path, Config* conf) {
    FILE* fh = fopen(path, "rb");
    if (fh == nullptr) {
        confplus::ConfException err;
        err[confplus::ConfException::Critical] << "Failed to open file: " << path;
        throw err;
    }

    yaml_event_type_t type = YAML_NO_EVENT;
    yaml_parser_t parse;

    /* Initialize parser */

    if (fh == nullptr) {
        throw "Failed to open file!";
    if (!yaml_parser_initialize(&parse)) {
        fclose(fh);
        confplus::ConfException err;
        err[confplus::ConfException::Critical] << "Failed to initialize yaml parser!";
        throw err;
    }

    if (!yaml_parser_initialize(&parse))
        throw "Failed to initialize parser!";

    /* Set input file */
    yaml_parser_set_input_file(&parse, fh);

    // Stack-based parser. Each frame is either a mapping or a sequence.
    // Paths are built from the stack; sequence elements get a numeric index
    // segment, e.g. /BLOGI/DOMAINS/0/NAMES/1. This produces a clean, fully
    // indexed tree that supports arbitrary nesting (sequences inside mappings
    // inside sequences, etc.).
    struct Frame {
        bool        isSeq;
        std::string path;     // path of this container
        std::string key;      // pending key (mapping only)
        bool        keySet;   // whether a key is waiting for its value
        int         seqIndex; // next index (sequence only)
        std::string path;     
        std::string key;      
        bool        keySet;   
        int         seqIndex; 
    };
    std::vector<Frame> st;

    // Compute the path for a new child container under `top`, consuming the
    // pending mapping key or advancing the sequence index.
    auto childPath = [](Frame &top) -> std::string {
        if (top.isSeq) {
            std::string p = top.path + "/" + std::to_string(top.seqIndex);
@@ -287,19 +272,15 @@ void confplus::Yaml::loadConfig(const char* path, Config* conf) {
            if (st.empty()) break;
            Frame &top = st.back();
            if (top.isSeq) {
                // Scalar element of a sequence -> store at the sequence path
                // with the running index as positional value.
                if (!top.path.empty()) {
                    Config::ConfigData *k = conf->setKey(top.path);
                    conf->setValue(k, top.seqIndex, s);
                }
                ++top.seqIndex;
            } else if (!top.keySet) {
                // Mapping key
                top.key = s;
                top.keySet = true;
            } else {
                // Mapping value
                std::string kp = top.path + "/" + top.key;
                if (kp.size() > 1) {
                    Config::ConfigData *k = conf->setKey(kp);
@@ -320,4 +301,3 @@ void confplus::Yaml::loadConfig(const char* path, Config* conf) {
    yaml_parser_delete(&parse);
    fclose(fh);
}
 No newline at end of file