/* * 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 . */ #include #include #include #include #include #include #include #include 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) : TreeNode(), _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), _exists(true) { if (name && name[0]) { // name must be non-empty path_comps.push(name); } if (val) { // value could be empty path_comps.push(val); } while (1) { if (path_comps.size() == 0) { // nothing to do for root node break; } setTmpl(cstore->parseTmpl(path_comps, false)); if (getTmpl().get()) { // got the def _is_tag = getTmpl()->isTag(); _is_leaf = (!_is_tag && !getTmpl()->isTypeless()); // match constructor from cstore (leaf node never _is_value) _is_value = (getTmpl()->isValue() && !_is_leaf); _is_multi = getTmpl()->isMulti(); /* XXX given the current definition of "default" (i.e., the * "post-bug 1219" definition), the concept of "default" doesn't * really apply to config files. however, if in the future we * do go back to the original, simpler definition of "default" * (which IMO is the right thing to do), the "default handling" * here and elsewhere in the backend library will need to be * revamped. * * in fact, in that case pretty much the only place that need to * worry about "default" is in the "output" (i.e., "show") * processing, and even there the only thing that needs to be * done is to compare the current value with the "default value" * in the template. */ _is_default = false; _is_deactivated = deact; vector tcnodes; cstore->tmplGetChildNodes(path_comps, tcnodes); if (tcnodes.size() == 0) { // typeless leaf node _is_leaf_typeless = true; } if (comment) { _comment = comment; } // ignore return } else { // not a valid node _is_invalid = true; if (tag_if_invalid) { /* this is only used when the parser is creating a "tag node". force * the node to be tag since we don't have template for invalid node. */ _is_tag = true; } if (val) { /* if parser got value for the invalid node, always treat it as * "tag value" for simplicity. */ _is_tag = true; _is_value = true; } break; } break; } // restore path_comps. also set value/name for both valid and invalid nodes. if (val) { if (_is_multi) { _values.push_back(val); } else { _value = val; } path_comps.pop(); } if (name && name[0]) { _name = name; path_comps.pop(); } } // for active/working config CfgNode::CfgNode(Cstore& cstore, Cpath& path_comps, bool active, bool recursive) : TreeNode(), _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), _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) { setTmpl(cstore.parseTmpl(path_comps, false)); if (getTmpl().get()) { // got the def if (!cstore.cfgPathExists(path_comps, active)) { // path doesn't exist _exists = false; return; } _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); // ignore return if (_is_leaf && _is_value) { /* "leaf value" so 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 cnodes; cstore.cfgPathGetChildNodesDA(path_comps, cnodes, active, true); if (cnodes.size() == 0) { // empty subtree. done. vector tcnodes; cstore.tmplGetChildNodes(path_comps, tcnodes); if (tcnodes.size() == 0) { // typeless leaf node _is_leaf_typeless = true; } return; } if (!recursive) { // nothing further to do return; } // recurse for (size_t i = 0; i < cnodes.size(); i++) { path_comps.push(cnodes[i]); CfgNode *cn = new CfgNode(cstore, path_comps, active, recursive); addChildNode(cn); path_comps.pop(); } }