diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2010-07-28 14:30:32 -0700 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2010-07-28 14:30:32 -0700 |
commit | 639c835bc2730a4fbffd915f5b2028a68375ee7a (patch) | |
tree | 203d61e1d5e8ef422d6aba3851d2f83a1f838b6b /src/cstore/cstore-varref.cpp | |
parent | 0247864ef578ac05bbac8dc5175e674ce7b82714 (diff) | |
download | vyatta-cfg-639c835bc2730a4fbffd915f5b2028a68375ee7a.tar.gz vyatta-cfg-639c835bc2730a4fbffd915f5b2028a68375ee7a.zip |
add new cstore library
Diffstat (limited to 'src/cstore/cstore-varref.cpp')
-rw-r--r-- | src/cstore/cstore-varref.cpp | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/src/cstore/cstore-varref.cpp b/src/cstore/cstore-varref.cpp new file mode 100644 index 0000000..6d71307 --- /dev/null +++ b/src/cstore/cstore-varref.cpp @@ -0,0 +1,288 @@ +/* + * 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 <vector> +#include <string> +#include <algorithm> + +#include "cstore-varref.hpp" + +extern "C" { +#include "cli_val.h" +#include "cli_objects.h" +} + +using namespace std; + +////// constructors/destructors +Cstore::VarRef::VarRef(Cstore *cstore, const string& ref_str, bool active) + : _cstore(cstore), _active(active) +{ + /* NOTE: this class will change the paths in the cstore. caller must do + * save/restore for the cstore if necessary. + */ + if (!_cstore) { + // no cstore + return; + } + + _absolute = (ref_str[0] == '/'); + while (!_absolute && !_cstore->cfg_path_at_root()) { + _orig_path_comps.insert(_orig_path_comps.begin(), + _cstore->pop_cfg_path()); + } + _cstore->reset_paths(); + /* at this point, cstore paths are at root. _orig_path_comps contains + * the path originally in cstore (or empty if _absolute). + */ + + size_t si = (_absolute ? 1 : 0); + size_t sn = 0; + vector<string> rcomps; + while (si < ref_str.length() + && (sn = ref_str.find('/', si)) != ref_str.npos) { + rcomps.push_back(ref_str.substr(si, sn - si)); + si = sn + 1; + } + if (si < ref_str.length()) { + rcomps.push_back(ref_str.substr(si)); + } + // NOTE: if path ends in '/', the trailing slash is ignored. + + // get the "at" string. this is set inside cli_new.c. + _at_string = get_at_string(); + + // process ref + vector<string> pcomps = _orig_path_comps; + process_ref(rcomps, pcomps, ERROR_TYPE); +} + +/* process the reference(s). + * this is a recursive function and always keeps the cstore paths unchanged + * between invocations. + * + * note: def_type is added into _paths along with the paths. when it's + * ERROR_TYPE, it means the path needs to be checked for existence. + * otherwise, the path is a "value" (or "values") read from the + * actual config (working or active). + */ +void +Cstore::VarRef::process_ref(const vector<string>& ref_comps, + const vector<string>& cur_path_comps, + vtw_type_e def_type) +{ + if (ref_comps.size() == 0) { + // done + _paths.push_back(pair<vector<string>, + vtw_type_e>(cur_path_comps, def_type)); + return; + } + + vector<string> rcomps = ref_comps; + vector<string> pcomps = cur_path_comps; + string cr_comp= rcomps.front(); + rcomps.erase(rcomps.begin()); + + vtw_def def; + bool got_tmpl = _cstore->get_parsed_tmpl(pcomps, false, def); + bool handle_leaf = false; + if (cr_comp == "@") { + if (!got_tmpl) { + // invalid path + return; + } + if (def.def_type == ERROR_TYPE) { + // no value for typeless node + return; + } + if (pcomps.size() == _orig_path_comps.size()) { + if (pcomps.size() == 0 + || equal(pcomps.begin(), pcomps.end(), _orig_path_comps.begin())) { + /* we are at the original path. this is a self-reference, e.g., + * $VAR(@), so use the "at string". + */ + pcomps.push_back(_at_string); + process_ref(rcomps, pcomps, def.def_type); + return; + } + } + if (pcomps.size() < _orig_path_comps.size()) { + // within the original path. @ translates to the path comp. + pcomps.push_back(_orig_path_comps[pcomps.size()]); + process_ref(rcomps, pcomps, def.def_type); + return; + } + if (def.is_value || def.tag) { + // invalid ref + return; + } + // handle leaf node + handle_leaf = true; + } else if (cr_comp == ".") { + process_ref(rcomps, pcomps, ERROR_TYPE); + } else if (cr_comp == "..") { + if (!got_tmpl || pcomps.size() == 0) { + // invalid path + return; + } + pcomps.pop_back(); + if (!_cstore->get_parsed_tmpl(pcomps, false, def)) { + // invalid tmpl path + return; + } + if (def.is_value && def.tag) { + // at "tag value", need to pop one more. + if (pcomps.size() == 0) { + // invalid path + return; + } + pcomps.pop_back(); + } + process_ref(rcomps, pcomps, ERROR_TYPE); + } else if (cr_comp == "@@") { + if (!got_tmpl) { + // invalid path + return; + } + if (def.def_type == ERROR_TYPE) { + // no value for typeless node + return; + } + if (def.is_value) { + // invalid ref + return; + } + if (def.tag) { + // tag node + vector<string> cnodes; + _cstore->cfgPathGetChildNodes(pcomps, cnodes, _active); + for (unsigned int i = 0; i < cnodes.size(); i++) { + pcomps.push_back(cnodes[i]); + process_ref(rcomps, pcomps, def.def_type); + pcomps.pop_back(); + } + } else { + // handle leaf node + handle_leaf = true; + } + } else { + // just text. go down 1 level. + if (got_tmpl && def.tag && !def.is_value) { + // at "tag node". need to go down 1 more level. + if (pcomps.size() >= _orig_path_comps.size()) { + // already under the original node. invalid ref. + return; + } + // within the original path. take the original tag value. + pcomps.push_back(_orig_path_comps[pcomps.size()]); + } + pcomps.push_back(cr_comp); + process_ref(rcomps, pcomps, ERROR_TYPE); + } + + if (handle_leaf) { + if (def.multi) { + // multi-value node + vector<string> vals; + if (!_cstore->cfgPathGetValues(pcomps, vals, _active)) { + return; + } + string val; + for (unsigned int i = 0; i < vals.size(); i++) { + if (val.length() > 0) { + val += " "; + } + val += vals[i]; + } + pcomps.push_back(val); + // treat "joined" multi-values as TEXT_TYPE + _paths.push_back(pair<vector<string>, vtw_type_e>(pcomps, TEXT_TYPE)); + // at leaf. stop recursion. + } else { + // single-value node + string val; + if (!_cstore->cfgPathGetValue(pcomps, val, _active)) { + return; + } + pcomps.push_back(val); + _paths.push_back(pair<vector<string>, vtw_type_e>(pcomps, def.def_type)); + // at leaf. stop recursion. + } + } +} + +bool +Cstore::VarRef::getValue(string& value, vtw_type_e& def_type) +{ + vector<string> result; + map<string, bool> added; + def_type = ERROR_TYPE; + for (unsigned int i = 0; i < _paths.size(); i++) { + if (_paths[i].first.size() == 0) { + // empty path + continue; + } + if (added.find(_paths[i].first.back()) != added.end()) { + // already added + continue; + } + if (_paths[i].second == ERROR_TYPE + && !_cstore->cfgPathExists(_paths[i].first, _active)) { + // path doesn't exist + continue; + } + if (_paths[i].second != ERROR_TYPE) { + // set def_type. all types should be the same if multiple entries exist. + def_type = _paths[i].second; + } + added[_paths[i].first.back()] = true; + result.push_back(_paths[i].first.back()); + } + if (result.size() == 0) { + // got nothing + return false; + } + if (result.size() > 1 || def_type == ERROR_TYPE) { + /* if no type is available or we are returning "joined" multiple values, + * treat it as text type. + */ + def_type = TEXT_TYPE; + } + value = ""; + for (unsigned int i = 0; i < result.size(); i++) { + if (i > 0) { + value += " "; + } + value += result[i]; + } + return true; +} + +bool +Cstore::VarRef::getSetPath(vector<string>& path_comps) +{ + /* XXX this function is currently unused and untested. see setVarRef() + * in Cstore for more information. + */ + if (_paths.size() != 1) { + // for set_var_ref operation, there can be only one path. + return false; + } + path_comps = _paths[0].first; + return true; +} + |