diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2010-12-02 14:35:25 -0800 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2010-12-02 14:35:25 -0800 |
commit | 352a9e94534933aca7403e91d1dc55c26bf633ce (patch) | |
tree | df413a5fbd1ab0e0b4776eff98149dd9cbc8006d /src | |
parent | 58005829f825c3e6843d0c2c36e1e343194ec3dd (diff) | |
download | vyatta-cfg-352a9e94534933aca7403e91d1dc55c26bf633ce.tar.gz vyatta-cfg-352a9e94534933aca7403e91d1dc55c26bf633ce.zip |
implement load function in new config input/output infrastructure.
* add "commands diff" functionality to config input/output infrastructure.
* consolidate similar logic in "commands diff" and "show diff".
* add loadFile functionality to cstore using "commands diff".
* export loadFile through shell API.
Diffstat (limited to 'src')
-rw-r--r-- | src/cli_shell_api.cpp | 31 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.cpp | 487 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.hpp | 15 | ||||
-rw-r--r-- | src/cstore/cstore.cpp | 75 | ||||
-rw-r--r-- | src/cstore/cstore.hpp | 8 |
5 files changed, 521 insertions, 95 deletions
diff --git a/src/cli_shell_api.cpp b/src/cli_shell_api.cpp index af0a320..b9b8188 100644 --- a/src/cli_shell_api.cpp +++ b/src/cli_shell_api.cpp @@ -24,6 +24,7 @@ #include <cstore/unionfs/cstore-unionfs.hpp> #include <cnode/cnode.hpp> #include <cnode/cnode-algorithm.hpp> +#include <cparse/cparse.hpp> /* This program provides an API for shell scripts (e.g., snippets in * templates, standalone scripts, etc.) to access the CLI cstore library. @@ -405,18 +406,27 @@ showCfg(const vector<string>& args) cnode::CfgNode aroot(cstore, nargs, true, true); if (active_only) { - // just show the active config - cnode::show_diff(aroot, aroot, op_show_show_defaults, - op_show_hide_secrets); - } else if (working_only) { - // just show the working config without diff markers - cnode::CfgNode wroot(cstore, nargs, false, true); - cnode::show_diff(wroot, wroot, op_show_show_defaults, - op_show_hide_secrets); + // just show the active config (no diff) + cnode::show_cfg(aroot, op_show_show_defaults, op_show_hide_secrets); } else { cnode::CfgNode wroot(cstore, nargs, false, true); - cnode::show_diff(aroot, wroot, op_show_show_defaults, - op_show_hide_secrets); + if (working_only) { + // just show the working config (no diff) + cnode::show_cfg(wroot, op_show_show_defaults, op_show_hide_secrets); + } else { + cnode::show_cfg_diff(aroot, wroot, op_show_show_defaults, + op_show_hide_secrets); + } + } +} + +static void +loadFile(const vector<string>& args) +{ + UnionfsCstore cstore(true); + if (!cstore.loadFile(args[0].c_str())) { + // loadFile failed + exit(1); } } @@ -463,6 +473,7 @@ static OpT ops[] = { OP(validateTmplValPath, -1, NULL, 1, "Must specify config path"), OP(showCfg, -1, NULL, -1, NULL), + OP(loadFile, 1, "Must specify config file", -1, NULL), {NULL, -1, NULL, -1, NULL, NULL} }; diff --git a/src/cnode/cnode-algorithm.cpp b/src/cnode/cnode-algorithm.cpp index 4480352..3a7ccdd 100644 --- a/src/cnode/cnode-algorithm.cpp +++ b/src/cnode/cnode-algorithm.cpp @@ -40,6 +40,133 @@ _show_diff(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def, bool hide_secret); static void +_get_cmds_diff(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path, + vector<vector<string> >& del_list, + vector<vector<string> >& set_list, + vector<vector<string> >& 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", + * respectively. + * + * return value indicates whether the node is different in the two configs. + * + * comparison follows the original perl logic. + */ +static bool +_cmp_multi_values(CfgNode *cfg1, CfgNode *cfg2, vector<string>& values, + vector<const char *>& pfxs) +{ + const vector<string>& ovec = cfg1->getValues(); + const vector<string>& nvec = cfg2->getValues(); + Cstore::MapT<string, bool> nmap; + bool changed = false; + for (size_t i = 0; i < nvec.size(); i++) { + nmap[nvec[i]] = true; + } + Cstore::MapT<string, bool> omap; + for (size_t i = 0; i < ovec.size(); i++) { + omap[ovec[i]] = true; + if (nmap.find(ovec[i]) == nmap.end()) { + values.push_back(ovec[i]); + pfxs.push_back(PFX_DIFF_DEL.c_str()); + changed = true; + } + } + + 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()); + changed = true; + } else if (i < ovec.size() && nvec[i] == ovec[i]) { + pfxs.push_back(PFX_DIFF_NONE.c_str()); + } else { + pfxs.push_back(PFX_DIFF_UPD.c_str()); + changed = true; + } + } + + return changed; +} + +static void +_cmp_non_leaf_nodes(CfgNode *cfg1, CfgNode *cfg2, vector<CfgNode *>& rcnodes1, + vector<CfgNode *>& rcnodes2, bool& not_tag_node, + bool& is_value, bool& is_leaf_typeless, + string& name, string& value) +{ + CfgNode *cfg = (cfg1 ? cfg1 : cfg2); + is_value = cfg->isValue(); + not_tag_node = (!cfg->isTag() || is_value); + is_leaf_typeless = cfg->isLeafTypeless(); + bool is_tag_node = !not_tag_node; + name = cfg->getName(); + if (is_value) { + value = cfg->getValue(); + } + + // handle child nodes + vector<CfgNode *> cnodes1, cnodes2; + if (cfg1) { + cnodes1 = cfg1->getChildNodes(); + } + if (cfg2) { + cnodes2 = cfg2->getChildNodes(); + } + + Cstore::MapT<string, bool> map; + Cstore::MapT<string, CfgNode *> nmap1, nmap2; + for (size_t i = 0; i < cnodes1.size(); i++) { + string key = (is_tag_node + ? cnodes1[i]->getValue() : cnodes1[i]->getName()); + map[key] = true; + nmap1[key] = cnodes1[i]; + } + for (size_t i = 0; i < cnodes2.size(); i++) { + string key = (is_tag_node + ? cnodes2[i]->getValue() : cnodes2[i]->getName()); + map[key] = true; + nmap2[key] = cnodes2[i]; + } + + vector<string> cnodes; + Cstore::MapT<string, bool>::iterator it = map.begin(); + for (; it != map.end(); ++it) { + cnodes.push_back((*it).first); + } + Cstore::sortNodes(cnodes); + + for (size_t i = 0; i < cnodes.size(); i++) { + bool in1 = (nmap1.find(cnodes[i]) != nmap1.end()); + bool in2 = (nmap2.find(cnodes[i]) != nmap2.end()); + CfgNode *c1 = (in1 ? nmap1[cnodes[i]] : NULL); + CfgNode *c2 = (in2 ? nmap2[cnodes[i]] : NULL); + rcnodes1.push_back(c1); + rcnodes2.push_back(c2); + } +} + +static void +_add_path_to_list(vector<vector<string> >& list, vector<string>& path, + const string *nptr, const string *vptr) +{ + if (nptr) { + path.push_back(*nptr); + } + if (vptr) { + path.push_back(*vptr); + } + list.push_back(path); + if (vptr) { + path.pop_back(); + } + if (nptr) { + path.pop_back(); + } +} + +static void _print_value_str(const string& name, const char *vstr, bool hide_secret) { // handle secret hiding first @@ -161,35 +288,9 @@ _diff_check_and_show_leaf(CfgNode *cfg1, CfgNode *cfg2, int level, } } else { // need to actually do a diff. - // this follows the original perl logic. - const vector<string>& ovec = cfg1->getValues(); - const vector<string>& nvec = cfg2->getValues(); vector<string> values; vector<const char *> pfxs; - Cstore::MapT<string, bool> nmap; - for (size_t i = 0; i < nvec.size(); i++) { - nmap[nvec[i]] = true; - } - Cstore::MapT<string, bool> omap; - for (size_t i = 0; i < ovec.size(); i++) { - omap[ovec[i]] = true; - if (nmap.find(ovec[i]) == nmap.end()) { - values.push_back(ovec[i]); - pfxs.push_back(PFX_DIFF_DEL.c_str()); - } - } - - 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()); - } else if (i < ovec.size() && nvec[i] == ovec[i]) { - pfxs.push_back(PFX_DIFF_NONE.c_str()); - } else { - pfxs.push_back(PFX_DIFF_UPD.c_str()); - } - } - + _cmp_multi_values(cfg1, cfg2, values, pfxs); for (size_t i = 0; i < values.size(); i++) { _diff_print_indent(cfg1, cfg2, level, pfxs[i]); printf("%s ", cfg->getName().c_str()); @@ -224,13 +325,10 @@ static void _diff_show_other(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def, bool hide_secret) { - CfgNode *cfg = NULL; const char *pfx_diff = PFX_DIFF_NONE.c_str(); if (!cfg1) { - cfg = cfg2; pfx_diff = PFX_DIFF_ADD.c_str(); } else { - cfg = cfg1; if (!cfg2) { pfx_diff = PFX_DIFF_DEL.c_str(); } else if (cfg1 == cfg2) { @@ -238,76 +336,41 @@ _diff_show_other(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def, } } + 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, + is_leaf_typeless, name, value); + /* only print "this" node if it * (1) is a tag value or an intermediate node, * (2) is not "root", and * (3) has a "name". */ - const string& name = cfg->getName(); - bool print_this = (((cfg1 && (!cfg1->isTag() || cfg1->isValue())) - || (cfg2 && (!cfg2->isTag() || cfg2->isValue()))) - && level >= 0 && name.size() > 0); + bool print_this = (not_tag_node && level >= 0 && name.size() > 0); if (print_this) { _diff_print_comment(cfg1, cfg2, level); _diff_print_indent(cfg1, cfg2, level, pfx_diff); - if (cfg->isValue()) { + if (is_value) { // at tag value - printf("%s %s", name.c_str(), cfg->getValue().c_str()); + printf("%s %s", name.c_str(), value.c_str()); } else { // at intermediate node printf("%s", name.c_str()); } - printf("%s\n", (cfg->isLeafTypeless() ? "" : " {")); + printf("%s\n", (is_leaf_typeless ? "" : " {")); } - // handle child nodes - vector<CfgNode *> cnodes1, cnodes2; - if (cfg1) { - cnodes1 = cfg1->getChildNodes(); - } - if (cfg2) { - cnodes2 = cfg2->getChildNodes(); - } - - Cstore::MapT<string, bool> map; - Cstore::MapT<string, CfgNode *> nmap1, nmap2; - for (size_t i = 0; i < cnodes1.size(); i++) { - string key - = ((cfg->isTag() && !cfg->isValue()) - ? cnodes1[i]->getValue() : cnodes1[i]->getName()); - map[key] = true; - nmap1[key] = cnodes1[i]; - } - for (size_t i = 0; i < cnodes2.size(); i++) { - string key - = ((cfg->isTag() && !cfg->isValue()) - ? cnodes2[i]->getValue() : cnodes2[i]->getName()); - map[key] = true; - nmap2[key] = cnodes2[i]; - } - - vector<string> cnodes; - Cstore::MapT<string, bool>::iterator it = map.begin(); - for (; it != map.end(); ++it) { - cnodes.push_back((*it).first); - } - Cstore::sortNodes(cnodes); - - for (size_t i = 0; i < cnodes.size(); i++) { - bool in1 = (nmap1.find(cnodes[i]) != nmap1.end()); - bool in2 = (nmap2.find(cnodes[i]) != nmap2.end()); - CfgNode *c1 = (in1 ? nmap1[cnodes[i]] : NULL); - CfgNode *c2 = (in2 ? nmap2[cnodes[i]] : NULL); - + for (size_t i = 0; i < rcnodes1.size(); i++) { int next_level = level + 1; if (!print_this) { next_level = (level >= 0 ? level : 0); } - _show_diff(c1, c2, next_level, show_def, hide_secret); + _show_diff(rcnodes1[i], rcnodes2[i], next_level, show_def, hide_secret); } // finish printing "this" node if necessary - if (print_this && !cfg->isLeafTypeless()) { + if (print_this && !is_leaf_typeless) { _diff_print_indent(cfg1, cfg2, level, pfx_diff); printf("}\n"); } @@ -353,11 +416,227 @@ _show_diff(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def, } } +static void +_get_comment_diff_cmd(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path, + vector<vector<string> >& com_list, const string *val) +{ + const string *comment = NULL; + const string *name = NULL; + string empty = ""; + string c1, c2; + if (cfg1 != cfg2) { + c1 = (cfg1 ? cfg1->getComment() : ""); + c2 = (cfg2 ? cfg2->getComment() : ""); + if (c1 != "") { + name = &(cfg1->getName()); + if (c2 != "") { + // in both + if (c1 != c2) { + // updated + comment = &c2; + } + } else { + // only in cfg1 => deleted + comment = ∅ + } + } else { + if (c2 != "") { + // only in cfg2 => added + name = &(cfg2->getName()); + comment = &c2; + } + } + } else { + // cfg1 == cfg2 => just getting all commands + c1 = cfg1->getComment(); + if (c1 != "") { + name = &(cfg1->getName()); + comment = &c1; + } + } + if (comment) { + if (val) { + cur_path.push_back(*name); + name = val; + } + _add_path_to_list(com_list, cur_path, name, comment); + if (val) { + cur_path.pop_back(); + } + } +} + +static bool +_get_cmds_diff_leaf(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path, + vector<vector<string> >& del_list, + vector<vector<string> >& set_list, + vector<vector<string> >& com_list) +{ + if ((cfg1 && !cfg1->isLeaf()) || (cfg2 && !cfg2->isLeaf())) { + // not a leaf node + return false; + } + + CfgNode *cfg = NULL; + vector<vector<string> > *list = NULL; + if (cfg1) { + cfg = cfg1; + if (!cfg2) { + // exists in cfg1 but not in cfg2 => delete and stop recursion + _add_path_to_list(del_list, cur_path, &(cfg1->getName()), NULL); + return true; + } else if (cfg1 == cfg2) { + // same config => just translating config to set commands + list = &set_list; + } + } else { + // !cfg1 => cfg2 must not be NULL + cfg = cfg2; + list = &set_list; + } + + _get_comment_diff_cmd(cfg1, cfg2, cur_path, com_list, NULL); + if (cfg->isMulti()) { + // multi-value node + if (list) { + const vector<string>& vvec = cfg->getValues(); + for (size_t i = 0; i < vvec.size(); i++) { + _add_path_to_list(*list, cur_path, &(cfg->getName()), &(vvec[i])); + } + } 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)) { + /* something changed. to get the correct ordering for multi-node + * values, need to delete the node and then set the new values. + */ + const vector<string>& nvec = cfg2->getValues(); + _add_path_to_list(del_list, cur_path, &(cfg->getName()), NULL); + for (size_t i = 0; i < nvec.size(); i++) { + _add_path_to_list(set_list, cur_path, &(cfg->getName()), &(nvec[i])); + } + } + } + } else { + // single-value node + string val = cfg->getValue(); + if (!list) { + const string& val1 = cfg1->getValue(); + val = cfg2->getValue(); + if (val != val1) { + // changed => need to set it + list = &set_list; + } + } + if (list) { + _add_path_to_list(*list, cur_path, &(cfg->getName()), &val); + } + } + + return true; +} + +static void +_get_cmds_diff_other(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path, + vector<vector<string> >& del_list, + vector<vector<string> >& set_list, + vector<vector<string> >& com_list) +{ + vector<vector<string> > *list = NULL; + if (cfg1) { + if (!cfg2) { + // exists in cfg1 but not in cfg2 => delete and stop recursion + _add_path_to_list(del_list, cur_path, &(cfg1->getName()), + (cfg1->isValue() ? &(cfg1->getValue()) : NULL)); + return; + } else if (cfg1 == cfg2) { + // same config => just translating config to set commands + list = &set_list; + } + } else { + // !cfg1 => cfg2 must not be NULL + list = &set_list; + } + + 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, + is_leaf_typeless, name, value); + if (rcnodes1.size() < 1 && list) { + // subtree is empty + _add_path_to_list(*list, cur_path, &name, (is_value ? &value : NULL)); + return; + } + + bool add_this = (not_tag_node && name.size() > 0); + if (add_this) { + const string *val = (is_value ? &value : NULL); + _get_comment_diff_cmd(cfg1, cfg2, cur_path, com_list, val); + + cur_path.push_back(name); + if (is_value) { + cur_path.push_back(value); + } + } + for (size_t i = 0; i < rcnodes1.size(); i++) { + _get_cmds_diff(rcnodes1[i], rcnodes2[i], cur_path, del_list, set_list, + com_list); + } + if (add_this) { + if (is_value) { + cur_path.pop_back(); + } + cur_path.pop_back(); + } +} + +static void +_get_cmds_diff(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path, + vector<vector<string> >& del_list, + vector<vector<string> >& set_list, + vector<vector<string> >& com_list) +{ + // if doesn't exist, treat as NULL + if (cfg1 && !cfg1->exists()) { + cfg1 = NULL; + } + if (cfg2 && !cfg2->exists()) { + cfg2 = NULL; + } + + if (!cfg1 && !cfg2) { + fprintf(stderr, "_get_cmds_diff error (both config NULL)\n"); + exit(1); + } + + if (_get_cmds_diff_leaf(cfg1, cfg2, cur_path, del_list, set_list, + com_list)) { + // leaf node has been shown. done. + return; + } else { + // intermediate node, tag node, or tag value + _get_cmds_diff_other(cfg1, cfg2, cur_path, del_list, set_list, com_list); + } +} + +static void +_print_cmds_list(const char *op, vector<vector<string> >& list) +{ + for (size_t i = 0; i < list.size(); i++) { + printf("%s", op); + for (size_t j = 0; j < list[i].size(); j++) { + printf(" '%s'", list[i][j].c_str()); + } + printf("\n"); + } +} ////// algorithms void -cnode::show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def, - bool hide_secret) +cnode::show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def, + bool hide_secret) { if (cfg1.isInvalid() || cfg2.isInvalid()) { printf("Specified configuration path is not valid\n"); @@ -372,3 +651,51 @@ cnode::show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def, show_def, hide_secret); } +void +cnode::show_cfg(const CfgNode& cfg, bool show_def, bool hide_secret) +{ + show_cfg_diff(cfg, cfg, show_def, hide_secret); +} + +void +cnode::show_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2) +{ + vector<string> cur_path; + vector<vector<string> > del_list; + vector<vector<string> > set_list; + vector<vector<string> > com_list; + _get_cmds_diff(const_cast<CfgNode *>(&cfg1), const_cast<CfgNode *>(&cfg2), + cur_path, del_list, set_list, com_list); + + _print_cmds_list("delete", del_list); + _print_cmds_list("set", set_list); + _print_cmds_list("comment", com_list); +} + +void +cnode::show_cmds(const CfgNode& cfg) +{ + show_cmds_diff(cfg, cfg); +} + +void +cnode::get_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2, + vector<vector<string> >& del_list, + vector<vector<string> >& set_list, + vector<vector<string> >& com_list) +{ + vector<string> cur_path; + _get_cmds_diff(const_cast<CfgNode *>(&cfg1), const_cast<CfgNode *>(&cfg2), + cur_path, del_list, set_list, com_list); +} + +void +cnode::get_cmds(const CfgNode& cfg, vector<vector<string> >& set_list, + vector<vector<string> >& com_list) +{ + vector<string> cur_path; + vector<vector<string> > del_list; + _get_cmds_diff(const_cast<CfgNode *>(&cfg), const_cast<CfgNode *>(&cfg), + cur_path, del_list, set_list, com_list); +} + diff --git a/src/cnode/cnode-algorithm.hpp b/src/cnode/cnode-algorithm.hpp index 86bce81..07faf07 100644 --- a/src/cnode/cnode-algorithm.hpp +++ b/src/cnode/cnode-algorithm.hpp @@ -21,8 +21,19 @@ namespace cnode { -void show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def, - bool hide_secret); +void show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def, + bool hide_secret); +void show_cfg(const CfgNode& cfg, bool show_def, bool hide_secret); + +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<vector<string> >& del_list, + vector<vector<string> >& set_list, + vector<vector<string> >& com_list); +void get_cmds(const CfgNode& cfg, vector<vector<string> >& set_list, + vector<vector<string> >& com_list); } // namespace cnode diff --git a/src/cstore/cstore.cpp b/src/cstore/cstore.cpp index ed18c9e..0ff8ba2 100644 --- a/src/cstore/cstore.cpp +++ b/src/cstore/cstore.cpp @@ -31,6 +31,9 @@ #include <cli_cstore.h> #include <cstore/cstore.hpp> #include <cstore/cstore-varref.hpp> +#include <cnode/cnode.hpp> +#include <cnode/cnode-algorithm.hpp> +#include <cparse/cparse.hpp> ////// constants @@ -1803,6 +1806,63 @@ Cstore::unmarkCfgPathDeactivated(const vector<string>& path_comps) return ret; } +// load specified config file +bool +Cstore::loadFile(const char *filename) +{ + if (!inSession()) { + output_user("Cannot load config outside configuration session\n"); + // exit handled by assert below + } + ASSERT_IN_SESSION; + + FILE *fin = fopen(filename, "r"); + if (!fin) { + output_user("Failed to open specified config file\n"); + return false; + } + + // get the config tree from the file + cnode::CfgNode *froot = cparse::parse_file(fin, *this); + if (!froot) { + output_user("Failed to parse specified config file\n"); + return false; + } + + // get the config tree from the active config + vector<string> args; + cnode::CfgNode aroot(*this, args, true, true); + + // get the "commands diff" between the two + vector<vector<string> > del_list; + vector<vector<string> > set_list; + vector<vector<string> > com_list; + cnode::get_cmds_diff(aroot, *froot, del_list, set_list, com_list); + + // "apply" the changes to the working config + for (size_t i = 0; i < del_list.size(); i++) { + vtw_def def; + if (!validateDeletePath(del_list[i], def) + || !deleteCfgPath(del_list[i], def)) { + print_str_vec("Delete [", "] failed\n", del_list[i], "'"); + } + } + for (size_t i = 0; i < set_list.size(); i++) { + if (!validateSetPath(set_list[i]) || !setCfgPath(set_list[i])) { + print_str_vec("Set [", "] failed\n", set_list[i], "'"); + } + } + for (size_t i = 0; i < com_list.size(); i++) { + vtw_def def; + if (!validateCommentArgs(com_list[i], def) + || !commentCfgPath(com_list[i], def)) { + print_str_vec("Comment [", "] failed\n", com_list[i], "'"); + } + } + + return true; +} + /* "changed" status handling. * the "changed" status is used during commit to check if a node has been * changed. note that if a node is "changed", all of its ancestors are also @@ -2797,3 +2857,18 @@ Cstore::shell_escape_squotes(string& str) } } +// print a vector of strings +void +Cstore::print_str_vec(const char *pre, const char *post, + const vector<string>& vec, const char *quote) +{ + output_user("%s", pre); + for (size_t i = 0; i < vec.size(); i++) { + if (i > 0) { + output_user(" "); + } + output_user("%s%s%s", quote, vec[i].c_str(), quote); + } + output_user("%s", post); +} + diff --git a/src/cstore/cstore.hpp b/src/cstore/cstore.hpp index 267dabe..d1d01fa 100644 --- a/src/cstore/cstore.hpp +++ b/src/cstore/cstore.hpp @@ -112,7 +112,7 @@ public: * edit-related commands (invoked from shell functions) * completion-related (for completion script) * session-related (setup, teardown, etc.) - * load (XXX currently still implemented in perl) + * load * * these operate on the "working config" and the session and MUST NOT * be used by anything other than the listed operations. @@ -165,8 +165,8 @@ public: virtual bool inSession() = 0; // commit bool unmarkCfgPathChanged(const vector<string>& path_comps); - // XXX load - //bool unmarkCfgPathDeactivatedDescendants(const vector<string>& path_comps); + // load + bool loadFile(const char *filename); /****** * these functions are observers of the current "working config" or @@ -476,6 +476,8 @@ private: // util functions string get_shell_prompt(const string& level); void shell_escape_squotes(string& str); + void print_str_vec(const char *pre, const char *post, + const vector<string>& vec, const char *quote); }; #endif /* _CSTORE_H_ */ |