diff options
-rw-r--r-- | src/include/tome/squelch/automatizer.hpp | 11 | ||||
-rw-r--r-- | src/include/tome/squelch/condition.hpp | 90 | ||||
-rw-r--r-- | src/include/tome/squelch/rule.hpp | 10 | ||||
-rw-r--r-- | src/squelch/automatizer.cc | 25 | ||||
-rw-r--r-- | src/squelch/condition.cc | 323 | ||||
-rw-r--r-- | src/squelch/rule.cc | 63 | ||||
-rw-r--r-- | src/squeltch.cc | 87 |
7 files changed, 319 insertions, 290 deletions
diff --git a/src/include/tome/squelch/automatizer.hpp b/src/include/tome/squelch/automatizer.hpp index 786ca1ae..4361941a 100644 --- a/src/include/tome/squelch/automatizer.hpp +++ b/src/include/tome/squelch/automatizer.hpp @@ -2,8 +2,8 @@ #include <boost/noncopyable.hpp> #include <memory> +#include <jsoncons/json.hpp> #include <vector> -#include <jansson.h> #include "tome/squelch/rule_fwd.hpp" #include "tome/squelch/cursor_fwd.hpp" @@ -44,15 +44,14 @@ public: bool apply_rules(object_type *o_ptr, int item_idx) const; /** - * Build a JSON data structure to represent - * all the rules. + * Build a JSON document to represent all the rules. */ - std::shared_ptr<json_t> to_json() const; + jsoncons::json to_json() const; /** - * Load rules from a JSON data structure. + * Load rules from a JSON document. */ - void load_json(json_t *json); + void load_json(jsoncons::json const &); /** * Remove currently selected condition or rule. diff --git a/src/include/tome/squelch/condition.hpp b/src/include/tome/squelch/condition.hpp index 5d1240f5..584ecb0e 100644 --- a/src/include/tome/squelch/condition.hpp +++ b/src/include/tome/squelch/condition.hpp @@ -3,10 +3,10 @@ #include "tome/squelch/condition_fwd.hpp" #include <boost/noncopyable.hpp> +#include <cstdint> #include <functional> #include <memory> -#include <cstdint> -#include <jansson.h> +#include <jsoncons/json.hpp> #include "tome/squelch/cursor_fwd.hpp" #include "tome/squelch/tree_printer_fwd.hpp" @@ -60,7 +60,7 @@ public: } public: - json_t *to_json() const; + jsoncons::json to_json() const; virtual void add_child(ConditionFactory const &factory) { // Default is to not support children. @@ -88,16 +88,16 @@ public: /** * Parse condition from JSON */ - static std::shared_ptr<Condition> parse_condition(json_t *); + static std::shared_ptr<Condition> parse_condition(jsoncons::json const &); /** * Convert an (optional) condition to JSON. */ - static json_t *optional_to_json(std::shared_ptr<Condition> condition); + static jsoncons::json optional_to_json(std::shared_ptr<Condition> condition); protected: virtual void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const = 0; - virtual void to_json(json_t *) const = 0; + virtual void to_json(jsoncons::json &) const = 0; // What do we want to match? match_type match; @@ -116,12 +116,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: uint8_t m_tval; @@ -140,12 +140,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: std::string m_name; @@ -164,12 +164,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: std::string m_contain; @@ -189,12 +189,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: uint8_t m_min; @@ -228,10 +228,10 @@ public: virtual std::shared_ptr<Condition> next_child(Condition *current) override; // Parse a list of conditions from JSON property - static std::vector< std::shared_ptr<Condition> > parse_conditions(json_t *); + static std::vector< std::shared_ptr<Condition> > parse_conditions(jsoncons::json const &); protected: - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; protected: std::vector< std::shared_ptr<Condition> > m_conditions; @@ -248,7 +248,7 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; @@ -265,7 +265,7 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; @@ -285,12 +285,12 @@ public: public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: status_type m_status; @@ -309,12 +309,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: std::string m_race; @@ -333,12 +333,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: std::string m_subrace; @@ -357,12 +357,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: std::string m_class; @@ -381,12 +381,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: std::string m_inscription; @@ -406,12 +406,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: int m_min; @@ -432,12 +432,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: int m_min; @@ -459,12 +459,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: uint16_t m_skill_idx; @@ -485,12 +485,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: identification_state m_state; @@ -509,12 +509,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: char m_symbol; @@ -533,12 +533,12 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; private: uint16_t m_ability_idx; @@ -563,10 +563,10 @@ public: virtual std::shared_ptr<Condition> first_child() override; protected: - void to_json(json_t *) const override; + void to_json(jsoncons::json &) const override; static std::shared_ptr<Condition> parse_single_subcondition( - json_t *condition_json); + jsoncons::json const &condition_json); protected: std::shared_ptr<Condition> m_subcondition; @@ -584,7 +584,7 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; @@ -603,7 +603,7 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: @@ -623,7 +623,7 @@ public: bool is_match(object_type *) const override; - static std::shared_ptr<Condition> from_json(json_t *); + static std::shared_ptr<Condition> from_json(jsoncons::json const &); protected: void write_tree(TreePrinter *, Cursor *, uint8_t, uint8_t) const override; diff --git a/src/include/tome/squelch/rule.hpp b/src/include/tome/squelch/rule.hpp index 63f1b6c0..752a0c2e 100644 --- a/src/include/tome/squelch/rule.hpp +++ b/src/include/tome/squelch/rule.hpp @@ -1,7 +1,7 @@ #pragma once -#include <jansson.h> #include <memory> +#include <jsoncons/json.hpp> #include "tome/squelch/condition_fwd.hpp" #include "tome/squelch/cursor_fwd.hpp" @@ -75,14 +75,14 @@ public: bool apply_rule(object_type *o_ptr, int item_idx) const; /** - * Convert rule to JSON + * Convert rule to JSON. */ - virtual json_t *to_json() const; + virtual jsoncons::json to_json() const; /** * Parse rule from JSON */ - static std::shared_ptr<Rule> parse_rule(json_t *); + static std::shared_ptr<Rule> parse_rule(jsoncons::json const &); protected: virtual bool do_apply_rule(object_type *, int) const = 0; @@ -148,7 +148,7 @@ public: , m_inscription(inscription) { } - json_t *to_json() const override; + jsoncons::json to_json() const override; protected: virtual void do_write_tree(TreePrinter *p) const override; diff --git a/src/squelch/automatizer.cc b/src/squelch/automatizer.cc index c3c52b1b..2f177ef9 100644 --- a/src/squelch/automatizer.cc +++ b/src/squelch/automatizer.cc @@ -12,20 +12,21 @@ namespace squelch { /** * Parse rules from JSON array */ -static std::vector< std::shared_ptr < Rule > > parse_rules(json_t *rules_j) +static std::vector< std::shared_ptr < Rule > > parse_rules(jsoncons::json const &rules_json) { std::vector< std::shared_ptr < Rule > > rules; - if (!json_is_array(rules_j)) + if (!rules_json.is_array()) { msg_format("Error 'rules' is not an array"); return rules; } - for (size_t i = 0; i < json_array_size(rules_j); i++) + auto rules_array = rules_json.array_value(); + + for (auto const &rule_value : rules_array) { - json_t *rule_j = json_array_get(rules_j, i); - auto rule = Rule::parse_rule(rule_j); + auto rule = Rule::parse_rule(rule_value); if (rule) { rules.push_back(rule); @@ -63,25 +64,25 @@ bool Automatizer::apply_rules(object_type *o_ptr, int item_idx) const return false; } -std::shared_ptr<json_t> Automatizer::to_json() const +jsoncons::json Automatizer::to_json() const { - auto rules_json = std::shared_ptr<json_t>(json_array(), &json_decref); + auto document = jsoncons::json::array(); for (auto rule : m_rules) { - json_array_append_new(rules_json.get(), rule->to_json()); + document.push_back(rule->to_json()); } - return rules_json; + return document; } -void Automatizer::load_json(json_t *json) +void Automatizer::load_json(jsoncons::json const &document) { // Go through all the found rules - auto rules = parse_rules(json); + auto rules = parse_rules(document); // Load rule - for (auto rule : rules) + for (auto rule: rules) { append_rule(rule); } diff --git a/src/squelch/condition.cc b/src/squelch/condition.cc index 9e93016e..e7429cab 100644 --- a/src/squelch/condition.cc +++ b/src/squelch/condition.cc @@ -57,12 +57,15 @@ EnumStringMap<identification_state> &identification_state_mapping() return *m; } -json_t *Condition::to_json() const +jsoncons::json Condition::to_json() const { - json_t *j = json_object(); - json_object_set_new(j, "type", - json_string(match_mapping().stringify(match))); + // Start with an object with only 'type' property + jsoncons::json j; + j["type"] = match_mapping().stringify(match); + + // Add sub-class properties to_json(j); + // Return the completed JSON return j; } @@ -85,11 +88,11 @@ void Condition::display(TreePrinter *tree_printer, Cursor *cursor) const tree_printer->dedent(); } -std::shared_ptr<Condition> Condition::parse_condition(json_t *condition_json) +std::shared_ptr<Condition> Condition::parse_condition(jsoncons::json const &condition_json) { // Parsers for concrete types of conditions. static std::map< match_type, - std::function< std::shared_ptr< Condition > ( json_t * ) > > parsers { + std::function<std::shared_ptr<Condition>(jsoncons::json const &)>> parsers { { match_type::AND, &AndCondition::from_json }, { match_type::OR, &OrCondition::from_json }, { match_type::NOT, &NotCondition::from_json }, @@ -111,15 +114,13 @@ std::shared_ptr<Condition> Condition::parse_condition(json_t *condition_json) { match_type::SKILL, &SkillCondition::from_json }, { match_type::ABILITY, &AbilityCondition::from_json } }; - if ((condition_json == nullptr) || json_is_null(condition_json)) + if (condition_json.is_null()) { return nullptr; } - cptr type_s = nullptr; - if (json_unpack(condition_json, - "{s:s}", - "type", &type_s) < 0) + cptr type_s = condition_json.get("type").as<cptr>(); + if (!type_s) { msg_print("Missing/invalid 'type' in condition"); return nullptr; @@ -143,11 +144,11 @@ std::shared_ptr<Condition> Condition::parse_condition(json_t *condition_json) return nullptr; } -json_t *Condition::optional_to_json(std::shared_ptr<Condition> condition) +jsoncons::json Condition::optional_to_json(std::shared_ptr<Condition> condition) { return condition ? condition->to_json() - : json_null(); + : jsoncons::json::null_type(); } bool TvalCondition::is_match(object_type *o_ptr) const @@ -155,22 +156,23 @@ bool TvalCondition::is_match(object_type *o_ptr) const return (o_ptr->tval == m_tval); } -std::shared_ptr<Condition> TvalCondition::from_json(json_t *j) +std::shared_ptr<Condition> TvalCondition::from_json(jsoncons::json const &j) { - int tval; - - if (json_unpack(j, "{s:i}", "tval", &tval) < 0) + auto tval_j = j.get("tval"); + if (!tval_j.is_uinteger()) { msg_print("Missing/invalid 'tval' property"); return nullptr; } + int tval = tval_j.as_uint(); + return std::make_shared<TvalCondition>(tval); } -void TvalCondition::to_json(json_t *j) const +void TvalCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "tval", json_integer(m_tval)); + j["tval"] = m_tval; } void TvalCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const @@ -192,14 +194,16 @@ bool NameCondition::is_match(object_type *o_ptr) const return boost::algorithm::iequals(m_name, buf1); } -std::shared_ptr<Condition> NameCondition::from_json(json_t *j) +std::shared_ptr<Condition> NameCondition::from_json(jsoncons::json const &j) { - cptr s = nullptr; - if (json_unpack(j, "{s:s}", "name", &s) < 0) + cptr s = j.get("name").as<cptr>(); + + if (!s) { msg_print("Missing/invalid 'name' property"); return nullptr; } + return std::make_shared<NameCondition>(s); } @@ -213,9 +217,9 @@ void NameCondition::write_tree(TreePrinter *p, Cursor *cursor, uint8_t ecol, uin p->write(TERM_WHITE, "\n"); } -void NameCondition::to_json(json_t *j) const +void NameCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "name", json_string(m_name.c_str())); + j["name"] = m_name; } bool ContainCondition::is_match(object_type *o_ptr) const @@ -225,14 +229,16 @@ bool ContainCondition::is_match(object_type *o_ptr) const return boost::algorithm::icontains(buf1, m_contain); } -std::shared_ptr<Condition> ContainCondition::from_json(json_t *j) +std::shared_ptr<Condition> ContainCondition::from_json(jsoncons::json const &j) { - cptr s = nullptr; - if (json_unpack(j, "{s:s}", "contain", &s) < 0) + cptr s = j.get("contain").as<cptr>(); + + if (!s) { msg_print("Missing/invalid 'contain' property"); return nullptr; } + return std::make_shared<ContainCondition>(s); } @@ -246,9 +252,9 @@ void ContainCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_ p->write(TERM_WHITE, "\n"); } -void ContainCondition::to_json(json_t *j) const +void ContainCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "contain", json_string(m_contain.c_str())); + j["contain"] = m_contain; } bool SvalCondition::is_match(object_type *o_ptr) const @@ -258,19 +264,25 @@ bool SvalCondition::is_match(object_type *o_ptr) const (o_ptr->sval <= m_max)); } -std::shared_ptr<Condition> SvalCondition::from_json(json_t *j) +std::shared_ptr<Condition> SvalCondition::from_json(jsoncons::json const &j) { - int min, max; + auto min_j = j.get("min"); + if (!min_j.is_uinteger()) + { + msg_print("Missing/invalid 'min' property"); + return nullptr; + } - if (json_unpack(j, "{s:i,s:i}", - "min", &min, - "max", &max) < 0) + auto max_j = j.get("max"); + if (!max_j.is_uinteger()) { - msg_print("Missing/invalid 'min'/'max' properties"); + msg_print("Missing/invalid 'max' property"); return nullptr; } - return std::make_shared<SvalCondition>(min, max); + return std::make_shared<SvalCondition>( + min_j.as_uint(), + max_j.as_uint()); } void SvalCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t bcol) const @@ -284,10 +296,10 @@ void SvalCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t b p->write(TERM_WHITE, "\n"); } -void SvalCondition::to_json(json_t *j) const +void SvalCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "min", json_integer(m_min)); - json_object_set_new(j, "max", json_integer(m_max)); + j["min"] = m_min; + j["max"] = m_max; } void GroupingCondition::add_child(ConditionFactory const &factory) @@ -369,16 +381,15 @@ std::shared_ptr<Condition> GroupingCondition::next_child(Condition *current) return nullptr; } -std::vector< std::shared_ptr<Condition> > GroupingCondition::parse_conditions(json_t *j) +std::vector< std::shared_ptr<Condition> > GroupingCondition::parse_conditions(jsoncons::json const &j) { - json_t *conditions_j = json_object_get(j, "conditions"); + auto conditions_j = j.get("conditions"); - if ((conditions_j == nullptr) || - (json_is_null(conditions_j))) + if (conditions_j.is_null()) { return std::vector< std::shared_ptr<Condition> >(); } - else if (!json_is_array(conditions_j)) + else if (!conditions_j.is_array()) { msg_print("'conditions' property has invalid type"); return std::vector< std::shared_ptr<Condition> >(); @@ -386,11 +397,8 @@ std::vector< std::shared_ptr<Condition> > GroupingCondition::parse_conditions(js else { std::vector< std::shared_ptr<Condition> > subconditions; - for (size_t i = 0; i < json_array_size(conditions_j); i++) + for (auto const &subcondition_j: conditions_j.array_value()) { - json_t *subcondition_j = - json_array_get(conditions_j, i); - std::shared_ptr<Condition> subcondition = parse_condition(subcondition_j); @@ -403,14 +411,16 @@ std::vector< std::shared_ptr<Condition> > GroupingCondition::parse_conditions(js } } -void GroupingCondition::to_json(json_t *j) const +void GroupingCondition::to_json(jsoncons::json &j) const { - json_t *ja = json_array(); + // Put all the sub-conditions into an array + jsoncons::json::array ja; for (auto condition_p : m_conditions) { - json_array_append_new(ja, optional_to_json(condition_p)); + ja.push_back(optional_to_json(condition_p)); } - json_object_set_new(j, "conditions", ja); + // Add to JSON object + j["conditions"] = ja; } bool AndCondition::is_match(object_type *o_ptr) const @@ -425,7 +435,7 @@ bool AndCondition::is_match(object_type *o_ptr) const return true; } -std::shared_ptr<Condition> AndCondition::from_json(json_t *j) +std::shared_ptr<Condition> AndCondition::from_json(jsoncons::json const &j) { auto condition = std::make_shared<AndCondition>(); for (auto subcondition : parse_conditions(j)) @@ -458,7 +468,7 @@ bool OrCondition::is_match(object_type *o_ptr) const return false; } -std::shared_ptr<Condition> OrCondition::from_json(json_t *j) +std::shared_ptr<Condition> OrCondition::from_json(jsoncons::json const &j) { std::shared_ptr<OrCondition> condition = std::make_shared<OrCondition>(); @@ -487,10 +497,11 @@ bool StatusCondition::is_match(object_type *o_ptr) const return m_status == object_status(o_ptr); } -std::shared_ptr<Condition> StatusCondition::from_json(json_t *j) +std::shared_ptr<Condition> StatusCondition::from_json(jsoncons::json const &j) { - cptr s; - if (json_unpack(j, "{s:s}", "status", &s) < 0) + cptr s = j.get("status").as<cptr>(); + + if (!s) { msg_print("Missing/invalid 'status' property"); return nullptr; @@ -517,9 +528,9 @@ void StatusCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t p->write(TERM_WHITE, "\n"); } -void StatusCondition::to_json(json_t *j) const +void StatusCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "status", json_string(status_mapping().stringify(m_status))); + j["status"] = status_mapping().stringify(m_status); } bool RaceCondition::is_match(object_type *o_ptr) const @@ -527,11 +538,11 @@ bool RaceCondition::is_match(object_type *o_ptr) const return boost::algorithm::iequals(m_race, rp_ptr->title); } -std::shared_ptr<Condition> RaceCondition::from_json(json_t *j) +std::shared_ptr<Condition> RaceCondition::from_json(jsoncons::json const &j) { - cptr s; + cptr s = j.get("race").as<cptr>(); - if (json_unpack(j, "{s:s}", "race", &s) < 0) + if (!s) { msg_print("Missing/invalid 'race' property"); return nullptr; @@ -551,9 +562,9 @@ void RaceCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t b p->write(TERM_WHITE, "\n"); } -void RaceCondition::to_json(json_t *j) const +void RaceCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "race", json_string(m_race.c_str())); + j["race"] = m_race; } bool SubraceCondition::is_match(object_type *o_ptr) const @@ -561,11 +572,11 @@ bool SubraceCondition::is_match(object_type *o_ptr) const return boost::algorithm::iequals(m_subrace, rmp_ptr->title); } -std::shared_ptr<Condition> SubraceCondition::from_json(json_t *j) +std::shared_ptr<Condition> SubraceCondition::from_json(jsoncons::json const &j) { - cptr s; + cptr s = j.get("subrace").as<cptr>(); - if (json_unpack(j, "{s:s}", "subrace", &s) < 0) + if (!s) { msg_print("Missing/invalid 'subrace' property"); return nullptr; @@ -585,9 +596,9 @@ void SubraceCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_ p->write(TERM_WHITE, "\n"); } -void SubraceCondition::to_json(json_t *j) const +void SubraceCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "subrace", json_string(m_subrace.c_str())); + j["subrace"] = m_subrace; } bool ClassCondition::is_match(object_type *o_ptr) const @@ -595,11 +606,11 @@ bool ClassCondition::is_match(object_type *o_ptr) const return boost::algorithm::iequals(m_class, spp_ptr->title); } -std::shared_ptr<Condition> ClassCondition::from_json(json_t *j) +std::shared_ptr<Condition> ClassCondition::from_json(jsoncons::json const &j) { - cptr s; + cptr s = j.get("class").as<cptr>(); - if (json_unpack(j, "{s:s}", "class", &s) < 0) + if (!s) { msg_print("Missing/invalid 'class' property"); return nullptr; @@ -619,9 +630,9 @@ void ClassCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t p->write(TERM_WHITE, "\n"); } -void ClassCondition::to_json(json_t *j) const +void ClassCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "class", json_string(m_class.c_str())); + j["class"] = m_class; } bool InscriptionCondition::is_match(object_type *o_ptr) const @@ -631,14 +642,16 @@ bool InscriptionCondition::is_match(object_type *o_ptr) const m_inscription); } -std::shared_ptr<Condition> InscriptionCondition::from_json(json_t *j) +std::shared_ptr<Condition> InscriptionCondition::from_json(jsoncons::json const &j) { - cptr s = nullptr; - if (json_unpack(j, "{s:s}", "inscription", &s) < 0) + cptr s = j.get("inscription").as<cptr>(); + + if (!s) { msg_print("Missing/invalid 'inscription' property"); return nullptr; } + return std::make_shared<InscriptionCondition>(s); } @@ -653,9 +666,9 @@ void InscriptionCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, ui p->write(TERM_WHITE, "\n"); } -void InscriptionCondition::to_json(json_t *j) const +void InscriptionCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "inscription", json_string(m_inscription.c_str())); + j["inscription"] = m_inscription; } bool DiscountCondition::is_match(object_type *o_ptr) const @@ -665,17 +678,23 @@ bool DiscountCondition::is_match(object_type *o_ptr) const (o_ptr->discount <= m_max)); } -std::shared_ptr<Condition> DiscountCondition::from_json(json_t *j) +std::shared_ptr<Condition> DiscountCondition::from_json(jsoncons::json const &j) { - int min, max; + auto min_j = j.get("min"); + if (!min_j.is_integer()) + { + msg_print("Missing/invalid 'min' property"); + return nullptr; + } + int min = min_j.as_int(); - if (json_unpack(j, "{s:i,s:i}", - "min", &min, - "max", &max) < 0) + auto max_j = j.get("max"); + if (!max_j.is_integer()) { - msg_print("Missing/invalid 'min'/'max' properties"); + msg_print("Missing/invalid 'max' property"); return nullptr; } + int max = max_j.as_int(); return std::make_shared<DiscountCondition>(min, max); } @@ -691,10 +710,10 @@ void DiscountCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8 p->write(TERM_WHITE, "\n"); } -void DiscountCondition::to_json(json_t *j) const +void DiscountCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "min", json_integer(m_min)); - json_object_set_new(j, "max", json_integer(m_max)); + j["min"] = m_min; + j["max"] = m_max; } bool LevelCondition::is_match(object_type *) const @@ -703,16 +722,23 @@ bool LevelCondition::is_match(object_type *) const (p_ptr->lev <= m_max)); } -std::shared_ptr<Condition> LevelCondition::from_json(json_t *j) +std::shared_ptr<Condition> LevelCondition::from_json(jsoncons::json const &j) { - int min, max; - if (json_unpack(j, "{s:i,s:i}", - "min", &min, - "max", &max) < 0) + auto min_j = j.get("min"); + if (!min_j.is_integer()) { - msg_print("Missing/invalid 'min'/'max' properties"); + msg_print("Missing/invalid 'min' property"); return nullptr; } + int min = min_j.as_int(); + + auto max_j = j.get("max"); + if (!max_j.is_integer()) + { + msg_print("Missing/invalid 'max' property"); + return nullptr; + } + int max = max_j.as_int(); return std::make_shared<LevelCondition>(min, max); } @@ -729,10 +755,10 @@ void LevelCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t p->write(TERM_WHITE, "\n"); } -void LevelCondition::to_json(json_t *j) const +void LevelCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "min", json_integer(m_min)); - json_object_set_new(j, "max", json_integer(m_max)); + j["min"] = m_min; + j["max"] = m_max; } bool SkillCondition::is_match(object_type *) const @@ -742,16 +768,28 @@ bool SkillCondition::is_match(object_type *) const (sk <= m_max)); } -std::shared_ptr<Condition> SkillCondition::from_json(json_t *j) +std::shared_ptr<Condition> SkillCondition::from_json(jsoncons::json const &j) { - cptr s; - int min, max; - if (json_unpack(j, "{s:i,s:i,s:s}", - "min", &min, - "max", &max, - "name", &s) < 0) + auto min_j = j.get("min"); + if (!min_j.is_integer()) + { + msg_print("Missing/invalid 'min' property"); + return nullptr; + } + int min = min_j.as_int(); + + auto max_j = j.get("max"); + if (!max_j.is_integer()) { - msg_print("Missing/invalid 'min'/'max'/'name' properties"); + msg_print("Missing/invalid 'max' property"); + return nullptr; + } + int max = max_j.as_int(); + + auto s = j.get("name").as<cptr>(); + if (!s) + { + msg_print("Missing/invalid 'name' property"); return nullptr; } @@ -776,14 +814,11 @@ void SkillCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t p->write(TERM_WHITE, "\n"); } -void SkillCondition::to_json(json_t *j) const +void SkillCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "name", - json_string(s_descriptors[m_skill_idx].name)); - json_object_set_new(j, "min", - json_integer(m_min)); - json_object_set_new(j, "max", - json_integer(m_max)); + j["name"] = s_descriptors[m_skill_idx].name; + j["min"] = m_min; + j["max"] = m_max; } bool StateCondition::is_match(object_type *o_ptr) const @@ -800,10 +835,11 @@ bool StateCondition::is_match(object_type *o_ptr) const return false; } -std::shared_ptr<Condition> StateCondition::from_json(json_t *j) +std::shared_ptr<Condition> StateCondition::from_json(jsoncons::json const &j) { - cptr s; - if (json_unpack(j, "{s:s}", "state", &s) < 0) + cptr s = j.get("state").as<cptr>(); + + if (!s) { msg_print("Missing/invalid 'state' property"); return nullptr; @@ -830,11 +866,9 @@ void StateCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t p->write(TERM_WHITE, "\n"); } -void StateCondition::to_json(json_t *j) const +void StateCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "state", - json_string(identification_state_mapping(). - stringify(m_state))); + j["state"] = identification_state_mapping().stringify(m_state); } bool SymbolCondition::is_match(object_type *o_ptr) const @@ -843,21 +877,16 @@ bool SymbolCondition::is_match(object_type *o_ptr) const return k_ptr->d_char == m_symbol; } -std::shared_ptr<Condition> SymbolCondition::from_json(json_t *j) +std::shared_ptr<Condition> SymbolCondition::from_json(jsoncons::json const &j) { - cptr s_ = nullptr; - if (json_unpack(j, "{s:s}", "symbol", &s_) < 0) - { - msg_print("Missing/invalid 'symbol' property"); - return nullptr; - } + auto s = j.get("symbol").as<std::string>(); - std::string s(s_); if (s.empty()) { - msg_print("Invalid 'symbol' property: Too short"); + msg_print("Missing/invalid 'symbol' property"); return nullptr; } + if (s.size() > 1) { msg_print("Invalid 'symbol' property: Too long"); @@ -878,10 +907,9 @@ void SymbolCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_t p->write(TERM_WHITE, "\n"); } -void SymbolCondition::to_json(json_t *j) const +void SymbolCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "symbol", - json_string(format("%c", m_symbol))); + j["symbol"] = format("%c", m_symbol); } bool AbilityCondition::is_match(object_type *) const @@ -889,10 +917,11 @@ bool AbilityCondition::is_match(object_type *) const return p_ptr->has_ability(m_ability_idx); } -std::shared_ptr<Condition> AbilityCondition::from_json(json_t *j) +std::shared_ptr<Condition> AbilityCondition::from_json(jsoncons::json const &j) { - cptr a; - if (json_unpack(j, "{s:s}", "ability", &a) < 0) + cptr a = j.get("ability").as<cptr>(); + + if (!a) { msg_print("Missing/invalid 'ability' property"); return nullptr; @@ -918,10 +947,9 @@ void AbilityCondition::write_tree(TreePrinter *p, Cursor *, uint8_t ecol, uint8_ p->write(TERM_WHITE, "\n"); } -void AbilityCondition::to_json(json_t *j) const +void AbilityCondition::to_json(jsoncons::json &j) const { - cptr ability_s = ab_info[m_ability_idx].name; - json_object_set_new(j, "ability", json_string(ability_s)); + j["ability"] = ab_info[m_ability_idx].name; } void SingleSubconditionCondition::add_child(std::function< std::shared_ptr<Condition> () > const &factory) @@ -946,23 +974,20 @@ std::shared_ptr<Condition> SingleSubconditionCondition::first_child() return m_subcondition; } -void SingleSubconditionCondition::to_json(json_t *j) const +void SingleSubconditionCondition::to_json(jsoncons::json &j) const { - json_object_set_new(j, "condition", - optional_to_json(m_subcondition)); + j["condition"] = optional_to_json(m_subcondition); } -std::shared_ptr<Condition> SingleSubconditionCondition::parse_single_subcondition(json_t *in_json) +std::shared_ptr<Condition> SingleSubconditionCondition::parse_single_subcondition(jsoncons::json const &in_json) { - json_t *condition_j = - json_object_get(in_json, "condition"); + auto condition_j = in_json.get("condition"); - if ((condition_j == nullptr) || - (json_is_null(condition_j))) + if (condition_j.is_null()) { return nullptr; } - else if (!json_is_object(condition_j)) + else if (!condition_j.is_object()) { msg_format("Invalid 'condition' property"); return nullptr; @@ -983,7 +1008,7 @@ bool NotCondition::is_match(object_type *o_ptr) const return !m_subcondition->is_match(o_ptr); } -std::shared_ptr<Condition> NotCondition::from_json(json_t *j) +std::shared_ptr<Condition> NotCondition::from_json(jsoncons::json const &j) { return std::make_shared<NotCondition>(parse_single_subcondition(j)); } @@ -1016,7 +1041,7 @@ bool InventoryCondition::is_match(object_type *) const return false; } -std::shared_ptr<Condition> InventoryCondition::from_json(json_t *j) +std::shared_ptr<Condition> InventoryCondition::from_json(jsoncons::json const &j) { return std::make_shared<InventoryCondition>( parse_single_subcondition(j)); @@ -1052,7 +1077,7 @@ bool EquipmentCondition::is_match(object_type *) const return false; } -std::shared_ptr<Condition> EquipmentCondition::from_json(json_t *j) +std::shared_ptr<Condition> EquipmentCondition::from_json(jsoncons::json const &j) { return std::make_shared<EquipmentCondition>( parse_single_subcondition(j)); diff --git a/src/squelch/rule.cc b/src/squelch/rule.cc index 223cf6d3..50a771ae 100644 --- a/src/squelch/rule.cc +++ b/src/squelch/rule.cc @@ -41,22 +41,16 @@ std::shared_ptr<Condition> Rule::get_condition() const return m_condition; } -json_t *Rule::to_json() const +jsoncons::json Rule::to_json() const { - json_t *rule_json = json_object(); - json_object_set_new(rule_json, - "name", - json_string(m_name.c_str())); - json_object_set_new(rule_json, - "action", - json_string(action_mapping().stringify(m_action))); - json_object_set_new(rule_json, - "module", - json_string(modules[m_module_idx].meta.name)); - json_object_set_new(rule_json, - "condition", - Condition::optional_to_json(m_condition)); - return rule_json; + jsoncons::json j; + + j["name"] = jsoncons::json::string_type(m_name); + j["action"] = action_mapping().stringify(m_action); + j["module"] = modules[m_module_idx].meta.name; + j["condition"] = Condition::optional_to_json(m_condition); + + return j; } void Rule::add_new_condition(Cursor *cursor, @@ -138,23 +132,19 @@ bool Rule::apply_rule(object_type *o_ptr, int item_idx) const return false; } -std::shared_ptr<Rule> Rule::parse_rule(json_t *rule_json) +std::shared_ptr<Rule> Rule::parse_rule(jsoncons::json const &rule_json) { - if (!json_is_object(rule_json)) + if (!rule_json.is_object()) { msg_print("Rule is not an object"); return nullptr; } // Retrieve the attributes - char *rule_name_s = nullptr; - char *rule_action_s = nullptr; - char *rule_module_s = nullptr; - if (json_unpack(rule_json, - "{s:s,s:s,s:s}", - "name", &rule_name_s, - "action", &rule_action_s, - "module", &rule_module_s) < 0) + char const *rule_name_s = rule_json.get("name").as<char const *>(); + char const *rule_action_s = rule_json.get("action").as<char const *>(); + char const *rule_module_s = rule_json.get("module").as<char const *>(); + if ((!rule_name_s) || (!rule_action_s) || (!rule_module_s)) { msg_print("Rule missing required field(s)"); return nullptr; @@ -178,28 +168,29 @@ std::shared_ptr<Rule> Rule::parse_rule(json_t *rule_json) // Parse condition std::shared_ptr<Condition> condition = - Condition::parse_condition(json_object_get(rule_json, "condition")); + Condition::parse_condition(rule_json.get("condition")); // Parse rule switch (action) { case action_type::AUTO_INSCRIBE: { - json_t *rule_inscription_j = json_object_get(rule_json, "inscription"); + auto rule_inscription_j = rule_json.get("inscription"); - if (rule_inscription_j == nullptr) + if (rule_inscription_j.is_null()) { msg_print("Inscription rule missing 'inscription' attribute"); return nullptr; } - if (!json_is_string(rule_inscription_j)) + + if (!rule_inscription_j.is_string()) { msg_print("Inscription rule 'inscription' attribute wrong type"); return nullptr; } - std::string inscription = - json_string_value(rule_inscription_j); + std::string inscription = rule_inscription_j.as<std::string>(); + return std::make_shared<InscribeRule>( rule_name_s, module_idx, condition, inscription); } @@ -290,14 +281,10 @@ bool PickUpRule::do_apply_rule(object_type *o_ptr, int item_idx) const return true; } -json_t *InscribeRule::to_json() const +jsoncons::json InscribeRule::to_json() const { - json_t *j = Rule::to_json(); - - json_object_set_new(j, - "inscription", - json_string(m_inscription.c_str())); - + jsoncons::json j; + j["inscription"] = m_inscription; return j; } diff --git a/src/squeltch.cc b/src/squeltch.cc index 69c25dfd..eed3bf1b 100644 --- a/src/squeltch.cc +++ b/src/squeltch.cc @@ -30,11 +30,10 @@ #include "variable.h" #include "variable.hpp" -#include <jansson.h> #include <algorithm> -#include <memory> #include <deque> #include <list> +#include <memory> #include <string> #include <vector> @@ -182,14 +181,28 @@ static void automatizer_save_rules() return; } + // Function for showing a message + auto show_message = [hgt, wid](std::string text) { + auto n = std::max<std::size_t>(text.size(), 28); + while (text.size() < n) + { + text += ' '; + } + c_put_str(TERM_WHITE, text.c_str(), hgt/2, wid/2 - 14); + }; + + // Function for showing an error message + auto error = [show_message]() { + show_message("Saving rules FAILED!"); + inkey(); + }; + // Build the filename path_build(buf, 1024, ANGBAND_DIR_USER, name); if (file_exist(buf)) { - c_put_str(TERM_WHITE, "File exists, continue?[y/n]", - hgt / 2, - wid / 2 - 14); + show_message("File exists, continue? [y/n]"); ch = inkey(); if ((ch != 'Y') && (ch != 'y')) { @@ -197,29 +210,32 @@ static void automatizer_save_rules() } } - // Write to file - { - auto rules_json = automatizer->to_json(); + // Pretty-printing options + jsoncons::output_format format; + format.indent(2); - int status = json_dump_file(rules_json.get(), buf, - JSON_INDENT(2) | - JSON_SORT_KEYS); - if (status == 0) - { - c_put_str(TERM_WHITE, "Saved rules in file ", - hgt / 2, - wid / 2 - 14); - } - else - { - c_put_str(TERM_WHITE, "Saving rules failed! ", - hgt / 2, - wid / 2 - 14); - } + // Convert to a JSON document + auto rules_document = automatizer->to_json(); - // Wait for keypress - inkey(); + // Open output stream + std::ofstream of(buf, std::ios_base::out | std::ios_base::binary); + if (of.fail()) + { + error(); + return; } + + // Write JSON to output + of << jsoncons::pretty_print(rules_document, format); + if (of.fail()) + { + error(); + return; + } + + // Success + show_message("Saved rules in file"); + inkey(); } static void rename_rule(Rule *rule) @@ -574,20 +590,21 @@ bool automatizer_load(boost::filesystem::path const &path) return false; // Not fatal; just skip } - // Parse file - json_error_t error; - std::shared_ptr<json_t> rules_json( - json_load_file(path.c_str(), 0, &error), - &json_decref); - if (rules_json == nullptr) + // Parse into memory + jsoncons::json rules_json; + try + { + rules_json = jsoncons::json::parse_file(path.string()); + } + catch (jsoncons::json_exception const &exc) { msg_format("Error parsing automatizer rules from '%s'.", path.c_str()); - msg_format("Line %d, Column %d", error.line, error.column); - msg_print(nullptr); + msg_print(exc.what()); return false; } - // Load rules - automatizer->load_json(rules_json.get()); + // We didn't return directly via an exception, so let's extract + // the rules. + automatizer->load_json(rules_json); return true; } |