void preprocess_types(rapidjson::Document & d) { /// pre record types for (auto & itr : d.GetArray()) { RAPIDJSON_ASSERT(itr.HasMember("category")); RAPIDJSON_ASSERT(itr.HasMember("name")); ensure_has_array_mem(itr, "attr", d); ensure_has_array_mem(itr, "msgid", d); ensure_has_object_mem(itr, "fields", d); ensure_has_array_mem(itr, "alias", d); s_type_lists[itr.FindMember("name")->value.GetString()] = &itr; for (auto & alias : itr.FindMember("alias")->value.GetArray()) { s_alias_lists[alias.GetString()] = & itr; } s_type_order.push_back(&itr); } /// messages enum for (auto & itr : d.GetArray()) { bool has_attr_msg = false; rapidjson::Value & attr_val = itr.FindMember("attr")->value; for (auto & sattr : attr_val.GetArray()) { RAPIDJSON_ASSERT(sattr.IsString()); if (sattr == "msg") { has_attr_msg = true; attr_val.GetArray().Erase(&sattr); } else if (sattr == "export") { s_export_order.push_back(&itr); } else if (sattr == "pqxx") { add_pqxx(d, itr, true); } } rapidjson::Value & msgid_val = itr.FindMember("msgid")->value; if (has_attr_msg) { RAPIDJSON_ASSERT(itr.HasMember("name")); rapidjson::Value new_name(itr.FindMember("name")->value, d.GetAllocator()); msgid_val.PushBack(new_name, d.GetAllocator()); } for (const auto & smsgid : msgid_val.GetArray()) { RAPIDJSON_ASSERT(smsgid.IsString()); s_msg_lists[smsgid.GetString()] = &itr; } if (msgid_val.GetArray().Size() > 0) { s_msg_order.push_back(&itr); } if (msgid_val.GetArray().Size() == 0) { itr.RemoveMember("msgid"); } } for (auto i : s_pqxx_order) { std::cout << "\t" << i->FindMember("name")->value.GetString() << std::endl;; } }
// Load all the Settings from a file. If 'initializing' is true, then any // corrupted or missing settings are given their default values. In that way, // when new settings are added in new versions of the firmware, any values for // existing settings will not be lost. bool Settings::Load(const std::string& filename, bool initializing) { bool retVal = false; std::vector<std::string> missing; try { FILE* pFile = fopen(filename.c_str(), "r"); char buf[LOAD_BUF_LEN]; FileReadStream frs1(pFile, buf, LOAD_BUF_LEN); // first parse into a temporary doc, for validation Document doc; doc.ParseStream(frs1); // make sure the file is valid RAPIDJSON_ASSERT(doc.IsObject() && doc.HasMember(SETTINGS_ROOT_KEY)) // create a default doc, to check that all the expected setting names // are present and have the correct type // (we may not yet have a valid _settingsDoc) Document defaultDoc; defaultDoc.Parse(_defaultJSON.c_str()); for (std::set<std::string>::iterator it = _names.begin(); it != _names.end(); ++it) { if (doc[SETTINGS_ROOT_KEY].HasMember(it->c_str())) { if (!AreSameType(defaultDoc[SETTINGS_ROOT_KEY][it->c_str()], doc[SETTINGS_ROOT_KEY][it->c_str()])) { HandleError(WrongTypeForSetting, true, it->c_str()); return false; } } else { if (initializing) // record the missing member to be added missing.push_back(*it); else throw std::exception(); } } // parse again, but now into _settingsDoc fseek(pFile, 0, SEEK_SET); FileReadStream frs2(pFile, buf, LOAD_BUF_LEN); _settingsDoc.ParseStream(frs2); fclose(pFile); if (initializing && missing.size() > 0) { // add any missing settings, with their default values for (std::vector<std::string>::iterator it = missing.begin(); it != missing.end(); ++it) { _settingsDoc[SETTINGS_ROOT_KEY].AddMember(StringRef(it->c_str()), defaultDoc[SETTINGS_ROOT_KEY][StringRef(it->c_str())], _settingsDoc.GetAllocator()); } Save(); } retVal = true; } catch(std::exception) { // if we're initializing, we'll handle this by simply regenerating // the settings file from scratch if (!initializing) HandleError(CantLoadSettings, true, filename.c_str()); } return retVal; }
static void convert_enum(rapidjson::Document & /*doc*/, rapidjson::Value & val, const std::size_t lvl) { filebuf & outf = s_outf_converter; RAPIDJSON_ASSERT(val.HasMember("name")); const char * ename = val.FindMember("name")->value.GetString(); bool is_flag = is_enum_flag(val); //bool is_msg = is_as_msg(val); //const char * fn_prefix = is_msg ? "" : "static inline "; RAPIDJSON_ASSERT(val.HasMember("fields")); auto & fields = val.FindMember("fields")->value; RAPIDJSON_ASSERT(fields.IsObject()); if (is_flag) { std::map<std::string, std::string, cmp_str_as_n> int2string; std::map<std::string, std::string> string2int; for (rapidjson::Value::MemberIterator itr = fields.MemberBegin(); itr != fields.MemberEnd(); ++itr) { const char * name = itr->name.GetString(); RAPIDJSON_ASSERT(itr->value.IsObject()); RAPIDJSON_ASSERT(itr->value.HasMember("value")); const rapidjson::Value & rval = itr->value.FindMember("value")->value; RAPIDJSON_ASSERT(rval.IsString()); int2string[rval.GetString()] = name; string2int[name] = rval.GetString(); } int val_num = (int)string2int.size(); #if 0 /// @note dec order std::vector<std::pair<std::string, std::string>> reorder_pairs; for (auto & i : string2int) reorder_pairs.push_back(i); std::sort(reorder_pairs.begin(), reorder_pairs.end(), [=](std::pair<std::string, std::string>& lhs, std::pair<std::string, std::string>& rhs) { unsigned long long lhs_n = std::stoull(lhs.second,0,0); unsigned long long rhs_n = std::stoull(rhs.second,0,0); bool ret = false; if (lhs_n < rhs_n) { ret = true; } else if (lhs_n == rhs_n) { ret = (lhs.first.compare(rhs.first) < 0); } else { ret = false; } return !ret; }); #endif const char * const etype = val.FindMember("type")->value.GetString(); outf.pf(lvl, "/// @%s : string to enum\n", ename); outf.pf(lvl, "static const struct {\n"); outf.pf(lvl+1, "rapidjson::Value::StringRefType name;\n"); outf.pf(lvl+1, "%s val;\n", etype); outf.pf(lvl, "} str2e_%s[%d] = {\n", ename, val_num); for (auto & i : string2int) { outf.pf(lvl+1, "{ \"%s\", %s },\n", i.first.c_str(), i.second.c_str()); } outf.pf(lvl, "};\n\n"); outf.pf(lvl, "/// @%s : enum to string\n", ename); outf.pf(lvl, "static const struct {\n"); outf.pf(lvl+1, "%s val;\n", etype); outf.pf(lvl+1, "rapidjson::Value::StringRefType name;\n"); outf.pf(lvl, "} e2str_%s[%d] = {\n", ename, val_num); for (auto & i : int2string) { outf.pf(lvl+1, "{ %s, \"%s\" },\n", i.first.c_str(), i.second.c_str()); } outf.pf(lvl, "};\n\n"); outf.pf(lvl, "static inline rapidjson::Value c2json(rapidjson::Document & jd, const enum %s src)\n", ename); outf.pf(lvl, "{ return e2flag(jd, e2str_%s, (%s)src); }\n\n", ename, etype); outf.pf(lvl, "static inline void json2c(enum %s & dst, const rapidjson::Value & src)\n", ename); outf.pf(lvl, "{ dst = (enum %s)flag2e(str2e_%s, src); }\n", ename, ename); } else { std::map<int, std::string> int2string; std::map<std::string, int> string2int; for (rapidjson::Value::MemberIterator itr = fields.MemberBegin(); itr != fields.MemberEnd(); ++itr) { const char * name = itr->name.GetString(); RAPIDJSON_ASSERT(itr->value.IsObject()); RAPIDJSON_ASSERT(itr->value.HasMember("value")); int rval = itr->value.FindMember("value")->value.GetInt(); int2string[rval] = name; string2int[name] = rval; } const int min_val = int2string.begin()->first; const int max_val = int2string.rbegin()->first; const int val_num = (int)int2string.size(); const char * etype = val.FindMember("type")->value.GetString(); outf.pf(lvl, "/// @%s : string to enum\n", ename); outf.pf(lvl, "static const struct {\n"); outf.pf(lvl+1, "rapidjson::Value::StringRefType name;\n"); outf.pf(lvl+1, "%s val;\n", etype); outf.pf(lvl, "} str2e_%s[%d] = {\n", ename, (int)string2int.size()); for (auto & i : string2int) { outf.pf(lvl+1, "{ \"%s\", %d },\n", i.first.c_str(), i.second); } outf.pf(lvl, "};\n\n"); outf.pf(lvl, "/// @%s : enum to string\n", ename); outf.pf(lvl, "static const struct {\n"); outf.pf(lvl+1, "%s val;\n", etype); outf.pf(lvl+1, "rapidjson::Value::StringRefType name;\n"); outf.pf(lvl, "} e2str_%s[%d] = {\n", ename, val_num); for (auto & i : int2string) { outf.pf(lvl+1, "{ %d, \"%s\" },\n", i.first, i.second.c_str()); } outf.pf(lvl, "};\n\n"); outf.pf(lvl, "static inline rapidjson::Value c2json(rapidjson::Document & /*jd*/, const enum %s src)\n", ename); if (val_num >= (max_val - min_val + 1)) { if (min_val == 0) { outf.pf(lvl, "{ return search_name_directly(e2str_%s, (%s)src); }\n\n", ename, etype); } else { outf.pf(lvl, "{ return search_name_directly(e2str_%s, (%s)src - %d); }\n\n", ename, etype, min_val); } } else { outf.pf(lvl, "{ return search_name_binary(e2str_%s, (%s)src); }\n\n", ename, etype); } outf.pf(lvl, "static inline void json2c(enum %s & dst, const rapidjson::Value & src)\n", ename); outf.pf(lvl, "{ dst = (enum %s)search_val_binary(str2e_%s, src); }\n", ename, ename); } outf.pf(0, "\n"); }