summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2011-02-28 18:25:01 -0800
committerAn-Cheng Huang <ancheng@vyatta.com>2011-02-28 18:25:01 -0800
commit24b3de8987f622b349cbe14dca99594f2c279902 (patch)
tree32d2b36144872943726b00ea63c274c0f7107933
parent2d0d7bc61e12779a56272f82bc66044a5580e778 (diff)
downloadvyatta-cfg-24b3de8987f622b349cbe14dca99594f2c279902.tar.gz
vyatta-cfg-24b3de8987f622b349cbe14dca99594f2c279902.zip
add config template abstraction
-rw-r--r--Makefile.am2
-rw-r--r--src/cli_bin.cpp12
-rw-r--r--src/cli_cstore.h2
-rw-r--r--src/cli_new.c14
-rw-r--r--src/cli_val.h2
-rw-r--r--src/cnode/cnode.cpp25
-rw-r--r--src/cstore/cstore-c.cpp13
-rw-r--r--src/cstore/cstore-c.h3
-rw-r--r--src/cstore/cstore-varref.cpp32
-rw-r--r--src/cstore/cstore.cpp503
-rw-r--r--src/cstore/cstore.hpp36
-rw-r--r--src/cstore/ctemplate.hpp126
-rw-r--r--src/cstore/unionfs/cstore-unionfs.cpp30
-rw-r--r--src/cstore/unionfs/cstore-unionfs.hpp6
14 files changed, 446 insertions, 360 deletions
diff --git a/Makefile.am b/Makefile.am
index ff384cb..3cd5fde 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,6 +57,8 @@ vinclude_HEADERS = src/cli_cstore.h
vcincdir = $(vincludedir)/cstore
vcinc_HEADERS = src/cstore/cstore-c.h
vcinc_HEADERS += src/cstore/cstore.hpp
+vcinc_HEADERS += src/cstore/cstore-varref.hpp
+vcinc_HEADERS += src/cstore/ctemplate.hpp
vcuincdir = $(vcincdir)/unionfs
vcuinc_HEADERS = src/cstore/unionfs/cstore-unionfs.hpp
diff --git a/src/cli_bin.cpp b/src/cli_bin.cpp
index 11c63a1..20da924 100644
--- a/src/cli_bin.cpp
+++ b/src/cli_bin.cpp
@@ -93,11 +93,7 @@ doSet(Cstore& cstore, const vector<string>& path_comps)
static void
doDelete(Cstore& cstore, const vector<string>& path_comps)
{
- vtw_def def;
- if (!cstore.validateDeletePath(path_comps, def)) {
- bye("invalid delete path");
- }
- if (!cstore.deleteCfgPath(path_comps, def)) {
+ if (!cstore.deleteCfgPath(path_comps)) {
bye("delete failed\n");
}
}
@@ -149,11 +145,7 @@ doCopy(Cstore& cstore, const vector<string>& path_comps)
static void
doComment(Cstore& cstore, const vector<string>& path_comps)
{
- vtw_def def;
- if (!cstore.validateCommentArgs(path_comps, def)) {
- bye("invalid comment args\n");
- }
- if (!cstore.commentCfgPath(path_comps, def)) {
+ if (!cstore.commentCfgPath(path_comps)) {
bye("comment cfg path failed\n");
}
}
diff --git a/src/cli_cstore.h b/src/cli_cstore.h
index 54da657..5f0b061 100644
--- a/src/cli_cstore.h
+++ b/src/cli_cstore.h
@@ -133,7 +133,7 @@ const valstruct *get_syntax_self_in_valstruct(vtw_node *vnode);
int get_shell_command_output(const char *cmd, char *buf,
unsigned int buf_size);
int parse_def(vtw_def *defp, const char *path, boolean type_only);
-boolean validate_value(vtw_def *def, char *value);
+boolean validate_value(const vtw_def *def, char *value);
const char *type_to_name(vtw_type_e type);
int initialize_output(const char *op);
void bye(const char *msg, ...) __attribute__((format(printf, 1, 2), noreturn));
diff --git a/src/cli_new.c b/src/cli_new.c
index a5dc082..950eb79 100644
--- a/src/cli_new.c
+++ b/src/cli_new.c
@@ -502,15 +502,16 @@ valstruct str2val(char *cp)
/****************************************************
STATIC FUNCTIONS
****************************************************/
-int char2val_notext(vtw_def *def, int my_type, int my_type2, char *value, valstruct **valp, char *buf);
-int char2val_text(vtw_def *def, char *value, valstruct **valp);
+int char2val_notext(const vtw_def *def, int my_type, int my_type2,
+ char *value, valstruct **valp, char *buf);
+int char2val_text(const vtw_def *def, char *value, valstruct **valp);
/**************************************************
char2val:
convert string into valstruct verifying the type
according to def
****************************************************/
-int char2val(vtw_def *def, char *value, valstruct *valp)
+int char2val(const vtw_def *def, char *value, valstruct *valp)
{
int my_type = def->def_type;
int my_type2 = def->def_type2;
@@ -549,7 +550,8 @@ int char2val(vtw_def *def, char *value, valstruct *valp)
//non-text type processing block
-int char2val_notext(vtw_def *def, int my_type, int my_type2, char *value, valstruct **valpp, char *err_buf)
+int char2val_notext(const vtw_def *def, int my_type, int my_type2,
+ char *value, valstruct **valpp, char *err_buf)
{
valstruct *valp = *valpp;
int token;
@@ -641,7 +643,7 @@ int char2val_notext(vtw_def *def, int my_type, int my_type2, char *value, valstr
return 0;
}
-int char2val_text(vtw_def *def, char *value, valstruct **valpp)
+int char2val_text(const vtw_def *def, char *value, valstruct **valpp)
{
valstruct *valp = *valpp;
char *endp, *cp;
@@ -1867,7 +1869,7 @@ void switch_path(first_seg *segp)
validates value against type and syntax
return TRUE if OK, FALSE otherwise
**************************************************/
-boolean validate_value(vtw_def *def, char *cp)
+boolean validate_value(const vtw_def *def, char *cp)
{
int status;
boolean ret=TRUE;
diff --git a/src/cli_val.h b/src/cli_val.h
index cd19471..a3eb201 100644
--- a/src/cli_val.h
+++ b/src/cli_val.h
@@ -59,7 +59,7 @@ typedef struct {
int print_offset; /* for additional optional output information */
} vtw_path; /* vyatta tree walk */
-extern int char2val(vtw_def *def, char *value, valstruct *valp);
+extern int char2val(const vtw_def *def, char *value, valstruct *valp);
extern int get_value(char **valpp, vtw_path *pathp);
extern vtw_node * make_node(vtw_oper_e oper, vtw_node *left,
vtw_node *right);
diff --git a/src/cnode/cnode.cpp b/src/cnode/cnode.cpp
index c88a495..f484fb1 100644
--- a/src/cnode/cnode.cpp
+++ b/src/cnode/cnode.cpp
@@ -19,6 +19,7 @@
#include <vector>
#include <string>
#include <algorithm>
+#include <memory>
#include <cli_cstore.h>
#include <cnode/cnode.hpp>
@@ -49,15 +50,15 @@ CfgNode::CfgNode(vector<string>& path_comps, char *name, char *val,
break;
}
- vtw_def def;
- if (cstore->validateTmplPath(path_comps, false, def)) {
+ auto_ptr<Ctemplate> def(cstore->parseTmpl(path_comps, false));
+ if (def.get()) {
// got the def
- _is_tag = def.tag;
- _is_leaf = (!def.tag && def.def_type != ERROR_TYPE);
+ _is_tag = def->isTag();
+ _is_leaf = (!_is_tag && !def->isTypeless());
// match constructor from cstore (leaf node never _is_value)
- _is_value = (def.is_value && !_is_leaf);
- _is_multi = def.multi;
+ _is_value = (def->isValue() && !_is_leaf);
+ _is_multi = def->isMulti();
/* XXX given the current definition of "default", the concept of
* "default" doesn't really apply to config files.
@@ -123,8 +124,8 @@ CfgNode::CfgNode(Cstore& cstore, vector<string>& path_comps,
* "root", treat it as an intermediate node.
*/
if (path_comps.size() > 0) {
- vtw_def def;
- if (cstore.validateTmplPath(path_comps, false, def)) {
+ auto_ptr<Ctemplate> def(cstore.parseTmpl(path_comps, false));
+ if (def.get()) {
// got the def
if (!cstore.cfgPathExists(path_comps, active)) {
// path doesn't exist
@@ -132,10 +133,10 @@ CfgNode::CfgNode(Cstore& cstore, vector<string>& path_comps,
return;
}
- _is_value = def.is_value;
- _is_tag = def.tag;
- _is_leaf = (!def.tag && def.def_type != ERROR_TYPE);
- _is_multi = def.multi;
+ _is_value = def->isValue();
+ _is_tag = def->isTag();
+ _is_leaf = (!_is_tag && !def->isTypeless());
+ _is_multi = def->isMulti();
_is_default = cstore.cfgPathDefault(path_comps, active);
_is_deactivated = cstore.cfgPathDeactivated(path_comps, active);
cstore.cfgPathGetComment(path_comps, _comment, active);
diff --git a/src/cstore/cstore-c.cpp b/src/cstore/cstore-c.cpp
index 50828c4..06f0067 100644
--- a/src/cstore/cstore-c.cpp
+++ b/src/cstore/cstore-c.cpp
@@ -60,19 +60,6 @@ cstore_validate_tmpl_path(void *handle, const char *path_comps[],
}
int
-cstore_validate_tmpl_path_d(void *handle, const char *path_comps[],
- int num_comps, int validate_tags, vtw_def *def)
-{
- if (handle) {
- vector<string> vs;
- _get_str_vec(vs, path_comps, num_comps);
- Cstore *cs = (Cstore *) handle;
- return (cs->validateTmplPath(vs, validate_tags, *def) ? 1 : 0);
- }
- return 0;
-}
-
-int
cstore_cfg_path_exists(void *handle, const char *path_comps[], int num_comps)
{
if (handle) {
diff --git a/src/cstore/cstore-c.h b/src/cstore/cstore-c.h
index 4f33672..44f1efd 100644
--- a/src/cstore/cstore-c.h
+++ b/src/cstore/cstore-c.h
@@ -26,9 +26,6 @@ void *cstore_init(void);
void cstore_free(void *handle);
int cstore_validate_tmpl_path(void *handle, const char *path_comps[],
int num_comps, int validate_tags);
-int cstore_validate_tmpl_path_d(void *handle, const char *path_comps[],
- int num_comps, int validate_tags,
- vtw_def *def);
int cstore_cfg_path_exists(void *handle, const char *path_comps[],
int num_comps);
int cstore_cfg_path_deactivated(void *handle, const char *path_comps[],
diff --git a/src/cstore/cstore-varref.cpp b/src/cstore/cstore-varref.cpp
index 79ab56f..2878dd0 100644
--- a/src/cstore/cstore-varref.cpp
+++ b/src/cstore/cstore-varref.cpp
@@ -93,15 +93,15 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
string cr_comp= rcomps.front();
rcomps.erase(rcomps.begin());
- vtw_def def;
- bool got_tmpl = _cstore->get_parsed_tmpl(pcomps, false, def);
+ auto_ptr<Ctemplate> def(_cstore->parseTmpl(pcomps, false));
+ bool got_tmpl = (def.get() != 0);
bool handle_leaf = false;
if (cr_comp == "@") {
if (!got_tmpl) {
// invalid path
return;
}
- if (def.def_type == ERROR_TYPE) {
+ if (def->isTypeless()) {
// no value for typeless node
return;
}
@@ -112,17 +112,17 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
* $VAR(@), so use the "at string".
*/
pcomps.push_back(_at_string);
- process_ref(rcomps, pcomps, def.def_type);
+ process_ref(rcomps, pcomps, def->getType(1));
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);
+ process_ref(rcomps, pcomps, def->getType(1));
return;
}
- if (def.is_value || def.tag) {
+ if (def->isValue() || def->isTag()) {
// invalid ref
return;
}
@@ -136,11 +136,12 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
return;
}
pcomps.pop_back();
- if (!_cstore->get_parsed_tmpl(pcomps, false, def)) {
+ def.reset(_cstore->parseTmpl(pcomps, false));
+ if (!def.get()) {
// invalid tmpl path
return;
}
- if (def.is_value && def.tag) {
+ if (def->isTagValue()) {
// at "tag value", need to pop one more.
if (pcomps.size() == 0) {
// invalid path
@@ -154,21 +155,21 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
// invalid path
return;
}
- if (def.def_type == ERROR_TYPE) {
+ if (def->isTypeless()) {
// no value for typeless node
return;
}
- if (def.is_value) {
+ if (def->isValue()) {
// invalid ref
return;
}
- if (def.tag) {
+ if (def->isTag()) {
// tag node
vector<string> cnodes;
_cstore->cfgPathGetChildNodes(pcomps, cnodes, _active);
for (size_t i = 0; i < cnodes.size(); i++) {
pcomps.push_back(cnodes[i]);
- process_ref(rcomps, pcomps, def.def_type);
+ process_ref(rcomps, pcomps, def->getType(1));
pcomps.pop_back();
}
} else {
@@ -177,7 +178,7 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
}
} else {
// just text. go down 1 level.
- if (got_tmpl && def.tag && !def.is_value) {
+ if (got_tmpl && def->isTagNode()) {
// at "tag node". need to go down 1 more level.
if (pcomps.size() >= _orig_path_comps.size()) {
// already under the original node. invalid ref.
@@ -191,7 +192,7 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
}
if (handle_leaf) {
- if (def.multi) {
+ if (def->isMulti()) {
// multi-value node
vector<string> vals;
if (!_cstore->cfgPathGetValues(pcomps, vals, _active)) {
@@ -215,7 +216,8 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps,
return;
}
pcomps.push_back(val);
- _paths.push_back(pair<vector<string>, vtw_type_e>(pcomps, def.def_type));
+ _paths.push_back(pair<vector<string>, vtw_type_e>(pcomps,
+ def->getType(1)));
// at leaf. stop recursion.
}
}
diff --git a/src/cstore/cstore.cpp b/src/cstore/cstore.cpp
index 39c57cd..f32e6ec 100644
--- a/src/cstore/cstore.cpp
+++ b/src/cstore/cstore.cpp
@@ -23,6 +23,7 @@
#include <fcntl.h>
#include <algorithm>
#include <sstream>
+#include <memory>
// for debian's version comparison algorithm
#define APT_COMPATIBILITY 986
@@ -121,22 +122,19 @@ Cstore::createCstore(const string& session_id, string& env)
bool
Cstore::validateTmplPath(const vector<string>& path_comps, bool validate_vals)
{
- vtw_def def;
// if we can get parsed tmpl, path is valid
- return get_parsed_tmpl(path_comps, validate_vals, def);
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, validate_vals));
+ return (def.get() != 0);
}
-/* same as above but return parsed template.
- * def: (output) parsed template.
+/* same as above but return parsed template. return 0 if invalid/failed.
* note: if last path component is "value" (i.e., def.is_value), parsed
* template is actually at "full path - 1". see get_parsed_tmpl() for details.
*/
-bool
-Cstore::validateTmplPath(const vector<string>& path_comps, bool validate_vals,
- vtw_def& def)
+Ctemplate *
+Cstore::parseTmpl(const vector<string>& path_comps, bool validate_vals)
{
- // if we can get parsed tmpl, path is valid
- return get_parsed_tmpl(path_comps, validate_vals, def);
+ return get_parsed_tmpl(path_comps, validate_vals);
}
/* get parsed template of specified path as a string-string map
@@ -147,7 +145,6 @@ bool
Cstore::getParsedTmpl(const vector<string>& path_comps,
Cstore::MapT<string, string>& tmap, bool allow_val)
{
- vtw_def def;
/* currently this function is used outside actual CLI operations, mainly
* from the perl API. since value validation is from the original CLI
* implementation, it doesn't seem to behave correctly in such cases,
@@ -155,54 +152,55 @@ Cstore::getParsedTmpl(const vector<string>& path_comps,
*
* anyway, not validating values in the following call.
*/
- if (!get_parsed_tmpl(path_comps, false, def)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false));
+ if (!def.get()) {
return false;
}
- if (!allow_val && def.is_value) {
+ if (!allow_val && def->isValue()) {
/* note: !allow_val means specified path must terminate at an actual
* "node", not a "value". so this fails since path ends in value.
* this emulates the original perl API behavior.
*/
return false;
}
- if (def.is_value) {
+ if (def->isValue()) {
tmap["is_value"] = "1";
}
// make the map
- if (def.def_type != ERROR_TYPE) {
- tmap["type"] = type_to_name(def.def_type);
+ if (!def->isTypeless(1)) {
+ tmap["type"] = def->getTypeName(1);
}
- if (def.def_type2 != ERROR_TYPE) {
- tmap["type2"] = type_to_name(def.def_type2);
+ if (!def->isTypeless(2)) {
+ tmap["type2"] = def->getTypeName(2);
}
- if (def.def_node_help) {
- tmap["help"] = def.def_node_help;
+ if (def->getNodeHelp()) {
+ tmap["help"] = def->getNodeHelp();
}
- if (def.multi) {
+ if (def->isMulti()) {
tmap["multi"] = "1";
- if (def.def_multi > 0) {
+ if (def->getMultiLimit() > 0) {
ostringstream s;
- s << def.def_multi;
+ s << def->getMultiLimit();
tmap["limit"] = s.str();
}
- } else if (def.tag) {
+ } else if (def->isTag()) {
tmap["tag"] = "1";
- if (def.def_tag > 0) {
+ if (def->getTagLimit() > 0) {
ostringstream s;
- s << def.def_tag;
+ s << def->getTagLimit();
tmap["limit"] = s.str();
}
- } else if (def.def_default) {
- tmap["default"] = def.def_default;
+ } else if (def->getDefault()) {
+ tmap["default"] = def->getDefault();
}
- if (def.def_enumeration) {
- tmap["enum"] = def.def_enumeration;
+ if (def->getEnumeration()) {
+ tmap["enum"] = def->getEnumeration();
}
- if (def.def_allowed) {
- tmap["allowed"] = def.def_allowed;
+ if (def->getAllowed()) {
+ tmap["allowed"] = def->getAllowed();
}
- if (def.def_val_help) {
- tmap["val_help"] = def.def_val_help;
+ if (def->getValHelp()) {
+ tmap["val_help"] = def->getValHelp();
}
return true;
}
@@ -223,19 +221,23 @@ Cstore::tmplGetChildNodes(const vector<string>& path_comps,
}
/* delete specified "logical path" from "working config".
- * def: parsed template corresponding to logical path path_comps.
* return true if successful. otherwise return false.
- * note: assume specified path has been validated
- * (i.e., validateDeletePath()).
*/
bool
-Cstore::deleteCfgPath(const vector<string>& path_comps, const vtw_def& def)
+Cstore::deleteCfgPath(const vector<string>& path_comps)
{
ASSERT_IN_SESSION;
+ string terr;
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr));
+ if (!def.get()) {
+ output_user("%s\n", terr.c_str());
+ return false;
+ }
+
if (!cfg_path_exists(path_comps, false, true)) {
output_user("Nothing to delete (the specified %s does not exist)\n",
- (!def.is_value || def.tag) ? "node" : "value");
+ (!def->isValue() || def->isTag()) ? "node" : "value");
// treat as success
return true;
}
@@ -247,11 +249,11 @@ Cstore::deleteCfgPath(const vector<string>& path_comps, const vtw_def& def)
* 2. no default value
* => remove config path
*/
- if (def.def_default) {
+ if (def->getDefault()) {
// case 1. construct path for value file.
SAVE_PATHS;
append_cfg_path(path_comps);
- if (def.is_value) {
+ if (def->isValue()) {
// last comp is "value". need to go up 1 level.
pop_cfg_path();
}
@@ -261,7 +263,7 @@ Cstore::deleteCfgPath(const vector<string>& path_comps, const vtw_def& def)
* also deactivated. note that unmark_deactivated() succeeds if it's
* not marked deactivated. also mark "changed".
*/
- bool ret = (write_value(def.def_default) && mark_display_default()
+ bool ret = (write_value(def->getDefault()) && mark_display_default()
&& unmark_deactivated() && mark_changed_with_ancestors());
if (!ret) {
output_user("Failed to set default value during delete\n");
@@ -287,15 +289,15 @@ Cstore::deleteCfgPath(const vector<string>& path_comps, const vtw_def& def)
bool ret = false;
SAVE_PATHS;
append_cfg_path(path_comps);
- if (!def.is_value) {
+ if (!def->isValue()) {
// sub-case (2)
ret = remove_node();
} else {
// last comp is value
- if (def.tag) {
+ if (def->isTag()) {
// sub-case (1c)
ret = remove_tag();
- } else if (def.multi) {
+ } else if (def->isMulti()) {
// sub-case (1b)
pop_cfg_path();
ret = remove_value_from_multi(path_comps[path_comps.size() - 1]);
@@ -325,17 +327,17 @@ Cstore::validateSetPath(const vector<string>& path_comps)
ASSERT_IN_SESSION;
// if we can get parsed tmpl, path is valid
- vtw_def def;
string terr;
- if (!get_parsed_tmpl(path_comps, true, def, terr)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, true, terr));
+ if (!def.get()) {
output_user("%s\n", terr.c_str());
return false;
}
bool ret = true;
SAVE_PATHS;
- if (!def.is_value) {
- if (def.def_type != ERROR_TYPE) {
+ if (!def->isValue()) {
+ if (!def->isTypeless()) {
/* disallow setting value node without value
* note: different from old behavior, which only disallow setting a
* single-value node without value. now all value nodes
@@ -353,7 +355,7 @@ Cstore::validateSetPath(const vector<string>& path_comps)
*/
append_cfg_path(path_comps);
append_tmpl_path(path_comps);
- if (!validate_val(&def, "")) {
+ if (!validate_val(def.get(), "")) {
ret = false;
}
}
@@ -362,22 +364,6 @@ Cstore::validateSetPath(const vector<string>& path_comps)
return ret;
}
-/* check if specified "logical path" is valid for "delete" operation
- * return true if valid. otherwise return false.
- */
-bool
-Cstore::validateDeletePath(const vector<string>& path_comps, vtw_def& def)
-{
- ASSERT_IN_SESSION;
-
- string terr;
- if (!get_parsed_tmpl(path_comps, false, def, terr)) {
- output_user("%s\n", terr.c_str());
- return false;
- }
- return true;
-}
-
/* check if specified "logical path" is valid for "activate" operation
* return true if valid. otherwise return false.
*/
@@ -386,8 +372,8 @@ Cstore::validateActivatePath(const vector<string>& path_comps)
{
ASSERT_IN_SESSION;
- vtw_def def;
- if (!validate_act_deact(path_comps, "activate", def)) {
+ auto_ptr<Ctemplate> def(validate_act_deact(path_comps, "activate"));
+ if (!def.get()) {
return false;
}
if (!cfgPathMarkedDeactivated(path_comps)) {
@@ -396,7 +382,7 @@ Cstore::validateActivatePath(const vector<string>& path_comps)
return false;
}
bool ret = true;
- if (def.is_value && def.tag && def.def_tag > 0) {
+ if (def->isTagValue() && def->getTagLimit() > 0) {
// we are activating a tag, and there is a limit on number of tags.
vector<string> cnodes;
SAVE_PATHS;
@@ -404,10 +390,10 @@ Cstore::validateActivatePath(const vector<string>& path_comps)
string t = pop_cfg_path();
// get child nodes, excluding deactivated ones.
get_all_child_node_names(cnodes, false, false);
- if (def.def_tag <= cnodes.size()) {
+ if (def->getTagLimit() <= cnodes.size()) {
// limit exceeded
output_user("Cannot activate \"%s\": number of values exceeds limit "
- "(%d allowed)\n", t.c_str(), def.def_tag);
+ "(%d allowed)\n", t.c_str(), def->getTagLimit());
ret = false;
}
RESTORE_PATHS;
@@ -423,8 +409,8 @@ Cstore::validateDeactivatePath(const vector<string>& path_comps)
{
ASSERT_IN_SESSION;
- vtw_def def;
- return validate_act_deact(path_comps, "deactivate", def);
+ auto_ptr<Ctemplate> def(validate_act_deact(path_comps, "deactivate"));
+ return (def.get() != 0);
}
/* check if specified "logical path" is valid for "edit" operation.
@@ -437,9 +423,9 @@ Cstore::getEditEnv(const vector<string>& path_comps, string& env)
{
ASSERT_IN_SESSION;
- vtw_def def;
string terr;
- if (!get_parsed_tmpl(path_comps, false, def, terr)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr));
+ if (!def.get()) {
output_user("%s\n", terr.c_str());
return false;
}
@@ -448,8 +434,7 @@ Cstore::getEditEnv(const vector<string>& path_comps, string& env)
* OR
* (2) "typeless node"
*/
- if (!(def.is_value && def.tag)
- && !(!def.is_value && def.def_type == ERROR_TYPE)) {
+ if (!def->isTagValue() && !def->isTypeless()) {
// neither "tag value" nor "typeless node"
output_user("The \"edit\" command cannot be issued "
"at the specified level\n");
@@ -502,19 +487,16 @@ Cstore::getEditUpEnv(string& env)
return false;
}
- /* get_parsed_tmpl() does not allow empty path, so use one component
- * from current paths.
- */
- vtw_def def;
string terr;
vector<string> path_comps;
- if (!get_parsed_tmpl(path_comps, false, def, terr)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr));
+ if (!def.get()) {
// this should not happen since it's using existing levels
output_user("%s\n", terr.c_str());
return false;
}
SAVE_PATHS;
- if (def.is_value && def.tag) {
+ if (def->isTagValue()) {
// edit level is at "tag value". go up 1 extra level.
pop_cfg_path();
pop_tmpl_path();
@@ -574,9 +556,13 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
bool ret = false;
SAVE_PATHS;
do {
- vtw_def def;
+ bool is_typeless = true;
+ bool is_leaf_value = false;
+ bool is_value = false;
+ auto_ptr<Ctemplate> def;
if (pcomps.size() > 0) {
- if (!get_parsed_tmpl(pcomps, false, def)) {
+ def.reset(get_parsed_tmpl(pcomps, false));
+ if (!def.get()) {
// invalid path
break;
}
@@ -586,16 +572,20 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
}
append_cfg_path(pcomps);
append_tmpl_path(pcomps);
+ is_typeless = def->isTypeless();
+ is_leaf_value = def->isLeafValue();
+ is_value = def->isValue();
} else {
- // we are at root. simulate a typeless node.
- def.def_type = ERROR_TYPE;
- def.tag = def.multi = def.is_value = 0;
+ /* we are at root. default values simulate a typeless node so nop.
+ * note that in this case def is "empty", so must ensure that it's
+ * not used.
+ */
}
/* at this point, cfg and tmpl paths are constructed up to the comp
* before last_comp, and def is parsed.
*/
- if (def.is_value && !def.tag) {
+ if (is_leaf_value) {
// invalid path (this means the comp before last_comp is a leaf value)
break;
}
@@ -605,7 +595,7 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
string comp_help;
vector<pair<string, string> > help_pairs;
bool last_comp_val = true;
- if (def.def_type == ERROR_TYPE || def.is_value) {
+ if (is_typeless || is_value) {
/* path so far is at a typeless node OR a tag value (tag already
* checked above):
* completions: from tmpl children.
@@ -615,6 +605,9 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
*
* note: for such completions, we filter non-existent nodes if
* necessary.
+ *
+ * also, the "root" node case above will reach this block, so
+ * must not use def in this block.
*/
vector<string> ufvec;
if (exists_only) {
@@ -638,9 +631,9 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
for (size_t i = 0; i < comp_vals.size(); i++) {
pair<string, string> hpair(comp_vals[i], "");
push_tmpl_path(hpair.first);
- vtw_def cdef;
- if (tmpl_parse(cdef) && cdef.def_node_help) {
- hpair.second = cdef.def_node_help;
+ auto_ptr<Ctemplate> cdef(tmpl_parse());
+ if (cdef.get() && cdef->getNodeHelp()) {
+ hpair.second = cdef->getNodeHelp();
} else {
hpair.second = "<No help text available>";
}
@@ -653,9 +646,11 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
/* path so far is at a "value node".
* note: follow the original implementation and don't filter
* non-existent values for such completions
+ *
+ * also, cannot be "root" node if we reach here, so def can be used.
*/
// first, handle completions.
- if (def.tag) {
+ if (def->isTag()) {
// it's a "tag node". get completions from tag values.
get_all_child_node_names(comp_vals, false, true);
} else {
@@ -667,7 +662,7 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
* "enumeration"
* "$VAR(@) in ..."
*/
- if (def.def_enumeration || def.def_allowed) {
+ if (def->getEnumeration() || def->getAllowed()) {
/* do "enumeration" or "allowed".
* note: emulate original implementation and set up COMP_WORDS and
* COMP_CWORD environment variables. these are needed by some
@@ -682,10 +677,10 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
cmd_str += (" '" + comps[i] + "'");
}
cmd_str += "); ";
- if (def.def_enumeration) {
- cmd_str += (C_ENUM_SCRIPT_DIR + "/" + def.def_enumeration);
+ if (def->getEnumeration()) {
+ cmd_str += (C_ENUM_SCRIPT_DIR + "/" + def->getEnumeration());
} else {
- string astr = def.def_allowed;
+ string astr = def->getAllowed();
shell_escape_squotes(astr);
cmd_str += "_cstore_internal_allowed () { eval '";
cmd_str += astr;
@@ -711,10 +706,10 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
* shell into an array of values.
*/
free(buf);
- } else if (def.actions[syntax_act].vtw_list_head) {
+ } else if (def->getActions(syntax_act)->vtw_list_head) {
// look for "self ref in values" from syntax
const valstruct *vals = get_syntax_self_in_valstruct(
- def.actions[syntax_act].vtw_list_head);
+ def->getActions(syntax_act)->vtw_list_head);
if (vals) {
if (vals->cnt == 0 && vals->val) {
comp_vals.push_back(vals->val);
@@ -729,23 +724,23 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
}
// now handle help.
- if (def.def_comp_help) {
+ if (def->getCompHelp()) {
// "comp_help" exists.
- comp_help = def.def_comp_help;
+ comp_help = def->getCompHelp();
shell_escape_squotes(comp_help);
}
- if (def.def_val_help) {
+ if (def->getValHelp()) {
// has val_help. first separate individual lines.
size_t start = 0, i = 0;
vector<string> vhelps;
- for (i = 0; def.def_val_help[i]; i++) {
- if (def.def_val_help[i] == '\n') {
- vhelps.push_back(string(&(def.def_val_help[start]), i - start));
+ for (i = 0; (def->getValHelp())[i]; i++) {
+ if ((def->getValHelp())[i] == '\n') {
+ vhelps.push_back(string(&((def->getValHelp())[start]), i - start));
start = i + 1;
}
}
if (start < i) {
- vhelps.push_back(string(&(def.def_val_help[start]), i - start));
+ vhelps.push_back(string(&((def->getValHelp())[start]), i - start));
}
// process each line
@@ -753,15 +748,15 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
size_t sc;
if ((sc = vhelps[i].find(';')) == vhelps[i].npos) {
// no ';'
- if (i == 0 && def.def_type != ERROR_TYPE) {
+ if (i == 0 && !def->isTypeless(1)) {
// first val_help. pair with "type".
help_pairs.push_back(pair<string, string>(
- type_to_name(def.def_type), vhelps[i]));
+ def->getTypeName(1), vhelps[i]));
}
- if (i == 1 && def.def_type2 != ERROR_TYPE) {
- // second val_help. pair with "type2".
+ if (i == 1 && !def->isTypeless(2)) {
+ // second val_help. pair with second "type".
help_pairs.push_back(pair<string, string>(
- type_to_name(def.def_type2), vhelps[i]));
+ def->getTypeName(2), vhelps[i]));
}
} else {
// ';' at index sc
@@ -770,13 +765,17 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env)
vhelps[i].substr(sc + 1)));
}
}
- } else if (def.def_type && def.def_node_help) {
+ } else if (!def->isTypeless(1) && def->getNodeHelp()) {
// simple case. just use "type" and "help"
- help_pairs.push_back(pair<string, string>(type_to_name(def.def_type),
- def.def_node_help));
+ help_pairs.push_back(pair<string, string>(def->getTypeName(1),
+ def->getNodeHelp()));
}
}
+ /* from this point on cannot use def (since the "root" node case
+ * can reach here).
+ */
+
// this var is the array of possible completions
env = (C_ENV_SHAPI_COMP_VALS + "=(");
for (size_t i = 0; i < comp_vals.size(); i++) {
@@ -896,61 +895,6 @@ Cstore::validateMoveArgs(const vector<string>& args)
return ret;
}
-/* check if specified "arguments" is valid for "comment" operation
- * return true if valid. otherwise return false.
- */
-bool
-Cstore::validateCommentArgs(const vector<string>& args, vtw_def& def)
-{
- ASSERT_IN_SESSION;
-
- /* separate path from comment.
- * follow the original implementation: the last arg is the comment, and
- * everything else is part of the path.
- */
- vector<string> path_comps(args);
- string comment = args.back();
- path_comps.pop_back();
-
- // check the path
- string terr;
- if (!get_parsed_tmpl(path_comps, false, def, terr)) {
- output_user("%s\n", terr.c_str());
- return false;
- }
- // here we want to include deactivated nodes
- if (!cfg_path_exists(path_comps, false, true)) {
- output_user("The specified config node does not exist\n");
- return false;
- }
- if (def.is_value && !def.tag) {
- /* XXX differ from the original implementation, which allows commenting
- * on a "value" BUT silently "promote" the comment to the parent
- * "node". this will probably create confusion for the user.
- *
- * just disallow such cases here.
- */
- output_user("Cannot comment on config values\n");
- return false;
- }
- if (def.tag && !def.is_value) {
- /* XXX follow original implementation and disallow comment on a
- * "tag node". this is because "show" does not display such
- * comments (see bug 5794).
- */
- output_user("Cannot add comment at this level\n");
- return false;
- }
- if (comment.find_first_of('*') != string::npos) {
- // don't allow '*'. this is due to config files using C-style /**/
- // comments. this probably belongs to lower-level, but we are enforcing
- // it here.
- output_user("Cannot use the '*' character in a comment\n");
- return false;
- }
- return true;
-}
-
/* perform rename in "working config" according to specified args.
* return true if successful. otherwise return false.
* note: assume args are already validated (i.e., validateRenameArgs()).
@@ -1000,15 +944,56 @@ Cstore::copyCfgPath(const vector<string>& args)
* return true if valid. otherwise return false.
*/
bool
-Cstore::commentCfgPath(const vector<string>& args, const vtw_def& def)
+Cstore::commentCfgPath(const vector<string>& args)
{
ASSERT_IN_SESSION;
- // separate path from comment
+ /* separate path from comment.
+ * follow the original implementation: the last arg is the comment, and
+ * everything else is part of the path.
+ */
vector<string> path_comps(args);
string comment = args.back();
path_comps.pop_back();
+ // check the path
+ string terr;
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr));
+ if (!def.get()) {
+ output_user("%s\n", terr.c_str());
+ return false;
+ }
+ // here we want to include deactivated nodes
+ if (!cfg_path_exists(path_comps, false, true)) {
+ output_user("The specified config node does not exist\n");
+ return false;
+ }
+ if (def->isLeafValue()) {
+ /* XXX differ from the original implementation, which allows commenting
+ * on a "value" BUT silently "promote" the comment to the parent
+ * "node". this will probably create confusion for the user.
+ *
+ * just disallow such cases here.
+ */
+ output_user("Cannot comment on config values\n");
+ return false;
+ }
+ if (def->isTagNode()) {
+ /* XXX follow original implementation and disallow comment on a
+ * "tag node". this is because "show" does not display such
+ * comments (see bug 5794).
+ */
+ output_user("Cannot add comment at this level\n");
+ return false;
+ }
+ if (comment.find_first_of('*') != string::npos) {
+ // don't allow '*'. this is due to config files using C-style /**/
+ // comments. this probably belongs to lower-level, but we are enforcing
+ // it here.
+ output_user("Cannot use the '*' character in a comment\n");
+ return false;
+ }
+
SAVE_PATHS;
append_cfg_path(path_comps);
bool ret;
@@ -1344,8 +1329,8 @@ Cstore::cfgPathGetValueDA(const vector<string>& path_comps, string& value,
ASSERT_IN_SESSION;
}
- vtw_def def;
- if (!get_parsed_tmpl(path_comps, false, def)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false));
+ if (!def.get()) {
// invalid node
return false;
}
@@ -1355,7 +1340,7 @@ Cstore::cfgPathGetValueDA(const vector<string>& path_comps, string& value,
* original API will return a single string that includes all values.
* this new function will return failure in such cases.
*/
- if (def.is_value || def.multi || def.tag || def.def_type == ERROR_TYPE) {
+ if (!def->isSingleLeafNode()) {
// specified path is not a single-value node
return false;
}
@@ -1405,8 +1390,8 @@ Cstore::cfgPathGetValuesDA(const vector<string>& path_comps,
ASSERT_IN_SESSION;
}
- vtw_def def;
- if (!get_parsed_tmpl(path_comps, false, def)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false));
+ if (!def.get()) {
// invalid node
return false;
}
@@ -1416,7 +1401,7 @@ Cstore::cfgPathGetValuesDA(const vector<string>& path_comps,
* original API will return the node's value. this new function
* will return failure in such cases.
*/
- if (def.is_value || !def.multi || def.tag || def.def_type == ERROR_TYPE) {
+ if (!def->isMultiLeafNode()) {
// specified path is not a multi-value node
return false;
}
@@ -1551,8 +1536,8 @@ Cstore::cfgPathDefault(const vector<string>& path_comps, bool active_cfg)
bool
Cstore::cfgPathEffective(const vector<string>& path_comps)
{
- vtw_def def;
- if (!validateTmplPath(path_comps, false, def)) {
+ auto_ptr<Ctemplate> def(parseTmpl(path_comps, false));
+ if (!def.get()) {
// invalid path
return false;
}
@@ -1573,10 +1558,10 @@ Cstore::cfgPathEffective(const vector<string>& path_comps)
append_cfg_path(path_comps);
if (!in_active && in_work) {
// check if case (2)
- ret = marked_committed(def, true);
+ ret = marked_committed(def.get(), true);
} else if (in_active && !in_work) {
// check if case (3)
- ret = !marked_committed(def, false);
+ ret = !marked_committed(def.get(), false);
}
RESTORE_PATHS;
@@ -1765,15 +1750,12 @@ Cstore::setVarRef(const string& ref_str, const string& value, bool to_active)
bool ret = false;
if (vref.getSetPath(pcomps)) {
reset_paths();
- vtw_def def;
- if (get_parsed_tmpl(pcomps, false, def)) {
- if (!def.is_value && !def.tag && !def.multi
- && def.def_type != ERROR_TYPE) {
- // currently only support single-value node
- append_cfg_path(pcomps);
- if (write_value(value, to_active)) {
- ret = true;
- }
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(pcomps, false));
+ if (def.get() && def->isSingleLeafNode()) {
+ // currently only support single-value node
+ append_cfg_path(pcomps);
+ if (write_value(value, to_active)) {
+ ret = true;
}
}
}
@@ -1859,9 +1841,7 @@ Cstore::loadFile(const char *filename)
// "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)) {
+ if (!deleteCfgPath(del_list[i])) {
print_str_vec("Delete [", "] failed\n", del_list[i], "'");
}
}
@@ -1871,9 +1851,7 @@ Cstore::loadFile(const char *filename)
}
}
for (size_t i = 0; i < com_list.size(); i++) {
- vtw_def def;
- if (!validateCommentArgs(com_list[i], def)
- || !commentCfgPath(com_list[i], def)) {
+ if (!commentCfgPath(com_list[i])) {
print_str_vec("Comment [", "] failed\n", com_list[i], "'");
}
}
@@ -2043,23 +2021,23 @@ Cstore::append_tmpl_path(const vector<string>& path_comps, bool& is_tag)
* then template at the path is parsed.
* path_comps: vector of path components.
* validate_vals: whether to validate all "values" along specified path.
- * def: (output) parsed template.
* error: (output) error message if failed.
- * return false if invalid template path. otherwise return true.
+ * return parsed template if successful. otherwise return 0.
* note:
- * also, if last path component is value (i.e., def.is_value), the template
+ * also, if last path component is value (i.e., isValue()), the template
* parsed is actually at "full path - 1".
*/
-bool
+Ctemplate *
Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
- vtw_def& def, string& error)
+ string& error)
{
+ Ctemplate *rtmpl = 0;
// default error message
error = "The specified configuration node is not valid";
if (tmpl_path_at_root() && path_comps.size() == 0) {
// empty path not valid
- return false;
+ return rtmpl;
}
/* note: this function may be invoked recursively (depth 1) when
@@ -2088,7 +2066,6 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
}
}
}
- bool ret = false;
do {
/* cases for template path:
* (1) valid path ending in "actual node", i.e., typeless node, tag node,
@@ -2125,7 +2102,7 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
* pop it.
*/
pop_tmpl_path();
- if (!validate_val(NULL, (*pcomps)[i])) {
+ if (!validate_val(0, (*pcomps)[i])) {
// invalid value
error = "Value validation failed";
valid = false;
@@ -2154,19 +2131,20 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
* we haven't done anything yet.
*/
if (pcomps->size() > 1) {
- if (tmpl_parse(def)) {
- if (def.tag || def.multi || def.def_type != ERROR_TYPE) {
+ auto_ptr<Ctemplate> ttmpl(tmpl_parse());
+ if (ttmpl.get()) {
+ if (ttmpl->isTag() || ttmpl->isMulti() || !ttmpl->isTypeless()) {
// case (2). last component is "value".
if (validate_vals) {
// validate value
- if (!validate_val(&def, (*pcomps)[pcomps->size() - 1])) {
+ if (!validate_val(ttmpl.get(), (*pcomps)[pcomps->size() - 1])) {
// invalid value
error = "Value validation failed";
break;
}
}
- def.is_value = 1;
- ret = true;
+ rtmpl = ttmpl.release();
+ rtmpl->setIsValue(true);
break;
}
}
@@ -2181,12 +2159,11 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
// no need to push cfg path (only needed for validate_val())
if (tmpl_node_exists()) {
// case (1). last component is "node".
- if (!tmpl_parse(def)) {
+ if (!(rtmpl = tmpl_parse())) {
exit_internal("failed to parse tmpl [%s]\n",
tmpl_path_to_str().c_str());
}
- def.is_value = 0;
- ret = true;
+ rtmpl->setIsValue(false);
break;
}
// case (3) (fall through)
@@ -2196,21 +2173,21 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
} else {
restore_paths(not_validating);
}
- return ret;
+ return rtmpl;
}
/* check if specified "logical path" is valid for "activate" or
* "deactivate" operation.
- * return true if valid. otherwise return false.
+ * return parsed template if valid. otherwise return 0.
*/
-bool
-Cstore::validate_act_deact(const vector<string>& path_comps, const string& op,
- vtw_def& def)
+Ctemplate *
+Cstore::validate_act_deact(const vector<string>& path_comps, const string& op)
{
string terr;
- if (!get_parsed_tmpl(path_comps, false, def, terr)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr));
+ if (!def.get()) {
output_user("%s\n", terr.c_str());
- return false;
+ return 0;
}
{
/* XXX this is a temporary workaround for bug 5708, which should be
@@ -2218,24 +2195,25 @@ Cstore::validate_act_deact(const vector<string>& path_comps, const string& op,
* resolved (see bug for more details). once those are resolved,
* this workaround should be removed and the bug fixed properly.
*/
- if (!def.tag && def.def_type != ERROR_TYPE) {
+ if (!def->isTag() && !def->isTypeless()) {
output_user("Cannot %s a leaf configuration node\n", op.c_str());
- return false;
+ return 0;
}
}
- if (def.is_value && !def.tag) {
+ if (def->isLeafValue()) {
/* last component is a value of a single- or multi-value node (i.e.,
* a leaf value) => not allowed
*/
output_user("Cannot %s a leaf configuration value\n", op.c_str());
- return false;
+ return 0;
}
if (!cfg_path_exists(path_comps, false, true)) {
output_user("Nothing to %s (the specified %s does not exist)\n",
- op.c_str(), (!def.is_value || def.tag) ? "node" : "value");
- return false;
+ op.c_str(),
+ (!def->isValue() || def->isTag()) ? "node" : "value");
+ return 0;
}
- return true;
+ return def.release();
}
/* check if specified args is valid for "rename" or "copy" operation.
@@ -2262,13 +2240,13 @@ Cstore::validate_rename_copy(const vector<string>& args, const string& op)
vector<string> ppath;
ppath.push_back(otagnode);
ppath.push_back(otagval);
- vtw_def def;
string terr;
- if (!get_parsed_tmpl(ppath, false, def, terr)) {
+ auto_ptr<Ctemplate> def(get_parsed_tmpl(ppath, false, terr));
+ if (!def.get()) {
output_user("%s\n", terr.c_str());
return false;
}
- if (!def.is_value || !def.tag) {
+ if (!def->isTagValue()) {
// can only rename "tagnode tagvalue"
output_user("Cannot %s under \"%s\"\n", op.c_str(), otagnode.c_str());
return false;
@@ -2287,7 +2265,8 @@ Cstore::validate_rename_copy(const vector<string>& args, const string& op)
ntagnode.c_str(), ntagval.c_str());
return false;
}
- if (!get_parsed_tmpl(ppath, true, def, terr)) {
+ def.reset(get_parsed_tmpl(ppath, true, terr));
+ if (!def.get()) {
output_user("%s\n", terr.c_str());
return false;
}
@@ -2359,7 +2338,7 @@ bool
Cstore::set_cfg_path(const vector<string>& path_comps, bool output)
{
vector<string> ppath;
- vtw_def def;
+ auto_ptr<Ctemplate> def;
bool ret = true;
bool path_exists = true;
// do the set from the top down
@@ -2369,7 +2348,8 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output)
ppath.push_back(path_comps[i]);
// get template at this level
- if (!get_parsed_tmpl(ppath, false, def)) {
+ def.reset(get_parsed_tmpl(ppath, false));
+ if (!def.get()) {
output_internal("paths[%s,%s]\n", cfg_path_to_str().c_str(),
tmpl_path_to_str().c_str());
for (size_t i = 0; i < ppath.size(); i++) {
@@ -2388,16 +2368,16 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output)
append_cfg_path(ppath);
append_tmpl_path(ppath);
- if (!def.is_value) {
+ if (!def->isValue()) {
// this level is a "node"
if (!add_node() || !create_default_children()) {
ret = false;
break;
}
- } else if (def.tag) {
+ } else if (def->isTag()) {
// this level is a "tag value".
// add the tag, taking the max tag limit into consideration.
- if (!add_tag(def) || !create_default_children()) {
+ if (!add_tag(def->getTagLimit()) || !create_default_children()) {
ret = false;
break;
}
@@ -2405,10 +2385,10 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output)
// this level is a "value" of a single-/multi-value node.
// go up 1 level to get the node.
pop_cfg_path();
- if (def.multi) {
+ if (def->isMulti()) {
// value of multi-value node.
// add the value, taking the max multi limit into consideration.
- if (!add_value_to_multi(def, ppath.back())) {
+ if (!add_value_to_multi(def->getMultiLimit(), ppath.back())) {
ret = false;
break;
}
@@ -2428,7 +2408,7 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output)
}
RESTORE_PATHS; // if "break" was hit
- if (ret && def.is_value && def.def_default) {
+ if (ret && def->isValue() && def->getDefault()) {
/* a node with default has been explicitly set. needs to be marked
* as non-default for display purposes.
*
@@ -2681,15 +2661,15 @@ Cstore::cfg_value_exists(const string& value, bool active_cfg)
* not the value.
*/
bool
-Cstore::validate_val(const vtw_def *def, const string& value)
+Cstore::validate_val(const Ctemplate *def, const string& value)
{
- vtw_def ndef;
+ auto_ptr<Ctemplate> ndef;
if (!def) {
- if (!tmpl_parse(ndef)) {
+ ndef.reset(tmpl_parse());
+ if (!(def = ndef.get())) {
exit_internal("failed to parse tmpl [%s]\n", tmpl_path_to_str().c_str());
}
- def = &ndef;
- if (def->def_type == ERROR_TYPE) {
+ if (def->isTypeless()) {
// not a value node
exit_internal("validating non-value node [%s]\n",
tmpl_path_to_str().c_str());
@@ -2701,7 +2681,7 @@ Cstore::validate_val(const vtw_def *def, const string& value)
char *vbuf = (char *) malloc(vlen + 1);
strncpy(vbuf, value.c_str(), vlen + 1);
vbuf[vlen] = 0;
- bool ret = validate_val_impl((vtw_def *) def, vbuf);
+ bool ret = validate_val_impl(def, vbuf);
free(vbuf);
return ret;
}
@@ -2712,7 +2692,7 @@ Cstore::validate_val(const vtw_def *def, const string& value)
* already exists.
*/
bool
-Cstore::add_tag(const vtw_def& def)
+Cstore::add_tag(unsigned int tlimit)
{
string t = pop_cfg_path();
vector<string> cnodes;
@@ -2720,23 +2700,18 @@ Cstore::add_tag(const vtw_def& def)
get_all_child_node_names(cnodes, false, false);
bool ret = false;
do {
- if (def.def_tag > 0 && def.def_tag <= cnodes.size()) {
+ if (tlimit > 0 && tlimit <= cnodes.size()) {
// limit exceeded
output_user("Cannot set node \"%s\": number of values exceeds limit"
- "(%d allowed)\n", t.c_str(), def.def_tag);
+ "(%d allowed)\n", t.c_str(), tlimit);
break;
}
- /* XXX the following is the original logic, which is wrong since def_tag
- * is unsigned.
+ /* XXX the original implementation contains special case where the
+ * previous tag should be replaced. this is probably unnecessary since
+ * "rename" can be used for tag node anyway. also the implementation
+ * used -1 as the limit for the special case, which can't work since
+ * the limit is unsigned. ignore the special case for now.
*/
- if (def.def_tag < 0 && cnodes.size() == 1) {
- /* XXX special case in the original implementation where the previous
- * tag should be replaced. this is probably unnecessary since
- * "rename" can be used for tag node anyway.
- */
- ret = rename_child_node(cnodes[0], t);
- break;
- }
// neither of the above. just add the tag.
ret = add_child_node(t);
} while (0);
@@ -2750,7 +2725,7 @@ Cstore::add_tag(const vtw_def& def)
* not configured for the node.
*/
bool
-Cstore::add_value_to_multi(const vtw_def& def, const string& value)
+Cstore::add_value_to_multi(unsigned int mlimit, const string& value)
{
// get current values
vector<string> vvec;
@@ -2770,10 +2745,10 @@ Cstore::add_value_to_multi(const vtw_def& def, const string& value)
*
* for now just apply the limit for anything >= 1.
*/
- if (def.def_multi >= 1 && vvec.size() >= def.def_multi) {
+ if (mlimit >= 1 && vvec.size() >= mlimit) {
// limit exceeded
output_user("Cannot set value \"%s\": number of values exceeded "
- "(%d allowed)\n", value.c_str(), def.def_multi);
+ "(%d allowed)\n", value.c_str(), mlimit);
return false;
}
@@ -2817,12 +2792,12 @@ Cstore::create_default_children()
bool ret = true;
for (size_t i = 0; i < tcnodes.size(); i++) {
push_tmpl_path(tcnodes[i]);
- vtw_def def;
- if (tmpl_node_exists() && tmpl_parse(def)) {
- if (def.def_default) {
+ if (tmpl_node_exists()) {
+ auto_ptr<Ctemplate> def(tmpl_parse());
+ if (def.get() && def->getDefault()) {
// has default value. set it.
push_cfg_path(tcnodes[i]);
- if (!add_node() || !write_value(def.def_default)
+ if (!add_node() || !write_value(def->getDefault())
|| !mark_display_default()) {
ret = false;
}
diff --git a/src/cstore/cstore.hpp b/src/cstore/cstore.hpp
index c76cb8f..6a76f31 100644
--- a/src/cstore/cstore.hpp
+++ b/src/cstore/cstore.hpp
@@ -22,6 +22,7 @@
#include <tr1/unordered_map>
#include <cli_cstore.h>
+#include <cstore/ctemplate.hpp>
/* declare perl internal functions. just need these two so don't include
* all the perl headers.
@@ -100,8 +101,7 @@ public:
//// functions implemented in this base class
// these operate on template path
bool validateTmplPath(const vector<string>& path_comps, bool validate_vals);
- bool validateTmplPath(const vector<string>& path_comps, bool validate_vals,
- vtw_def& def);
+ Ctemplate *parseTmpl(const vector<string>& path_comps, bool validate_vals);
bool getParsedTmpl(const vector<string>& path_comps,
MapT<string, string>& tmap, bool allow_val = true);
void tmplGetChildNodes(const vector<string>& path_comps,
@@ -130,8 +130,7 @@ public:
bool validateSetPath(const vector<string>& path_comps);
bool setCfgPath(const vector<string>& path_comps);
// delete
- bool validateDeletePath(const vector<string>& path_comps, vtw_def& def);
- bool deleteCfgPath(const vector<string>& path_comps, const vtw_def& def);
+ bool deleteCfgPath(const vector<string>& path_comps);
// activate (actually "unmark deactivated" since it is 2-state, not 3)
bool validateActivatePath(const vector<string>& path_comps);
bool unmarkCfgPathDeactivated(const vector<string>& path_comps);
@@ -145,8 +144,7 @@ public:
bool validateCopyArgs(const vector<string>& args);
bool copyCfgPath(const vector<string>& args);
// comment
- bool validateCommentArgs(const vector<string>& args, vtw_def& def);
- bool commentCfgPath(const vector<string>& args, const vtw_def& def);
+ bool commentCfgPath(const vector<string>& args);
// discard
bool discardChanges();
// move
@@ -340,7 +338,7 @@ private:
// these operate on current tmpl path
virtual bool tmpl_node_exists() = 0;
- virtual bool tmpl_parse(vtw_def& def) = 0;
+ virtual Ctemplate *tmpl_parse() = 0;
// these operate on current work path (or active with "active_cfg")
virtual bool remove_node() = 0;
@@ -374,10 +372,10 @@ private:
virtual bool marked_display_default(bool active_cfg) = 0;
// observers during commit operation
- virtual bool marked_committed(const vtw_def& def, bool is_set) = 0;
+ virtual bool marked_committed(const Ctemplate *def, bool is_set) = 0;
// these operate on both current tmpl and work paths
- virtual bool validate_val_impl(vtw_def *def, char *value) = 0;
+ virtual bool validate_val_impl(const Ctemplate *def, char *value) = 0;
// observers for "edit/tmpl levels" (for "edit"-related operations)
/* note that these should be handled in the base class since they
@@ -435,15 +433,15 @@ private:
// these require full path
// (note: get_parsed_tmpl also uses current tmpl path)
- bool get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
- vtw_def& def, string& error);
- bool get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals,
- vtw_def& def) {
+ Ctemplate *get_parsed_tmpl(const vector<string>& path_comps,
+ bool validate_vals, string& error);
+ Ctemplate *get_parsed_tmpl(const vector<string>& path_comps,
+ bool validate_vals) {
string dummy;
- return get_parsed_tmpl(path_comps, validate_vals, def, dummy);
+ return get_parsed_tmpl(path_comps, validate_vals, dummy);
};
- bool validate_act_deact(const vector<string>& path_comps, const string& op,
- vtw_def& def);
+ Ctemplate *validate_act_deact(const vector<string>& path_comps,
+ const string& op);
bool validate_rename_copy(const vector<string>& args, const string& op);
bool conv_move_args_for_rename(const vector<string>& args,
vector<string>& edit_path_comps,
@@ -465,8 +463,8 @@ private:
vector<string> vvec(1, value);
return write_value_vec(vvec, active_cfg);
};
- bool add_tag(const vtw_def& def);
- bool add_value_to_multi(const vtw_def& def, const string& value);
+ bool add_tag(unsigned int tlimit);
+ bool add_value_to_multi(unsigned int mlimit, const string& value);
bool add_child_node(const string& name) {
push_cfg_path(name);
bool ret = add_node();
@@ -480,7 +478,7 @@ private:
bool cfg_value_exists(const string& value, bool active_cfg);
// these operate on both current tmpl and work paths
- bool validate_val(const vtw_def *def, const string& value);
+ bool validate_val(const Ctemplate *def, const string& value);
bool create_default_children();
void get_edit_env(string& env);
diff --git a/src/cstore/ctemplate.hpp b/src/cstore/ctemplate.hpp
new file mode 100644
index 0000000..b9d1d8c
--- /dev/null
+++ b/src/cstore/ctemplate.hpp
@@ -0,0 +1,126 @@
+/*
+ * 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 _CTEMPLATE_H_
+#define _CTEMPLATE_H_
+
+#include <tr1/memory>
+
+#include <cli_cstore.h>
+#include <cstore/cstore.hpp>
+
+namespace cstore { // begin namespace cstore
+
+using namespace std;
+
+class Ctemplate {
+public:
+ Ctemplate(tr1::shared_ptr<vtw_def> def) : _def(def) {};
+ ~Ctemplate() {};
+
+ bool isValue() const { return _def->is_value; };
+ bool isMulti() const { return _def->multi; };
+ bool isTag() const { return _def->tag; };
+ bool isTagNode() const { return (isTag() && !isValue()); };
+ bool isTagValue() const { return (isTag() && isValue()); };
+ bool isLeafValue() const { return (!isTag() && isValue()); };
+ bool isTypeless(size_t tnum = 1) const {
+ /* note: the current "multi-type" implementation only supports two types.
+ * the interface here is generalized so it can support more in the
+ * future.
+ *
+ * isTypeless(i) implies isTypeless(j) for all (j > i).
+ * therefore, isTypeless() means the node has no types at all
+ * and is equivalent to isTypeless(1).
+ *
+ * originally, some "users" of vtw_def checks both is_value and
+ * def_type for typeless nodes. this should not be necessary so
+ * here we only check def_type.
+ */
+ return ((tnum == 1) ? (_def->def_type == ERROR_TYPE)
+ : (_def->def_type2 == ERROR_TYPE));
+ };
+ bool isSingleLeafNode() const {
+ return (!isValue() && !isMulti() && !isTag() && !isTypeless());
+ };
+ bool isSingleLeafValue() const {
+ // assume isValue implies !isTypeless
+ return (isValue() && !isMulti() && !isTag());
+ };
+ bool isMultiLeafNode() const {
+ // assume isMulti implies !isTag && !isTypeless
+ return (!isValue() && isMulti());
+ };
+ bool isMultiLeafValue() const {
+ // assume isMulti implies !isTag && !isTypeless
+ return (isValue() && isMulti());
+ };
+
+ size_t getNumTypes() const {
+ return (isTypeless(1) ? 0 : (isTypeless(2) ? 1 : 2));
+ };
+ vtw_type_e getType(size_t tnum = 1) const {
+ return ((tnum == 1) ? _def->def_type : _def->def_type2);
+ };
+ const char *getTypeName(size_t tnum = 1) const {
+ return type_to_name(getType(tnum));
+ };
+ const char *getDefault() const { return _def->def_default; };
+ const char *getNodeHelp() const { return _def->def_node_help; };
+ const char *getEnumeration() const { return _def->def_enumeration; };
+ const char *getAllowed() const { return _def->def_allowed; };
+ const vtw_list *getActions(vtw_act_type act) const {
+ return &(_def->actions[act]);
+ };
+ const char *getCompHelp() const { return _def->def_comp_help; };
+ const char *getValHelp() const { return _def->def_val_help; };
+ unsigned int getTagLimit() const { return _def->def_tag; };
+ unsigned int getMultiLimit() const { return _def->def_multi; };
+
+ void setIsValue(bool is_val) { _def->is_value = is_val; };
+
+ const vtw_def *getDef() const {
+ /* XXX this is a hack for code that has not been converted and is still
+ * using vtw_def directly. this should go away once the transition
+ * is completed.
+ */
+ return _def.get();
+ };
+
+private:
+ /* XXX ideally, template should be parsed directly into this class instead
+ * of wrapping the vtw_def struct in here. however, the legacy code
+ * (e.g., commit and code used by commit) still requires vtw_def, so
+ * need to keep it around for now until the transition is completed.
+ *
+ * note that the use of shared_ptr deals with the memory of the vtw_def
+ * struct *itself*. however, various members of vtw_def are allocated
+ * dynamically by the parser and were never freed before, i.e., they
+ * have always been leaked since the beginning. such leaks are not going
+ * to be fixed by the shared_ptr use here.
+ *
+ * once the transition is completed, vtw_def can be eliminated, and
+ * template data should be stored directly in this class using more
+ * suitable containers so that memory allocation/deallocation can be
+ * handled properly.
+ */
+ tr1::shared_ptr<vtw_def> _def;
+};
+
+} // end namespace cstore
+
+#endif /* _CTEMPLATE_H_ */
+
diff --git a/src/cstore/unionfs/cstore-unionfs.cpp b/src/cstore/unionfs/cstore-unionfs.cpp
index 59b5582..b42c8f8 100644
--- a/src/cstore/unionfs/cstore-unionfs.cpp
+++ b/src/cstore/unionfs/cstore-unionfs.cpp
@@ -415,17 +415,21 @@ UnionfsCstore::tmpl_node_exists()
return (b_fs_exists(tmpl_path) && b_fs_is_directory(tmpl_path));
}
-/* parse template at current tmpl_path.
- * def: for storing parsed template.
- * return true if successful. otherwise return false.
+/* parse template at current tmpl_path and return an allocated Ctemplate
+ * pointer if successful. otherwise return 0.
*/
-bool
-UnionfsCstore::tmpl_parse(vtw_def& def)
+Ctemplate *
+UnionfsCstore::tmpl_parse()
{
+ tr1::shared_ptr<vtw_def> def(new vtw_def);
+ vtw_def *_def = def.get();
b_fs::path tp = tmpl_path / C_DEF_NAME;
- bool ret = (b_fs_exists(tp) && b_fs_is_regular(tp)
- && parse_def(&def, tp.file_string().c_str(), 0) == 0);
- return ret;
+ if (_def && b_fs_exists(tp) && b_fs_is_regular(tp)
+ && parse_def(_def, tp.file_string().c_str(), 0) == 0) {
+ // succes
+ return (new Ctemplate(def));
+ }
+ return 0;
}
bool
@@ -905,11 +909,11 @@ UnionfsCstore::cfg_node_changed()
* be only one operation on the path).
*/
bool
-UnionfsCstore::marked_committed(const vtw_def& def, bool is_set)
+UnionfsCstore::marked_committed(const Ctemplate *def, bool is_set)
{
b_fs::path cpath = mutable_cfg_path;
string com_str = cpath.file_string() + "/";
- if (def.is_value && !def.tag) {
+ if (def->isLeafValue()) {
// path includes leaf value. construct the right string.
string val = _unescape_path_name(cpath.filename());
cpath = cpath.parent_path();
@@ -917,7 +921,7 @@ UnionfsCstore::marked_committed(const vtw_def& def, bool is_set)
* single-value nodes but not for multi-value nodes for some
* reason. the following match current behavior.
*/
- if (!def.multi) {
+ if (!def->isMulti()) {
val = _escape_path_name(val);
}
com_str = cpath.file_string() + "/value:" + val;
@@ -927,7 +931,7 @@ UnionfsCstore::marked_committed(const vtw_def& def, bool is_set)
}
bool
-UnionfsCstore::validate_val_impl(vtw_def *def, char *value)
+UnionfsCstore::validate_val_impl(const Ctemplate *def, char *value)
{
/* XXX filesystem paths/accesses are completely embedded in var ref lib.
* for now, treat the lib as a unionfs-specific implementation.
@@ -936,7 +940,7 @@ UnionfsCstore::validate_val_impl(vtw_def *def, char *value)
* processing. this is a global var in cli_new.c.
*/
var_ref_handle = (void *) this;
- bool ret = validate_value(def, value);
+ bool ret = validate_value(def->getDef(), value);
var_ref_handle = NULL;
return ret;
}
diff --git a/src/cstore/unionfs/cstore-unionfs.hpp b/src/cstore/unionfs/cstore-unionfs.hpp
index 29f6822..82bda2a 100644
--- a/src/cstore/unionfs/cstore-unionfs.hpp
+++ b/src/cstore/unionfs/cstore-unionfs.hpp
@@ -150,7 +150,7 @@ private:
// these operate on current tmpl path
bool tmpl_node_exists();
- bool tmpl_parse(vtw_def& def);
+ Ctemplate *tmpl_parse();
// these operate on current work path
bool add_node();
@@ -184,10 +184,10 @@ private:
bool marked_display_default(bool active_cfg);
// observers during commit operation
- bool marked_committed(const vtw_def& def, bool is_set);
+ bool marked_committed(const Ctemplate *def, bool is_set);
// these operate on both current tmpl and work paths
- bool validate_val_impl(vtw_def *def, char *value);
+ bool validate_val_impl(const Ctemplate *def, char *value);
// observers for "edit/tmpl levels" (for "edit"-related operations).
// note that these should be moved to base class in the future.