summaryrefslogtreecommitdiff
path: root/src/cnode
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2011-04-30 21:42:12 +0800
committerAn-Cheng Huang <ancheng@vyatta.com>2011-05-10 09:25:13 +0800
commit491b4c361f3a612835e76604fbd751e6e6905c3d (patch)
tree0fdb2e86fab5938bf171d23ef7cf23ccd555e531 /src/cnode
parent4c5199a11c951361934c7c5d4bd91e7e2ae8679a (diff)
downloadvyatta-cfg-491b4c361f3a612835e76604fbd751e6e6905c3d.tar.gz
vyatta-cfg-491b4c361f3a612835e76604fbd751e6e6905c3d.zip
preliminary implementation of new commit
(cherry picked from commit 1b2a0fd1ae1e6dfc18e4f75f73cd7befb47cf538)
Diffstat (limited to 'src/cnode')
-rw-r--r--src/cnode/cnode-algorithm.cpp64
-rw-r--r--src/cnode/cnode-algorithm.hpp53
-rw-r--r--src/cnode/cnode-util.hpp84
-rw-r--r--src/cnode/cnode.cpp40
-rw-r--r--src/cnode/cnode.hpp56
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