17e078dfaSTrond Norbye/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
27e078dfaSTrond Norbye/*
38b3dea0cSBen Huddleston *     Copyright 2019 Couchbase, Inc
47e078dfaSTrond Norbye *
57e078dfaSTrond Norbye *   Licensed under the Apache License, Version 2.0 (the "License");
67e078dfaSTrond Norbye *   you may not use this file except in compliance with the License.
77e078dfaSTrond Norbye *   You may obtain a copy of the License at
87e078dfaSTrond Norbye *
97e078dfaSTrond Norbye *       http://www.apache.org/licenses/LICENSE-2.0
107e078dfaSTrond Norbye *
117e078dfaSTrond Norbye *   Unless required by applicable law or agreed to in writing, software
127e078dfaSTrond Norbye *   distributed under the License is distributed on an "AS IS" BASIS,
137e078dfaSTrond Norbye *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147e078dfaSTrond Norbye *   See the License for the specific language governing permissions and
157e078dfaSTrond Norbye *   limitations under the License.
167e078dfaSTrond Norbye */
178b3dea0cSBen Huddleston
188b3dea0cSBen Huddleston#include <json_utilities.h>
198b3dea0cSBen Huddleston#include <platform/dirutils.h>
208b3dea0cSBen Huddleston
218b3dea0cSBen Huddleston#include <nlohmann/json.hpp>
228b3dea0cSBen Huddleston
237e078dfaSTrond Norbye#include <sys/stat.h>
247e078dfaSTrond Norbye#include <string>
257e078dfaSTrond Norbye#include <sstream>
267e078dfaSTrond Norbye#include <iostream>
277e078dfaSTrond Norbye#include <fstream>
287e078dfaSTrond Norbye#include <map>
297e078dfaSTrond Norbye
308b3dea0cSBen Huddlestonstd::stringstream prototypes;
318b3dea0cSBen Huddlestonstd::stringstream initialization;
328b3dea0cSBen Huddlestonstd::stringstream implementation;
337e078dfaSTrond Norbye
348b3dea0cSBen Huddlestontypedef std::string (*getValidatorCode)(const std::string&,
358b3dea0cSBen Huddleston                                        const nlohmann::json&);
367e078dfaSTrond Norbye
378b3dea0cSBen Huddlestonstd::map<std::string, getValidatorCode> validators;
388b3dea0cSBen Huddlestonstd::map<std::string, std::string> datatypes;
397e078dfaSTrond Norbye
408b3dea0cSBen Huddlestonstatic std::string getDatatype(const std::string& key,
418b3dea0cSBen Huddleston                               const nlohmann::json& json) {
428b3dea0cSBen Huddleston    auto ret = json["type"].get<std::string>();
438b3dea0cSBen Huddleston    auto iter = datatypes.find(ret);
448b3dea0cSBen Huddleston    if (iter == datatypes.end()) {
458b3dea0cSBen Huddleston        std::cerr << "Invalid datatype specified for \"" << key << "\": " << ret
468b3dea0cSBen Huddleston                  << std::endl;
478b3dea0cSBen Huddleston        exit(1);
48fc93fa1bSWill Gardner    }
497e078dfaSTrond Norbye
508b3dea0cSBen Huddleston    return iter->second;
518b3dea0cSBen Huddleston}
527e078dfaSTrond Norbye
538b3dea0cSBen Huddlestonstatic std::string getRangeValidatorCode(const std::string& key,
548b3dea0cSBen Huddleston                                         const nlohmann::json& json) {
558b3dea0cSBen Huddleston    // We've already made the checks to verify that these objects exist
568b3dea0cSBen Huddleston    auto validator = json["validator"];
578b3dea0cSBen Huddleston    auto first = validator.begin();
588b3dea0cSBen Huddleston
598b3dea0cSBen Huddleston    auto min = first->find("min");
608b3dea0cSBen Huddleston    auto max = first->find("max");
618b3dea0cSBen Huddleston    if (min == first->end() && max == first->end()) {
628b3dea0cSBen Huddleston        std::cerr << "Incorrect syntax for a range validator specified for"
638b3dea0cSBen Huddleston                  << "\"" << key << "\"." << std::endl
648b3dea0cSBen Huddleston                  << "You need at least one of a min or a max clause."
658b3dea0cSBen Huddleston                  << std::endl;
667e078dfaSTrond Norbye        exit(1);
677e078dfaSTrond Norbye    }
687e078dfaSTrond Norbye
698b3dea0cSBen Huddleston    // If min exists and is not a numeric type
708b3dea0cSBen Huddleston    if (min != first->end() &&
718b3dea0cSBen Huddleston        !(min->type() == nlohmann::json::value_t::number_integer ||
728b3dea0cSBen Huddleston          min->type() == nlohmann::json::value_t::number_unsigned ||
738b3dea0cSBen Huddleston          min->type() == nlohmann::json::value_t::number_float)) {
748b3dea0cSBen Huddleston        std::cerr << "Incorrect datatype for the range validator specified for "
758b3dea0cSBen Huddleston                  << "\"" << key << "\"." << std::endl
768b3dea0cSBen Huddleston                  << "Only numbers are supported." << std::endl;
777e078dfaSTrond Norbye        exit(1);
787e078dfaSTrond Norbye    }
798b3dea0cSBen Huddleston
808b3dea0cSBen Huddleston    // If max exists and is not of the correct type
818b3dea0cSBen Huddleston    if (max != first->end() &&
828b3dea0cSBen Huddleston        !(max->type() == nlohmann::json::value_t::number_integer ||
838b3dea0cSBen Huddleston          max->type() == nlohmann::json::value_t::number_unsigned ||
848b3dea0cSBen Huddleston          max->type() == nlohmann::json::value_t::number_float ||
858b3dea0cSBen Huddleston          (max->type() == nlohmann::json::value_t::string &&
868b3dea0cSBen Huddleston           max->get<std::string>() == "NUM_CPU"))) {
878b3dea0cSBen Huddleston        std::cerr << "Incorrect datatype for the range validator specified for "
888b3dea0cSBen Huddleston                  << "\"" << key << "\"." << std::endl
898b3dea0cSBen Huddleston                  << "Only numbers are supported." << std::endl;
90fc93fa1bSWill Gardner        exit(1);
91fc93fa1bSWill Gardner    }
927e078dfaSTrond Norbye
938b3dea0cSBen Huddleston    std::string validator_type;
948b3dea0cSBen Huddleston    std::string mins;
958b3dea0cSBen Huddleston    std::string maxs;
96fc93fa1bSWill Gardner
978b3dea0cSBen Huddleston    if (getDatatype(key, json) == "float") {
98fc93fa1bSWill Gardner        validator_type = "FloatRangeValidator";
998b3dea0cSBen Huddleston        if (min != first->end()) {
1008b3dea0cSBen Huddleston            mins = std::to_string(min->get<float>());
101fc93fa1bSWill Gardner        } else {
102fc93fa1bSWill Gardner            mins = "std::numeric_limits<float>::min()";
103fc93fa1bSWill Gardner        }
1048b3dea0cSBen Huddleston        if (max != first->end()) {
1058b3dea0cSBen Huddleston            maxs = std::to_string(max->get<float>());
106fc93fa1bSWill Gardner        } else {
107fc93fa1bSWill Gardner            maxs = "std::numeric_limits<float>::max()";
108fc93fa1bSWill Gardner        }
1098b3dea0cSBen Huddleston    } else if (getDatatype(key, json) == "ssize_t") {
110fc93fa1bSWill Gardner        validator_type = "SSizeRangeValidator";
1118b3dea0cSBen Huddleston        if (min != first->end()) {
1128b3dea0cSBen Huddleston            mins = std::to_string(min->get<int64_t>());
113fc93fa1bSWill Gardner        } else {
114fc93fa1bSWill Gardner            mins = "std::numeric_limits<ssize_t>::min()";
115fc93fa1bSWill Gardner        }
1168b3dea0cSBen Huddleston        if (max != first->end()) {
1178b3dea0cSBen Huddleston            maxs = std::to_string(max->get<int64_t>());
118fc93fa1bSWill Gardner        } else {
119fc93fa1bSWill Gardner            maxs = "std::numeric_limits<ssize_t>::max()";
120fc93fa1bSWill Gardner        }
1217e078dfaSTrond Norbye    } else {
122fc93fa1bSWill Gardner        validator_type = "SizeRangeValidator";
1238b3dea0cSBen Huddleston        if (min != first->end()) {
1248b3dea0cSBen Huddleston            mins = std::to_string(min->get<uint64_t>());
125fc93fa1bSWill Gardner        } else {
1268b3dea0cSBen Huddleston            mins = "std::numeric_limits<size_t>::main()";
127fc93fa1bSWill Gardner        }
1288b3dea0cSBen Huddleston        if (max != first->end() &&
1298b3dea0cSBen Huddleston            max->type() == nlohmann::json::value_t::string &&
1308b3dea0cSBen Huddleston            max->get<std::string>() == "NUM_CPU") {
131ad594c5eSJames Harrison            maxs = "Couchbase::get_available_cpu_count()";
1328b3dea0cSBen Huddleston        } else if (max != first->end()) {
1338b3dea0cSBen Huddleston            maxs = std::to_string(max->get<uint64_t>());
134fc93fa1bSWill Gardner        } else {
135fc93fa1bSWill Gardner            maxs = "std::numeric_limits<size_t>::max()";
136fc93fa1bSWill Gardner        }
1377e078dfaSTrond Norbye    }
1387e078dfaSTrond Norbye
1398b3dea0cSBen Huddleston    std::string out = "(new " + validator_type + "())->min(" + mins +
1408b3dea0cSBen Huddleston                      ")->max(" + maxs + ")";
141fc93fa1bSWill Gardner    return out;
1427e078dfaSTrond Norbye}
1437e078dfaSTrond Norbye
1448b3dea0cSBen Huddlestonstatic std::string getEnumValidatorCode(const std::string& key,
1458b3dea0cSBen Huddleston                                        const nlohmann::json& json) {
1468b3dea0cSBen Huddleston    // We've already made the checks to verify if these objects exist
1478b3dea0cSBen Huddleston    auto validator = json["validator"];
1488b3dea0cSBen Huddleston    auto first = validator.begin();
1497e078dfaSTrond Norbye
1508b3dea0cSBen Huddleston    if (first->type() != nlohmann::json::value_t::array) {
1518b3dea0cSBen Huddleston        std::cerr << "Incorrect enum value for " << key
1528b3dea0cSBen Huddleston                  << ".  Array of values is required." << std::endl;
1537e078dfaSTrond Norbye        exit(1);
1547e078dfaSTrond Norbye    }
1557e078dfaSTrond Norbye
1568b3dea0cSBen Huddleston    if (first->size() < 1) {
1578b3dea0cSBen Huddleston        std::cerr << "At least one validator enum element is required (" << key
1588b3dea0cSBen Huddleston                  << ")" << std::endl;
1597e078dfaSTrond Norbye        exit(1);
1607e078dfaSTrond Norbye    }
1617e078dfaSTrond Norbye
1628b3dea0cSBen Huddleston    std::stringstream ss;
1637e078dfaSTrond Norbye    ss << "(new EnumValidator())";
1647e078dfaSTrond Norbye
1658b3dea0cSBen Huddleston    for (auto& obj : *first) {
1668b3dea0cSBen Huddleston        if (obj.type() != nlohmann::json::value_t::string) {
1678b3dea0cSBen Huddleston            std::cerr << "Incorrect validator for " << key
1688b3dea0cSBen Huddleston                      << ", all enum entries must be strings." << std::endl;
1697e078dfaSTrond Norbye            exit(1);
1707e078dfaSTrond Norbye        }
1718b3dea0cSBen Huddleston        ss << "\n\t\t->add(\"" << obj.get<std::string>() << "\")";
1727e078dfaSTrond Norbye    }
1737e078dfaSTrond Norbye    return ss.str();
1747e078dfaSTrond Norbye}
1757e078dfaSTrond Norbye
1767e078dfaSTrond Norbyestatic void initialize() {
1771c1309feSDave Rigby    const char* header = R"(/*
1781c1309feSDave Rigby *     Copyright 2019 Couchbase, Inc
1791c1309feSDave Rigby *
1801c1309feSDave Rigby *   Licensed under the Apache License, Version 2.0 (the "License");
1811c1309feSDave Rigby *   you may not use this file except in compliance with the License.
1821c1309feSDave Rigby *   You may obtain a copy of the License at
1831c1309feSDave Rigby *
1841c1309feSDave Rigby *       http://www.apache.org/licenses/LICENSE-2.0"
1851c1309feSDave Rigby *
1861c1309feSDave Rigby *   Unless required by applicable law or agreed to in writing, software
1871c1309feSDave Rigby *   distributed under the License is distributed on an "AS IS" BASIS,
1881c1309feSDave Rigby *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1891c1309feSDave Rigby *   See the License for the specific language governing permissions and
1901c1309feSDave Rigby *   limitations under the License.
1911c1309feSDave Rigby */
1921c1309feSDave Rigby
1931c1309feSDave Rigby// ###########################################
1941c1309feSDave Rigby// # DO NOT EDIT! THIS IS A GENERATED FILE
1951c1309feSDave Rigby// ###########################################
1961c1309feSDave Rigby)";
1971c1309feSDave Rigby
1981c1309feSDave Rigby    prototypes << header << R"(
1991c1309feSDave Rigby#pragma once
2001c1309feSDave Rigby
2011c1309feSDave Rigby#include <string>
2021c1309feSDave Rigby)";
2031c1309feSDave Rigby
2041c1309feSDave Rigby    implementation << header << R"(
2051c1309feSDave Rigby#include "configuration.h"
2061c1309feSDave Rigby#include "configuration_impl.h"
2071c1309feSDave Rigby#include <platform/sysinfo.h>
2081c1309feSDave Rigby#include <limits>
2091c1309feSDave Rigby
210440f45bcSDave Rigbyusing namespace std::string_literals;
211440f45bcSDave Rigby
2121c1309feSDave Rigby)";
2131c1309feSDave Rigby
2147e078dfaSTrond Norbye    validators["range"] = getRangeValidatorCode;
2157e078dfaSTrond Norbye    validators["enum"] = getEnumValidatorCode;
2167e078dfaSTrond Norbye    datatypes["bool"] = "bool";
2177e078dfaSTrond Norbye    datatypes["size_t"] = "size_t";
2187e078dfaSTrond Norbye    datatypes["ssize_t"] = "ssize_t";
2197e078dfaSTrond Norbye    datatypes["float"] = "float";
2207e078dfaSTrond Norbye    datatypes["string"] = "std::string";
2217e078dfaSTrond Norbye    datatypes["std::string"] = "std::string";
2227e078dfaSTrond Norbye}
2237e078dfaSTrond Norbye
2248b3dea0cSBen Huddlestonstatic bool isReadOnly(const nlohmann::json& json) {
2258b3dea0cSBen Huddleston    try {
2268b3dea0cSBen Huddleston        return !cb::jsonGet<bool>(json, "dynamic");
2278b3dea0cSBen Huddleston    } catch (const nlohmann::json::exception& e) {
2288b3dea0cSBen Huddleston        std::cerr << e.what() << std::endl;
229c08c8d1cSSriram Ganesan        exit(1);
230c08c8d1cSSriram Ganesan    }
231c08c8d1cSSriram Ganesan    return false;
2327e078dfaSTrond Norbye}
2337e078dfaSTrond Norbye
2348b3dea0cSBen Huddlestonstatic bool hasAliases(const nlohmann::json& json) {
2358b3dea0cSBen Huddleston    auto aliases = json.find("aliases");
2368b3dea0cSBen Huddleston    if (aliases == json.end()) {
2374781fd61SJames Harrison        return false;
2384781fd61SJames Harrison    }
2394781fd61SJames Harrison
2408b3dea0cSBen Huddleston    if (aliases->type() == nlohmann::json::value_t::string ||
2418b3dea0cSBen Huddleston        aliases->type() == nlohmann::json::value_t::array) {
2424781fd61SJames Harrison        return true;
2434781fd61SJames Harrison    }
2444781fd61SJames Harrison
2454781fd61SJames Harrison    return false;
2464781fd61SJames Harrison}
2474781fd61SJames Harrison
2488b3dea0cSBen Huddlestonstatic std::vector<std::string> getAliases(const nlohmann::json& json) {
2498b3dea0cSBen Huddleston    auto aliases = json.find("aliases");
2504781fd61SJames Harrison
2514781fd61SJames Harrison    std::vector<std::string> output;
2524781fd61SJames Harrison
2538b3dea0cSBen Huddleston    if (aliases->type() == nlohmann::json::value_t::string) {
2548b3dea0cSBen Huddleston        output.emplace_back(aliases->get<std::string>());
2558b3dea0cSBen Huddleston    } else if (aliases->type() == nlohmann::json::value_t::array) {
2568b3dea0cSBen Huddleston        for (auto elem : *aliases) {
2578b3dea0cSBen Huddleston            output.emplace_back(elem.get<std::string>());
2584781fd61SJames Harrison        }
2594781fd61SJames Harrison    }
2604781fd61SJames Harrison
2614781fd61SJames Harrison    return output;
2624781fd61SJames Harrison}
2634781fd61SJames Harrison
2648b3dea0cSBen Huddlestonstatic std::string getValidator(const std::string& key,
2658b3dea0cSBen Huddleston                                const nlohmann::json& json) {
2668b3dea0cSBen Huddleston    auto validator = json.find("validator");
2678b3dea0cSBen Huddleston    if (validator == json.end()) {
2688b3dea0cSBen Huddleston        // No validator found
2697e078dfaSTrond Norbye        return "";
2707e078dfaSTrond Norbye    }
2717e078dfaSTrond Norbye
2728b3dea0cSBen Huddleston    // Abort early if the validator is bad
2738b3dea0cSBen Huddleston    if (validator->size() != 1) {
2748b3dea0cSBen Huddleston        std::cerr << "Only one validator can be specified for " << key
2758b3dea0cSBen Huddleston                  << std::endl;
2768b3dea0cSBen Huddleston        exit(1);
277fc93fa1bSWill Gardner    }
278fc93fa1bSWill Gardner
2798b3dea0cSBen Huddleston    // Get the validator json (first element)
2808b3dea0cSBen Huddleston    auto first = validator->begin();
2817e078dfaSTrond Norbye
2828b3dea0cSBen Huddleston    // Lookup the correct function from the map
2838b3dea0cSBen Huddleston    std::map<std::string, getValidatorCode>::iterator iter;
2848b3dea0cSBen Huddleston    iter = validators.find(first.key());
2857e078dfaSTrond Norbye    if (iter == validators.end()) {
2868b3dea0cSBen Huddleston        std::cerr << "Unknown validator specified for \"" << key << "\": \""
2878b3dea0cSBen Huddleston                  << first->get<std::string>() << "\"" << std::endl;
2887e078dfaSTrond Norbye        exit(1);
2897e078dfaSTrond Norbye    }
2907e078dfaSTrond Norbye
2918b3dea0cSBen Huddleston    return (iter->second)(key, json);
2927e078dfaSTrond Norbye}
2937e078dfaSTrond Norbye
2949a7e1093SJames Harrison/**
2959a7e1093SJames Harrison * Generates code from the requirements field.
2969a7e1093SJames Harrison *
2979a7e1093SJames Harrison * Generates code to be used in generated_configuration.cc constructing the
2989a7e1093SJames Harrison * Requirement object and adding the appropriate requirements.
2999a7e1093SJames Harrison * @param key key to generate requirements for
3008b3dea0cSBen Huddleston * @param json json object representing the config parameter
3019a7e1093SJames Harrison * @param params json object of all parameters, required to determine the
3029a7e1093SJames Harrison * intended type of the required parameter.
3039a7e1093SJames Harrison * @return string of the code constructing a Requirement object.
3049a7e1093SJames Harrison */
3058b3dea0cSBen Huddlestonstatic std::string getRequirements(const std::string& key,
3068b3dea0cSBen Huddleston                                   const nlohmann::json& json,
3078b3dea0cSBen Huddleston                                   const nlohmann::json& params) {
3088b3dea0cSBen Huddleston    auto requirements = json.find("requires");
3098b3dea0cSBen Huddleston    if (requirements == json.end() || requirements->size() <= 0) {
3109a7e1093SJames Harrison        return "";
3119a7e1093SJames Harrison    }
3129a7e1093SJames Harrison
3139a7e1093SJames Harrison    std::ostringstream ss;
3149a7e1093SJames Harrison
3159a7e1093SJames Harrison    ss << "(new Requirement)\n";
3169a7e1093SJames Harrison
3178b3dea0cSBen Huddleston    for (auto req : requirements->items()) {
3188b3dea0cSBen Huddleston        auto reqKey = req.key();
3199a7e1093SJames Harrison
3208b3dea0cSBen Huddleston        auto reqParam = params.find(key);
3218b3dea0cSBen Huddleston        if (reqParam == params.end()) {
3228b3dea0cSBen Huddleston            std::cerr << "Required parameter \"" << reqKey
3238b3dea0cSBen Huddleston                      << "\" for parameter \"" << key << "\" does not exist"
3248b3dea0cSBen Huddleston                      << std::endl;
3259a7e1093SJames Harrison            exit(1);
3269a7e1093SJames Harrison        }
3279a7e1093SJames Harrison
3288b3dea0cSBen Huddleston        auto type = getDatatype(reqKey, params[reqKey]);
3298b3dea0cSBen Huddleston        std::string value;
3309a7e1093SJames Harrison
3318b3dea0cSBen Huddleston        switch (req.value().type()) {
3328b3dea0cSBen Huddleston        case nlohmann::json::value_t::string:
3338b3dea0cSBen Huddleston            value = std::string("\"") + req.value().get<std::string>() + "\"";
3349a7e1093SJames Harrison            break;
3358b3dea0cSBen Huddleston        case nlohmann::json::value_t::number_unsigned:
3368b3dea0cSBen Huddleston            value = std::to_string(req.value().get<uint64_t>());
337822ea99eSTrond Norbye            break;
3388b3dea0cSBen Huddleston        case nlohmann::json::value_t::number_integer:
3398b3dea0cSBen Huddleston            value = std::to_string(req.value().get<int64_t>());
3409a7e1093SJames Harrison            break;
3418b3dea0cSBen Huddleston        case nlohmann::json::value_t::number_float:
3428b3dea0cSBen Huddleston            value = std::to_string(req.value().get<float_t>());
3439a7e1093SJames Harrison            break;
3448b3dea0cSBen Huddleston        case nlohmann::json::value_t::boolean:
3458b3dea0cSBen Huddleston            value = req.value().get<bool>() ? "true" : "false";
3468b3dea0cSBen Huddleston            break;
3478b3dea0cSBen Huddleston        case nlohmann::json::value_t::array:
3488b3dea0cSBen Huddleston        case nlohmann::json::value_t::discarded:
3498b3dea0cSBen Huddleston        case nlohmann::json::value_t::null:
3508b3dea0cSBen Huddleston        case nlohmann::json::value_t::object:
3519a7e1093SJames Harrison            break;
3529a7e1093SJames Harrison        }
3539a7e1093SJames Harrison
3548b3dea0cSBen Huddleston        ss << "        ->add(\"" << reqKey << "\", (" << type << ")" << value
3559a7e1093SJames Harrison           << ")";
3569a7e1093SJames Harrison    }
3579a7e1093SJames Harrison
3589a7e1093SJames Harrison    return ss.str();
3599a7e1093SJames Harrison}
3609a7e1093SJames Harrison
3618b3dea0cSBen Huddlestonstatic std::string getGetterPrefix(const std::string& str) {
3627e078dfaSTrond Norbye    if (str.compare("bool") == 0) {
3637e078dfaSTrond Norbye        return "is";
3647e078dfaSTrond Norbye    } else {
3657e078dfaSTrond Norbye        return "get";
3667e078dfaSTrond Norbye    }
3677e078dfaSTrond Norbye}
3687e078dfaSTrond Norbye
3698b3dea0cSBen Huddlestonstatic std::string getCppName(const std::string& str) {
3708b3dea0cSBen Huddleston    std::stringstream ss;
3717e078dfaSTrond Norbye    bool doUpper = true;
3727e078dfaSTrond Norbye
3738b3dea0cSBen Huddleston    std::string::const_iterator iter;
3747e078dfaSTrond Norbye    for (iter = str.begin(); iter != str.end(); ++iter) {
3757e078dfaSTrond Norbye        if (*iter == '_') {
3767e078dfaSTrond Norbye            doUpper = true;
3777e078dfaSTrond Norbye        } else {
3787e078dfaSTrond Norbye            if (doUpper) {
3797e078dfaSTrond Norbye                ss << (char)toupper(*iter);
3807e078dfaSTrond Norbye                doUpper = false;
3817e078dfaSTrond Norbye            } else {
3827e078dfaSTrond Norbye                ss << (char)*iter;
3837e078dfaSTrond Norbye            }
3847e078dfaSTrond Norbye        }
3857e078dfaSTrond Norbye    }
3867e078dfaSTrond Norbye    return ss.str();
3877e078dfaSTrond Norbye}
3887e078dfaSTrond Norbye
3898b3dea0cSBen Huddlestonstatic void generate(const nlohmann::json& params, const std::string& key) {
3908b3dea0cSBen Huddleston    std::string cppName = getCppName(key);
3917e078dfaSTrond Norbye
3928b3dea0cSBen Huddleston    auto json = params[key];
3938b3dea0cSBen Huddleston    std::string type = getDatatype(key, json);
3948b3dea0cSBen Huddleston    std::string defaultVal = json["default"].get<std::string>();
3957e078dfaSTrond Norbye
3967e078dfaSTrond Norbye    if (defaultVal.compare("max") == 0 || defaultVal.compare("min") == 0) {
3977e078dfaSTrond Norbye        if (type.compare("std::string") != 0) {
3988b3dea0cSBen Huddleston            std::stringstream ss;
3997e078dfaSTrond Norbye            ss << "std::numeric_limits<" << type << ">::" << defaultVal << "()";
4007e078dfaSTrond Norbye            defaultVal = ss.str();
4017e078dfaSTrond Norbye        }
4027e078dfaSTrond Norbye    }
4037e078dfaSTrond Norbye
4048b3dea0cSBen Huddleston    std::string validator = getValidator(key, json);
4058b3dea0cSBen Huddleston    std::string requirements = getRequirements(key, json, params);
4067e078dfaSTrond Norbye
4077e078dfaSTrond Norbye    // Generate prototypes
4088b3dea0cSBen Huddleston    prototypes << "    " << type << " " << getGetterPrefix(type) << cppName
4098b3dea0cSBen Huddleston               << "() const;" << std::endl;
4103e816d39SDave Rigby    const auto dynamic = !isReadOnly(json);
4113e816d39SDave Rigby
4123e816d39SDave Rigby    if (dynamic) {
4138b3dea0cSBen Huddleston        prototypes << "    void set" << cppName << "(const " << type
4148b3dea0cSBen Huddleston                   << " &nval);" << std::endl;
4157e078dfaSTrond Norbye    }
4167e078dfaSTrond Norbye
4177e078dfaSTrond Norbye    // Generate initialization code
4183e816d39SDave Rigby    initialization << "    addParameter(\"" << key << "\", " << std::boolalpha;
419440f45bcSDave Rigby    if (type == "std::string") {
4203e816d39SDave Rigby        initialization << "\"" << defaultVal << "\"s, ";
4217e078dfaSTrond Norbye    } else {
4223e816d39SDave Rigby        initialization << type << "(" << defaultVal << "), ";
4237e078dfaSTrond Norbye    }
4243e816d39SDave Rigby    initialization << dynamic << ");" << std::endl;
4253e816d39SDave Rigby
4267e078dfaSTrond Norbye    if (!validator.empty()) {
4278b3dea0cSBen Huddleston        initialization << "    setValueValidator(\"" << key << "\", "
4288b3dea0cSBen Huddleston                       << validator << ");" << std::endl;
4297e078dfaSTrond Norbye    }
4309a7e1093SJames Harrison    if (!requirements.empty()) {
4318b3dea0cSBen Huddleston        initialization << "    setRequirements(\"" << key << "\", "
4328b3dea0cSBen Huddleston                       << requirements << ");" << std::endl;
4339a7e1093SJames Harrison    }
4348b3dea0cSBen Huddleston    if (hasAliases(json)) {
4358b3dea0cSBen Huddleston        for (std::string alias : getAliases(json)) {
4368b3dea0cSBen Huddleston            initialization << "    addAlias(\"" << key << "\", \"" << alias
4378b3dea0cSBen Huddleston                           << "\");" << std::endl;
4384781fd61SJames Harrison        }
4394781fd61SJames Harrison    }
4407e078dfaSTrond Norbye
4417e078dfaSTrond Norbye    // Generate the getter
4427e078dfaSTrond Norbye    implementation << type << " Configuration::" << getGetterPrefix(type)
4438b3dea0cSBen Huddleston                   << cppName << "() const {" << std::endl
444b7591f86SJames Harrison                   << "    return "
4458b3dea0cSBen Huddleston                   << "getParameter<" << datatypes[type] << ">(\"" << key
4468b3dea0cSBen Huddleston                   << "\");" << std::endl
4478b3dea0cSBen Huddleston                   << "}" << std::endl;
4487e078dfaSTrond Norbye
4498b3dea0cSBen Huddleston    if (!isReadOnly(json)) {
4507e078dfaSTrond Norbye        // generate the setter
4518b3dea0cSBen Huddleston        implementation << "void Configuration::set" << cppName << "(const "
4528b3dea0cSBen Huddleston                       << type << " &nval) {" << std::endl
4538b3dea0cSBen Huddleston                       << "    setParameter(\"" << key << "\", nval);"
4548b3dea0cSBen Huddleston                       << std::endl
4558b3dea0cSBen Huddleston                       << "}" << std::endl;
4567e078dfaSTrond Norbye    }
4577e078dfaSTrond Norbye}
4587e078dfaSTrond Norbye
4597e078dfaSTrond Norbye/**
4607e078dfaSTrond Norbye * Read "configuration.json" and generate getters and setters
4617e078dfaSTrond Norbye * for the parameters in there
4627e078dfaSTrond Norbye */
4637e078dfaSTrond Norbyeint main(int argc, char **argv) {
464f93d6427SDave Rigby    if (argc < 4) {
4658b3dea0cSBen Huddleston        std::cerr << "Usage: " << argv[0]
4668b3dea0cSBen Huddleston                  << "<input config file> <header> <source>\n";
467f93d6427SDave Rigby        return 1;
4687e078dfaSTrond Norbye    }
4697e078dfaSTrond Norbye
470f93d6427SDave Rigby    const char* file = argv[1];
471f93d6427SDave Rigby    const char* header = argv[2];
472f93d6427SDave Rigby    const char* source = argv[3];
473f93d6427SDave Rigby
4747e078dfaSTrond Norbye    initialize();
4757e078dfaSTrond Norbye
4768b3dea0cSBen Huddleston    nlohmann::json json;
4778b3dea0cSBen Huddleston    try {
4788b3dea0cSBen Huddleston        json = nlohmann::json::parse(cb::io::loadFile(file));
4798b3dea0cSBen Huddleston    } catch (const nlohmann::json::exception& e) {
4808b3dea0cSBen Huddleston        std::cerr << "Failed to parse JSON. e.what()=" << e.what() << std::endl;
4817e078dfaSTrond Norbye        return 1;
4827e078dfaSTrond Norbye    }
4837e078dfaSTrond Norbye
4848b3dea0cSBen Huddleston    auto params = json.find("params");
4858b3dea0cSBen Huddleston    if (params == json.end()) {
4868b3dea0cSBen Huddleston        std::cerr << "FATAL: could not find \"params\" section" << std::endl;
4877e078dfaSTrond Norbye        return 1;
4887e078dfaSTrond Norbye    }
4897e078dfaSTrond Norbye
4908b3dea0cSBen Huddleston    for (const auto& obj : params->items()) {
4918b3dea0cSBen Huddleston        generate(*params, obj.key());
4927e078dfaSTrond Norbye    }
4937e078dfaSTrond Norbye
4948b3dea0cSBen Huddleston    std::ofstream headerfile(header);
4957e078dfaSTrond Norbye    headerfile << prototypes.str();
4967e078dfaSTrond Norbye    headerfile.close();
4977e078dfaSTrond Norbye
4988b3dea0cSBen Huddleston    std::ofstream implfile(source);
4998b3dea0cSBen Huddleston    implfile << implementation.str() << std::endl
5008b3dea0cSBen Huddleston             << "void Configuration::initialize() {" << std::endl
5018b3dea0cSBen Huddleston             << initialization.str() << "}" << std::endl;
5027e078dfaSTrond Norbye    implfile.close();
5037e078dfaSTrond Norbye    return 0;
5047e078dfaSTrond Norbye}
505