diff options
Diffstat (limited to 'src/cnode')
-rw-r--r-- | src/cnode/cnode-algorithm.cpp | 64 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.hpp | 53 | ||||
-rw-r--r-- | src/cnode/cnode-util.hpp | 84 | ||||
-rw-r--r-- | src/cnode/cnode.cpp | 40 | ||||
-rw-r--r-- | src/cnode/cnode.hpp | 56 |
5 files changed, 220 insertions, 77 deletions
diff --git a/src/cnode/cnode-algorithm.cpp b/src/cnode/cnode-algorithm.cpp index 607d5d2..6638936 100644 --- a/src/cnode/cnode-algorithm.cpp +++ b/src/cnode/cnode-algorithm.cpp @@ -25,6 +25,8 @@ #include <cnode/cnode-algorithm.hpp> using namespace cnode; +using namespace cstore; +using namespace std; ////// constants @@ -38,6 +40,24 @@ const string cnode::ACTIVE_CFG = "@ACTIVE"; const string cnode::WORKING_CFG = "@WORKING"; ////// static (internal) functions +static inline const char * +diff_to_pfx(DiffState s) +{ + switch (s) { + case DIFF_ADD: + return PFX_DIFF_ADD.c_str(); + case DIFF_DEL: + return PFX_DIFF_DEL.c_str(); + case DIFF_UPD: + return PFX_DIFF_UPD.c_str(); + case DIFF_NONE: + return PFX_DIFF_NONE.c_str(); + case DIFF_NULL: + default: + return PFX_DIFF_NULL.c_str(); + } +} + static void _show_diff(const CfgNode *cfg1, const CfgNode *cfg2, int level, Cpath& cur_path, Cpath& last_ctx, bool show_def, @@ -49,16 +69,16 @@ _get_cmds_diff(const CfgNode *cfg1, const CfgNode *cfg2, vector<Cpath>& set_list, vector<Cpath>& com_list); /* compare the values of a "multi" node in the two configs. the values and - * the "prefix" of each value are returned in "values" and "pfxs", + * the "diff" of each value are returned in "values" and "pfxs", * respectively. * * return value indicates whether the node is different in the two configs. * * comparison follows the original perl logic. */ -static bool -_cmp_multi_values(const CfgNode *cfg1, const CfgNode *cfg2, - vector<string>& values, vector<const char *>& pfxs) +bool +cnode::cmp_multi_values(const CfgNode *cfg1, const CfgNode *cfg2, + vector<string>& values, vector<DiffState>& pfxs) { const vector<string>& ovec = cfg1->getValues(); const vector<string>& nvec = cfg2->getValues(); @@ -72,7 +92,7 @@ _cmp_multi_values(const CfgNode *cfg1, const CfgNode *cfg2, omap[ovec[i]] = true; if (nmap.find(ovec[i]) == nmap.end()) { values.push_back(ovec[i]); - pfxs.push_back(PFX_DIFF_DEL.c_str()); + pfxs.push_back(DIFF_DEL); changed = true; } } @@ -80,12 +100,12 @@ _cmp_multi_values(const CfgNode *cfg1, const CfgNode *cfg2, for (size_t i = 0; i < nvec.size(); i++) { values.push_back(nvec[i]); if (omap.find(nvec[i]) == omap.end()) { - pfxs.push_back(PFX_DIFF_ADD.c_str()); + pfxs.push_back(DIFF_ADD); changed = true; } else if (i < ovec.size() && nvec[i] == ovec[i]) { - pfxs.push_back(PFX_DIFF_NONE.c_str()); + pfxs.push_back(DIFF_NONE); } else { - pfxs.push_back(PFX_DIFF_UPD.c_str()); + pfxs.push_back(DIFF_UPD); changed = true; } } @@ -93,12 +113,12 @@ _cmp_multi_values(const CfgNode *cfg1, const CfgNode *cfg2, return changed; } -static void -_cmp_non_leaf_nodes(const CfgNode *cfg1, const CfgNode *cfg2, - vector<CfgNode *>& rcnodes1, - vector<CfgNode *>& rcnodes2, bool& not_tag_node, - bool& is_value, bool& is_leaf_typeless, - string& name, string& value) +void +cnode::cmp_non_leaf_nodes(const CfgNode *cfg1, const CfgNode *cfg2, + vector<CfgNode *>& rcnodes1, + vector<CfgNode *>& rcnodes2, bool& not_tag_node, + bool& is_value, bool& is_leaf_typeless, + string& name, string& value) { const CfgNode *cfg = (cfg1 ? cfg1 : cfg2); is_value = cfg->isValue(); @@ -361,12 +381,12 @@ _diff_check_and_show_leaf(const CfgNode *cfg1, const CfgNode *cfg2, int level, } else { // need to actually do a diff. vector<string> values; - vector<const char *> pfxs; - bool changed = _cmp_multi_values(cfg1, cfg2, values, pfxs); + vector<DiffState> pfxs; + bool changed = cmp_multi_values(cfg1, cfg2, values, pfxs); if (!context_diff || changed) { // not context diff OR there is a difference => print the node for (size_t i = 0; i < values.size(); i++) { - if (context_diff && pfxs[i] == PFX_DIFF_NONE.c_str()) { + if (context_diff && pfxs[i] == DIFF_NONE) { // not printing unchanged values if doing context diff continue; } @@ -380,7 +400,7 @@ _diff_check_and_show_leaf(const CfgNode *cfg1, const CfgNode *cfg2, int level, _diff_print_context(cur_path, last_ctx); cprint = true; } - _diff_print_indent(cfg1, cfg2, level, pfxs[i]); + _diff_print_indent(cfg1, cfg2, level, diff_to_pfx(pfxs[i])); printf("%s ", cfg->getName().c_str()); _print_value_str(cfg->getName(), values[i].c_str(), hide_secret); printf("\n"); @@ -441,7 +461,7 @@ _diff_show_other(const CfgNode *cfg1, const CfgNode *cfg2, int level, string name, value; bool not_tag_node, is_value, is_leaf_typeless; vector<CfgNode *> rcnodes1, rcnodes2; - _cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value, + cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value, is_leaf_typeless, name, value); /* only print "this" node if it @@ -700,8 +720,8 @@ _get_cmds_diff_leaf(const CfgNode *cfg1, const CfgNode *cfg2, } else { // need to actually do a diff. vector<string> dummy_vals; - vector<const char *> dummy_pfxs; - if (_cmp_multi_values(cfg1, cfg2, dummy_vals, dummy_pfxs)) { + vector<DiffState> dummy_pfxs; + if (cmp_multi_values(cfg1, cfg2, dummy_vals, dummy_pfxs)) { /* something changed. to get the correct ordering for multi-node * values, need to delete the node and then set the new values. */ @@ -755,7 +775,7 @@ _get_cmds_diff_other(const CfgNode *cfg1, const CfgNode *cfg2, string name, value; bool not_tag_node, is_value, is_leaf_typeless; vector<CfgNode *> rcnodes1, rcnodes2; - _cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value, + cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value, is_leaf_typeless, name, value); if (rcnodes1.size() < 1 && list) { // subtree is empty diff --git a/src/cnode/cnode-algorithm.hpp b/src/cnode/cnode-algorithm.hpp index 547b55c..509f875 100644 --- a/src/cnode/cnode-algorithm.hpp +++ b/src/cnode/cnode-algorithm.hpp @@ -17,12 +17,34 @@ #ifndef _CNODE_ALGORITHM_HPP_ #define _CNODE_ALGORITHM_HPP_ +#include <vector> +#include <string> + +#include <cstore/cpath.hpp> #include <cnode/cnode.hpp> namespace cnode { +enum DiffState { + DIFF_ADD, + DIFF_DEL, + DIFF_UPD, + DIFF_NONE, + DIFF_NULL +}; + +bool cmp_multi_values(const CfgNode *cfg1, const CfgNode *cfg2, + std::vector<std::string>& values, + std::vector<DiffState>& pfxs); +void cmp_non_leaf_nodes(const CfgNode *cfg1, const CfgNode *cfg2, + std::vector<CfgNode *>& rcnodes1, + std::vector<CfgNode *>& rcnodes2, + bool& not_tag_node, bool& is_value, + bool& is_leaf_typeless, std::string& name, + std::string& value); + void show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, - Cpath& cur_path, bool show_def = false, + cstore::Cpath& cur_path, bool show_def = false, bool hide_secret = false, bool context_diff = false); void show_cfg(const CfgNode& cfg, bool show_def = false, bool hide_secret = false); @@ -31,24 +53,27 @@ void show_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2); void show_cmds(const CfgNode& cfg); void get_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2, - vector<Cpath>& del_list, vector<Cpath>& set_list, - vector<Cpath>& com_list); -void get_cmds(const CfgNode& cfg, vector<Cpath>& set_list, - vector<Cpath>& com_list); + std::vector<cstore::Cpath>& del_list, + std::vector<cstore::Cpath>& set_list, + std::vector<cstore::Cpath>& com_list); +void get_cmds(const CfgNode& cfg, std::vector<cstore::Cpath>& set_list, + std::vector<cstore::Cpath>& com_list); -extern const string ACTIVE_CFG; -extern const string WORKING_CFG; +extern const std::string ACTIVE_CFG; +extern const std::string WORKING_CFG; -void showConfig(const string& cfg1, const string& cfg2, - const Cpath& path, bool show_def = false, +void showConfig(const std::string& cfg1, const std::string& cfg2, + const cstore::Cpath& path, bool show_def = false, bool hide_secret = false, bool context_diff = false, bool show_cmds = false, bool ignore_edit = false); -CfgNode *findCfgNode(CfgNode *root, const Cpath& path, bool& is_value); -CfgNode *findCfgNode(CfgNode *root, const Cpath& path); -bool getCfgNodeValue(CfgNode *root, const Cpath& path, string& value); -bool getCfgNodeValues(CfgNode *root, const Cpath& path, - vector<string>& values); +CfgNode *findCfgNode(CfgNode *root, const cstore::Cpath& path, + bool& is_value); +CfgNode *findCfgNode(CfgNode *root, const cstore::Cpath& path); +bool getCfgNodeValue(CfgNode *root, const cstore::Cpath& path, + std::string& value); +bool getCfgNodeValues(CfgNode *root, const cstore::Cpath& path, + std::vector<std::string>& values); } // namespace cnode diff --git a/src/cnode/cnode-util.hpp b/src/cnode/cnode-util.hpp new file mode 100644 index 0000000..aeeeb08 --- /dev/null +++ b/src/cnode/cnode-util.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2011 Vyatta, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _CNODE_UTIL_HPP_ +#define _CNODE_UTIL_HPP_ +#include <vector> + +namespace cnode { + +template<class N> class TreeNode { +public: + typedef N node_type; + typedef std::vector<N *> nodes_vec_type; + typedef typename nodes_vec_type::iterator nodes_iter_type; + + TreeNode() : _parent(0) {} + virtual ~TreeNode() {} + + const nodes_vec_type& getChildNodes() const { return _child_nodes; } + size_t numChildNodes() const { + return _child_nodes.size(); + } + node_type *getParent() const { return _parent; } + node_type *childAt(size_t idx) { return _child_nodes[idx]; } + void setParent(node_type *p) { _parent = p; } + void clearChildNodes() { _child_nodes.clear(); } + void addChildNode(node_type *cnode) { + _child_nodes.push_back(cnode); + cnode->_parent = static_cast<node_type *>(this); + } + + bool removeChildNode(node_type *cnode) { + nodes_iter_type it = _child_nodes.begin(); + while (it != _child_nodes.end()) { + if (*it == cnode) { + _child_nodes.erase(it); + return true; + } + ++it; + } + return false; + } + + bool detachFromParent() { + if (!_parent) { + // not attached to tree + return false; + } + if (_parent->removeChildNode(static_cast<node_type *>(this))) { + _parent = 0; + return true; + } + return false; + } + + void detachFromChildren() { + for (size_t i = 0; i < _child_nodes.size(); i++) { + _child_nodes[i]->_parent = 0; + } + _child_nodes.clear(); + } + +private: + node_type *_parent; + nodes_vec_type _child_nodes; +}; + +} // namespace cnode + +#endif /* _CNODE_UTIL_HPP_ */ + diff --git a/src/cnode/cnode.cpp b/src/cnode/cnode.cpp index cd4f6cf..279ee9a 100644 --- a/src/cnode/cnode.cpp +++ b/src/cnode/cnode.cpp @@ -25,14 +25,17 @@ #include <cnode/cnode.hpp> using namespace cnode; +using namespace cstore; ////// constructors/destructors +// for parser CfgNode::CfgNode(Cpath& path_comps, char *name, char *val, char *comment, int deact, Cstore *cstore, bool tag_if_invalid) - : _is_tag(false), _is_leaf(false), _is_multi(false), _is_value(false), + : TreeNode<CfgNode>(), + _is_tag(false), _is_leaf(false), _is_multi(false), _is_value(false), _is_default(false), _is_deactivated(false), _is_leaf_typeless(false), - _is_invalid(false), _is_empty(true), _exists(true) + _is_invalid(false), _exists(true) { if (name && name[0]) { // name must be non-empty @@ -49,15 +52,15 @@ CfgNode::CfgNode(Cpath& path_comps, char *name, char *val, char *comment, break; } - tr1::shared_ptr<Ctemplate> def(cstore->parseTmpl(path_comps, false)); - if (def.get()) { + setTmpl(cstore->parseTmpl(path_comps, false)); + if (getTmpl().get()) { // got the def - _is_tag = def->isTag(); - _is_leaf = (!_is_tag && !def->isTypeless()); + _is_tag = getTmpl()->isTag(); + _is_leaf = (!_is_tag && !getTmpl()->isTypeless()); // match constructor from cstore (leaf node never _is_value) - _is_value = (def->isValue() && !_is_leaf); - _is_multi = def->isMulti(); + _is_value = (getTmpl()->isValue() && !_is_leaf); + _is_multi = getTmpl()->isMulti(); /* XXX given the current definition of "default", the concept of * "default" doesn't really apply to config files. @@ -113,18 +116,20 @@ CfgNode::CfgNode(Cpath& path_comps, char *name, char *val, char *comment, } } +// for active/working config CfgNode::CfgNode(Cstore& cstore, Cpath& path_comps, bool active, bool recursive) - : _is_tag(false), _is_leaf(false), _is_multi(false), _is_value(false), + : TreeNode<CfgNode>(), + _is_tag(false), _is_leaf(false), _is_multi(false), _is_value(false), _is_default(false), _is_deactivated(false), _is_leaf_typeless(false), - _is_invalid(false), _is_empty(false), _exists(true) + _is_invalid(false), _exists(true) { /* first get the def (only if path is not empty). if path is empty, i.e., * "root", treat it as an intermediate node. */ if (path_comps.size() > 0) { - tr1::shared_ptr<Ctemplate> def(cstore.parseTmpl(path_comps, false)); - if (def.get()) { + setTmpl(cstore.parseTmpl(path_comps, false)); + if (getTmpl().get()) { // got the def if (!cstore.cfgPathExists(path_comps, active)) { // path doesn't exist @@ -132,10 +137,10 @@ CfgNode::CfgNode(Cstore& cstore, Cpath& path_comps, bool active, return; } - _is_value = def->isValue(); - _is_tag = def->isTag(); - _is_leaf = (!_is_tag && !def->isTypeless()); - _is_multi = def->isMulti(); + _is_value = getTmpl()->isValue(); + _is_tag = getTmpl()->isTag(); + _is_leaf = (!_is_tag && !getTmpl()->isTypeless()); + _is_multi = getTmpl()->isMulti(); _is_default = cstore.cfgPathDefault(path_comps, active); _is_deactivated = cstore.cfgPathDeactivated(path_comps, active); cstore.cfgPathGetComment(path_comps, _comment, active); @@ -190,7 +195,6 @@ CfgNode::CfgNode(Cstore& cstore, Cpath& path_comps, bool active, // typeless leaf node _is_leaf_typeless = true; } - _is_empty = true; return; } @@ -203,7 +207,7 @@ CfgNode::CfgNode(Cstore& cstore, Cpath& path_comps, bool active, for (size_t i = 0; i < cnodes.size(); i++) { path_comps.push(cnodes[i]); CfgNode *cn = new CfgNode(cstore, path_comps, active, recursive); - _child_nodes.push_back(cn); + addChildNode(cn); path_comps.pop(); } } diff --git a/src/cnode/cnode.hpp b/src/cnode/cnode.hpp index a684514..2d38737 100644 --- a/src/cnode/cnode.hpp +++ b/src/cnode/cnode.hpp @@ -16,24 +16,29 @@ #ifndef _CNODE_HPP_ #define _CNODE_HPP_ +#include <cstdio> #include <vector> #include <string> #include <cstore/cstore.hpp> +#include <cnode/cnode-util.hpp> +#include <commit/commit-algorithm.hpp> namespace cnode { -using namespace cstore; - -class CfgNode { +class CfgNode : public TreeNode<CfgNode>, public commit::CommitData { public: - CfgNode(Cpath& path_comps, char *name, char *val, char *comment, - int deact, Cstore *cstore, bool tag_if_invalid = false); - CfgNode(Cstore& cstore, Cpath& path_comps, bool active = false, - bool recursive = true); + // constructor for parser + CfgNode(cstore::Cpath& path_comps, char *name, char *val, char *comment, + int deact, cstore::Cstore *cstore, bool tag_if_invalid = false); + // constructor for active/working config + CfgNode(cstore::Cstore& cstore, cstore::Cpath& path_comps, + bool active = false, bool recursive = true); + ~CfgNode() {}; bool isTag() const { return _is_tag; } + bool isTagNode() const { return (_is_tag && !_is_value); } bool isLeaf() const { return _is_leaf; } bool isMulti() const { return _is_multi; } bool isValue() const { return _is_value; } @@ -41,22 +46,29 @@ public: bool isDeactivated() const { return _is_deactivated; } bool isLeafTypeless() const { return _is_leaf_typeless; } bool isInvalid() const { return _is_invalid; } - bool isEmpty() const { return _is_empty; } + bool isEmpty() const { return (!_is_leaf && numChildNodes() == 0); } bool exists() const { return _exists; } - const string& getName() const { return _name; } - const string& getValue() const { return _value; } - const vector<string>& getValues() const { return _values; } - const string& getComment() const { return _comment; } - const vector<CfgNode *>& getChildNodes() const { return _child_nodes; } + const std::string& getName() const { return _name; } + const std::string& getValue() const { return _value; } + const std::vector<std::string>& getValues() const { return _values; } + const std::string& getComment() const { return _comment; } void addMultiValue(char *val) { _values.push_back(val); } - void addChildNode(CfgNode *cnode) { - _child_nodes.push_back(cnode); - _is_empty = false; - } void setValue(char *val) { _value = val; } + // XXX testing + void rprint(size_t lvl) { + for (size_t i = 0; i < lvl; i++) { + printf(" "); + } + printf("[%u][%s][%d]\n", getPriority(), + getCommitPath().to_string().c_str(), getCommitState()); + for (size_t i = 0; i < numChildNodes(); i++) { + childAt(i)->rprint(lvl + 1); + } + } + private: bool _is_tag; bool _is_leaf; @@ -66,13 +78,11 @@ private: bool _is_deactivated; bool _is_leaf_typeless; bool _is_invalid; - bool _is_empty; bool _exists; - string _name; - string _value; - vector<string> _values; - string _comment; - vector<CfgNode *> _child_nodes; + std::string _name; + std::string _value; + std::vector<std::string> _values; + std::string _comment; }; } // namespace cnode |