diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2010-11-09 18:38:49 -0800 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2010-11-09 18:38:49 -0800 |
commit | 1e615a4e3f3681f8bd02d49d688001d61aa8b815 (patch) | |
tree | ed5ce2367d540d5414a283e1e2b9c2e20d0239cd | |
parent | b8f85d2744a42eb18ac78451c29dc6de7bab5fea (diff) | |
download | vyatta-cfg-1e615a4e3f3681f8bd02d49d688001d61aa8b815.tar.gz vyatta-cfg-1e615a4e3f3681f8bd02d49d688001d61aa8b815.zip |
initial rework of config output framework
* separate data from algorithm.
* prepare for unified input/output framework.
-rw-r--r-- | Makefile.am | 6 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.cpp | 411 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.hpp | 30 | ||||
-rw-r--r-- | src/cnode/cnode.cpp | 123 | ||||
-rw-r--r-- | src/cnode/cnode.hpp | 70 | ||||
-rw-r--r-- | src/cstore/cstore.hpp | 23 |
6 files changed, 655 insertions, 8 deletions
diff --git a/Makefile.am b/Makefile.am index 903e4eb..69071ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,8 @@ src_libvyatta_cfg_la_SOURCES += src/cstore/cstore.cpp src_libvyatta_cfg_la_SOURCES += src/cstore/cstore-varref.cpp src_libvyatta_cfg_la_SOURCES += src/cstore/cstore-node.cpp src_libvyatta_cfg_la_SOURCES += src/cstore/unionfs/cstore-unionfs.cpp +src_libvyatta_cfg_la_SOURCES += src/cnode/cnode.cpp +src_libvyatta_cfg_la_SOURCES += src/cnode/cnode-algorithm.cpp CLEANFILES = src/cli_parse.c src/cli_parse.h src/cli_def.c src/cli_val.c LDADD = src/libvyatta-cfg.la LDADD += /usr/lib/libglib-2.0.la @@ -48,6 +50,10 @@ vcinc_HEADERS += src/cstore/cstore.hpp vcuincdir = $(vcincdir)/unionfs vcuinc_HEADERS = src/cstore/unionfs/cstore-unionfs.hpp +vnincdir = $(vincludedir)/cnode +vninc_HEADERS = src/cnode/cnode.hpp +vninc_HEADERS += src/cnode/cnode-algorithm.hpp + sbin_PROGRAMS = src/priority sbin_PROGRAMS += src/my_commit sbin_PROGRAMS += src/exe_action diff --git a/src/cnode/cnode-algorithm.cpp b/src/cnode/cnode-algorithm.cpp new file mode 100644 index 0000000..9f67d7d --- /dev/null +++ b/src/cnode/cnode-algorithm.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2010 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/>. + */ + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#include <cstore/cstore.hpp> +#include <cnode/cnode.hpp> +#include <cnode/cnode-algorithm.hpp> + +using namespace std; +using namespace cnode; + + +////// constants +static const string PFX_DIFF_ADD = "+"; // added +static const string PFX_DIFF_DEL = "-"; // deleted +static const string PFX_DIFF_UPD = ">"; // changed +static const string PFX_DIFF_NONE = " "; +static const string PFX_DIFF_NULL = ""; + +static const string PFX_DEACT_D = "!"; // deactivated +static const string PFX_DEACT_DP = "D"; // deactivate pending +static const string PFX_DEACT_AP = "A"; // activate pending +static const string PFX_DEACT_NONE = " "; + + +////// static (internal) functions +static void +_show_diff(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def, + bool hide_secret); + +static void +_print_value_str(const string& name, const char *vstr, bool hide_secret) +{ + // handle secret hiding first + if (hide_secret) { + static const char *sname[] = { "passphrase", "password", + "pre-shared-secret", "key", NULL }; + static size_t slen[] = { 10, 8, 17, 3, 0 }; + size_t nlen = name.length(); + for (size_t i = 0; sname[i]; i++) { + if (nlen < slen[i]) { + // can't match + continue; + } + if (name.find(sname[i], nlen - slen[i]) != name.npos) { + // found secret + printf("****************"); + return; + } + } + } + + const char *quote = ""; + size_t vlen = strlen(vstr); + if (*vstr == 0 || strcspn(vstr, "*}{;\011\012\013\014\015 ") < vlen) { + quote = "\""; + } + printf("%s%s%s", quote, vstr, quote); +} + +static void +_diff_print_indent(CfgNode *cfg1, CfgNode *cfg2, int level, + const char *pfx_diff) +{ + const char *pfx_deact = PFX_DEACT_NONE.c_str(); + if (cfg1 && cfg2) { + if (cfg1->isDeactivated()) { + if (cfg2->isDeactivated()) { + pfx_deact = PFX_DEACT_D.c_str(); + } else { + pfx_deact = PFX_DEACT_AP.c_str(); + } + } else { + if (cfg2->isDeactivated()) { + pfx_deact = PFX_DEACT_DP.c_str(); + } + // 4th case handled by default + } + } + + printf("%s %s", pfx_deact, pfx_diff); + for (int i = 0; i < level; i++) { + printf(" "); + } +} + +static void +_diff_print_comment(CfgNode *cfg1, CfgNode *cfg2, int level) +{ + const char *pfx_diff = PFX_DIFF_NONE.c_str(); + string comment = ""; + if (cfg1 != cfg2) { + string c1 = (cfg1 ? cfg1->getComment() : ""); + string c2 = (cfg2 ? cfg2->getComment() : ""); + if (c1 != "") { + if (c2 != "") { + // in both + comment = c2; + if (c1 != c2) { + pfx_diff = PFX_DIFF_UPD.c_str(); + } + } else { + // only in cfg1 + comment = c1; + pfx_diff = PFX_DIFF_DEL.c_str(); + } + } else { + if (c2 != "") { + // only in cfg2 + comment = c2; + pfx_diff = PFX_DIFF_ADD.c_str(); + } + // 4th case handled by default + } + } else { + // same node => no diff + pfx_diff = PFX_DIFF_NULL.c_str(); + } + if (comment == "") { + // no comment + return; + } + _diff_print_indent(cfg1, cfg2, level, pfx_diff); + printf("/* %s */\n", comment.c_str()); +} + +static bool +_diff_check_and_show_leaf(CfgNode *cfg1, CfgNode *cfg2, int level, + bool show_def, bool hide_secret) +{ + if ((cfg1 && !cfg1->isLeaf()) || (cfg2 && !cfg2->isLeaf())) { + // not a leaf node + return false; + } + + CfgNode *cfg = NULL; + const char *force_pfx_diff = NULL; + if (!cfg1) { + cfg = cfg2; + force_pfx_diff = PFX_DIFF_ADD.c_str(); + } else { + cfg = cfg1; + if (!cfg2) { + force_pfx_diff = PFX_DIFF_DEL.c_str(); + } else if (cfg1 == cfg2) { + force_pfx_diff = PFX_DIFF_NULL.c_str(); + } + } + + if (cfg->isMulti()) { + // multi-value node + _diff_print_comment(cfg1, cfg2, level); + if (force_pfx_diff) { + // simple case: just use the same diff prefix for all values + const vector<string>& vvec = cfg->getValues(); + for (size_t i = 0; i < vvec.size(); i++) { + _diff_print_indent(cfg1, cfg2, level, force_pfx_diff); + printf("%s ", cfg->getName().c_str()); + _print_value_str(cfg->getName(), vvec[i].c_str(), hide_secret); + printf("\n"); + } + } else { + // need to actually do a diff. + // this follows the original perl logic. + const vector<string>& ovec = cfg1->getValues(); + const vector<string>& nvec = cfg1->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()); + } + } + + for (size_t i = 0; i < values.size(); i++) { + _diff_print_indent(cfg1, cfg2, level, pfxs[i]); + printf("%s ", cfg->getName().c_str()); + _print_value_str(cfg->getName(), values[i].c_str(), hide_secret); + printf("\n"); + } + } + } else { + // single-value node + if (show_def || !cfg->isDefault()) { + const string& val = cfg->getValue(); + if (!force_pfx_diff) { + const string& val1 = cfg1->getValue(); + if (val == val1) { + force_pfx_diff = PFX_DIFF_NONE.c_str(); + } else { + force_pfx_diff = PFX_DIFF_UPD.c_str(); + } + } + _diff_print_indent(cfg1, cfg2, level, force_pfx_diff); + printf("%s ", cfg->getName().c_str()); + _print_value_str(cfg->getName(), val.c_str(), hide_secret); + printf("\n"); + } + } + + return true; +} + +static bool +_diff_check_and_show_tag(CfgNode *cfg1, CfgNode *cfg2, int level, + bool show_def, bool hide_secret) +{ + if ((cfg1 && !cfg1->isTag()) || (cfg2 && !cfg2->isTag())) { + // not a tag node + return false; + } + + vector<CfgNode *> vals1, vals2; + if (cfg1) { + vals1 = cfg1->getTagValues(); + } + if (cfg2) { + vals2 = cfg2->getTagValues(); + } + + Cstore::MapT<string, bool> vmap; + Cstore::MapT<string, CfgNode *> vnmap1, vnmap2; + for (size_t i = 0; i < vals1.size(); i++) { + vmap[vals1[i]->getValue()] = true; + vnmap1[vals1[i]->getValue()] = vals1[i]; + } + for (size_t i = 0; i < vals2.size(); i++) { + vmap[vals2[i]->getValue()] = true; + vnmap2[vals2[i]->getValue()] = vals2[i]; + } + + vector<string> values; + Cstore::MapT<string, bool>::iterator it = vmap.begin(); + for (; it != vmap.end(); ++it) { + values.push_back((*it).first); + } + Cstore::sortNodes(values); + + for (size_t i = 0; i < values.size(); i++) { + bool in1 = (vnmap1.find(values[i]) != vnmap1.end()); + bool in2 = (vnmap2.find(values[i]) != vnmap2.end()); + CfgNode *c1 = (in1 ? vnmap1[values[i]] : NULL); + CfgNode *c2 = (in2 ? vnmap2[values[i]] : NULL); + /* note: if the root is a tag node (level == -1), then need to make + * level 0 when calling tag values' show(). + */ + _show_diff(c1, c2, ((level >= 0) ? level : 0), show_def, hide_secret); + } + return true; +} + +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) { + pfx_diff = PFX_DIFF_NULL.c_str(); + } + } + + const string& name = cfg->getName(); + bool print_this = (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()) { + // at tag value + printf("%s %s", name.c_str(), cfg->getValue().c_str()); + } else { + // at intermediate node + printf("%s", name.c_str()); + } + printf("%s\n", (cfg->isLeafTypeless() ? "" : " {")); + } + + 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++) { + map[cnodes1[i]->getName()] = true; + nmap1[cnodes1[i]->getName()] = cnodes1[i]; + } + for (size_t i = 0; i < cnodes2.size(); i++) { + map[cnodes2[i]->getName()] = true; + nmap2[cnodes2[i]->getName()] = 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); + _show_diff(c1, c2, level + 1, show_def, hide_secret); + } + + if (print_this && !cfg->isLeafTypeless()) { + _diff_print_indent(cfg1, cfg2, level, pfx_diff); + printf("}\n"); + } +} + +static void +_show_diff(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def, + bool hide_secret) +{ + /* cfg1 and cfg2 point to the same config node in two configs. a "diff" + * output is shown comparing the two configs recursively with this node + * as the root of the config tree. + * + * there are four possible scenarios: + * (1) (cfg1 && cfg2) && (cfg1 != cfg2): node exists in both config. + * (2) (cfg1 && cfg2) && (cfg1 == cfg2): the two point to the same config. + * this will be just a "show". + * (3) (!cfg1 && cfg2): node exists in cfg2 but not in cfg1 (added). + * (4) (cfg1 && !cfg2): node exists in cfg1 but not in cfg1 (deleted). + * + * calling this with both NULL is invalid. + */ + if (!cfg1 && !cfg2) { + fprintf(stderr, "_show_diff error (both config NULL)\n"); + exit(1); + } + + if (_diff_check_and_show_leaf(cfg1, cfg2, level, show_def, hide_secret)) { + // leaf node has been shown. done. + return; + } else if (_diff_check_and_show_tag(cfg1, cfg2, level, show_def, + hide_secret)) { + // tag node has been shown. done. + return; + } else { + // intermediate node or tag value + _diff_show_other(cfg1, cfg2, level, show_def, hide_secret); + } +} + + +////// algorithms +void +cnode::show_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"); + return; + } + if (cfg1.isEmpty() && cfg2.isEmpty()) { + printf("Configuration under specified path is empty\n"); + return; + } + _show_diff(const_cast<CfgNode *>(&cfg1), const_cast<CfgNode *>(&cfg2), -1, + show_def, hide_secret); +} + diff --git a/src/cnode/cnode-algorithm.hpp b/src/cnode/cnode-algorithm.hpp new file mode 100644 index 0000000..86bce81 --- /dev/null +++ b/src/cnode/cnode-algorithm.hpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 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_ALGORITHM_HPP_ +#define _CNODE_ALGORITHM_HPP_ + +#include <cnode/cnode.hpp> + +namespace cnode { + +void show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def, + bool hide_secret); + +} // namespace cnode + +#endif /* _CNODE_ALGORITHM_HPP_ */ + diff --git a/src/cnode/cnode.cpp b/src/cnode/cnode.cpp new file mode 100644 index 0000000..d1f519e --- /dev/null +++ b/src/cnode/cnode.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2010 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/>. + */ + +#include <cstdio> +#include <cstring> +#include <vector> +#include <string> +#include <algorithm> + +#include <cli_cstore.h> +#include <cnode/cnode.hpp> + +using namespace std; +using namespace cnode; + +////// constructors/destructors +CfgNode::CfgNode(Cstore& cstore, vector<string>& path_comps, + bool active, bool recursive) + : _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) +{ + /* 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) { + vtw_def def; + if (cstore.validateTmplPath(path_comps, false, def)) { + // got the def + _is_value = def.is_value; + _is_tag = (def.tag && !_is_value); + _is_leaf = (!_is_tag && !_is_value && def.def_type != ERROR_TYPE); + _is_multi = (_is_leaf && def.multi); + _is_default = cstore.cfgPathDefault(path_comps, active); + _is_deactivated = cstore.cfgPathDeactivated(path_comps, active); + cstore.cfgPathGetComment(path_comps, _comment, active); + + if (_is_leaf && _is_value) { + /* recursion should never reach here. if path is specified by user, + * nothing further to do. + */ + return; + } + } else { + // not a valid node + _is_invalid = true; + return; + } + } + + // handle leaf node (note path_comps must be non-empty if this is leaf) + if (_is_leaf) { + _name = path_comps[path_comps.size() - 1]; + if (_is_multi) { + // multi-value node + cstore.cfgPathGetValuesDA(path_comps, _values, active, true); + // ignore return value + } else { + // single-value node + cstore.cfgPathGetValueDA(path_comps, _value, active, true); + // ignore return value + } + return; + } + + // handle intermediate (typeless) or tag + if (_is_value) { + // tag value + _name = path_comps[path_comps.size() - 2]; + _value = path_comps[path_comps.size() - 1]; + } else { + // tag node or typeless node + _name = (path_comps.size() > 0 ? path_comps[path_comps.size() - 1] : ""); + } + + // check child nodes + vector<string> cnodes; + cstore.cfgPathGetChildNodesDA(path_comps, cnodes, active, true); + if (cnodes.size() == 0) { + // empty subtree. done. + vector<string> tcnodes; + cstore.tmplGetChildNodes(path_comps, tcnodes); + if (tcnodes.size() == 0) { + // typeless leaf node + _is_leaf_typeless = true; + } + _is_empty = true; + return; + } + + if (!recursive) { + // nothing further to do + return; + } + + // recurse + for (size_t i = 0; i < cnodes.size(); i++) { + path_comps.push_back(cnodes[i]); + CfgNode *cn = new CfgNode(cstore, path_comps, active, recursive); + if (_is_tag && !_is_value) { + // tag node + _tag_values.push_back(cn); + } else { + // intermediate node or tag value + _child_nodes.push_back(cn); + } + path_comps.pop_back(); + } +} + diff --git a/src/cnode/cnode.hpp b/src/cnode/cnode.hpp new file mode 100644 index 0000000..3143370 --- /dev/null +++ b/src/cnode/cnode.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 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_HPP_ +#define _CNODE_HPP_ +#include <vector> +#include <string> + +#include <cstore/cstore.hpp> + +namespace cnode { + +class CfgNode { +public: + CfgNode(Cstore& cstore, std::vector<string>& path_comps, + bool active = false, bool recursive = true); + ~CfgNode() {}; + + bool isTag() const { return _is_tag; } + bool isLeaf() const { return _is_leaf; } + bool isMulti() const { return _is_multi; } + bool isValue() const { return _is_value; } + bool isDefault() const { return _is_default; } + 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; } + + 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; } + const std::vector<CfgNode *>& getTagValues() const { return _tag_values; } + const std::vector<CfgNode *>& getChildNodes() const { return _child_nodes; } + +private: + bool _is_tag; + bool _is_leaf; + bool _is_multi; + bool _is_value; + bool _is_default; + bool _is_deactivated; + bool _is_leaf_typeless; + bool _is_invalid; + bool _is_empty; + std::string _name; + std::string _value; + std::vector<std::string> _values; + std::string _comment; + std::vector<CfgNode *> _tag_values; + std::vector<CfgNode *> _child_nodes; +}; + +} // namespace cnode + +#endif /* _CNODE_HPP_ */ + diff --git a/src/cstore/cstore.hpp b/src/cstore/cstore.hpp index c7f179b..267dabe 100644 --- a/src/cstore/cstore.hpp +++ b/src/cstore/cstore.hpp @@ -78,6 +78,14 @@ public: static const size_t MAX_CMD_OUTPUT_SIZE = 4096; + // for sorting + /* apparently unordered_map template does not work with "enum" type, so + * change this to simply unsigned ints to allow unifying all map types, + * i.e., "Cstore::MapT". + */ + static const unsigned int SORT_DEFAULT; + static const unsigned int SORT_DEB_VERSION; + static const unsigned int SORT_NONE; ////// the public cstore interface //// functions implemented in this base class @@ -273,6 +281,11 @@ public: get_child_nodes_status_da(path_comps, cmap, &sorted_keys); }; + // util functions + static void sortNodes(vector<string>& nvec, + unsigned int sort_alg = SORT_DEFAULT) { + sort_nodes(nvec, sort_alg); + }; /* these are internal API functions and operate on current cfg and * tmpl paths during cstore operations. they are only used to work around @@ -377,18 +390,12 @@ private: ////// implemented // for sorting - /* apparently unordered_map template does not work with "enum" type, so - * change this to simply unsigned ints to allow unifying all map types, - * i.e., "Cstore::MapT". - */ - static const unsigned int SORT_DEFAULT; - static const unsigned int SORT_DEB_VERSION; - static const unsigned int SORT_NONE; typedef bool (*SortFuncT)(std::string, std::string); static MapT<unsigned int, SortFuncT> _sort_func_map; static bool sort_func_deb_version(string a, string b); - void sort_nodes(vector<string>& nvec, unsigned int sort_alg = SORT_DEFAULT); + static void sort_nodes(vector<string>& nvec, + unsigned int sort_alg = SORT_DEFAULT); // init static bool _init; |