diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2011-03-17 11:48:54 -0700 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2011-03-17 11:48:54 -0700 |
commit | eb9f5718d412022015bb65eb08c30785c79e79e6 (patch) | |
tree | be0b6a9de27965e39c44c5c8a88adf9caa13abf8 | |
parent | cda3f423c311fd30e8cc24e2de67d99baf352b2a (diff) | |
download | vyatta-cfg-eb9f5718d412022015bb65eb08c30785c79e79e6.tar.gz vyatta-cfg-eb9f5718d412022015bb65eb08c30785c79e79e6.zip |
add config path abstraction and high-level caching
* part of the config backend cleanup/optimization work.
* improves the performance of "load" (w/o commit) by ~55% and "show" by ~15%.
-rw-r--r-- | perl_dmod/Cstore/Cstore.xs | 145 | ||||
-rw-r--r-- | perl_dmod/Cstore/typemap | 15 | ||||
-rw-r--r-- | src/cli_bin.cpp | 25 | ||||
-rw-r--r-- | src/cli_cstore.h | 2 | ||||
-rw-r--r-- | src/cli_shell_api.cpp | 92 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.cpp | 126 | ||||
-rw-r--r-- | src/cnode/cnode-algorithm.hpp | 16 | ||||
-rw-r--r-- | src/cnode/cnode.cpp | 25 | ||||
-rw-r--r-- | src/cnode/cnode.hpp | 26 | ||||
-rw-r--r-- | src/cparse/cparse.ypp | 25 | ||||
-rw-r--r-- | src/cstore/cpath.hpp | 88 | ||||
-rw-r--r-- | src/cstore/cstore-c.cpp | 33 | ||||
-rw-r--r-- | src/cstore/cstore-varref.cpp | 69 | ||||
-rw-r--r-- | src/cstore/cstore-varref.hpp | 10 | ||||
-rw-r--r-- | src/cstore/cstore.cpp | 1250 | ||||
-rw-r--r-- | src/cstore/cstore.hpp | 214 | ||||
-rw-r--r-- | src/cstore/ctemplate.hpp | 9 | ||||
-rw-r--r-- | src/cstore/svector.hpp | 345 | ||||
-rw-r--r-- | src/cstore/unionfs/cstore-unionfs.cpp | 407 | ||||
-rw-r--r-- | src/cstore/unionfs/cstore-unionfs.hpp | 117 | ||||
-rw-r--r-- | src/cstore/unionfs/fspath.hpp | 92 |
21 files changed, 1844 insertions, 1287 deletions
diff --git a/perl_dmod/Cstore/Cstore.xs b/perl_dmod/Cstore/Cstore.xs index 730a936..e5fd126 100644 --- a/perl_dmod/Cstore/Cstore.xs +++ b/perl_dmod/Cstore/Cstore.xs @@ -31,6 +31,7 @@ using namespace cstore; typedef SV STRVEC; +typedef SV CPATH; typedef SV STRSTRMAP; MODULE = Cstore PACKAGE = Cstore @@ -45,43 +46,43 @@ OUTPUT: bool -Cstore::cfgPathExists(STRVEC *vref, bool active_cfg) +Cstore::cfgPathExists(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathExists(arg_strvec, active_cfg); + RETVAL = THIS->cfgPathExists(arg_cpath, active_cfg); OUTPUT: RETVAL bool -Cstore::cfgPathDefault(STRVEC *vref, bool active_cfg) +Cstore::cfgPathDefault(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathDefault(arg_strvec, active_cfg); + RETVAL = THIS->cfgPathDefault(arg_cpath, active_cfg); OUTPUT: RETVAL STRVEC * -Cstore::cfgPathGetChildNodes(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetChildNodes(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetChildNodes(arg_strvec, ret_strvec, active_cfg); + THIS->cfgPathGetChildNodes(arg_cpath, ret_strvec, active_cfg); OUTPUT: RETVAL SV * -Cstore::cfgPathGetValue(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetValue(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: string value; - if (THIS->cfgPathGetValue(arg_strvec, value, active_cfg)) { + if (THIS->cfgPathGetValue(arg_cpath, value, active_cfg)) { RETVAL = newSVpv(value.c_str(), 0); } else { XSRETURN_UNDEF; @@ -91,44 +92,44 @@ OUTPUT: STRVEC * -Cstore::cfgPathGetValues(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetValues(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetValues(arg_strvec, ret_strvec, active_cfg); + THIS->cfgPathGetValues(arg_cpath, ret_strvec, active_cfg); OUTPUT: RETVAL bool -Cstore::cfgPathEffective(STRVEC *vref) +Cstore::cfgPathEffective(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathEffective(arg_strvec); + RETVAL = THIS->cfgPathEffective(arg_cpath); OUTPUT: RETVAL STRVEC * -Cstore::cfgPathGetEffectiveChildNodes(STRVEC *vref) +Cstore::cfgPathGetEffectiveChildNodes(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetEffectiveChildNodes(arg_strvec, ret_strvec); + THIS->cfgPathGetEffectiveChildNodes(arg_cpath, ret_strvec); OUTPUT: RETVAL SV * -Cstore::cfgPathGetEffectiveValue(STRVEC *vref) +Cstore::cfgPathGetEffectiveValue(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: string value; - if (THIS->cfgPathGetEffectiveValue(arg_strvec, value)) { + if (THIS->cfgPathGetEffectiveValue(arg_cpath, value)) { RETVAL = newSVpv(value.c_str(), 0); } else { XSRETURN_UNDEF; @@ -138,97 +139,97 @@ OUTPUT: STRVEC * -Cstore::cfgPathGetEffectiveValues(STRVEC *vref) +Cstore::cfgPathGetEffectiveValues(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetEffectiveValues(arg_strvec, ret_strvec); + THIS->cfgPathGetEffectiveValues(arg_cpath, ret_strvec); OUTPUT: RETVAL bool -Cstore::cfgPathDeleted(STRVEC *vref) +Cstore::cfgPathDeleted(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathDeleted(arg_strvec); + RETVAL = THIS->cfgPathDeleted(arg_cpath); OUTPUT: RETVAL bool -Cstore::cfgPathAdded(STRVEC *vref) +Cstore::cfgPathAdded(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathAdded(arg_strvec); + RETVAL = THIS->cfgPathAdded(arg_cpath); OUTPUT: RETVAL bool -Cstore::cfgPathChanged(STRVEC *vref) +Cstore::cfgPathChanged(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathChanged(arg_strvec); + RETVAL = THIS->cfgPathChanged(arg_cpath); OUTPUT: RETVAL STRVEC * -Cstore::cfgPathGetDeletedChildNodes(STRVEC *vref) +Cstore::cfgPathGetDeletedChildNodes(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetDeletedChildNodes(arg_strvec, ret_strvec); + THIS->cfgPathGetDeletedChildNodes(arg_cpath, ret_strvec); OUTPUT: RETVAL STRVEC * -Cstore::cfgPathGetDeletedValues(STRVEC *vref) +Cstore::cfgPathGetDeletedValues(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetDeletedValues(arg_strvec, ret_strvec); + THIS->cfgPathGetDeletedValues(arg_cpath, ret_strvec); OUTPUT: RETVAL STRSTRMAP * -Cstore::cfgPathGetChildNodesStatus(STRVEC *vref) +Cstore::cfgPathGetChildNodesStatus(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: Cstore::MapT<string, string> ret_strstrmap; - THIS->cfgPathGetChildNodesStatus(arg_strvec, ret_strstrmap); + THIS->cfgPathGetChildNodesStatus(arg_cpath, ret_strstrmap); OUTPUT: RETVAL STRVEC * -Cstore::cfgPathGetValuesDA(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetValuesDA(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetValuesDA(arg_strvec, ret_strvec, active_cfg); + THIS->cfgPathGetValuesDA(arg_cpath, ret_strvec, active_cfg); OUTPUT: RETVAL SV * -Cstore::cfgPathGetValueDA(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetValueDA(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: string value; - if (THIS->cfgPathGetValueDA(arg_strvec, value, active_cfg)) { + if (THIS->cfgPathGetValueDA(arg_cpath, value, active_cfg)) { RETVAL = newSVpv(value.c_str(), 0); } else { XSRETURN_UNDEF; @@ -238,65 +239,65 @@ OUTPUT: STRVEC * -Cstore::cfgPathGetChildNodesDA(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetChildNodesDA(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->cfgPathGetChildNodesDA(arg_strvec, ret_strvec, active_cfg); + THIS->cfgPathGetChildNodesDA(arg_cpath, ret_strvec, active_cfg); OUTPUT: RETVAL bool -Cstore::cfgPathDeactivated(STRVEC *vref, bool active_cfg) +Cstore::cfgPathDeactivated(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->cfgPathDeactivated(arg_strvec, active_cfg); + RETVAL = THIS->cfgPathDeactivated(arg_cpath, active_cfg); OUTPUT: RETVAL STRSTRMAP * -Cstore::cfgPathGetChildNodesStatusDA(STRVEC *vref) +Cstore::cfgPathGetChildNodesStatusDA(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: Cstore::MapT<string, string> ret_strstrmap; - THIS->cfgPathGetChildNodesStatusDA(arg_strvec, ret_strstrmap); + THIS->cfgPathGetChildNodesStatusDA(arg_cpath, ret_strstrmap); OUTPUT: RETVAL STRVEC * -Cstore::tmplGetChildNodes(STRVEC *vref) +Cstore::tmplGetChildNodes(CPATH *pref) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: vector<string> ret_strvec; - THIS->tmplGetChildNodes(arg_strvec, ret_strvec); + THIS->tmplGetChildNodes(arg_cpath, ret_strvec); OUTPUT: RETVAL bool -Cstore::validateTmplPath(STRVEC *vref, bool validate_vals) +Cstore::validateTmplPath(CPATH *pref, bool validate_vals) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: - RETVAL = THIS->validateTmplPath(arg_strvec, validate_vals); + RETVAL = THIS->validateTmplPath(arg_cpath, validate_vals); OUTPUT: RETVAL STRSTRMAP * -Cstore::getParsedTmpl(STRVEC *vref, bool allow_val) +Cstore::getParsedTmpl(CPATH *pref, bool allow_val) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: Cstore::MapT<string, string> ret_strstrmap; - if (!THIS->getParsedTmpl(arg_strvec, ret_strstrmap, allow_val)) { + if (!THIS->getParsedTmpl(arg_cpath, ret_strstrmap, allow_val)) { XSRETURN_UNDEF; } OUTPUT: @@ -304,12 +305,12 @@ OUTPUT: SV * -Cstore::cfgPathGetComment(STRVEC *vref, bool active_cfg) +Cstore::cfgPathGetComment(CPATH *pref, bool active_cfg) PREINIT: - vector<string> arg_strvec; + Cpath arg_cpath; CODE: string comment; - if (THIS->cfgPathGetComment(arg_strvec, comment, active_cfg)) { + if (THIS->cfgPathGetComment(arg_cpath, comment, active_cfg)) { RETVAL = newSVpv(comment.c_str(), 0); } else { XSRETURN_UNDEF; diff --git a/perl_dmod/Cstore/typemap b/perl_dmod/Cstore/typemap index 6df545b..7f70899 100644 --- a/perl_dmod/Cstore/typemap +++ b/perl_dmod/Cstore/typemap @@ -14,6 +14,7 @@ Cstore * O_CPPOBJ STRVEC * T_STRVEC_REF +CPATH * T_CPATH_REF STRSTRMAP * T_STRSTRMAP_REF @@ -66,3 +67,17 @@ T_STRVEC_REF } } +T_CPATH_REF + { + int i = 0; + I32 num = 0; + if (!SvROK($arg) || SvTYPE(SvRV($arg)) != SVt_PVAV) { + XSRETURN_UNDEF; + } + num = av_len((AV *) SvRV($arg)); + /* if input array is empty, path will be empty as well. */ + for (i = 0; i <= num; i++) { + arg_cpath.push(SvPV_nolen(*av_fetch((AV *) SvRV($arg), i, 0))); + } + } + diff --git a/src/cli_bin.cpp b/src/cli_bin.cpp index 20da924..4d32c15 100644 --- a/src/cli_bin.cpp +++ b/src/cli_bin.cpp @@ -80,7 +80,7 @@ static const bool op_need_cfg_node_args[] = { #define OP_need_cfg_node_args op_need_cfg_node_args[op_idx] static void -doSet(Cstore& cstore, const vector<string>& path_comps) +doSet(Cstore& cstore, const Cpath& path_comps) { if (!cstore.validateSetPath(path_comps)) { bye("invalid set path\n"); @@ -91,7 +91,7 @@ doSet(Cstore& cstore, const vector<string>& path_comps) } static void -doDelete(Cstore& cstore, const vector<string>& path_comps) +doDelete(Cstore& cstore, const Cpath& path_comps) { if (!cstore.deleteCfgPath(path_comps)) { bye("delete failed\n"); @@ -99,7 +99,7 @@ doDelete(Cstore& cstore, const vector<string>& path_comps) } static void -doActivate(Cstore& cstore, const vector<string>& path_comps) +doActivate(Cstore& cstore, const Cpath& path_comps) { if (!cstore.validateActivatePath(path_comps)) { bye("%s validate failed", OP_str); @@ -110,7 +110,7 @@ doActivate(Cstore& cstore, const vector<string>& path_comps) } static void -doDeactivate(Cstore& cstore, const vector<string>& path_comps) +doDeactivate(Cstore& cstore, const Cpath& path_comps) { if (!cstore.validateDeactivatePath(path_comps)) { bye("%s validate failed", OP_str); @@ -121,7 +121,7 @@ doDeactivate(Cstore& cstore, const vector<string>& path_comps) } static void -doRename(Cstore& cstore, const vector<string>& path_comps) +doRename(Cstore& cstore, const Cpath& path_comps) { if (!cstore.validateRenameArgs(path_comps)) { bye("invalid rename args\n"); @@ -132,7 +132,7 @@ doRename(Cstore& cstore, const vector<string>& path_comps) } static void -doCopy(Cstore& cstore, const vector<string>& path_comps) +doCopy(Cstore& cstore, const Cpath& path_comps) { if (!cstore.validateCopyArgs(path_comps)) { bye("invalid copy args\n"); @@ -143,7 +143,7 @@ doCopy(Cstore& cstore, const vector<string>& path_comps) } static void -doComment(Cstore& cstore, const vector<string>& path_comps) +doComment(Cstore& cstore, const Cpath& path_comps) { if (!cstore.commentCfgPath(path_comps)) { bye("comment cfg path failed\n"); @@ -151,7 +151,7 @@ doComment(Cstore& cstore, const vector<string>& path_comps) } static void -doDiscard(Cstore& cstore, const vector<string>& args) +doDiscard(Cstore& cstore, const Cpath& args) { if (args.size() > 0) { OUTPUT_USER("Invalid discard command\n"); @@ -163,7 +163,7 @@ doDiscard(Cstore& cstore, const vector<string>& args) } static void -doMove(Cstore& cstore, const vector<string>& path_comps) +doMove(Cstore& cstore, const Cpath& path_comps) { if (!cstore.validateMoveArgs(path_comps)) { bye("invalid move args\n"); @@ -174,7 +174,7 @@ doMove(Cstore& cstore, const vector<string>& path_comps) } typedef void (*OpFuncT)(Cstore& cstore, - const vector<string>& path_comps); + const Cpath& path_comps); OpFuncT OpFunc[] = { &doSet, &doDelete, @@ -214,10 +214,7 @@ main(int argc, char **argv) // actual CLI operations use the edit levels from environment, so pass true. Cstore *cstore = Cstore::createCstore(true); - vector<string> path_comps; - for (int i = 1; i < argc; i++) { - path_comps.push_back(argv[i]); - } + Cpath path_comps(const_cast<const char **>(argv + 1), argc - 1); // call the op function OpFunc[op_idx](*cstore, path_comps); diff --git a/src/cli_cstore.h b/src/cli_cstore.h index 5f0b061..6f4ec51 100644 --- a/src/cli_cstore.h +++ b/src/cli_cstore.h @@ -109,8 +109,6 @@ typedef struct { boolean tag; boolean multi; vtw_list actions[top_act]; - int is_value; /* this is used by the config store to indicate whether - * the last path component is a "value". */ } vtw_def; /* extern variables */ diff --git a/src/cli_shell_api.cpp b/src/cli_shell_api.cpp index 41d18e2..8fea74a 100644 --- a/src/cli_shell_api.cpp +++ b/src/cli_shell_api.cpp @@ -63,7 +63,7 @@ int op_show_commands = 0; char *op_show_cfg1 = NULL; char *op_show_cfg2 = NULL; -typedef void (*OpFuncT)(Cstore& cstore, const vector<string>& args); +typedef void (*OpFuncT)(Cstore& cstore, const Cpath& args); typedef struct { const char *op_name; @@ -77,7 +77,7 @@ typedef struct { /* outputs an environment string to be "eval"ed */ static void -getSessionEnv(Cstore& cstore, const vector<string>& args) +getSessionEnv(Cstore& cstore, const Cpath& args) { // need a "session-specific" cstore so ignore the default one string env; @@ -88,7 +88,7 @@ getSessionEnv(Cstore& cstore, const vector<string>& args) /* outputs an environment string to be "eval"ed */ static void -getEditEnv(Cstore& cstore, const vector<string>& args) +getEditEnv(Cstore& cstore, const Cpath& args) { string env; if (!cstore.getEditEnv(args, env)) { @@ -99,7 +99,7 @@ getEditEnv(Cstore& cstore, const vector<string>& args) /* outputs an environment string to be "eval"ed */ static void -getEditUpEnv(Cstore& cstore, const vector<string>& args) +getEditUpEnv(Cstore& cstore, const Cpath& args) { string env; if (!cstore.getEditUpEnv(env)) { @@ -110,7 +110,7 @@ getEditUpEnv(Cstore& cstore, const vector<string>& args) /* outputs an environment string to be "eval"ed */ static void -getEditResetEnv(Cstore& cstore, const vector<string>& args) +getEditResetEnv(Cstore& cstore, const Cpath& args) { string env; if (!cstore.getEditResetEnv(env)) { @@ -120,14 +120,14 @@ getEditResetEnv(Cstore& cstore, const vector<string>& args) } static void -editLevelAtRoot(Cstore& cstore, const vector<string>& args) +editLevelAtRoot(Cstore& cstore, const Cpath& args) { exit(cstore.editLevelAtRoot() ? 0 : 1); } /* outputs an environment string to be "eval"ed */ static void -getCompletionEnv(Cstore& cstore, const vector<string>& args) +getCompletionEnv(Cstore& cstore, const Cpath& args) { string env; if (!cstore.getCompletionEnv(args, env)) { @@ -138,15 +138,19 @@ getCompletionEnv(Cstore& cstore, const vector<string>& args) /* outputs a string */ static void -getEditLevelStr(Cstore& cstore, const vector<string>& args) +getEditLevelStr(Cstore& cstore, const Cpath& args) { - vector<string> lvec; + Cpath lvec; cstore.getEditLevel(lvec); - print_vec(lvec, " ", ""); + vector<string> vec; + for (size_t i = 0; i < lvec.size(); i++) { + vec.push_back(lvec[i]); + } + print_vec(vec, " ", ""); } static void -markSessionUnsaved(Cstore& cstore, const vector<string>& args) +markSessionUnsaved(Cstore& cstore, const Cpath& args) { if (!cstore.markSessionUnsaved()) { exit(1); @@ -154,7 +158,7 @@ markSessionUnsaved(Cstore& cstore, const vector<string>& args) } static void -unmarkSessionUnsaved(Cstore& cstore, const vector<string>& args) +unmarkSessionUnsaved(Cstore& cstore, const Cpath& args) { if (!cstore.unmarkSessionUnsaved()) { exit(1); @@ -162,7 +166,7 @@ unmarkSessionUnsaved(Cstore& cstore, const vector<string>& args) } static void -sessionUnsaved(Cstore& cstore, const vector<string>& args) +sessionUnsaved(Cstore& cstore, const Cpath& args) { if (!cstore.sessionUnsaved()) { exit(1); @@ -170,7 +174,7 @@ sessionUnsaved(Cstore& cstore, const vector<string>& args) } static void -sessionChanged(Cstore& cstore, const vector<string>& args) +sessionChanged(Cstore& cstore, const Cpath& args) { if (!cstore.sessionChanged()) { exit(1); @@ -178,7 +182,7 @@ sessionChanged(Cstore& cstore, const vector<string>& args) } static void -teardownSession(Cstore& cstore, const vector<string>& args) +teardownSession(Cstore& cstore, const Cpath& args) { if (!cstore.teardownSession()) { exit(1); @@ -186,7 +190,7 @@ teardownSession(Cstore& cstore, const vector<string>& args) } static void -setupSession(Cstore& cstore, const vector<string>& args) +setupSession(Cstore& cstore, const Cpath& args) { if (!cstore.setupSession()) { exit(1); @@ -194,7 +198,7 @@ setupSession(Cstore& cstore, const vector<string>& args) } static void -inSession(Cstore& cstore, const vector<string>& args) +inSession(Cstore& cstore, const Cpath& args) { if (!cstore.inSession()) { exit(1); @@ -203,21 +207,21 @@ inSession(Cstore& cstore, const vector<string>& args) /* same as exists() in Perl API */ static void -exists(Cstore& cstore, const vector<string>& args) +exists(Cstore& cstore, const Cpath& args) { exit(cstore.cfgPathExists(args, false) ? 0 : 1); } /* same as existsOrig() in Perl API */ static void -existsActive(Cstore& cstore, const vector<string>& args) +existsActive(Cstore& cstore, const Cpath& args) { exit(cstore.cfgPathExists(args, true) ? 0 : 1); } /* same as isEffective() in Perl API */ static void -existsEffective(Cstore& cstore, const vector<string>& args) +existsEffective(Cstore& cstore, const Cpath& args) { exit(cstore.cfgPathEffective(args) ? 0 : 1); } @@ -235,7 +239,7 @@ existsEffective(Cstore& cstore, const vector<string>& args) * eval "nodes=($(cli-shell-api listNodes interfaces))" */ static void -listNodes(Cstore& cstore, const vector<string>& args) +listNodes(Cstore& cstore, const Cpath& args) { vector<string> cnodes; cstore.cfgPathGetChildNodes(args, cnodes, false); @@ -248,7 +252,7 @@ listNodes(Cstore& cstore, const vector<string>& args) * "eval"ed into an array of nodes. see listNodes above. */ static void -listActiveNodes(Cstore& cstore, const vector<string>& args) +listActiveNodes(Cstore& cstore, const Cpath& args) { vector<string> cnodes; cstore.cfgPathGetChildNodes(args, cnodes, true); @@ -261,7 +265,7 @@ listActiveNodes(Cstore& cstore, const vector<string>& args) * "eval"ed into an array of nodes. see listNodes above. */ static void -listEffectiveNodes(Cstore& cstore, const vector<string>& args) +listEffectiveNodes(Cstore& cstore, const Cpath& args) { vector<string> cnodes; cstore.cfgPathGetEffectiveChildNodes(args, cnodes); @@ -270,7 +274,7 @@ listEffectiveNodes(Cstore& cstore, const vector<string>& args) /* same as returnValue() in Perl API. outputs a string. */ static void -returnValue(Cstore& cstore, const vector<string>& args) +returnValue(Cstore& cstore, const Cpath& args) { string val; if (!cstore.cfgPathGetValue(args, val, false)) { @@ -281,7 +285,7 @@ returnValue(Cstore& cstore, const vector<string>& args) /* same as returnOrigValue() in Perl API. outputs a string. */ static void -returnActiveValue(Cstore& cstore, const vector<string>& args) +returnActiveValue(Cstore& cstore, const Cpath& args) { string val; if (!cstore.cfgPathGetValue(args, val, true)) { @@ -292,7 +296,7 @@ returnActiveValue(Cstore& cstore, const vector<string>& args) /* same as returnEffectiveValue() in Perl API. outputs a string. */ static void -returnEffectiveValue(Cstore& cstore, const vector<string>& args) +returnEffectiveValue(Cstore& cstore, const Cpath& args) { string val; if (!cstore.cfgPathGetEffectiveValue(args, val)) { @@ -322,7 +326,7 @@ returnEffectiveValue(Cstore& cstore, const vector<string>& args) * failure would result in an empty array after the eval. */ static void -returnValues(Cstore& cstore, const vector<string>& args) +returnValues(Cstore& cstore, const Cpath& args) { vector<string> vvec; if (!cstore.cfgPathGetValues(args, vvec, false)) { @@ -337,7 +341,7 @@ returnValues(Cstore& cstore, const vector<string>& args) * "eval"ed into an array of values. see returnValues above. */ static void -returnActiveValues(Cstore& cstore, const vector<string>& args) +returnActiveValues(Cstore& cstore, const Cpath& args) { vector<string> vvec; if (!cstore.cfgPathGetValues(args, vvec, true)) { @@ -352,7 +356,7 @@ returnActiveValues(Cstore& cstore, const vector<string>& args) * "eval"ed into an array of values. see returnValues above. */ static void -returnEffectiveValues(Cstore& cstore, const vector<string>& args) +returnEffectiveValues(Cstore& cstore, const Cpath& args) { vector<string> vvec; if (!cstore.cfgPathGetEffectiveValues(args, vvec)) { @@ -365,24 +369,31 @@ returnEffectiveValues(Cstore& cstore, const vector<string>& args) * the validity of any "tag values" along the path. */ static void -validateTmplPath(Cstore& cstore, const vector<string>& args) +validateTmplPath(Cstore& cstore, const Cpath& args) { - exit(cstore.validateTmplPath(args, false) ? 0 : 1); + printf("validate:"); + Cpath p; + for (size_t i = 0; i < args.size(); i++) { + p.push(args[i]); + printf(" [%s]", p[i]); + } + printf("\n"); + exit(cstore.validateTmplPath(p, false) ? 0 : 1); } /* checks if specified path is a valid "template path", *including* the * validity of any "tag values" along the path. */ static void -validateTmplValPath(Cstore& cstore, const vector<string>& args) +validateTmplValPath(Cstore& cstore, const Cpath& args) { exit(cstore.validateTmplPath(args, true) ? 0 : 1); } static void -showCfg(Cstore& cstore, const vector<string>& args) +showCfg(Cstore& cstore, const Cpath& args) { - vector<string> nargs(args); + Cpath nargs(args); bool active_only = (!cstore.inSession() || op_show_active_only); bool working_only = (cstore.inSession() && op_show_working_only); cnode::CfgNode aroot(cstore, nargs, true, true); @@ -396,7 +407,7 @@ showCfg(Cstore& cstore, const vector<string>& args) // just show the working config (no diff) cnode::show_cfg(wroot, op_show_show_defaults, op_show_hide_secrets); } else { - vector<string> cur_path; + Cpath cur_path; cstore.getEditLevel(cur_path); cnode::show_cfg_diff(aroot, wroot, cur_path, op_show_show_defaults, op_show_hide_secrets, op_show_context_diff); @@ -434,7 +445,7 @@ showCfg(Cstore& cstore, const vector<string>& args) * both "args" and "edit level" are ignored. */ static void -showConfig(Cstore& cstore, const vector<string>& args) +showConfig(Cstore& cstore, const Cpath& args) { string cfg1 = cnode::ACTIVE_CFG; string cfg2 = cnode::WORKING_CFG; @@ -456,9 +467,9 @@ showConfig(Cstore& cstore, const vector<string>& args) } static void -loadFile(Cstore& cstore, const vector<string>& args) +loadFile(Cstore& cstore, const Cpath& args) { - if (!cstore.loadFile(args[0].c_str())) { + if (!cstore.loadFile(args[0])) { // loadFile failed exit(1); } @@ -582,10 +593,7 @@ main(int argc, char **argv) exit(1); } - vector<string> args; - for (int i = 0; i < nargs; i++) { - args.push_back(nargv[i]); - } + Cpath args(const_cast<const char **>(nargv), nargs); // call the op function Cstore *cstore = Cstore::createCstore(OP_use_edit); diff --git a/src/cnode/cnode-algorithm.cpp b/src/cnode/cnode-algorithm.cpp index 9256e7c..c6b91f9 100644 --- a/src/cnode/cnode-algorithm.cpp +++ b/src/cnode/cnode-algorithm.cpp @@ -40,14 +40,13 @@ const string cnode::WORKING_CFG = "@WORKING"; ////// static (internal) functions static void _show_diff(const CfgNode *cfg1, const CfgNode *cfg2, int level, - vector<string>& cur_path, vector<string>& last_ctx, - bool show_def, bool hide_secret, bool context_diff); + Cpath& cur_path, Cpath& last_ctx, bool show_def, + bool hide_secret, bool context_diff); static void _get_cmds_diff(const CfgNode *cfg1, const CfgNode *cfg2, - vector<string>& cur_path, vector<vector<string> >& del_list, - vector<vector<string> >& set_list, - vector<vector<string> >& com_list); + Cpath& cur_path, vector<Cpath>& del_list, + vector<Cpath>& set_list, vector<Cpath>& com_list); /* compare the values of a "multi" node in the two configs. the values and * the "prefix" of each value are returned in "values" and "pfxs", @@ -155,21 +154,21 @@ _cmp_non_leaf_nodes(const CfgNode *cfg1, const CfgNode *cfg2, } static void -_add_path_to_list(vector<vector<string> >& list, vector<string>& path, - const string *nptr, const string *vptr) +_add_path_to_list(vector<Cpath>& list, Cpath& path, const string *nptr, + const string *vptr) { if (nptr) { - path.push_back(*nptr); + path.push(*nptr); } if (vptr) { - path.push_back(*vptr); + path.push(*vptr); } list.push_back(path); if (vptr) { - path.pop_back(); + path.pop(); } if (nptr) { - path.pop_back(); + path.pop(); } } @@ -221,7 +220,7 @@ _diff_print_indent(const CfgNode *cfg1, const CfgNode *cfg2, int level, * like in JUNOS "show | compare". */ static void -_diff_print_context(vector<string>& cur_path, vector<string>& last_ctx) +_diff_print_context(Cpath& cur_path, Cpath& last_ctx) { if (last_ctx == cur_path) { // don't repeat the context if it's still the same as the last one @@ -230,7 +229,7 @@ _diff_print_context(vector<string>& cur_path, vector<string>& last_ctx) last_ctx = cur_path; printf("[edit"); for (size_t i = 0; i < cur_path.size(); i++) { - printf(" %s", cur_path[i].c_str()); + printf(" %s", cur_path[i]); } printf("]\n"); } @@ -249,8 +248,7 @@ _diff_print_context(vector<string>& cur_path, vector<string>& last_ctx) */ static bool _diff_print_comment(const CfgNode *cfg1, const CfgNode *cfg2, int level, - vector<string>& cur_path, vector<string>& last_ctx, - bool context_diff) + Cpath& cur_path, Cpath& last_ctx, bool context_diff) { const char *pfx_diff = PFX_DIFF_NONE.c_str(); string comment = ""; @@ -307,8 +305,8 @@ _diff_print_comment(const CfgNode *cfg1, const CfgNode *cfg2, int level, static bool _diff_check_and_show_leaf(const CfgNode *cfg1, const CfgNode *cfg2, int level, - vector<string>& cur_path, vector<string>& last_ctx, - bool show_def, bool hide_secret, bool context_diff) + Cpath& cur_path, Cpath& last_ctx, bool show_def, + bool hide_secret, bool context_diff) { if ((cfg1 && !cfg1->isLeaf()) || (cfg2 && !cfg2->isLeaf())) { // not a leaf node @@ -424,8 +422,8 @@ _diff_check_and_show_leaf(const CfgNode *cfg1, const CfgNode *cfg2, int level, static void _diff_show_other(const CfgNode *cfg1, const CfgNode *cfg2, int level, - vector<string>& cur_path, vector<string>& last_ctx, - bool show_def, bool hide_secret, bool context_diff) + Cpath& cur_path, Cpath& last_ctx, bool show_def, + bool hide_secret, bool context_diff) { bool orig_cdiff = context_diff; const char *pfx_diff = PFX_DIFF_NONE.c_str(); @@ -522,9 +520,9 @@ _diff_show_other(const CfgNode *cfg1, const CfgNode *cfg2, int level, } } - cur_path.push_back(name); + cur_path.push(name); if (is_value) { - cur_path.push_back(value); + cur_path.push(value); } } else { next_level = (level >= 0 ? level : 0); @@ -537,9 +535,9 @@ _diff_show_other(const CfgNode *cfg1, const CfgNode *cfg2, int level, // finish printing "this" node if necessary if (print_this) { - cur_path.pop_back(); + cur_path.pop(); if (is_value) { - cur_path.pop_back(); + cur_path.pop(); } if (!orig_cdiff || pfx_diff != PFX_DIFF_NONE.c_str()) { /* not context diff OR there is a difference => print closing '}' @@ -556,8 +554,8 @@ _diff_show_other(const CfgNode *cfg1, const CfgNode *cfg2, int level, static void _show_diff(const CfgNode *cfg1, const CfgNode *cfg2, int level, - vector<string>& cur_path, vector<string>& last_ctx, - bool show_def, bool hide_secret, bool context_diff) + Cpath& cur_path, Cpath& last_ctx, bool show_def, + bool hide_secret, bool context_diff) { // if doesn't exist, treat as NULL if (cfg1 && !cfg1->exists()) { @@ -613,8 +611,8 @@ _show_diff(const CfgNode *cfg1, const CfgNode *cfg2, int level, static void _get_comment_diff_cmd(const CfgNode *cfg1, const CfgNode *cfg2, - vector<string>& cur_path, - vector<vector<string> >& com_list, const string *val) + Cpath& cur_path, vector<Cpath>& com_list, + const string *val) { const string *comment = NULL; const string *name = NULL; @@ -652,22 +650,20 @@ _get_comment_diff_cmd(const CfgNode *cfg1, const CfgNode *cfg2, } if (comment) { if (val) { - cur_path.push_back(*name); + cur_path.push(*name); name = val; } _add_path_to_list(com_list, cur_path, name, comment); if (val) { - cur_path.pop_back(); + cur_path.pop(); } } } static bool _get_cmds_diff_leaf(const CfgNode *cfg1, const CfgNode *cfg2, - vector<string>& cur_path, - vector<vector<string> >& del_list, - vector<vector<string> >& set_list, - vector<vector<string> >& com_list) + Cpath& cur_path, vector<Cpath>& del_list, + vector<Cpath>& set_list, vector<Cpath>& com_list) { if ((cfg1 && !cfg1->isLeaf()) || (cfg2 && !cfg2->isLeaf())) { // not a leaf node @@ -675,7 +671,7 @@ _get_cmds_diff_leaf(const CfgNode *cfg1, const CfgNode *cfg2, } const CfgNode *cfg = NULL; - vector<vector<string> > *list = NULL; + vector<Cpath> *list = NULL; if (cfg1) { cfg = cfg1; if (!cfg2) { @@ -736,12 +732,10 @@ _get_cmds_diff_leaf(const CfgNode *cfg1, const CfgNode *cfg2, static void _get_cmds_diff_other(const CfgNode *cfg1, const CfgNode *cfg2, - vector<string>& cur_path, - vector<vector<string> >& del_list, - vector<vector<string> >& set_list, - vector<vector<string> >& com_list) + Cpath& cur_path, vector<Cpath>& del_list, + vector<Cpath>& set_list, vector<Cpath>& com_list) { - vector<vector<string> > *list = NULL; + vector<Cpath> *list = NULL; if (cfg1) { if (!cfg2) { // exists in cfg1 but not in cfg2 => delete and stop recursion @@ -773,9 +767,9 @@ _get_cmds_diff_other(const CfgNode *cfg1, const CfgNode *cfg2, const string *val = (is_value ? &value : NULL); _get_comment_diff_cmd(cfg1, cfg2, cur_path, com_list, val); - cur_path.push_back(name); + cur_path.push(name); if (is_value) { - cur_path.push_back(value); + cur_path.push(value); } } for (size_t i = 0; i < rcnodes1.size(); i++) { @@ -784,17 +778,16 @@ _get_cmds_diff_other(const CfgNode *cfg1, const CfgNode *cfg2, } if (add_this) { if (is_value) { - cur_path.pop_back(); + cur_path.pop(); } - cur_path.pop_back(); + cur_path.pop(); } } static void _get_cmds_diff(const CfgNode *cfg1, const CfgNode *cfg2, - vector<string>& cur_path, vector<vector<string> >& del_list, - vector<vector<string> >& set_list, - vector<vector<string> >& com_list) + Cpath& cur_path, vector<Cpath>& del_list, + vector<Cpath>& set_list, vector<Cpath>& com_list) { // if doesn't exist, treat as NULL if (cfg1 && !cfg1->exists()) { @@ -820,12 +813,12 @@ _get_cmds_diff(const CfgNode *cfg1, const CfgNode *cfg2, } static void -_print_cmds_list(const char *op, vector<vector<string> >& list) +_print_cmds_list(const char *op, vector<Cpath>& list) { for (size_t i = 0; i < list.size(); i++) { printf("%s", op); for (size_t j = 0; j < list[i].size(); j++) { - printf(" '%s'", list[i][j].c_str()); + printf(" '%s'", list[i][j]); } printf("\n"); } @@ -834,8 +827,8 @@ _print_cmds_list(const char *op, vector<vector<string> >& list) ////// algorithms void cnode::show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, - vector<string>& cur_path, bool show_def, - bool hide_secret, bool context_diff) + Cpath& cur_path, bool show_def, bool hide_secret, + bool context_diff) { if (cfg1.isInvalid() || cfg2.isInvalid()) { printf("Specified configuration path is not valid\n"); @@ -847,7 +840,7 @@ cnode::show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, return; } // use an invalid value for initial last_ctx - vector<string> last_ctx(1, ""); + Cpath last_ctx; _show_diff(&cfg1, &cfg2, -1, cur_path, last_ctx, show_def, hide_secret, context_diff); } @@ -855,17 +848,17 @@ cnode::show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, void cnode::show_cfg(const CfgNode& cfg, bool show_def, bool hide_secret) { - vector<string> cur_path; + Cpath cur_path; show_cfg_diff(cfg, cfg, cur_path, show_def, hide_secret); } void cnode::show_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2) { - vector<string> cur_path; - vector<vector<string> > del_list; - vector<vector<string> > set_list; - vector<vector<string> > com_list; + Cpath cur_path; + vector<Cpath> del_list; + vector<Cpath> set_list; + vector<Cpath> com_list; _get_cmds_diff(&cfg1, &cfg2, cur_path, del_list, set_list, com_list); _print_cmds_list("delete", del_list); @@ -881,32 +874,31 @@ cnode::show_cmds(const CfgNode& cfg) void cnode::get_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2, - vector<vector<string> >& del_list, - vector<vector<string> >& set_list, - vector<vector<string> >& com_list) + vector<Cpath>& del_list, vector<Cpath>& set_list, + vector<Cpath>& com_list) { - vector<string> cur_path; + Cpath cur_path; _get_cmds_diff(&cfg1, &cfg2, cur_path, del_list, set_list, com_list); } void -cnode::get_cmds(const CfgNode& cfg, vector<vector<string> >& set_list, - vector<vector<string> >& com_list) +cnode::get_cmds(const CfgNode& cfg, vector<Cpath>& set_list, + vector<Cpath>& com_list) { - vector<string> cur_path; - vector<vector<string> > del_list; + Cpath cur_path; + vector<Cpath> del_list; _get_cmds_diff(&cfg, &cfg, cur_path, del_list, set_list, com_list); } void cnode::showConfig(const string& cfg1, const string& cfg2, - const vector<string>& path, bool show_def, bool hide_secret, + const Cpath& path, bool show_def, bool hide_secret, bool context_diff, bool show_cmds) { tr1::shared_ptr<CfgNode> aroot, wroot, croot1, croot2; tr1::shared_ptr<Cstore> cstore; - vector<string> rpath(path); - vector<string> cur_path; + Cpath rpath(path); + Cpath cur_path; if ((cfg1 == ACTIVE_CFG || cfg1 == WORKING_CFG) && (cfg2 == ACTIVE_CFG || cfg2 == WORKING_CFG)) { diff --git a/src/cnode/cnode-algorithm.hpp b/src/cnode/cnode-algorithm.hpp index c473d6a..2f8995d 100644 --- a/src/cnode/cnode-algorithm.hpp +++ b/src/cnode/cnode-algorithm.hpp @@ -22,9 +22,8 @@ namespace cnode { void show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, - vector<string>& cur_path, - bool show_def = false, bool hide_secret = false, - bool context_diff = false); + Cpath& cur_path, bool show_def = false, + bool hide_secret = false, bool context_diff = false); void show_cfg(const CfgNode& cfg, bool show_def = false, bool hide_secret = false); @@ -32,17 +31,16 @@ void show_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2); void show_cmds(const CfgNode& cfg); void get_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2, - vector<vector<string> >& del_list, - vector<vector<string> >& set_list, - vector<vector<string> >& com_list); -void get_cmds(const CfgNode& cfg, vector<vector<string> >& set_list, - vector<vector<string> >& com_list); + vector<Cpath>& del_list, vector<Cpath>& set_list, + vector<Cpath>& com_list); +void get_cmds(const CfgNode& cfg, vector<Cpath>& set_list, + vector<Cpath>& com_list); extern const string ACTIVE_CFG; extern const string WORKING_CFG; void showConfig(const string& cfg1, const string& cfg2, - const vector<string>& path, bool show_def = false, + const Cpath& path, bool show_def = false, bool hide_secret = false, bool context_diff = false, bool show_cmds = false); diff --git a/src/cnode/cnode.cpp b/src/cnode/cnode.cpp index f484fb1..cd4f6cf 100644 --- a/src/cnode/cnode.cpp +++ b/src/cnode/cnode.cpp @@ -28,20 +28,19 @@ using namespace cnode; ////// constructors/destructors -CfgNode::CfgNode(vector<string>& path_comps, char *name, char *val, - char *comment, int deact, Cstore *cstore, - bool tag_if_invalid) +CfgNode::CfgNode(Cpath& path_comps, char *name, char *val, char *comment, + int deact, Cstore *cstore, bool tag_if_invalid) : _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(true), _exists(true) { if (name && name[0]) { // name must be non-empty - path_comps.push_back(name); + path_comps.push(name); } if (val) { // value could be empty - path_comps.push_back(val); + path_comps.push(val); } while (1) { @@ -50,7 +49,7 @@ CfgNode::CfgNode(vector<string>& path_comps, char *name, char *val, break; } - auto_ptr<Ctemplate> def(cstore->parseTmpl(path_comps, false)); + tr1::shared_ptr<Ctemplate> def(cstore->parseTmpl(path_comps, false)); if (def.get()) { // got the def _is_tag = def->isTag(); @@ -106,16 +105,16 @@ CfgNode::CfgNode(vector<string>& path_comps, char *name, char *val, } else { _value = val; } - path_comps.pop_back(); + path_comps.pop(); } if (name && name[0]) { _name = name; - path_comps.pop_back(); + path_comps.pop(); } } -CfgNode::CfgNode(Cstore& cstore, vector<string>& path_comps, - bool active, bool recursive) +CfgNode::CfgNode(Cstore& cstore, Cpath& 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), _exists(true) @@ -124,7 +123,7 @@ CfgNode::CfgNode(Cstore& cstore, vector<string>& path_comps, * "root", treat it as an intermediate node. */ if (path_comps.size() > 0) { - auto_ptr<Ctemplate> def(cstore.parseTmpl(path_comps, false)); + tr1::shared_ptr<Ctemplate> def(cstore.parseTmpl(path_comps, false)); if (def.get()) { // got the def if (!cstore.cfgPathExists(path_comps, active)) { @@ -202,10 +201,10 @@ CfgNode::CfgNode(Cstore& cstore, vector<string>& path_comps, // recurse for (size_t i = 0; i < cnodes.size(); i++) { - path_comps.push_back(cnodes[i]); + path_comps.push(cnodes[i]); CfgNode *cn = new CfgNode(cstore, path_comps, active, recursive); _child_nodes.push_back(cn); - path_comps.pop_back(); + path_comps.pop(); } } diff --git a/src/cnode/cnode.hpp b/src/cnode/cnode.hpp index b7afc36..a684514 100644 --- a/src/cnode/cnode.hpp +++ b/src/cnode/cnode.hpp @@ -27,10 +27,10 @@ using namespace cstore; class CfgNode { public: - CfgNode(vector<string>& path_comps, char *name, char *val, char *comment, + CfgNode(Cpath& path_comps, char *name, char *val, char *comment, int deact, Cstore *cstore, bool tag_if_invalid = false); - CfgNode(Cstore& cstore, std::vector<string>& path_comps, - bool active = false, bool recursive = true); + CfgNode(Cstore& cstore, Cpath& path_comps, bool active = false, + bool recursive = true); ~CfgNode() {}; bool isTag() const { return _is_tag; } @@ -44,11 +44,11 @@ public: bool isEmpty() const { return _is_empty; } bool exists() const { return _exists; } - 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 *>& getChildNodes() const { return _child_nodes; } + const string& getName() const { return _name; } + const string& getValue() const { return _value; } + const vector<string>& getValues() const { return _values; } + const string& getComment() const { return _comment; } + const vector<CfgNode *>& getChildNodes() const { return _child_nodes; } void addMultiValue(char *val) { _values.push_back(val); } void addChildNode(CfgNode *cnode) { @@ -68,11 +68,11 @@ private: bool _is_invalid; bool _is_empty; bool _exists; - std::string _name; - std::string _value; - std::vector<std::string> _values; - std::string _comment; - std::vector<CfgNode *> _child_nodes; + string _name; + string _value; + vector<string> _values; + string _comment; + vector<CfgNode *> _child_nodes; }; } // namespace cnode diff --git a/src/cparse/cparse.ypp b/src/cparse/cparse.ypp index 24abbad..6b5d5c6 100644 --- a/src/cparse/cparse.ypp +++ b/src/cparse/cparse.ypp @@ -1,7 +1,6 @@ %{ #include <cstdio> #include <vector> -#include <map> #include <string> #include <cstore/cstore.hpp> @@ -39,25 +38,25 @@ static char *ncomment = NULL; static char *nname = NULL; static char *nval = NULL; -// XXX optimize: use unordered_map with non-vector -static map<vector<string>, CfgNode *> node_map; +typedef Cstore::MapT<Cpath, CfgNode *, CpathHash> NmapT; +static NmapT node_map; static Cstore *cstore_ = NULL; static CfgNode *cur_node = NULL; static CfgNode *cur_parent = NULL; static vector<CfgNode *> cur_path; -static vector<string> pcomps; +static Cpath pcomps; static vector<bool> pcomp_is_value; static void add_node() { - pcomps.push_back(nname); + pcomps.push(nname); CfgNode *onode = NULL; - map<vector<string>, CfgNode *>::iterator it = node_map.find(pcomps); + NmapT::iterator it = node_map.find(pcomps); if (it != node_map.end()) { onode = it->second; } - pcomps.pop_back(); + pcomps.pop(); if (onode) { if (nval) { if (onode->isMulti()) { @@ -92,9 +91,9 @@ add_node() mapped_node = p; } cur_parent->addChildNode(mapped_node); - pcomps.push_back(nname); + pcomps.push(nname); node_map[pcomps] = mapped_node; - pcomps.pop_back(); + pcomps.pop(); } } @@ -104,10 +103,10 @@ go_down() cur_path.push_back(cur_parent); cur_parent = cur_node; - pcomps.push_back(nname); + pcomps.push(nname); pcomp_is_value.push_back(false); if (nval) { - pcomps.push_back(nval); + pcomps.push(nval); pcomp_is_value.push_back(true); } } @@ -119,10 +118,10 @@ go_up() cur_path.pop_back(); if (pcomp_is_value.back()) { - pcomps.pop_back(); + pcomps.pop(); pcomp_is_value.pop_back(); } - pcomps.pop_back(); + pcomps.pop(); pcomp_is_value.pop_back(); } diff --git a/src/cstore/cpath.hpp b/src/cstore/cpath.hpp new file mode 100644 index 0000000..ed26a92 --- /dev/null +++ b/src/cstore/cpath.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 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 _CPATH_HPP_ +#define _CPATH_HPP_ +#include <string> + +#include <cstore/svector.hpp> + +namespace cstore { // begin namespace cstore + +class Cpath { +public: + Cpath() : _data() {}; + Cpath(const Cpath& p) : _data() { operator=(p); }; + Cpath(const char *comps[], size_t num_comps) : _data() { + for (size_t i = 0; i < num_comps; i++) { + push(comps[i]); + } + }; + ~Cpath() {}; + + void push(const char *comp) { _data.push_back(comp); }; + void push(const std::string& comp) { _data.push_back(comp.c_str()); }; + void pop() { _data.pop_back(); }; + void pop(std::string& last) { _data.pop_back(last); }; + void clear() { _data.assign("", 0); }; + + Cpath& operator=(const Cpath& p) { + _data = p._data; + return *this; + }; + Cpath& operator/=(const Cpath& p) { + _data /= p._data; + return *this; + } + Cpath operator/(const Cpath& rhs) { + Cpath lhs(*this); + lhs /= rhs; + return lhs; + }; + + bool operator==(const Cpath& rhs) const { + return (_data == rhs._data); + }; + const char *operator[](size_t idx) const { + return _data[idx]; + }; + + size_t size() const { return _data.size(); }; + size_t hash() const { return _data.hash(); }; + const char *back() const { + return (size() > 0 ? _data[size() - 1] : NULL); + }; + +private: + struct CpathParams { + static const char separator = 0; + static const size_t static_num_elems = 24; + static const size_t static_buf_len = 256; + }; + + cstore::svector<CpathParams> _data; +}; + +struct CpathHash { + inline size_t operator()(const Cpath& p) const { + return p.hash(); + }; +}; + +} // end namespace cstore + +#endif /* _CPATH_HPP_ */ + diff --git a/src/cstore/cstore-c.cpp b/src/cstore/cstore-c.cpp index 06f0067..86b544e 100644 --- a/src/cstore/cstore-c.cpp +++ b/src/cstore/cstore-c.cpp @@ -24,14 +24,6 @@ using namespace cstore; -static void -_get_str_vec(vector<string>& vec, const char *strs[], int num_strs) -{ - for (int i = 0; i < num_strs; i++) { - vec.push_back(strs[i]); - } -} - void * cstore_init(void) { @@ -51,10 +43,9 @@ cstore_validate_tmpl_path(void *handle, const char *path_comps[], int num_comps, int validate_tags) { if (handle) { - vector<string> vs; - _get_str_vec(vs, path_comps, num_comps); + Cpath p(path_comps, num_comps); Cstore *cs = (Cstore *) handle; - return (cs->validateTmplPath(vs, validate_tags) ? 1 : 0); + return (cs->validateTmplPath(p, validate_tags) ? 1 : 0); } return 0; } @@ -63,10 +54,9 @@ int cstore_cfg_path_exists(void *handle, const char *path_comps[], int num_comps) { if (handle) { - vector<string> vs; - _get_str_vec(vs, path_comps, num_comps); + Cpath p(path_comps, num_comps); Cstore *cs = (Cstore *) handle; - return (cs->cfgPathExists(vs) ? 1 : 0); + return (cs->cfgPathExists(p) ? 1 : 0); } return 0; } @@ -99,10 +89,9 @@ cstore_cfg_path_deactivated(void *handle, const char *path_comps[], int num_comps, int in_active) { if (handle) { - vector<string> vs; - _get_str_vec(vs, path_comps, num_comps); + Cpath p(path_comps, num_comps); Cstore *cs = (Cstore *) handle; - return (cs->cfgPathDeactivated(vs, in_active) ? 1 : 0); + return (cs->cfgPathDeactivated(p, in_active) ? 1 : 0); } return 0; } @@ -112,11 +101,10 @@ cstore_cfg_path_get_effective_value(void *handle, const char *path_comps[], int num_comps) { if (handle) { - vector<string> vs; - _get_str_vec(vs, path_comps, num_comps); + Cpath p(path_comps, num_comps); Cstore *cs = (Cstore *) handle; string val; - if (!cs->cfgPathGetEffectiveValue(vs, val)) { + if (!cs->cfgPathGetEffectiveValue(p, val)) { return NULL; } @@ -138,10 +126,9 @@ cstore_unmark_cfg_path_changed(void *handle, const char *path_comps[], int num_comps) { if (handle) { - vector<string> vs; - _get_str_vec(vs, path_comps, num_comps); + Cpath p(path_comps, num_comps); Cstore *cs = (Cstore *) handle; - return (cs->unmarkCfgPathChanged(vs) ? 1 : 0); + return (cs->unmarkCfgPathChanged(p) ? 1 : 0); } return 0; } diff --git a/src/cstore/cstore-varref.cpp b/src/cstore/cstore-varref.cpp index 2878dd0..2ec3c51 100644 --- a/src/cstore/cstore-varref.cpp +++ b/src/cstore/cstore-varref.cpp @@ -37,9 +37,15 @@ Cstore::VarRef::VarRef(Cstore *cstore, const string& ref_str, bool active) } _absolute = (ref_str[0] == '/'); + vector<string> tmp; while (!_absolute && !_cstore->cfg_path_at_root()) { - _orig_path_comps.insert(_orig_path_comps.begin(), - _cstore->pop_cfg_path()); + string last; + _cstore->pop_cfg_path(last); + tmp.push_back(last); + } + while (tmp.size() > 0) { + _orig_path_comps.push(tmp.back()); + tmp.pop_back(); } _cstore->reset_paths(); /* at this point, cstore paths are at root. _orig_path_comps contains @@ -48,14 +54,14 @@ Cstore::VarRef::VarRef(Cstore *cstore, const string& ref_str, bool active) size_t si = (_absolute ? 1 : 0); size_t sn = 0; - vector<string> rcomps; + Cpath rcomps; while (si < ref_str.length() && (sn = ref_str.find('/', si)) != ref_str.npos) { - rcomps.push_back(ref_str.substr(si, sn - si)); + rcomps.push(ref_str.substr(si, sn - si)); si = sn + 1; } if (si < ref_str.length()) { - rcomps.push_back(ref_str.substr(si)); + rcomps.push(ref_str.substr(si)); } // NOTE: if path ends in '/', the trailing slash is ignored. @@ -63,7 +69,7 @@ Cstore::VarRef::VarRef(Cstore *cstore, const string& ref_str, bool active) _at_string = get_at_string(); // process ref - vector<string> pcomps = _orig_path_comps; + Cpath pcomps(_orig_path_comps); process_ref(rcomps, pcomps, ERROR_TYPE); } @@ -77,23 +83,24 @@ Cstore::VarRef::VarRef(Cstore *cstore, const string& ref_str, bool active) * actual config (working or active). */ void -Cstore::VarRef::process_ref(const vector<string>& ref_comps, - const vector<string>& cur_path_comps, +Cstore::VarRef::process_ref(const Cpath& ref_comps, + const Cpath& 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)); + _paths.push_back(pair<Cpath, 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()); + Cpath rcomps; + Cpath pcomps(cur_path_comps); + string cr_comp = ref_comps[0]; + for (size_t i = 1; i < ref_comps.size(); i++) { + rcomps.push(ref_comps[i]); + } - auto_ptr<Ctemplate> def(_cstore->parseTmpl(pcomps, false)); + tr1::shared_ptr<Ctemplate> def(_cstore->parseTmpl(pcomps, false)); bool got_tmpl = (def.get() != 0); bool handle_leaf = false; if (cr_comp == "@") { @@ -106,19 +113,18 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, return; } if (pcomps.size() == _orig_path_comps.size()) { - if (pcomps.size() == 0 - || equal(pcomps.begin(), pcomps.end(), _orig_path_comps.begin())) { + if (pcomps.size() == 0 || pcomps == _orig_path_comps) { /* we are at the original path. this is a self-reference, e.g., * $VAR(@), so use the "at string". */ - pcomps.push_back(_at_string); + pcomps.push(_at_string); 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()]); + pcomps.push(_orig_path_comps[pcomps.size()]); process_ref(rcomps, pcomps, def->getType(1)); return; } @@ -135,8 +141,8 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, // invalid path return; } - pcomps.pop_back(); - def.reset(_cstore->parseTmpl(pcomps, false)); + pcomps.pop(); + def = _cstore->parseTmpl(pcomps, false); if (!def.get()) { // invalid tmpl path return; @@ -147,7 +153,7 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, // invalid path return; } - pcomps.pop_back(); + pcomps.pop(); } process_ref(rcomps, pcomps, ERROR_TYPE); } else if (cr_comp == "@@") { @@ -168,9 +174,9 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, vector<string> cnodes; _cstore->cfgPathGetChildNodes(pcomps, cnodes, _active); for (size_t i = 0; i < cnodes.size(); i++) { - pcomps.push_back(cnodes[i]); + pcomps.push(cnodes[i]); process_ref(rcomps, pcomps, def->getType(1)); - pcomps.pop_back(); + pcomps.pop(); } } else { // handle leaf node @@ -185,9 +191,9 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, return; } // within the original path. take the original tag value. - pcomps.push_back(_orig_path_comps[pcomps.size()]); + pcomps.push(_orig_path_comps[pcomps.size()]); } - pcomps.push_back(cr_comp); + pcomps.push(cr_comp); process_ref(rcomps, pcomps, ERROR_TYPE); } @@ -205,9 +211,9 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, } val += vals[i]; } - pcomps.push_back(val); + pcomps.push(val); // treat "joined" multi-values as TEXT_TYPE - _paths.push_back(pair<vector<string>, vtw_type_e>(pcomps, TEXT_TYPE)); + _paths.push_back(pair<Cpath, vtw_type_e>(pcomps, TEXT_TYPE)); // at leaf. stop recursion. } else { // single-value node @@ -215,9 +221,8 @@ Cstore::VarRef::process_ref(const vector<string>& ref_comps, if (!_cstore->cfgPathGetValue(pcomps, val, _active)) { return; } - pcomps.push_back(val); - _paths.push_back(pair<vector<string>, vtw_type_e>(pcomps, - def->getType(1))); + pcomps.push(val); + _paths.push_back(pair<Cpath, vtw_type_e>(pcomps, def->getType(1))); // at leaf. stop recursion. } } @@ -273,7 +278,7 @@ Cstore::VarRef::getValue(string& value, vtw_type_e& def_type) } bool -Cstore::VarRef::getSetPath(vector<string>& path_comps) +Cstore::VarRef::getSetPath(Cpath& path_comps) { /* XXX this function is currently unused and untested. see setVarRef() * in Cstore for more information. diff --git a/src/cstore/cstore-varref.hpp b/src/cstore/cstore-varref.hpp index 3b842a9..acfe4d1 100644 --- a/src/cstore/cstore-varref.hpp +++ b/src/cstore/cstore-varref.hpp @@ -30,18 +30,18 @@ public: ~VarRef() {}; bool getValue(string& value, vtw_type_e& def_type); - bool getSetPath(vector<string>& path_comps); + bool getSetPath(Cpath& path_comps); private: Cstore *_cstore; bool _active; bool _absolute; string _at_string; - vector<string> _orig_path_comps; - vector<pair<vector<string>, vtw_type_e> > _paths; + Cpath _orig_path_comps; + vector<pair<Cpath, vtw_type_e> > _paths; - void process_ref(const vector<string>& ref_comps, - const vector<string>& cur_path_comps, vtw_type_e def_type); + void process_ref(const Cpath& ref_comps, + const Cpath& cur_path_comps, vtw_type_e def_type); }; } // end namespace cstore diff --git a/src/cstore/cstore.cpp b/src/cstore/cstore.cpp index 91d82e3..70f1c55 100644 --- a/src/cstore/cstore.cpp +++ b/src/cstore/cstore.cpp @@ -37,7 +37,7 @@ #include <cnode/cnode-algorithm.hpp> #include <cparse/cparse.hpp> -using namespace cstore; +namespace cstore { // begin namespace cstore ////// constants //// node status @@ -103,14 +103,14 @@ Cstore::Cstore(string& env) Cstore * Cstore::createCstore(bool use_edit_level) { - return (new UnionfsCstore(use_edit_level)); + return (new unionfs::UnionfsCstore(use_edit_level)); } // for "specific session" (see UnionfsCstore constructor for details) Cstore * Cstore::createCstore(const string& session_id, string& env) { - return (new UnionfsCstore(session_id, env)); + return (new unionfs::UnionfsCstore(session_id, env)); } @@ -120,10 +120,10 @@ Cstore::createCstore(const string& session_id, string& env) * return true if valid. otherwise return false. */ bool -Cstore::validateTmplPath(const vector<string>& path_comps, bool validate_vals) +Cstore::validateTmplPath(const Cpath& path_comps, bool validate_vals) { // if we can get parsed tmpl, path is valid - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, validate_vals)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, validate_vals)); return (def.get() != 0); } @@ -131,8 +131,8 @@ Cstore::validateTmplPath(const vector<string>& path_comps, bool validate_vals) * 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. */ -Ctemplate * -Cstore::parseTmpl(const vector<string>& path_comps, bool validate_vals) +tr1::shared_ptr<Ctemplate> +Cstore::parseTmpl(const Cpath& path_comps, bool validate_vals) { return get_parsed_tmpl(path_comps, validate_vals); } @@ -142,7 +142,7 @@ Cstore::parseTmpl(const vector<string>& path_comps, bool validate_vals) * return true if successful. otherwise return false. */ bool -Cstore::getParsedTmpl(const vector<string>& path_comps, +Cstore::getParsedTmpl(const Cpath& path_comps, Cstore::MapT<string, string>& tmap, bool allow_val) { /* currently this function is used outside actual CLI operations, mainly @@ -152,7 +152,7 @@ Cstore::getParsedTmpl(const vector<string>& path_comps, * * anyway, not validating values in the following call. */ - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); if (!def.get()) { return false; } @@ -210,26 +210,25 @@ Cstore::getParsedTmpl(const vector<string>& path_comps, * note: if specified path is at a "tag node", "node.tag" will be returned. */ void -Cstore::tmplGetChildNodes(const vector<string>& path_comps, +Cstore::tmplGetChildNodes(const Cpath& path_comps, vector<string>& cnodes) { - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_tmpl_path(path_comps); get_all_tmpl_child_node_names(cnodes); sort_nodes(cnodes); - RESTORE_PATHS; } /* delete specified "logical path" from "working config". * return true if successful. otherwise return false. */ bool -Cstore::deleteCfgPath(const vector<string>& path_comps) +Cstore::deleteCfgPath(const Cpath& path_comps) { ASSERT_IN_SESSION; string terr; - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); if (!def.get()) { output_user("%s\n", terr.c_str()); return false; @@ -251,7 +250,7 @@ Cstore::deleteCfgPath(const vector<string>& path_comps) */ if (def->getDefault()) { // case 1. construct path for value file. - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); if (def->isValue()) { // last comp is "value". need to go up 1 level. @@ -263,13 +262,12 @@ Cstore::deleteCfgPath(const vector<string>& path_comps) * also deactivated. note that unmark_deactivated() succeeds if it's * not marked deactivated. also mark "changed". */ - bool ret = (write_value(def->getDefault()) && mark_display_default() - && unmark_deactivated() && mark_changed_with_ancestors()); - if (!ret) { + if (!(write_value(def->getDefault()) && mark_display_default() + && unmark_deactivated() && mark_changed_with_ancestors())) { output_user("Failed to set default value during delete\n"); + return false; } - RESTORE_PATHS; - return ret; + return true; } /* case 2. @@ -287,7 +285,7 @@ Cstore::deleteCfgPath(const vector<string>& path_comps) * => remove node */ bool ret = false; - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); if (!def->isValue()) { // sub-case (2) @@ -311,7 +309,6 @@ Cstore::deleteCfgPath(const vector<string>& path_comps) // mark changed ret = mark_changed_with_ancestors(); } - RESTORE_PATHS; if (!ret) { output_user("Failed to delete specified config path\n"); } @@ -322,20 +319,19 @@ Cstore::deleteCfgPath(const vector<string>& path_comps) * return true if valid. otherwise return false. */ bool -Cstore::validateSetPath(const vector<string>& path_comps) +Cstore::validateSetPath(const Cpath& path_comps) { ASSERT_IN_SESSION; // if we can get parsed tmpl, path is valid string terr; - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, true, terr)); + tr1::shared_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; + auto_ptr<SavePaths> save(create_save_paths()); if (!def->isValue()) { if (!def->isTypeless()) { /* disallow setting value node without value @@ -344,7 +340,7 @@ Cstore::validateSetPath(const vector<string>& path_comps) * (single-value, multi-value, and tag) must be set with value. */ output_user("The specified configuration node requires a value\n"); - ret = false; + return false; } else { /* typeless node * note: XXX the following is present in the original logic, perhaps @@ -355,24 +351,23 @@ Cstore::validateSetPath(const vector<string>& path_comps) */ append_cfg_path(path_comps); append_tmpl_path(path_comps); - if (!validate_val(def.get(), "")) { - ret = false; + if (!validate_val(def, "")) { + return false; } } } - RESTORE_PATHS; - return ret; + return true; } /* check if specified "logical path" is valid for "activate" operation * return true if valid. otherwise return false. */ bool -Cstore::validateActivatePath(const vector<string>& path_comps) +Cstore::validateActivatePath(const Cpath& path_comps) { ASSERT_IN_SESSION; - auto_ptr<Ctemplate> def(validate_act_deact(path_comps, "activate")); + tr1::shared_ptr<Ctemplate> def(validate_act_deact(path_comps, "activate")); if (!def.get()) { return false; } @@ -381,35 +376,35 @@ Cstore::validateActivatePath(const vector<string>& path_comps) "deactivate\ncommand has been performed.\n"); return false; } - bool ret = true; + 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; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - string t = pop_cfg_path(); + string t; + pop_cfg_path(t); // get child nodes, excluding deactivated ones. get_all_child_node_names(cnodes, false, false); if (def->getTagLimit() <= cnodes.size()) { // limit exceeded output_user("Cannot activate \"%s\": number of values exceeds limit " "(%d allowed)\n", t.c_str(), def->getTagLimit()); - ret = false; + return false; } - RESTORE_PATHS; } - return ret; + return true; } /* check if specified "logical path" is valid for "deactivate" operation * return true if valid. otherwise return false. */ bool -Cstore::validateDeactivatePath(const vector<string>& path_comps) +Cstore::validateDeactivatePath(const Cpath& path_comps) { ASSERT_IN_SESSION; - auto_ptr<Ctemplate> def(validate_act_deact(path_comps, "deactivate")); + tr1::shared_ptr<Ctemplate> def(validate_act_deact(path_comps, "deactivate")); return (def.get() != 0); } @@ -419,12 +414,12 @@ Cstore::validateDeactivatePath(const vector<string>& path_comps) * operation and return true. */ bool -Cstore::getEditEnv(const vector<string>& path_comps, string& env) +Cstore::getEditEnv(const Cpath& path_comps, string& env) { ASSERT_IN_SESSION; string terr; - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); if (!def.get()) { output_user("%s\n", terr.c_str()); return false; @@ -453,11 +448,10 @@ Cstore::getEditEnv(const vector<string>& path_comps, string& env) return false; } } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); append_tmpl_path(path_comps); get_edit_env(env); - RESTORE_PATHS; /* doing the save/restore above to be consistent with the rest of the API. * however, after the caller evals the returned environment string, the * levels in "this" will become out-of-sync with the environment. so @@ -488,14 +482,14 @@ Cstore::getEditUpEnv(string& env) } string terr; - vector<string> path_comps; - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); + Cpath path_comps; + tr1::shared_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; + auto_ptr<SavePaths> save(create_save_paths()); if (def->isTagValue()) { // edit level is at "tag value". go up 1 extra level. pop_cfg_path(); @@ -504,7 +498,6 @@ Cstore::getEditUpEnv(string& env) pop_cfg_path(); pop_tmpl_path(); get_edit_env(env); - RESTORE_PATHS; // also see getEditEnv for comment on save/restore above return true; @@ -518,13 +511,12 @@ Cstore::getEditResetEnv(string& env) { ASSERT_IN_SESSION; - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); while (!edit_level_at_root()) { pop_cfg_path(); pop_tmpl_path(); } get_edit_env(env); - RESTORE_PATHS; // also see getEditEnv for comment on save/restore above return true; @@ -537,15 +529,17 @@ Cstore::getEditResetEnv(string& env) * first path element (which can be empty string). */ bool -Cstore::getCompletionEnv(const vector<string>& comps, string& env) +Cstore::getCompletionEnv(const Cpath& comps, string& env) { ASSERT_IN_SESSION; - vector<string> pcomps = comps; - string cmd = pcomps[0]; - string last_comp = pcomps.back(); - pcomps.erase(pcomps.begin()); - pcomps.pop_back(); + string cmd = comps[0]; + string last_comp = comps.back(); + Cpath pcomps; + for (size_t i = 1; i < (comps.size() - 1); i++) { + pcomps.push(comps[i]); + } + bool exists_only = (cmd == "delete" || cmd == "show" || cmd == "comment" || cmd == "activate" || cmd == "deactivate"); @@ -553,290 +547,294 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env) /* at this point, pcomps contains the command line arguments minus the * "command" and the last one. */ - bool ret = false; - SAVE_PATHS; - do { - bool is_typeless = true; - bool is_leaf_value = false; - bool is_value = false; - auto_ptr<Ctemplate> def; - if (pcomps.size() > 0) { - def.reset(get_parsed_tmpl(pcomps, false)); - if (!def.get()) { - // invalid path - break; - } - if (exists_only && !cfg_path_exists(pcomps, false, true)) { - // invalid path for the command (must exist) - break; - } - 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. default values simulate a typeless node so nop. - * note that in this case def is "empty", so must ensure that it's - * not used. - */ + auto_ptr<SavePaths> save(create_save_paths()); + bool is_typeless = true; + bool is_leaf_value = false; + bool is_value = false; + tr1::shared_ptr<Ctemplate> def; + if (pcomps.size() > 0) { + def = get_parsed_tmpl(pcomps, false); + if (!def.get()) { + // invalid path + return false; + } + if (exists_only && !cfg_path_exists(pcomps, false, true)) { + // invalid path for the command (must exist) + return false; } + 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. 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. + /* at this point, cfg and tmpl paths are constructed up to the comp + * before last_comp, and def is parsed. + */ + if (is_leaf_value) { + // invalid path (this means the comp before last_comp is a leaf value) + return false; + } + + vector<string> comp_vals; + string comp_string; + string comp_help; + vector<pair<string, string> > help_pairs; + bool last_comp_val = true; + 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. + * help: + * values: same as completions. + * text: "help" from child templates. + * + * 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. */ - if (is_leaf_value) { - // invalid path (this means the comp before last_comp is a leaf value) - break; + vector<string> ufvec; + if (exists_only) { + // only return existing config nodes + get_all_child_node_names(ufvec, false, true); + } else { + // return all template children + get_all_tmpl_child_node_names(ufvec); } + for (size_t i = 0; i < ufvec.size(); i++) { + if (last_comp == "" + || ufvec[i].compare(0, last_comp.length(), last_comp) == 0) { + comp_vals.push_back(ufvec[i]); + } + } + if (comp_vals.size() == 0) { + // no matches + return false; + } + sort(comp_vals.begin(), comp_vals.end()); - vector<string> comp_vals; - string comp_string; - string comp_help; - vector<pair<string, string> > help_pairs; - bool last_comp_val = true; - 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. - * help: - * values: same as completions. - * text: "help" from child templates. - * - * 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) { - // only return existing config nodes - get_all_child_node_names(ufvec, false, true); + /* loop below calls get_parsed_tmpl(), which takes the whole path. + * so need to save current paths and reset them before (and restore them + * after). + */ + auto_ptr<SavePaths> save1(create_save_paths()); + reset_paths(); + for (size_t i = 0; i < comp_vals.size(); i++) { + pair<string, string> hpair(comp_vals[i], ""); + pcomps.push(comp_vals[i]); + tr1::shared_ptr<Ctemplate> cdef(get_parsed_tmpl(pcomps, false)); + if (cdef.get() && cdef->getNodeHelp()) { + hpair.second = cdef->getNodeHelp(); } else { - // return all template children - get_all_tmpl_child_node_names(ufvec); - } - for (size_t i = 0; i < ufvec.size(); i++) { - if (last_comp == "" - || ufvec[i].compare(0, last_comp.length(), last_comp) == 0) { - comp_vals.push_back(ufvec[i]); - } - } - if (comp_vals.size() == 0) { - // no matches - break; + hpair.second = "<No help text available>"; } - sort(comp_vals.begin(), comp_vals.end()); - for (size_t i = 0; i < comp_vals.size(); i++) { - pair<string, string> hpair(comp_vals[i], ""); - push_tmpl_path(hpair.first); - auto_ptr<Ctemplate> cdef(tmpl_parse()); - if (cdef.get() && cdef->getNodeHelp()) { - hpair.second = cdef->getNodeHelp(); - } else { - hpair.second = "<No help text available>"; - } - help_pairs.push_back(hpair); - pop_tmpl_path(); - } - // last comp is not value - last_comp_val = false; + help_pairs.push_back(hpair); + pcomps.pop(); + } + // last comp is not value + last_comp_val = false; + } else { + /* 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->isTag()) { + // it's a "tag node". get completions from tag values. + get_all_child_node_names(comp_vals, false, true); } else { - /* 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. + // it's a "leaf value node". get completions from values. + read_value_vec(comp_vals, false); + } + /* more possible completions from this node's template: + * "allowed" + * "enumeration" + * "$VAR(@) in ..." + */ + 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 + * "allowed" scripts. */ - // first, handle completions. - if (def->isTag()) { - // it's a "tag node". get completions from tag values. - get_all_child_node_names(comp_vals, false, true); + ostringstream cword_count; + cword_count << (comps.size() - 1); + string cmd_str = ("export " + C_ENV_SHELL_CWORD_COUNT + "=" + + cword_count.str() + "; "); + cmd_str += ("export " + C_ENV_SHELL_CWORDS + "=("); + for (size_t i = 0; i < comps.size(); i++) { + cmd_str += " '"; + cmd_str += comps[i]; + cmd_str += "'"; + } + cmd_str += "); "; + if (def->getEnumeration()) { + cmd_str += (C_ENUM_SCRIPT_DIR + "/" + def->getEnumeration()); } else { - // it's a "leaf value node". get completions from values. - read_value_vec(comp_vals, false); + string astr = def->getAllowed(); + shell_escape_squotes(astr); + cmd_str += "_cstore_internal_allowed () { eval '"; + cmd_str += astr; + cmd_str += "'; }; _cstore_internal_allowed"; } - /* more possible completions from this node's template: - * "allowed" - * "enumeration" - * "$VAR(@) in ..." - */ - 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 - * "allowed" scripts. - */ - ostringstream cword_count; - cword_count << (comps.size() - 1); - string cmd_str = ("export " + C_ENV_SHELL_CWORD_COUNT + "=" - + cword_count.str() + "; "); - cmd_str += ("export " + C_ENV_SHELL_CWORDS + "=("); - for (size_t i = 0; i < comps.size(); i++) { - cmd_str += (" '" + comps[i] + "'"); - } - cmd_str += "); "; - if (def->getEnumeration()) { - cmd_str += (C_ENUM_SCRIPT_DIR + "/" + def->getEnumeration()); - } else { - string astr = def->getAllowed(); - shell_escape_squotes(astr); - cmd_str += "_cstore_internal_allowed () { eval '"; - cmd_str += astr; - cmd_str += "'; }; _cstore_internal_allowed"; - } - char *buf = (char *) malloc(MAX_CMD_OUTPUT_SIZE); - int ret = get_shell_command_output(cmd_str.c_str(), buf, - MAX_CMD_OUTPUT_SIZE); - if (ret > 0) { - // '<' and '>' need to be escaped - char *ptr = buf; - while (*ptr) { - if (*ptr == '<' || *ptr == '>') { - comp_string += "\\"; - } - comp_string += *ptr; - ptr++; + char *buf = (char *) malloc(MAX_CMD_OUTPUT_SIZE); + int ret = get_shell_command_output(cmd_str.c_str(), buf, + MAX_CMD_OUTPUT_SIZE); + if (ret > 0) { + // '<' and '>' need to be escaped + char *ptr = buf; + while (*ptr) { + if (*ptr == '<' || *ptr == '>') { + comp_string += "\\"; } + comp_string += *ptr; + ptr++; } - /* note that for "enumeration" and "allowed", comp_string is the - * complete output of the command and it is to be evaled by the - * shell into an array of values. - */ - free(buf); - } 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->getActions(syntax_act)->vtw_list_head); - if (vals) { - if (vals->cnt == 0 && vals->val) { - comp_vals.push_back(vals->val); - } else if (vals->cnt > 0) { - for (int i = 0; i < vals->cnt; i++) { - if (vals->vals[i]) { - comp_vals.push_back(vals->vals[i]); - } + } + /* note that for "enumeration" and "allowed", comp_string is the + * complete output of the command and it is to be evaled by the + * shell into an array of values. + */ + free(buf); + } 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->getActions(syntax_act)->vtw_list_head); + if (vals) { + if (vals->cnt == 0 && vals->val) { + comp_vals.push_back(vals->val); + } else if (vals->cnt > 0) { + for (int i = 0; i < vals->cnt; i++) { + if (vals->vals[i]) { + comp_vals.push_back(vals->vals[i]); } } } } + } - // now handle help. - if (def->getCompHelp()) { - // "comp_help" exists. - comp_help = def->getCompHelp(); - shell_escape_squotes(comp_help); - } - if (def->getValHelp()) { - // has val_help. first separate individual lines. - size_t start = 0, i = 0; - vector<string> vhelps; - 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) { + // now handle help. + if (def->getCompHelp()) { + // "comp_help" exists. + comp_help = def->getCompHelp(); + shell_escape_squotes(comp_help); + } + if (def->getValHelp()) { + // has val_help. first separate individual lines. + size_t start = 0, i = 0; + vector<string> vhelps; + 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->getValHelp())[start]), i - start)); + } - // process each line - for (i = 0; i < vhelps.size(); i++) { - size_t sc; - if ((sc = vhelps[i].find(';')) == vhelps[i].npos) { - // no ';' - if (i == 0 && !def->isTypeless(1)) { - // first val_help. pair with "type". - help_pairs.push_back(pair<string, string>( - def->getTypeName(1), vhelps[i])); - } - if (i == 1 && !def->isTypeless(2)) { - // second val_help. pair with second "type". - help_pairs.push_back(pair<string, string>( - def->getTypeName(2), vhelps[i])); - } - } else { - // ';' at index sc + // process each line + for (i = 0; i < vhelps.size(); i++) { + size_t sc; + if ((sc = vhelps[i].find(';')) == vhelps[i].npos) { + // no ';' + if (i == 0 && !def->isTypeless(1)) { + // first val_help. pair with "type". help_pairs.push_back(pair<string, string>( - vhelps[i].substr(0, sc), - vhelps[i].substr(sc + 1))); + def->getTypeName(1), vhelps[i])); } + if (i == 1 && !def->isTypeless(2)) { + // second val_help. pair with second "type". + help_pairs.push_back(pair<string, string>( + def->getTypeName(2), vhelps[i])); + } + } else { + // ';' at index sc + help_pairs.push_back(pair<string, string>( + vhelps[i].substr(0, sc), + vhelps[i].substr(sc + 1))); } - } else if (!def->isTypeless(1) && def->getNodeHelp()) { - // simple case. just use "type" and "help" - help_pairs.push_back(pair<string, string>(def->getTypeName(1), - def->getNodeHelp())); } + } else if (!def->isTypeless(1) && def->getNodeHelp()) { + // simple case. just use "type" and "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). - */ + /* 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++) { - shell_escape_squotes(comp_vals[i]); - env += ("'" + comp_vals[i] + "' "); + // this var is the array of possible completions + env = (C_ENV_SHAPI_COMP_VALS + "=("); + for (size_t i = 0; i < comp_vals.size(); i++) { + shell_escape_squotes(comp_vals[i]); + env += ("'" + comp_vals[i] + "' "); + } + /* as mentioned above, comp_string is the complete command output. + * let the shell eval it into the array since we don't want to + * re-implement the shell interpretation here. + * + * note that as a result, we will not be doing the filtering here. + * instead, the completion script will do the filtering on + * the resulting comp_values array. should be straightforward since + * there's no "existence filtering", only "prefix filtering". + */ + env += (comp_string + "); "); + + /* this var indicates whether the last comp is "value" + * follow original implementation: if last comp is value, completion + * script needs to do the following. + * use comp_help if exists + * prefix filter comp_values + * replace any <*> in comp_values with "" + * convert help items to data representation + */ + env += (C_ENV_SHAPI_LCOMP_VAL + "="); + env += (last_comp_val ? "true; " : "false; "); + + // this var is the "comp_help" string + env += (C_ENV_SHAPI_COMP_HELP + "='" + comp_help + "'; "); + + // this var is the array of "help items", i.e., type names, etc. + string hitems = (C_ENV_SHAPI_HELP_ITEMS + "=("); + // this var is the array of "help strings" corresponding to the items + string hstrs = (C_ENV_SHAPI_HELP_STRS + "=("); + for (size_t i = 0; i < help_pairs.size(); i++) { + string hi = help_pairs[i].first; + string hs = help_pairs[i].second; + shell_escape_squotes(hi); + shell_escape_squotes(hs); + // get rid of leading/trailing "space" chars in help string + while (hi.size() > 0 && isspace(hi[0])) { + hi.erase(0, 1); } - /* as mentioned above, comp_string is the complete command output. - * let the shell eval it into the array since we don't want to - * re-implement the shell interpretation here. - * - * note that as a result, we will not be doing the filtering here. - * instead, the completion script will do the filtering on - * the resulting comp_values array. should be straightforward since - * there's no "existence filtering", only "prefix filtering". - */ - env += (comp_string + "); "); - - /* this var indicates whether the last comp is "value" - * follow original implementation: if last comp is value, completion - * script needs to do the following. - * use comp_help if exists - * prefix filter comp_values - * replace any <*> in comp_values with "" - * convert help items to data representation - */ - env += (C_ENV_SHAPI_LCOMP_VAL + "="); - env += (last_comp_val ? "true; " : "false; "); - - // this var is the "comp_help" string - env += (C_ENV_SHAPI_COMP_HELP + "='" + comp_help + "'; "); - - // this var is the array of "help items", i.e., type names, etc. - string hitems = (C_ENV_SHAPI_HELP_ITEMS + "=("); - // this var is the array of "help strings" corresponding to the items - string hstrs = (C_ENV_SHAPI_HELP_STRS + "=("); - for (size_t i = 0; i < help_pairs.size(); i++) { - string hi = help_pairs[i].first; - string hs = help_pairs[i].second; - shell_escape_squotes(hi); - shell_escape_squotes(hs); - // get rid of leading/trailing "space" chars in help string - while (hi.size() > 0 && isspace(hi[0])) { - hi.erase(0, 1); - } - while (hs.size() > 0 && isspace(hs[0])) { - hs.erase(0, 1); - } - while (hi.size() > 0 && isspace(hi[hi.size() - 1])) { - hi.erase(hi.size() - 1); - } - while (hs.size() > 0 && isspace(hs[hs.size() - 1])) { - hs.erase(hs.size() - 1); - } - hitems += ("'" + hi + "' "); - hstrs += ("'" + hs + "' "); + while (hs.size() > 0 && isspace(hs[0])) { + hs.erase(0, 1); } - env += (hitems + "); " + hstrs + "); "); - ret = true; - } while(0); - RESTORE_PATHS; - return ret; + while (hi.size() > 0 && isspace(hi[hi.size() - 1])) { + hi.erase(hi.size() - 1); + } + while (hs.size() > 0 && isspace(hs[hs.size() - 1])) { + hs.erase(hs.size() - 1); + } + hitems += ("'" + hi + "' "); + hstrs += ("'" + hs + "' "); + } + env += (hitems + "); " + hstrs + "); "); + return true; } /* set specified "logical path" in "working config". @@ -844,7 +842,7 @@ Cstore::getCompletionEnv(const vector<string>& comps, string& env) * note: assume specified path is valid (i.e., validateSetPath()). */ bool -Cstore::setCfgPath(const vector<string>& path_comps) +Cstore::setCfgPath(const Cpath& path_comps) { ASSERT_IN_SESSION; @@ -855,7 +853,7 @@ Cstore::setCfgPath(const vector<string>& path_comps) * return true if valid. otherwise return false. */ bool -Cstore::validateRenameArgs(const vector<string>& args) +Cstore::validateRenameArgs(const Cpath& args) { ASSERT_IN_SESSION; @@ -866,7 +864,7 @@ Cstore::validateRenameArgs(const vector<string>& args) * return true if valid. otherwise return false. */ bool -Cstore::validateCopyArgs(const vector<string>& args) +Cstore::validateCopyArgs(const Cpath& args) { ASSERT_IN_SESSION; @@ -877,22 +875,20 @@ Cstore::validateCopyArgs(const vector<string>& args) * return true if valid. otherwise return false. */ bool -Cstore::validateMoveArgs(const vector<string>& args) +Cstore::validateMoveArgs(const Cpath& args) { ASSERT_IN_SESSION; - vector<string> epath; - vector<string> nargs; + Cpath epath; + Cpath nargs; if (!conv_move_args_for_rename(args, epath, nargs)) { output_user("Invalid move command\n"); return false; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(epath); append_tmpl_path(epath); - bool ret = validate_rename_copy(nargs, "move"); - RESTORE_PATHS; - return ret; + return validate_rename_copy(nargs, "move"); } /* perform rename in "working config" according to specified args. @@ -900,13 +896,13 @@ Cstore::validateMoveArgs(const vector<string>& args) * note: assume args are already validated (i.e., validateRenameArgs()). */ bool -Cstore::renameCfgPath(const vector<string>& args) +Cstore::renameCfgPath(const Cpath& args) { ASSERT_IN_SESSION; - string otagnode = args[0]; - string otagval = args[1]; - string ntagval = args[4]; + const char *otagnode = args[0]; + const char *otagval = args[1]; + const char *ntagval = args[4]; push_cfg_path(otagnode); /* also mark changed. note that it's marking the "tag node" but not the * "tag values" since one is being "deleted" and the other is being @@ -923,13 +919,13 @@ Cstore::renameCfgPath(const vector<string>& args) * note: assume args are already validated (i.e., validateCopyArgs()). */ bool -Cstore::copyCfgPath(const vector<string>& args) +Cstore::copyCfgPath(const Cpath& args) { ASSERT_IN_SESSION; - string otagnode = args[0]; - string otagval = args[1]; - string ntagval = args[4]; + const char *otagnode = args[0]; + const char *otagval = args[1]; + const char *ntagval = args[4]; push_cfg_path(otagnode); /* also mark changed. note that it's marking the "tag node" but not the * new "tag value" since it is being "added" anyway. @@ -944,7 +940,7 @@ Cstore::copyCfgPath(const vector<string>& args) * return true if valid. otherwise return false. */ bool -Cstore::commentCfgPath(const vector<string>& args) +Cstore::commentCfgPath(const Cpath& args) { ASSERT_IN_SESSION; @@ -952,13 +948,13 @@ Cstore::commentCfgPath(const vector<string>& args) * 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(); + Cpath path_comps(args); + string comment; + path_comps.pop(comment); // check the path string terr; - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); if (!def.get()) { output_user("%s\n", terr.c_str()); return false; @@ -994,22 +990,23 @@ Cstore::commentCfgPath(const vector<string>& args) return false; } - SAVE_PATHS; - append_cfg_path(path_comps); - bool ret; - if (comment == "") { - // follow original impl: empty comment => remove it - ret = remove_comment(); - if (!ret) { - output_user("Failed to remove comment for specified config node\n"); - } - } else { - ret = set_comment(comment); - if (!ret) { - output_user("Failed to add comment for specified config node\n"); + bool ret = false; + { + auto_ptr<SavePaths> save(create_save_paths()); + append_cfg_path(path_comps); + if (comment == "") { + // follow original impl: empty comment => remove it + ret = remove_comment(); + if (!ret) { + output_user("Failed to remove comment for specified config node\n"); + } + } else { + ret = set_comment(comment); + if (!ret) { + output_user("Failed to add comment for specified config node\n"); + } } } - RESTORE_PATHS; if (ret) { // mark the root as changed for "comment" ret = mark_changed_with_ancestors(); @@ -1043,22 +1040,20 @@ Cstore::discardChanges() * note: assume args are already validated (i.e., validateMoveArgs()). */ bool -Cstore::moveCfgPath(const vector<string>& args) +Cstore::moveCfgPath(const Cpath& args) { ASSERT_IN_SESSION; - vector<string> epath; - vector<string> nargs; + Cpath epath; + Cpath nargs; if (!conv_move_args_for_rename(args, epath, nargs)) { output_user("Invalid move command\n"); return false; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(epath); append_tmpl_path(epath); - bool ret = renameCfgPath(nargs); - RESTORE_PATHS; - return ret; + return renameCfgPath(nargs); } /* check if specified "logical path" exists in working config (i.e., the union) @@ -1066,7 +1061,7 @@ Cstore::moveCfgPath(const vector<string>& args) * return true if it exists. otherwise return false. */ bool -Cstore::cfgPathExists(const vector<string>& path_comps, bool active_cfg) +Cstore::cfgPathExists(const Cpath& path_comps, bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; @@ -1077,7 +1072,7 @@ Cstore::cfgPathExists(const vector<string>& path_comps, bool active_cfg) // same as above but "deactivate-aware" bool -Cstore::cfgPathExistsDA(const vector<string>& path_comps, bool active_cfg, +Cstore::cfgPathExistsDA(const Cpath& path_comps, bool active_cfg, bool include_deactivated) { if (!active_cfg) { @@ -1090,7 +1085,7 @@ Cstore::cfgPathExistsDA(const vector<string>& path_comps, bool active_cfg, /* check if specified "logical path" has been deleted in working config. */ bool -Cstore::cfgPathDeleted(const vector<string>& path_comps) +Cstore::cfgPathDeleted(const Cpath& path_comps) { ASSERT_IN_SESSION; @@ -1102,7 +1097,7 @@ Cstore::cfgPathDeleted(const vector<string>& path_comps) /* check if specified "logical path" has been added in working config. */ bool -Cstore::cfgPathAdded(const vector<string>& path_comps) +Cstore::cfgPathAdded(const Cpath& path_comps) { ASSERT_IN_SESSION; @@ -1130,25 +1125,23 @@ Cstore::cfgPathAdded(const vector<string>& path_comps) * (3) cfg_node_changed() */ bool -Cstore::cfgPathChanged(const vector<string>& path_comps) +Cstore::cfgPathChanged(const Cpath& path_comps) { ASSERT_IN_SESSION; if (cfgPathDeleted(path_comps) || cfgPathAdded(path_comps)) { return true; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = cfg_node_changed(); - RESTORE_PATHS; - return ret; + return cfg_node_changed(); } /* get names of "deleted" child nodes of specified path during commit * operation. names are returned in cnodes. */ void -Cstore::cfgPathGetDeletedChildNodes(const vector<string>& path_comps, +Cstore::cfgPathGetDeletedChildNodes(const Cpath& path_comps, vector<string>& cnodes) { ASSERT_IN_SESSION; @@ -1158,7 +1151,7 @@ Cstore::cfgPathGetDeletedChildNodes(const vector<string>& path_comps, // same as above but "deactivate-aware" void -Cstore::cfgPathGetDeletedChildNodesDA(const vector<string>& path_comps, +Cstore::cfgPathGetDeletedChildNodesDA(const Cpath& path_comps, vector<string>& cnodes, bool include_deactivated) { @@ -1189,8 +1182,7 @@ Cstore::cfgPathGetDeletedChildNodesDA(const vector<string>& path_comps, * status is purely based on the presence/absence of a value. */ void -Cstore::cfgPathGetDeletedValues(const vector<string>& path_comps, - vector<string>& dvals) +Cstore::cfgPathGetDeletedValues(const Cpath& path_comps, vector<string>& dvals) { ASSERT_IN_SESSION; @@ -1199,7 +1191,7 @@ Cstore::cfgPathGetDeletedValues(const vector<string>& path_comps, // same as above but DA void -Cstore::cfgPathGetDeletedValuesDA(const vector<string>& path_comps, +Cstore::cfgPathGetDeletedValuesDA(const Cpath& path_comps, vector<string>& dvals, bool include_deactivated) { @@ -1229,15 +1221,15 @@ Cstore::cfgPathGetDeletedValuesDA(const vector<string>& path_comps, * "marked deactivated". */ bool -Cstore::cfgPathDeactivated(const vector<string>& path_comps, bool active_cfg) +Cstore::cfgPathDeactivated(const Cpath& path_comps, bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; } - vector<string> ppath; + Cpath ppath; for (size_t i = 0; i < path_comps.size(); i++) { - ppath.push_back(path_comps[i]); + ppath.push(path_comps[i]); if (cfgPathMarkedDeactivated(ppath, active_cfg)) { // an ancestor or itself is marked deactivated return true; @@ -1252,26 +1244,23 @@ Cstore::cfgPathDeactivated(const vector<string>& path_comps, bool active_cfg) * performed on the node. */ bool -Cstore::cfgPathMarkedDeactivated(const vector<string>& path_comps, - bool active_cfg) +Cstore::cfgPathMarkedDeactivated(const Cpath& path_comps, bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = marked_deactivated(active_cfg); - RESTORE_PATHS; - return ret; + return marked_deactivated(active_cfg); } /* get names of child nodes of specified path in working config or active * config. names are returned in cnodes. */ void -Cstore::cfgPathGetChildNodes(const vector<string>& path_comps, - vector<string>& cnodes, bool active_cfg) +Cstore::cfgPathGetChildNodes(const Cpath& path_comps, vector<string>& cnodes, + bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; @@ -1282,9 +1271,8 @@ Cstore::cfgPathGetChildNodes(const vector<string>& path_comps, // same as above but "deactivate-aware" void -Cstore::cfgPathGetChildNodesDA(const vector<string>& path_comps, - vector<string>& cnodes, bool active_cfg, - bool include_deactivated) +Cstore::cfgPathGetChildNodesDA(const Cpath& path_comps, vector<string>& cnodes, + bool active_cfg, bool include_deactivated) { if (!active_cfg) { ASSERT_IN_SESSION; @@ -1296,10 +1284,11 @@ Cstore::cfgPathGetChildNodesDA(const vector<string>& path_comps, */ return; } - SAVE_PATHS; - append_cfg_path(path_comps); - get_all_child_node_names(cnodes, active_cfg, include_deactivated); - RESTORE_PATHS; + { + auto_ptr<SavePaths> save(create_save_paths()); + append_cfg_path(path_comps); + get_all_child_node_names(cnodes, active_cfg, include_deactivated); + } sort_nodes(cnodes); } @@ -1310,7 +1299,7 @@ Cstore::cfgPathGetChildNodesDA(const vector<string>& path_comps, * otherwise return true. */ bool -Cstore::cfgPathGetValue(const vector<string>& path_comps, string& value, +Cstore::cfgPathGetValue(const Cpath& path_comps, string& value, bool active_cfg) { if (!active_cfg) { @@ -1322,14 +1311,14 @@ Cstore::cfgPathGetValue(const vector<string>& path_comps, string& value, // same as above but "deactivate-aware" bool -Cstore::cfgPathGetValueDA(const vector<string>& path_comps, string& value, +Cstore::cfgPathGetValueDA(const Cpath& path_comps, string& value, bool active_cfg, bool include_deactivated) { if (!active_cfg) { ASSERT_IN_SESSION; } - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); if (!def.get()) { // invalid node return false; @@ -1349,18 +1338,16 @@ Cstore::cfgPathGetValueDA(const vector<string>& path_comps, string& value, return false; } vector<string> vvec; - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = false; if (read_value_vec(vvec, active_cfg)) { if (vvec.size() >= 1) { // if for some reason we got multiple values, just take the first one. value = vvec[0]; - ret = true; + return true; } } - RESTORE_PATHS; - return ret; + return false; } /* get values of specified multi-value node. @@ -1370,8 +1357,8 @@ Cstore::cfgPathGetValueDA(const vector<string>& path_comps, string& value, * otherwise return true. */ bool -Cstore::cfgPathGetValues(const vector<string>& path_comps, - vector<string>& values, bool active_cfg) +Cstore::cfgPathGetValues(const Cpath& path_comps, vector<string>& values, + bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; @@ -1382,15 +1369,14 @@ Cstore::cfgPathGetValues(const vector<string>& path_comps, // same as above but "deactivate-aware" bool -Cstore::cfgPathGetValuesDA(const vector<string>& path_comps, - vector<string>& values, bool active_cfg, - bool include_deactivated) +Cstore::cfgPathGetValuesDA(const Cpath& path_comps, vector<string>& values, + bool active_cfg, bool include_deactivated) { if (!active_cfg) { ASSERT_IN_SESSION; } - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); if (!def.get()) { // invalid node return false; @@ -1409,11 +1395,9 @@ Cstore::cfgPathGetValuesDA(const vector<string>& path_comps, // specified node doesn't exist return false; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = read_value_vec(values, active_cfg); - RESTORE_PATHS; - return ret; + return read_value_vec(values, active_cfg); } /* get comment of specified node. @@ -1423,18 +1407,16 @@ Cstore::cfgPathGetValuesDA(const vector<string>& path_comps, * otherwise return true. */ bool -Cstore::cfgPathGetComment(const vector<string>& path_comps, string& comment, +Cstore::cfgPathGetComment(const Cpath& path_comps, string& comment, bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = get_comment(comment, active_cfg); - RESTORE_PATHS; - return ret; + return get_comment(comment, active_cfg); } /* return whether specified path is "default". if a node is "default", it @@ -1442,17 +1424,15 @@ Cstore::cfgPathGetComment(const vector<string>& path_comps, string& comment, * active_cfg: whether to observe active config. */ bool -Cstore::cfgPathDefault(const vector<string>& path_comps, bool active_cfg) +Cstore::cfgPathDefault(const Cpath& path_comps, bool active_cfg) { if (!active_cfg) { ASSERT_IN_SESSION; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = marked_display_default(active_cfg); - RESTORE_PATHS; - return ret; + return marked_display_default(active_cfg); } /* the following functions are observers of the "effective" config. @@ -1534,9 +1514,9 @@ Cstore::cfgPathDefault(const vector<string>& path_comps, bool active_cfg) // return whether specified path is "effective". bool -Cstore::cfgPathEffective(const vector<string>& path_comps) +Cstore::cfgPathEffective(const Cpath& path_comps) { - auto_ptr<Ctemplate> def(parseTmpl(path_comps, false)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false)); if (!def.get()) { // invalid path return false; @@ -1553,19 +1533,17 @@ Cstore::cfgPathEffective(const vector<string>& path_comps) // case (1) return true; } - bool ret = false; - SAVE_PATHS; + + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); if (!in_active && in_work) { // check if case (2) - ret = marked_committed(def.get(), true); + return marked_committed(def, true); } else if (in_active && !in_work) { // check if case (3) - ret = !marked_committed(def.get(), false); + return !marked_committed(def, false); } - RESTORE_PATHS; - - return ret; + return false; } /* get names of "effective" child nodes of specified path during commit @@ -1573,7 +1551,7 @@ Cstore::cfgPathEffective(const vector<string>& path_comps) * names are returned in cnodes. */ void -Cstore::cfgPathGetEffectiveChildNodes(const vector<string>& path_comps, +Cstore::cfgPathGetEffectiveChildNodes(const Cpath& path_comps, vector<string>& cnodes) { if (!inSession()) { @@ -1596,15 +1574,15 @@ Cstore::cfgPathGetEffectiveChildNodes(const vector<string>& path_comps, } // get only the effective ones from the union - vector<string> ppath = path_comps; + Cpath ppath(path_comps); MapT<string, bool>::iterator it = cmap.begin(); for (; it != cmap.end(); ++it) { string c = (*it).first; - ppath.push_back(c); + ppath.push(c); if (cfgPathEffective(ppath)) { cnodes.push_back(c); } - ppath.pop_back(); + ppath.pop(); } sort_nodes(cnodes); } @@ -1614,15 +1592,14 @@ Cstore::cfgPathGetEffectiveChildNodes(const vector<string>& path_comps, * return true if successful. otherwise return false. */ bool -Cstore::cfgPathGetEffectiveValue(const vector<string>& path_comps, - string& value) +Cstore::cfgPathGetEffectiveValue(const Cpath& path_comps, string& value) { if (!inSession()) { // not in a config session. use active config only. return cfgPathGetValue(path_comps, value, true); } - vector<string> ppath = path_comps; + Cpath ppath(path_comps); string oval, nval; bool oret = cfgPathGetValue(path_comps, oval, true); bool nret = cfgPathGetValue(path_comps, nval, false); @@ -1630,7 +1607,7 @@ Cstore::cfgPathGetEffectiveValue(const vector<string>& path_comps, // all 4 combinations of oret and nret are covered below if (nret) { // got new value - ppath.push_back(nval); + ppath.push(nval); if (cfgPathEffective(ppath)) { // nval already effective value = nval; @@ -1644,7 +1621,7 @@ Cstore::cfgPathGetEffectiveValue(const vector<string>& path_comps, } } else if (oret) { // got oval only - ppath.push_back(oval); + ppath.push(oval); if (cfgPathEffective(ppath)) { // oval still effective value = oval; @@ -1659,7 +1636,7 @@ Cstore::cfgPathGetEffectiveValue(const vector<string>& path_comps, * return true if successful. otherwise return false. */ bool -Cstore::cfgPathGetEffectiveValues(const vector<string>& path_comps, +Cstore::cfgPathGetEffectiveValues(const Cpath& path_comps, vector<string>& values) { if (!inSession()) { @@ -1682,15 +1659,15 @@ Cstore::cfgPathGetEffectiveValues(const vector<string>& path_comps, } // get only the effective ones from the union - vector<string> ppath = path_comps; + Cpath ppath(path_comps); MapT<string, bool>::iterator it = vmap.begin(); for (; it != vmap.end(); ++it) { string c = (*it).first; - ppath.push_back(c); + ppath.push(c); if (cfgPathEffective(ppath)) { values.push_back(c); } - ppath.pop_back(); + ppath.pop(); } return (values.size() > 0); } @@ -1704,20 +1681,18 @@ Cstore::cfgPathGetEffectiveValues(const vector<string>& path_comps, * otherwise return NULL. */ char * -Cstore::getVarRef(const string& ref_str, vtw_type_e& type, bool from_active) +Cstore::getVarRef(const char *ref_str, vtw_type_e& type, bool from_active) { - char *ret = NULL; - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); VarRef vref(this, ref_str, from_active); string val; vtw_type_e t; if (vref.getValue(val, t)) { type = t; // follow original implementation. caller is supposed to free this. - ret = strdup(val.c_str()); + return strdup(val.c_str()); } - RESTORE_PATHS; - return ret; + return NULL; } /* set the node corresponding to specified variable ref string to specified @@ -1729,7 +1704,7 @@ Cstore::getVarRef(const string& ref_str, vtw_type_e& type, bool from_active) * return true if successful. otherwise return false. */ bool -Cstore::setVarRef(const string& ref_str, const string& value, bool to_active) +Cstore::setVarRef(const char *ref_str, const char *value, bool to_active) { /* XXX functions in cli_new only performs "set var ref" operations (e.g., * '$VAR(@) = ""', which sets current node's value to empty string) @@ -1744,23 +1719,21 @@ Cstore::setVarRef(const string& ref_str, const string& value, bool to_active) * from high-level functions). as a result, this function is unused * and untested at the moment. must revisit when converting commit. */ - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); VarRef vref(this, ref_str, to_active); - vector<string> pcomps; - bool ret = false; + Cpath pcomps; if (vref.getSetPath(pcomps)) { reset_paths(); - auto_ptr<Ctemplate> def(get_parsed_tmpl(pcomps, false)); + tr1::shared_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; + return true; } } } - RESTORE_PATHS; - return ret; + return false; } /* perform deactivate operation on a node, i.e., make the node @@ -1770,7 +1743,7 @@ Cstore::setVarRef(const string& ref_str, const string& value, bool to_active) * that had been marked deactivated are unmarked. */ bool -Cstore::markCfgPathDeactivated(const vector<string>& path_comps) +Cstore::markCfgPathDeactivated(const Cpath& path_comps) { ASSERT_IN_SESSION; @@ -1780,13 +1753,11 @@ Cstore::markCfgPathDeactivated(const vector<string>& path_comps) return true; } - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); // note: also mark changed - bool ret = (mark_deactivated() && unmark_deactivated_descendants() - && mark_changed_with_ancestors()); - RESTORE_PATHS; - return ret; + return (mark_deactivated() && unmark_deactivated_descendants() + && mark_changed_with_ancestors()); } /* perform activate operation on a node, i.e., make the node no longer @@ -1794,16 +1765,14 @@ Cstore::markCfgPathDeactivated(const vector<string>& path_comps) * note: assume all validations have been peformed (see activate.cpp). */ bool -Cstore::unmarkCfgPathDeactivated(const vector<string>& path_comps) +Cstore::unmarkCfgPathDeactivated(const Cpath& path_comps) { ASSERT_IN_SESSION; - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); // note: also mark changed - bool ret = (unmark_deactivated() && mark_changed_with_ancestors()); - RESTORE_PATHS; - return ret; + return (unmark_deactivated() && mark_changed_with_ancestors()); } // load specified config file @@ -1830,29 +1799,29 @@ Cstore::loadFile(const char *filename) } // get the config tree from the active config - vector<string> args; + Cpath args; cnode::CfgNode aroot(*this, args, true, true); // get the "commands diff" between the two - vector<vector<string> > del_list; - vector<vector<string> > set_list; - vector<vector<string> > com_list; + vector<Cpath> del_list; + vector<Cpath> set_list; + vector<Cpath> com_list; cnode::get_cmds_diff(aroot, *froot, del_list, set_list, com_list); // "apply" the changes to the working config for (size_t i = 0; i < del_list.size(); i++) { if (!deleteCfgPath(del_list[i])) { - print_str_vec("Delete [", "] failed\n", del_list[i], "'"); + print_path_vec("Delete [", "] failed\n", del_list[i], "'"); } } for (size_t i = 0; i < set_list.size(); i++) { if (!validateSetPath(set_list[i]) || !setCfgPath(set_list[i])) { - print_str_vec("Set [", "] failed\n", set_list[i], "'"); + print_path_vec("Set [", "] failed\n", set_list[i], "'"); } } for (size_t i = 0; i < com_list.size(); i++) { if (!commentCfgPath(com_list[i])) { - print_str_vec("Comment [", "] failed\n", com_list[i], "'"); + print_path_vec("Comment [", "] failed\n", com_list[i], "'"); } } @@ -1907,19 +1876,20 @@ Cstore::loadFile(const char *filename) * return true if successful. otherwise return false. */ bool -Cstore::unmarkCfgPathChanged(const vector<string>& path_comps) +Cstore::unmarkCfgPathChanged(const Cpath& path_comps) { ASSERT_IN_SESSION; - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(path_comps); - bool ret = unmark_changed_with_descendants(); - RESTORE_PATHS; - return ret; + return unmark_changed_with_descendants(); } ////// protected functions +Cstore::SavePaths::~SavePaths() { +} + void Cstore::output_user(const char *fmt, ...) { @@ -1991,12 +1961,17 @@ Cstore::sort_nodes(vector<string>& nvec, unsigned int sort_alg) /* try to append the logical path to template path. * is_tag: (output) whether the last component is a "tag". * return false if logical path is not valid. otherwise return true. + * + * note: if the last comp is already "node.tag", is_tag won't be set. + * currently this should only happen when get_parsed_tmpl() "borrows" + * comps from the current tmpl path, in which case this is not + * a problem. */ bool -Cstore::append_tmpl_path(const vector<string>& path_comps, bool& is_tag) +Cstore::append_tmpl_path(const Cpath& path_comps, bool& is_tag) { - is_tag = false; for (size_t i = 0; i < path_comps.size(); i++) { + is_tag = false; push_tmpl_path(path_comps[i]); if (tmpl_node_exists()) { // got exact match. continue to next component. @@ -2007,10 +1982,7 @@ Cstore::append_tmpl_path(const vector<string>& path_comps, bool& is_tag) push_tmpl_path_tag(); if (tmpl_node_exists()) { // got tag match. continue to next component. - if (i == (path_comps.size() - 1)) { - // last comp - is_tag = true; - } + is_tag = true; continue; } // not a valid path @@ -2019,9 +1991,12 @@ Cstore::append_tmpl_path(const vector<string>& path_comps, bool& is_tag) return true; } +typedef Cstore::MapT<Cpath, tr1::shared_ptr<Ctemplate>, CpathHash> TmplCacheT; +static TmplCacheT _tmpl_cache; + /* check whether specified "logical path" is valid template path. * then template at the path is parsed. - * path_comps: vector of path components. + * path_comps: path components. * validate_vals: whether to validate all "values" along specified path. * error: (output) error message if failed. * return parsed template if successful. otherwise return 0. @@ -2029,44 +2004,53 @@ Cstore::append_tmpl_path(const vector<string>& path_comps, bool& is_tag) * also, if last path component is value (i.e., isValue()), the template * parsed is actually at "full path - 1". */ -Ctemplate * -Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, +tr1::shared_ptr<Ctemplate> +Cstore::get_parsed_tmpl(const Cpath& path_comps, bool validate_vals, string& error) { - Ctemplate *rtmpl = 0; + tr1::shared_ptr<Ctemplate> rtmpl; // 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 rtmpl; + bool do_caching = false; + if (tmpl_path_at_root()) { + if (path_comps.size() == 0) { + // empty path not valid + return rtmpl; + } + // we are starting from root => caching applies + do_caching = true; + TmplCacheT::iterator p = _tmpl_cache.find(path_comps); + if (p != _tmpl_cache.end()) { + // return cached + return p->second; + } } - /* note: this function may be invoked recursively (depth 1) when - * validating values, i.e., validate_value will process variable - * reference, which calls this indirectly to get templates. - * so need special save/restore identifier. - */ - const char *not_validating = "get_parsed_tmpl_not_validating"; - if (validate_vals) { - SAVE_PATHS; - } else { - save_paths(not_validating); - } + auto_ptr<SavePaths> save(create_save_paths()); + /* need at least 1 comp to work. 2 comps if last comp is value. * so pop tmpl_path and prepend them. note that path_comps remain * constant. */ - vector<string> *pcomps = const_cast<vector<string> *>(&path_comps); - vector<string> new_path_comps; - if (path_comps.size() < 2) { - new_path_comps = path_comps; - pcomps = &new_path_comps; - for (unsigned int i = 0; i < 2 && pcomps->size() < 2; i++) { + Cpath *pcomps = const_cast<Cpath *>(&path_comps); + Cpath new_path_comps; + size_t p_size = path_comps.size(); + if (p_size < 2) { + Cpath tmp; + for (unsigned int i = 0; i < 2 && (i + p_size) < 2; i++) { if (!tmpl_path_at_root()) { - pcomps->insert(pcomps->begin(), pop_tmpl_path()); + string last; + pop_tmpl_path(last); + tmp.push(last); } } + while (tmp.size() > 0) { + new_path_comps.push(tmp.back()); + tmp.pop(); + } + new_path_comps /= path_comps; + pcomps = &new_path_comps; } do { /* cases for template path: @@ -2089,7 +2073,7 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, // first scan up to "full path - 1" bool valid = true; for (size_t i = 0; i < (pcomps->size() - 1); i++) { - if ((*pcomps)[i] == "") { + if ((*pcomps)[i][0] == 0) { // only the last component is potentially allowed to be empty str valid = false; break; @@ -2104,7 +2088,8 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, * pop it. */ pop_tmpl_path(); - if (!validate_val(0, (*pcomps)[i])) { + tr1::shared_ptr<Ctemplate> ttmpl(tmpl_parse()); + if (!validate_val(ttmpl, (*pcomps)[i])) { // invalid value error = "Value validation failed"; valid = false; @@ -2133,19 +2118,19 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, * we haven't done anything yet. */ if (pcomps->size() > 1) { - auto_ptr<Ctemplate> ttmpl(tmpl_parse()); + tr1::shared_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(ttmpl.get(), (*pcomps)[pcomps->size() - 1])) { + if (!validate_val(ttmpl, (*pcomps)[pcomps->size() - 1])) { // invalid value error = "Value validation failed"; break; } } - rtmpl = ttmpl.release(); + rtmpl = ttmpl; rtmpl->setIsValue(true); break; } @@ -2153,7 +2138,7 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, // if no valid template or not a value, it's not case (2) so continue. } // now check last component - if ((*pcomps)[pcomps->size() - 1] == "") { + if ((*pcomps)[pcomps->size() - 1][0] == 0) { // only value is potentially allowed to be empty str break; } @@ -2161,8 +2146,9 @@ 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 (!(rtmpl = tmpl_parse())) { - exit_internal("failed to parse tmpl [%s]\n", + rtmpl.reset(tmpl_parse()); + if (!rtmpl.get()) { + exit_internal("get_parsed_tmpl: failed to parse tmpl [%s]\n", tmpl_path_to_str().c_str()); } rtmpl->setIsValue(false); @@ -2170,10 +2156,10 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, } // case (3) (fall through) } while (0); - if (validate_vals) { - RESTORE_PATHS; - } else { - restore_paths(not_validating); + + if (do_caching && rtmpl.get()) { + // only cache if we got a valid template + _tmpl_cache[path_comps] = rtmpl; } return rtmpl; } @@ -2182,14 +2168,15 @@ Cstore::get_parsed_tmpl(const vector<string>& path_comps, bool validate_vals, * "deactivate" operation. * return parsed template if valid. otherwise return 0. */ -Ctemplate * -Cstore::validate_act_deact(const vector<string>& path_comps, const string& op) +tr1::shared_ptr<Ctemplate> +Cstore::validate_act_deact(const Cpath& path_comps, const char *op) { string terr; - auto_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(path_comps, false, terr)); + tr1::shared_ptr<Ctemplate> none; if (!def.get()) { output_user("%s\n", terr.c_str()); - return 0; + return none; } { /* XXX this is a temporary workaround for bug 5708, which should be @@ -2198,76 +2185,72 @@ Cstore::validate_act_deact(const vector<string>& path_comps, const string& op) * this workaround should be removed and the bug fixed properly. */ if (!def->isTag() && !def->isTypeless()) { - output_user("Cannot %s a leaf configuration node\n", op.c_str()); - return 0; + output_user("Cannot %s a leaf configuration node\n", op); + return none; } } 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 0; + output_user("Cannot %s a leaf configuration value\n", op); + return none; } if (!cfg_path_exists(path_comps, false, true)) { output_user("Nothing to %s (the specified %s does not exist)\n", - op.c_str(), - (!def->isValue() || def->isTag()) ? "node" : "value"); - return 0; + op, (!def->isValue() || def->isTag()) ? "node" : "value"); + return none; } - return def.release(); + return def; } /* check if specified args is valid for "rename" or "copy" operation. * return true if valid. otherwise return false. */ bool -Cstore::validate_rename_copy(const vector<string>& args, const string& op) +Cstore::validate_rename_copy(const Cpath& args, const char *op) { - if (args.size() != 5 || args[2] != "to") { - output_user("Invalid %s command\n", op.c_str()); + if (args.size() != 5 || strcmp(args[2], "to") != 0) { + output_user("Invalid %s command\n", op); return false; } - string otagnode = args[0]; - string otagval = args[1]; - string ntagnode = args[3]; - string ntagval = args[4]; - if (otagnode != ntagnode) { - output_user("Cannot %s from \"%s\" to \"%s\"\n", - op.c_str(), otagnode.c_str(), ntagnode.c_str()); + const char *otagnode = args[0]; + const char *otagval = args[1]; + const char *ntagnode = args[3]; + const char *ntagval = args[4]; + if (strcmp(otagnode, ntagnode) != 0) { + output_user("Cannot %s from \"%s\" to \"%s\"\n", op, otagnode, ntagnode); return false; } // check the old path - vector<string> ppath; - ppath.push_back(otagnode); - ppath.push_back(otagval); + Cpath ppath; + ppath.push(otagnode); + ppath.push(otagval); string terr; - auto_ptr<Ctemplate> def(get_parsed_tmpl(ppath, false, terr)); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(ppath, false, terr)); if (!def.get()) { output_user("%s\n", terr.c_str()); return false; } if (!def->isTagValue()) { // can only rename "tagnode tagvalue" - output_user("Cannot %s under \"%s\"\n", op.c_str(), otagnode.c_str()); + output_user("Cannot %s under \"%s\"\n", op, otagnode); return false; } if (!cfg_path_exists(ppath, false, true)) { - output_user("Configuration \"%s %s\" does not exist\n", - otagnode.c_str(), otagval.c_str()); + output_user("Configuration \"%s %s\" does not exist\n", otagnode, otagval); return false; } // check the new path - ppath.pop_back(); - ppath.push_back(ntagval); + ppath.pop(); + ppath.push(ntagval); if (cfg_path_exists(ppath, false, true)) { - output_user("Configuration \"%s %s\" already exists\n", - ntagnode.c_str(), ntagval.c_str()); + output_user("Configuration \"%s %s\" already exists\n", ntagnode, ntagval); return false; } - def.reset(get_parsed_tmpl(ppath, true, terr)); + def = get_parsed_tmpl(ppath, true, terr); if (!def.get()) { output_user("%s\n", terr.c_str()); return false; @@ -2277,9 +2260,8 @@ Cstore::validate_rename_copy(const vector<string>& args, const string& op) // convert args for "move" to be used for equivalent "rename" operation bool -Cstore::conv_move_args_for_rename(const vector<string>& args, - vector<string>& edit_path_comps, - vector<string>& rn_args) +Cstore::conv_move_args_for_rename(const Cpath& args, Cpath& edit_path_comps, + Cpath& rn_args) { /* note: * "move interfaces ethernet eth2 vif 100 to 200" @@ -2294,13 +2276,13 @@ Cstore::conv_move_args_for_rename(const vector<string>& args, return false; } for (size_t i = 0; i < (num_args - 4); i++) { - edit_path_comps.push_back(args[i]); + edit_path_comps.push(args[i]); } - rn_args.push_back(args[num_args - 4]); // vif - rn_args.push_back(args[num_args - 3]); // 100 - rn_args.push_back(args[num_args - 2]); // to - rn_args.push_back(args[num_args - 4]); // vif - rn_args.push_back(args[num_args - 1]); // 200 + rn_args.push(args[num_args - 4]); // vif + rn_args.push(args[num_args - 3]); // 100 + rn_args.push(args[num_args - 2]); // to + rn_args.push(args[num_args - 4]); // vif + rn_args.push(args[num_args - 1]); // 200 return true; } @@ -2310,19 +2292,21 @@ Cstore::conv_move_args_for_rename(const vector<string>& args, * return true if it exists. otherwise return false. */ bool -Cstore::cfg_path_exists(const vector<string>& path_comps, - bool active_cfg, bool include_deactivated) +Cstore::cfg_path_exists(const Cpath& path_comps, bool active_cfg, + bool include_deactivated) { - SAVE_PATHS; - append_cfg_path(path_comps); - // first check if it's a "node". - bool ret = cfg_node_exists(active_cfg); - if (!ret) { - // doesn't exist as a node. maybe a value? - pop_cfg_path(); - ret = cfg_value_exists(path_comps[path_comps.size() - 1], active_cfg); + bool ret = false; + { + auto_ptr<SavePaths> save(create_save_paths()); + append_cfg_path(path_comps); + // first check if it's a "node". + ret = cfg_node_exists(active_cfg); + if (!ret) { + // doesn't exist as a node. maybe a value? + pop_cfg_path(); + ret = cfg_value_exists(path_comps[path_comps.size() - 1], active_cfg); + } } - RESTORE_PATHS; if (ret && !include_deactivated && cfgPathDeactivated(path_comps, active_cfg)) { // don't include deactivated @@ -2337,25 +2321,24 @@ Cstore::cfg_path_exists(const vector<string>& path_comps, * note: assume specified path is valid (i.e., validateSetPath()). */ bool -Cstore::set_cfg_path(const vector<string>& path_comps, bool output) +Cstore::set_cfg_path(const Cpath& path_comps, bool output) { - vector<string> ppath; - auto_ptr<Ctemplate> def; + Cpath ppath; + tr1::shared_ptr<Ctemplate> def; bool ret = true; bool path_exists = true; // do the set from the top down - SAVE_PATHS; for (size_t i = 0; i < path_comps.size(); i++) { // partial path - ppath.push_back(path_comps[i]); + ppath.push(path_comps[i]); // get template at this level - def.reset(get_parsed_tmpl(ppath, false)); + def = 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++) { - output_internal(" [%s]\n", ppath[i].c_str()); + output_internal(" [%s]\n", ppath[i]); } exit_internal("failed to get tmpl during set. not validate first?\n"); } @@ -2364,6 +2347,10 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output) if (cfg_path_exists(ppath, false, true)) { continue; } + + // paths have not been changed up to this point. now save them. + auto_ptr<SavePaths> save(create_save_paths()); + path_exists = false; // this level not in working. set it. @@ -2372,14 +2359,19 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output) if (!def->isValue()) { // this level is a "node" - if (!add_node() || !create_default_children()) { + if (!add_node()) { + ret = false; + break; + } + if (!def->isTag() && !create_default_children(ppath)) { + // failed to create default child nodes for a typeless node ret = false; break; } } else if (def->isTag()) { // this level is a "tag value". // add the tag, taking the max tag limit into consideration. - if (!add_tag(def->getTagLimit()) || !create_default_children()) { + if (!add_tag(def->getTagLimit()) || !create_default_children(ppath)) { ret = false; break; } @@ -2406,11 +2398,10 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output) ret = false; break; } - RESTORE_PATHS; } - RESTORE_PATHS; // if "break" was hit if (ret && def->isValue() && def->getDefault()) { + auto_ptr<SavePaths> save(create_save_paths()); /* a node with default has been explicitly set. needs to be marked * as non-default for display purposes. * @@ -2450,7 +2441,6 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output) ret = mark_changed_with_ancestors(); } } - RESTORE_PATHS; } if (path_exists) { // whole path already exists @@ -2471,7 +2461,7 @@ Cstore::set_cfg_path(const vector<string>& path_comps, bool output) * note: this function is NOT "deactivate-aware". */ void -Cstore::get_child_nodes_status(const vector<string>& path_comps, +Cstore::get_child_nodes_status(const Cpath& path_comps, Cstore::MapT<string, string>& cmap, vector<string> *sorted_keys) { @@ -2489,11 +2479,11 @@ Cstore::get_child_nodes_status(const vector<string>& path_comps, } // get the status of each one - vector<string> ppath = path_comps; + Cpath ppath(path_comps); MapT<string, bool>::iterator it = umap.begin(); for (; it != umap.end(); ++it) { string c = (*it).first; - ppath.push_back(c); + ppath.push(c); if (sorted_keys) { sorted_keys->push_back(c); } @@ -2507,7 +2497,7 @@ Cstore::get_child_nodes_status(const vector<string>& path_comps, } else { cmap[c] = C_NODE_STATUS_STATIC; } - ppath.pop_back(); + ppath.pop(); } if (sorted_keys) { sort_nodes(*sorted_keys); @@ -2521,7 +2511,7 @@ Cstore::get_child_nodes_status(const vector<string>& path_comps, * note: this follows the original perl API listNodeStatus() implementation. */ void -Cstore::get_child_nodes_status_da(const vector<string>& path_comps, +Cstore::get_child_nodes_status_da(const Cpath& path_comps, Cstore::MapT<string, string>& cmap, vector<string> *sorted_keys) { @@ -2538,9 +2528,9 @@ Cstore::get_child_nodes_status_da(const vector<string>& path_comps, // get all nodes in working config vector<string> work_nodes; cfgPathGetChildNodesDA(path_comps, work_nodes, false); - vector<string> ppath = path_comps; + Cpath ppath(path_comps); for (size_t i = 0; i < work_nodes.size(); i++) { - ppath.push_back(work_nodes[i]); + ppath.push(work_nodes[i]); if (sorted_keys) { sorted_keys->push_back(work_nodes[i]); } @@ -2561,17 +2551,16 @@ Cstore::get_child_nodes_status_da(const vector<string>& path_comps, && cfg_path_exists(ppath, false, true)) { cmap[work_nodes[i]] = C_NODE_STATUS_ADDED; } else { - SAVE_PATHS; + auto_ptr<SavePaths> save(create_save_paths()); append_cfg_path(ppath); if (cfg_node_changed()) { cmap[work_nodes[i]] = C_NODE_STATUS_CHANGED; } else { cmap[work_nodes[i]] = C_NODE_STATUS_STATIC; } - RESTORE_PATHS; } - ppath.pop_back(); + ppath.pop(); } if (sorted_keys) { sort_nodes(*sorted_keys); @@ -2592,7 +2581,8 @@ Cstore::remove_tag() // go up one level and check if that was the last tag bool ret = true; - string c = pop_cfg_path(); + string c; + pop_cfg_path(c); vector<string> cnodes; // get child nodes, including deactivated ones. get_all_child_node_names(cnodes, false, true); @@ -2602,7 +2592,7 @@ Cstore::remove_tag() ret = false; } } - push_cfg_path(c); + push_cfg_path(c.c_str()); return ret; } @@ -2656,33 +2646,21 @@ Cstore::cfg_value_exists(const string& value, bool active_cfg) } /* validate value at current template path. - * def: pointer to parsed template. NULL if none. + * def: pointer to parsed template. * val: value to be validated. * return true if valid. otherwise return false. * note: current template and cfg paths both point to the node, * not the value. */ bool -Cstore::validate_val(const Ctemplate *def, const string& value) +Cstore::validate_val(const tr1::shared_ptr<Ctemplate>& def, const char *value) { - auto_ptr<Ctemplate> ndef; - if (!def) { - ndef.reset(tmpl_parse()); - if (!(def = ndef.get())) { - exit_internal("failed to parse tmpl [%s]\n", tmpl_path_to_str().c_str()); - } - if (def->isTypeless()) { - // not a value node - exit_internal("validating non-value node [%s]\n", - tmpl_path_to_str().c_str()); - } + if (!def.get()) { + exit_internal("validate_val: no tmpl [%s]\n", tmpl_path_to_str().c_str()); } // validate_value() may change "value". make a copy first. - size_t vlen = value.size(); - char *vbuf = (char *) malloc(vlen + 1); - strncpy(vbuf, value.c_str(), vlen + 1); - vbuf[vlen] = 0; + char *vbuf = strdup(value); bool ret = validate_val_impl(def, vbuf); free(vbuf); return ret; @@ -2696,7 +2674,8 @@ Cstore::validate_val(const Ctemplate *def, const string& value) bool Cstore::add_tag(unsigned int tlimit) { - string t = pop_cfg_path(); + string t; + pop_cfg_path(t); vector<string> cnodes; // get child nodes, excluding deactivated ones. get_all_child_node_names(cnodes, false, false); @@ -2717,7 +2696,7 @@ Cstore::add_tag(unsigned int tlimit) // neither of the above. just add the tag. ret = add_child_node(t); } while (0); - push_cfg_path(t); + push_cfg_path(t.c_str()); return ret; } @@ -2770,7 +2749,7 @@ Cstore::get_all_child_node_names(vector<string>& cnodes, bool active_cfg, get_all_child_node_names_impl(nodes, active_cfg); for (size_t i = 0; i < nodes.size(); i++) { if (!include_deactivated) { - push_cfg_path(nodes[i]); + push_cfg_path(nodes[i].c_str()); bool skip = marked_deactivated(active_cfg); pop_cfg_path(); if (skip) { @@ -2782,31 +2761,36 @@ Cstore::get_all_child_node_names(vector<string>& cnodes, bool active_cfg, } /* create all child nodes of current work path that have default values + * path_comps: path components. MUST match the work path and is only + * needed for the get_parsed_tmpl() call. * return true if successful. otherwise return false. * note: assume current work path has just been created so no child * nodes exist. */ bool -Cstore::create_default_children() +Cstore::create_default_children(const Cpath& path_comps) { vector<string> tcnodes; get_all_tmpl_child_node_names(tcnodes); + bool ret = true; + Cpath pcomps(path_comps); + // need to save/reset/restore paths for get_parsed_tmpl() + auto_ptr<SavePaths> save(create_save_paths()); + reset_paths(); for (size_t i = 0; i < tcnodes.size(); i++) { - push_tmpl_path(tcnodes[i]); - 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->getDefault()) - || !mark_display_default()) { - ret = false; - } - pop_cfg_path(); + pcomps.push(tcnodes[i]); + tr1::shared_ptr<Ctemplate> def(get_parsed_tmpl(pcomps, false)); + if (def.get() && def->getDefault()) { + // has default value. set it. + append_cfg_path(pcomps); + if (!add_node() || !write_value(def->getDefault()) + || !mark_display_default()) { + ret = false; } + reset_paths(); } - pop_tmpl_path(); + pcomps.pop(); if (!ret) { break; } @@ -2820,7 +2804,7 @@ Cstore::create_default_children() void Cstore::get_edit_env(string& env) { - vector<string> lvec; + Cpath lvec; get_edit_level(lvec); string lvl; for (size_t i = 0; i < lvec.size(); i++) { @@ -2860,15 +2844,15 @@ Cstore::shell_escape_squotes(string& str) // print a vector of strings void -Cstore::print_str_vec(const char *pre, const char *post, - const vector<string>& vec, const char *quote) +Cstore::print_path_vec(const char *pre, const char *post, + const Cpath& pvec, const char *quote) { output_user("%s", pre); - for (size_t i = 0; i < vec.size(); i++) { + for (size_t i = 0; i < pvec.size(); i++) { if (i > 0) { output_user(" "); } - output_user("%s%s%s", quote, vec[i].c_str(), quote); + output_user("%s%s%s", quote, pvec[i], quote); } output_user("%s", post); } @@ -2931,3 +2915,5 @@ Cstore::vexit_internal(const char *fmt, va_list alist) } } +} // end namespace cstore + diff --git a/src/cstore/cstore.hpp b/src/cstore/cstore.hpp index 6a76f31..62677c1 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/cpath.hpp> #include <cstore/ctemplate.hpp> /* declare perl internal functions. just need these two so don't include @@ -40,12 +41,6 @@ extern "C" void* Perl_get_context(void) __func__); -/* macros for saving/restoring paths. - * note: this allows "nested" save/restore invocations but NOT recursive ones. - */ -#define SAVE_PATHS save_paths(&__func__) -#define RESTORE_PATHS restore_paths(&__func__) - namespace cstore { // begin namespace cstore using namespace std; @@ -61,8 +56,8 @@ public: static Cstore *createCstore(const string& session_id, string& env); // types - template<class K, class V> - class MapT : public tr1::unordered_map<K, V> {}; + template<class K, class V, class H = tr1::hash<K> > + class MapT : public tr1::unordered_map<K, V, H> {}; // constants static const string C_NODE_STATUS_DELETED; @@ -100,12 +95,12 @@ public: ////// the public cstore interface //// functions implemented in this base class // these operate on template path - bool validateTmplPath(const vector<string>& path_comps, bool validate_vals); - 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, - vector<string>& cnodes); + bool validateTmplPath(const Cpath& path_comps, bool validate_vals); + tr1::shared_ptr<Ctemplate> parseTmpl(const Cpath& path_comps, + bool validate_vals); + bool getParsedTmpl(const Cpath& path_comps, MapT<string, string>& tmap, + bool allow_val = true); + void tmplGetChildNodes(const Cpath& path_comps, vector<string>& cnodes); /****** * functions for actual CLI operations: @@ -127,39 +122,39 @@ public: * be used by anything other than the listed operations. */ // set - bool validateSetPath(const vector<string>& path_comps); - bool setCfgPath(const vector<string>& path_comps); + bool validateSetPath(const Cpath& path_comps); + bool setCfgPath(const Cpath& path_comps); // delete - bool deleteCfgPath(const vector<string>& path_comps); + bool deleteCfgPath(const Cpath& 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); + bool validateActivatePath(const Cpath& path_comps); + bool unmarkCfgPathDeactivated(const Cpath& path_comps); // deactivate - bool validateDeactivatePath(const vector<string>& path_comps); - bool markCfgPathDeactivated(const vector<string>& path_comps); + bool validateDeactivatePath(const Cpath& path_comps); + bool markCfgPathDeactivated(const Cpath& path_comps); // rename - bool validateRenameArgs(const vector<string>& args); - bool renameCfgPath(const vector<string>& args); + bool validateRenameArgs(const Cpath& args); + bool renameCfgPath(const Cpath& args); // copy - bool validateCopyArgs(const vector<string>& args); - bool copyCfgPath(const vector<string>& args); + bool validateCopyArgs(const Cpath& args); + bool copyCfgPath(const Cpath& args); // comment - bool commentCfgPath(const vector<string>& args); + bool commentCfgPath(const Cpath& args); // discard bool discardChanges(); // move - bool validateMoveArgs(const vector<string>& args); - bool moveCfgPath(const vector<string>& args); + bool validateMoveArgs(const Cpath& args); + bool moveCfgPath(const Cpath& args); // edit-related - bool getEditEnv(const vector<string>& path_comps, string& env); + bool getEditEnv(const Cpath& path_comps, string& env); bool getEditUpEnv(string& env); bool getEditResetEnv(string& env); bool editLevelAtRoot() { return edit_level_at_root(); }; // completion-related - bool getCompletionEnv(const vector<string>& comps, string& env); - void getEditLevel(vector<string>& comps) { + bool getCompletionEnv(const Cpath& comps, string& env); + void getEditLevel(Cpath& comps) { get_edit_level(comps); }; // session-related @@ -171,7 +166,7 @@ public: virtual bool teardownSession() = 0; virtual bool inSession() = 0; // commit - bool unmarkCfgPathChanged(const vector<string>& path_comps); + bool unmarkCfgPathChanged(const Cpath& path_comps); // load bool loadFile(const char *filename); @@ -190,34 +185,32 @@ public: * config, of course). */ // observers for "working config" (by default) OR "active config" - bool cfgPathExists(const vector<string>& path_comps, - bool active_cfg = false); - void cfgPathGetChildNodes(const vector<string>& path_comps, - vector<string>& cnodes, bool active_cfg = false); - bool cfgPathGetValue(const vector<string>& path_comps, string& value, + bool cfgPathExists(const Cpath& path_comps, bool active_cfg = false); + void cfgPathGetChildNodes(const Cpath& path_comps, vector<string>& cnodes, + bool active_cfg = false); + bool cfgPathGetValue(const Cpath& path_comps, string& value, bool active_cfg = false); - bool cfgPathGetValues(const vector<string>& path_comps, - vector<string>& values, bool active_cfg = false); - bool cfgPathGetComment(const vector<string>& path_comps, string& comment, + bool cfgPathGetValues(const Cpath& path_comps, vector<string>& values, + bool active_cfg = false); + bool cfgPathGetComment(const Cpath& path_comps, string& comment, bool active_cfg = false); - bool cfgPathDefault(const vector<string>& path_comps, - bool active_cfg = false); + bool cfgPathDefault(const Cpath& path_comps, bool active_cfg = false); /* observers for working AND active configs (at the same time). * MUST ONLY be used during config session. */ - bool cfgPathDeleted(const vector<string>& path_comps); - bool cfgPathAdded(const vector<string>& path_comps); - bool cfgPathChanged(const vector<string>& path_comps); - void cfgPathGetDeletedChildNodes(const vector<string>& path_comps, + bool cfgPathDeleted(const Cpath& path_comps); + bool cfgPathAdded(const Cpath& path_comps); + bool cfgPathChanged(const Cpath& path_comps); + void cfgPathGetDeletedChildNodes(const Cpath& path_comps, vector<string>& cnodes); - void cfgPathGetDeletedValues(const vector<string>& path_comps, + void cfgPathGetDeletedValues(const Cpath& path_comps, vector<string>& dvals); - void cfgPathGetChildNodesStatus(const vector<string>& path_comps, + void cfgPathGetChildNodesStatus(const Cpath& path_comps, MapT<string, string>& cmap) { get_child_nodes_status(path_comps, cmap, NULL); }; - void cfgPathGetChildNodesStatus(const vector<string>& path_comps, + void cfgPathGetChildNodesStatus(const Cpath& path_comps, MapT<string, string>& cmap, vector<string>& sorted_keys) { get_child_nodes_status(path_comps, cmap, &sorted_keys); @@ -227,12 +220,11 @@ public: * session and outside a config session. more detailed information * can be found in the source file. */ - bool cfgPathEffective(const vector<string>& path_comps); - void cfgPathGetEffectiveChildNodes(const vector<string>& path_comps, + bool cfgPathEffective(const Cpath& path_comps); + void cfgPathGetEffectiveChildNodes(const Cpath& path_comps, vector<string>& cnodes); - bool cfgPathGetEffectiveValue(const vector<string>& path_comps, - string& value); - bool cfgPathGetEffectiveValues(const vector<string>& path_comps, + bool cfgPathGetEffectiveValue(const Cpath& path_comps, string& value); + bool cfgPathGetEffectiveValues(const Cpath& path_comps, vector<string>& values); /****** @@ -253,36 +245,32 @@ public: * passed in when calling them. */ // working or active config - bool cfgPathDeactivated(const vector<string>& path_comps, - bool active_cfg = false); - bool cfgPathMarkedDeactivated(const vector<string>& path_comps, + bool cfgPathDeactivated(const Cpath& path_comps, bool active_cfg = false); + bool cfgPathMarkedDeactivated(const Cpath& path_comps, bool active_cfg = false); - bool cfgPathExistsDA(const vector<string>& path_comps, - bool active_cfg = false, + bool cfgPathExistsDA(const Cpath& path_comps, bool active_cfg = false, bool include_deactivated = true); - void cfgPathGetChildNodesDA(const vector<string>& path_comps, - vector<string>& cnodes, + void cfgPathGetChildNodesDA(const Cpath& path_comps, vector<string>& cnodes, bool active_cfg = false, bool include_deactivated = true); - bool cfgPathGetValueDA(const vector<string>& path_comps, string& value, + bool cfgPathGetValueDA(const Cpath& path_comps, string& value, bool active_cfg = false, bool include_deactivated = true); - bool cfgPathGetValuesDA(const vector<string>& path_comps, - vector<string>& values, + bool cfgPathGetValuesDA(const Cpath& path_comps, vector<string>& values, bool active_cfg = false, bool include_deactivated = true); // working AND active configs - void cfgPathGetDeletedChildNodesDA(const vector<string>& path_comps, + void cfgPathGetDeletedChildNodesDA(const Cpath& path_comps, vector<string>& cnodes, bool include_deactivated = true); - void cfgPathGetDeletedValuesDA(const vector<string>& path_comps, + void cfgPathGetDeletedValuesDA(const Cpath& path_comps, vector<string>& dvals, bool include_deactivated = true); - void cfgPathGetChildNodesStatusDA(const vector<string>& path_comps, + void cfgPathGetChildNodesStatusDA(const Cpath& path_comps, MapT<string, string>& cmap) { get_child_nodes_status_da(path_comps, cmap, NULL); }; - void cfgPathGetChildNodesStatusDA(const vector<string>& path_comps, + void cfgPathGetChildNodesStatusDA(const Cpath& path_comps, MapT<string, string>& cmap, vector<string>& sorted_keys) { get_child_nodes_status_da(path_comps, cmap, &sorted_keys); @@ -299,10 +287,15 @@ public: * the limitations of the original CLI library implementation and MUST NOT * be used by anyone other than the original CLI library. */ - char *getVarRef(const string& ref_str, vtw_type_e& type, bool from_active); - bool setVarRef(const string& ref_str, const string& value, bool to_active); + char *getVarRef(const char *ref_str, vtw_type_e& type, bool from_active); + bool setVarRef(const char *ref_str, const char *value, bool to_active); protected: + class SavePaths { + public: + virtual ~SavePaths() = 0; + }; + ////// functions for subclasses static void output_user(const char *fmt, ...); static void output_user_err(const char *fmt, ...); @@ -323,15 +316,16 @@ private: * the same as before invocation. */ // begin path modifiers - virtual void push_tmpl_path(const string& path_comp) = 0; + virtual void push_tmpl_path(const char *path_comp) = 0; virtual void push_tmpl_path_tag() = 0; - virtual string pop_tmpl_path() = 0; - virtual void push_cfg_path(const string& path_comp) = 0; - virtual string pop_cfg_path() = 0; - virtual void append_cfg_path(const vector<string>& path_comps) = 0; + virtual void pop_tmpl_path() = 0; + virtual void pop_tmpl_path(string& last) = 0; + virtual void push_cfg_path(const char *path_comp) = 0; + virtual void pop_cfg_path() = 0; + virtual void pop_cfg_path(string& last) = 0; + virtual void append_cfg_path(const Cpath& path_comps) = 0; virtual void reset_paths() = 0; - virtual void save_paths(const void *handle = NULL) = 0; - virtual void restore_paths(const void *handle = NULL) = 0; + virtual auto_ptr<SavePaths> create_save_paths() = 0; virtual bool cfg_path_at_root() = 0; virtual bool tmpl_path_at_root() = 0; // end path modifiers @@ -348,8 +342,8 @@ private: virtual bool write_value_vec(const vector<string>& vvec, bool active_cfg = false) = 0; virtual bool add_node() = 0; - virtual bool rename_child_node(const string& oname, const string& nname) = 0; - virtual bool copy_child_node(const string& oname, const string& nname) = 0; + virtual bool rename_child_node(const char *oname, const char *nname) = 0; + virtual bool copy_child_node(const char *oname, const char *nname) = 0; virtual bool mark_display_default() = 0; virtual bool unmark_display_default() = 0; virtual bool mark_deactivated() = 0; @@ -372,10 +366,12 @@ private: virtual bool marked_display_default(bool active_cfg) = 0; // observers during commit operation - virtual bool marked_committed(const Ctemplate *def, bool is_set) = 0; + virtual bool marked_committed(const tr1::shared_ptr<Ctemplate>& def, + bool is_set) = 0; // these operate on both current tmpl and work paths - virtual bool validate_val_impl(const Ctemplate *def, char *value) = 0; + virtual bool validate_val_impl(const tr1::shared_ptr<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 @@ -390,7 +386,7 @@ private: */ virtual string get_edit_level_path() = 0; virtual string get_tmpl_level_path() = 0; - virtual void get_edit_level(vector<string>& path_comps) = 0; + virtual void get_edit_level(Cpath& path_comps) = 0; virtual bool edit_level_at_root() = 0; // these are for testing/debugging @@ -417,15 +413,17 @@ private: } // begin path modifiers (only these can change path permanently) - bool append_tmpl_path(const vector<string>& path_comps, bool& is_tag); - bool append_tmpl_path(const vector<string>& path_comps) { + bool append_tmpl_path(const Cpath& path_comps, bool& is_tag); + bool append_tmpl_path(const Cpath& path_comps) { bool dummy; return append_tmpl_path(path_comps, dummy); }; - bool append_tmpl_path(const string& path_comp, bool& is_tag) { - return append_tmpl_path(vector<string>(1, path_comp), is_tag); + bool append_tmpl_path(const char *path_comp, bool& is_tag) { + Cpath p; + p.push(path_comp); + return append_tmpl_path(p, is_tag); }; - bool append_tmpl_path(const string& path_comp) { + bool append_tmpl_path(const char *path_comp) { bool dummy; return append_tmpl_path(path_comp, dummy); }; @@ -433,26 +431,26 @@ private: // these require full path // (note: get_parsed_tmpl also uses current tmpl path) - 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) { + tr1::shared_ptr<Ctemplate> get_parsed_tmpl(const Cpath& path_comps, + bool validate_vals, + string& error); + tr1::shared_ptr<Ctemplate> get_parsed_tmpl(const Cpath& path_comps, + bool validate_vals) { string dummy; return get_parsed_tmpl(path_comps, validate_vals, dummy); }; - 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, - vector<string>& rn_args); - bool cfg_path_exists(const vector<string>& path_comps, - bool active_cfg, bool include_deactivated); - bool set_cfg_path(const vector<string>& path_comps, bool output); - void get_child_nodes_status(const vector<string>& path_comps, + tr1::shared_ptr<Ctemplate> validate_act_deact(const Cpath& path_comps, + const char *op); + bool validate_rename_copy(const Cpath& args, const char *op); + bool conv_move_args_for_rename(const Cpath& args, Cpath& edit_path_comps, + Cpath& rn_args); + bool cfg_path_exists(const Cpath& path_comps, bool active_cfg, + bool include_deactivated); + bool set_cfg_path(const Cpath& path_comps, bool output); + void get_child_nodes_status(const Cpath& path_comps, Cstore::MapT<string, string>& cmap, vector<string> *sorted_keys); - void get_child_nodes_status_da(const vector<string>& path_comps, + void get_child_nodes_status_da(const Cpath& path_comps, Cstore::MapT<string, string>& cmap, vector<string> *sorted_keys); @@ -466,7 +464,7 @@ private: 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); + push_cfg_path(name.c_str()); bool ret = add_node(); pop_cfg_path(); return ret; @@ -478,15 +476,17 @@ private: bool cfg_value_exists(const string& value, bool active_cfg); // these operate on both current tmpl and work paths - bool validate_val(const Ctemplate *def, const string& value); - bool create_default_children(); + bool validate_val(const tr1::shared_ptr<Ctemplate>& def, const char *value); + bool create_default_children(const Cpath& path_comps); /* this requires + * path_comps but DOES operate on current work path. + */ void get_edit_env(string& env); // util functions string get_shell_prompt(const string& level); void shell_escape_squotes(string& str); - void print_str_vec(const char *pre, const char *post, - const vector<string>& vec, const char *quote); + void print_path_vec(const char *pre, const char *post, + const Cpath& pvec, const char *quote); // output functions static void voutput_user(FILE *out, FILE *dout, const char *fmt, diff --git a/src/cstore/ctemplate.hpp b/src/cstore/ctemplate.hpp index 1915273..e970a5d 100644 --- a/src/cstore/ctemplate.hpp +++ b/src/cstore/ctemplate.hpp @@ -28,10 +28,10 @@ using namespace std; class Ctemplate { public: - Ctemplate(tr1::shared_ptr<vtw_def> def) : _def(def) {}; + Ctemplate(tr1::shared_ptr<vtw_def> def) : _def(def), _is_value(false) {}; ~Ctemplate() {}; - bool isValue() const { return _def->is_value; }; + bool isValue() const { return _is_value; }; bool isMulti() const { return _def->multi; }; bool isTag() const { return _def->tag; }; bool isTagNode() const { return (isTag() && !isValue()); }; @@ -90,7 +90,7 @@ public: 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; }; + void setIsValue(bool is_val) { _is_value = is_val; }; const vtw_def *getDef() const { /* XXX this is a hack for code that has not been converted and is still @@ -118,6 +118,9 @@ private: * handled properly. */ tr1::shared_ptr<vtw_def> _def; + bool _is_value; /* whether the last path component is a "value". set by + * the cstore in get_parsed_tmpl(). + */ }; } // end namespace cstore diff --git a/src/cstore/svector.hpp b/src/cstore/svector.hpp new file mode 100644 index 0000000..fd63297 --- /dev/null +++ b/src/cstore/svector.hpp @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2011 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 _SVECTOR_HPP_ +#define _SVECTOR_HPP_ +#include <cstdlib> +#include <cstring> +#include <string> +#include <tr1/functional> + +namespace cstore { + +template<int v> +struct Int2Type { + enum { + value = v + }; +}; + +template<class P> +class svector { +public: + static const char ELEM_SEP = P::separator; + static const bool RAW_CSTR_DATA = (ELEM_SEP != 0); + static const bool RANDOM_ACCESS = (ELEM_SEP == 0); + static const size_t STATIC_NUM_ELEMS = P::static_num_elems; + static const size_t STATIC_BUF_LEN = P::static_buf_len; + + svector(); + svector(const svector<P>& v); + svector(const char *raw_cstr); + svector(const std::string& str); + svector(const char *raw_data, size_t dlen); + ~svector(); + + void push_back(const char *e); + void pop_back(); + void pop_back(std::string& last); + + svector<P>& operator=(const char *raw_cstr) { + assign(raw_cstr); + return *this; + }; + svector<P>& operator=(const std::string& str) { + return operator=(str.c_str()); + }; + svector<P>& operator=(const svector<P>& v); + svector<P>& operator/=(const svector<P>& v); + svector<P> operator/(const svector<P>& v) { + svector<P> lhs(*this); + lhs /= v; + return lhs; + }; + void assign(const char *raw_cstr) { + assign_raw_cstr(raw_cstr, Int2Type<RAW_CSTR_DATA>()); + }; + void assign(const char *raw_data, size_t dlen); + + bool operator==(const svector<P>& rhs) const { + return (_len == rhs._len && memcmp(_data, rhs._data, _len) == 0); + }; + const char *operator[](size_t idx) const { + return elem_at(idx, Int2Type<RANDOM_ACCESS>()); + }; + + size_t size() const { return _num_elems; }; + size_t length() const { return _len; }; + const char *get_cstr() const { + return get_raw_cstr(Int2Type<RAW_CSTR_DATA>()); + }; + const char *get_data(size_t& dlen) const { + dlen = _len; + return _data; + }; + size_t hash() const { + return std::tr1::_Fnv_hash<sizeof(size_t)>::hash(_data, _len); + }; + +private: + size_t _num_elems; + size_t _len; + size_t _ebuf_size; + size_t _buf_size; + char **_elems; + char *_elems_buf[STATIC_NUM_ELEMS]; + char **_elems_dbuf; + char *_data; + char _data_buf[STATIC_BUF_LEN]; + char *_data_dbuf; + + void grow_data(); + void grow_elems(); + void inc_num_elems() { + ++_num_elems; + if (_num_elems >= _ebuf_size) { + grow_elems(); + } + }; + void assign_raw_cstr(const char *raw_cstr, Int2Type<true>) { + assign(raw_cstr, strlen(raw_cstr)); + }; + const char *get_raw_cstr(Int2Type<true>) const { + return _data; + }; + const char *elem_at(size_t idx, Int2Type<true>) const { + return (idx < _num_elems ? (_elems[idx] + 1) : NULL); + } +}; + +template<class P> +svector<P>::svector() + : _num_elems(0), _len(0), _ebuf_size(STATIC_NUM_ELEMS), + _buf_size(STATIC_BUF_LEN), _elems(_elems_buf), _elems_dbuf(0), + _data(_data_buf), _data_dbuf(0) +{ + _elems[0] = _data; + _data[0] = 0; +} + +template<class P> +svector<P>::svector(const svector<P>& v) + : _num_elems(0), _len(0), _ebuf_size(STATIC_NUM_ELEMS), + _buf_size(STATIC_BUF_LEN), _elems(_elems_buf), _elems_dbuf(0), + _data(_data_buf), _data_dbuf(0) +{ + _elems[0] = _data; + _data[0] = 0; + operator=(v); +} + +template<class P> +svector<P>::svector(const char *raw_cstr) + : _num_elems(0), _len(0), _ebuf_size(STATIC_NUM_ELEMS), + _buf_size(STATIC_BUF_LEN), _elems(_elems_buf), _elems_dbuf(0), + _data(_data_buf), _data_dbuf(0) +{ + assign(raw_cstr); +} + +template<class P> +svector<P>::svector(const std::string& str) + : _num_elems(0), _len(0), _ebuf_size(STATIC_NUM_ELEMS), + _buf_size(STATIC_BUF_LEN), _elems(_elems_buf), _elems_dbuf(0), + _data(_data_buf), _data_dbuf(0) +{ + assign(str.c_str()); +} + +template<class P> +svector<P>::svector(const char *raw_data, size_t dlen) + : _num_elems(0), _len(0), _ebuf_size(STATIC_NUM_ELEMS), + _buf_size(STATIC_BUF_LEN), _elems(_elems_buf), _elems_dbuf(0), + _data(_data_buf), _data_dbuf(0) +{ + assign(raw_data, dlen); +} + +template<class P> +svector<P>::~svector() +{ + if (_elems_dbuf) { + delete [] _elems_dbuf; + } + if (_data_dbuf) { + delete [] _data_dbuf; + } +} + +template<class P> void +svector<P>::push_back(const char *e) +{ + size_t elen = strlen(e); + while ((_len + elen + 2) >= _buf_size) { + // make sure there's space for (data + SEP + e + 0) + grow_data(); + } + + char *start = _elems[_num_elems]; + *start = ELEM_SEP; + memcpy(start + 1, e, elen + 1); + inc_num_elems(); + _len += (elen + 1); + _elems[_num_elems] = start + 1 + elen; +} + +template<class P> void +svector<P>::pop_back() +{ + if (_num_elems == 0) { + return; + } + --_num_elems; + _len = _elems[_num_elems] - _data; + _data[_len] = 0; +} + +template<class P> void +svector<P>::pop_back(std::string& last) +{ + if (_num_elems == 0) { + return; + } + last = _elems[_num_elems - 1] + 1; + pop_back(); +} + +template<class P> svector<P>& +svector<P>::operator=(const svector<P>& v) +{ + if (this == &v) { + return *this; + } + + while (_buf_size < v._buf_size) { + grow_data(); + } + if (_ebuf_size >= v._ebuf_size) { + _num_elems = v._num_elems; + } else { + _num_elems = 0; + while (_num_elems < v._num_elems) { + inc_num_elems(); + } + } + _len = v._len; + memcpy(_data, v._data, _len + 1); + memcpy(_elems, v._elems, sizeof(char *) * (_num_elems + 1)); + const char *o0 = _elems[0]; + for (size_t i = 0; i <= _num_elems; i++) { + _elems[i] = _data + (_elems[i] - o0); + } + return *this; +} + +template<class P> svector<P>& +svector<P>::operator/=(const svector<P>& v) +{ + while ((_len + v._len + 1) >= _buf_size) { + // make sure there's space for (data + data + 0) + grow_data(); + } + + size_t v_num_elems = v._num_elems; + size_t olen = _len; + memcpy(_data + _len, v._data, v._len + 1); + _len += v._len; + for (size_t i = 1; i <= v_num_elems; i++) { + inc_num_elems(); + _elems[_num_elems] = _data + olen + (v._elems[i] - v._data); + } + return *this; +} + +template<class P> void +svector<P>::assign(const char *raw_data, size_t dlen) +{ + _num_elems = 0; + _len = 0; + _elems[0] = _data; + if (dlen == 0 || (dlen == 1 && raw_data[0] == ELEM_SEP)) { + _data[0] = 0; + return; + } + + while ((dlen + 2) >= _buf_size) { + // make sure there's space for (SEP + raw_data + 0) + grow_data(); + } + _len = dlen; + + if (raw_data[0] != ELEM_SEP) { + _data[0] = ELEM_SEP; + memcpy(_data + 1, raw_data, _len + 1); + ++_len; + } else { + memcpy(_data, raw_data, _len + 1); + } + for (size_t i = 1; i < _len; i++) { + if (_data[i] == ELEM_SEP) { + inc_num_elems(); + _elems[_num_elems] = &(_data[i]); + } + } + inc_num_elems(); + _elems[_num_elems] = _data + _len; +} + +template<class P> void +svector<P>::grow_data() +{ + char *tmp = new char[_buf_size + STATIC_BUF_LEN]; + if (!tmp) { + // doomed + exit(1); + } + memcpy(tmp, _data, _len + 1); + + if (tmp != _data_dbuf) { + for (size_t i = 0; i <= _num_elems; i++) { + _elems[i] = tmp + (_elems[i] - _data); + } + } + + if (_data_dbuf) { + delete [] _data_dbuf; + } + _data_dbuf = tmp; + _data = _data_dbuf; + _buf_size += STATIC_BUF_LEN; +} + +template<class P> void +svector<P>::grow_elems() +{ + char **tmp = new char *[_ebuf_size + STATIC_NUM_ELEMS]; + if (!tmp) { + // doomed + exit(1); + } + memcpy(tmp, _elems, _ebuf_size * sizeof(char *)); + if (_elems_dbuf) { + delete [] _elems_dbuf; + } + _elems_dbuf = tmp; + _elems = _elems_dbuf; + _ebuf_size += STATIC_NUM_ELEMS; +} + +} // end namespace cstore + +#endif /* _SVECTOR_HPP_ */ + diff --git a/src/cstore/unionfs/cstore-unionfs.cpp b/src/cstore/unionfs/cstore-unionfs.cpp index b59ddd3..f926540 100644 --- a/src/cstore/unionfs/cstore-unionfs.cpp +++ b/src/cstore/unionfs/cstore-unionfs.cpp @@ -26,7 +26,8 @@ #include <cli_cstore.h> #include <cstore/unionfs/cstore-unionfs.hpp> -using namespace cstore; +namespace cstore { // begin namespace cstore +namespace unionfs { // begin namespace unionfs ////// constants // environment vars defining root dirs @@ -205,7 +206,8 @@ UnionfsCstore::UnionfsCstore(bool use_edit_level) * starts with '/', so only append it if it is at least two chars * (i.e., it is not "/"). */ - tmpl_path /= val; + FsPath tlvl(val); + tmpl_path /= tlvl; } } _init_fs_escape_chars(); @@ -239,11 +241,11 @@ UnionfsCstore::UnionfsCstore(const string& sid, string& env) string declr = " declare -x -r "; // readonly vars env += " umask 002; {"; - env += (declr + C_ENV_ACTIVE_ROOT + "=" + active_root.file_string()); - env += (declr + C_ENV_CHANGE_ROOT + "=" + change_root.file_string() + ";"); - env += (declr + C_ENV_WORK_ROOT + "=" + work_root.file_string() + ";"); - env += (declr + C_ENV_TMP_ROOT + "=" + tmp_root.file_string() + ";"); - env += (declr + C_ENV_TMPL_ROOT + "=" + tmpl_root.file_string() + ";"); + env += (declr + C_ENV_ACTIVE_ROOT + "=" + active_root.path_cstr()); + env += (declr + C_ENV_CHANGE_ROOT + "=" + change_root.path_cstr() + ";"); + env += (declr + C_ENV_WORK_ROOT + "=" + work_root.path_cstr() + ";"); + env += (declr + C_ENV_TMP_ROOT + "=" + tmp_root.path_cstr() + ";"); + env += (declr + C_ENV_TMPL_ROOT + "=" + tmpl_root.path_cstr() + ";"); env += " } >&/dev/null || true"; // set up path strings using level vars @@ -254,7 +256,8 @@ UnionfsCstore::UnionfsCstore(const string& sid, string& env) } if ((val = getenv(C_ENV_TMPL_LEVEL.c_str())) && val[0] && val[1]) { // see comment in the other constructor - tmpl_path /= val; + FsPath tlvl(val); + tmpl_path /= tlvl; } _init_fs_escape_chars(); @@ -269,14 +272,14 @@ UnionfsCstore::~UnionfsCstore() bool UnionfsCstore::markSessionUnsaved() { - b_fs::path marker = work_root / C_MARKER_UNSAVED; - if (path_exists(marker.file_string().c_str())) { + FsPath marker = work_root; + marker.push(C_MARKER_UNSAVED); + if (path_exists(marker)) { // already marked. treat as success. return true; } - if (!create_file(marker.file_string())) { - output_internal("failed to mark unsaved [%s]\n", - marker.file_string().c_str()); + if (!create_file(marker)) { + output_internal("failed to mark unsaved [%s]\n", marker.path_cstr()); return false; } return true; @@ -285,16 +288,16 @@ UnionfsCstore::markSessionUnsaved() bool UnionfsCstore::unmarkSessionUnsaved() { - b_fs::path marker = work_root / C_MARKER_UNSAVED; - if (!path_exists(marker.file_string().c_str())) { + FsPath marker = work_root; + marker.push(C_MARKER_UNSAVED); + if (!path_exists(marker)) { // not marked. treat as success. return true; } try { - b_fs::remove(marker); + b_fs::remove(marker.path_cstr()); } catch (...) { - output_internal("failed to unmark unsaved [%s]\n", - marker.file_string().c_str()); + output_internal("failed to unmark unsaved [%s]\n", marker.path_cstr()); return false; } return true; @@ -303,15 +306,17 @@ UnionfsCstore::unmarkSessionUnsaved() bool UnionfsCstore::sessionUnsaved() { - b_fs::path marker = work_root / C_MARKER_UNSAVED; - return path_exists(marker.file_string().c_str()); + FsPath marker = work_root; + marker.push(C_MARKER_UNSAVED); + return path_exists(marker); } bool UnionfsCstore::sessionChanged() { - b_fs::path marker = work_root / C_MARKER_CHANGED; - return path_exists(marker.file_string().c_str()); + FsPath marker = work_root; + marker.push(C_MARKER_CHANGED); + return path_exists(marker); } /* set up the session associated with this object. @@ -321,15 +326,15 @@ UnionfsCstore::sessionChanged() bool UnionfsCstore::setupSession() { - if (!path_exists(work_root.file_string().c_str())) { + if (!path_exists(work_root)) { // session doesn't exist. create dirs. try { - b_fs::create_directories(work_root); - b_fs::create_directories(change_root); - b_fs::create_directories(tmp_root); - if (!path_exists(active_root.file_string().c_str())) { + b_fs::create_directories(work_root.path_cstr()); + b_fs::create_directories(change_root.path_cstr()); + b_fs::create_directories(tmp_root.path_cstr()); + if (!path_exists(active_root)) { // this should only be needed on boot - b_fs::create_directories(active_root); + b_fs::create_directories(active_root.path_cstr()); } } catch (...) { output_internal("setup session failed to create session directories\n"); @@ -337,17 +342,20 @@ UnionfsCstore::setupSession() } // union mount - string mopts = ("dirs=" + change_root.file_string() + "=rw:" - + active_root.file_string() + "=ro"); - if (mount("unionfs", work_root.file_string().c_str(), "unionfs", 0, + string mopts = "dirs="; + mopts += change_root.path_cstr(); + mopts += "=rw:"; + mopts += active_root.path_cstr(); + mopts += "=ro"; + if (mount("unionfs", work_root.path_cstr(), "unionfs", 0, mopts.c_str()) != 0) { output_internal("setup session mount failed [%s][%s]\n", - strerror(errno), work_root.file_string().c_str()); + strerror(errno), work_root.path_cstr()); return false; } - } else if (!path_is_directory(work_root.file_string().c_str())) { + } else if (!path_is_directory(work_root)) { output_internal("setup session not dir [%s]\n", - work_root.file_string().c_str()); + work_root.path_cstr()); return false; } return true; @@ -361,10 +369,9 @@ bool UnionfsCstore::teardownSession() { // check if session exists - string wstr = work_root.file_string(); + string wstr = work_root.path_cstr(); if (wstr.empty() || wstr.find(C_DEF_WORK_PREFIX) != 0 - || !path_exists(work_root.file_string().c_str()) - || !path_is_directory(work_root.file_string().c_str())) { + || !path_exists(work_root) || !path_is_directory(work_root)) { // no session output_internal("teardown invalid session [%s]\n", wstr.c_str()); return false; @@ -380,9 +387,9 @@ UnionfsCstore::teardownSession() // remove session directories bool ret = false; try { - if (b_fs::remove_all(work_root) != 0 - && b_fs::remove_all(change_root) != 0 - && b_fs::remove_all(tmp_root) != 0) { + if (b_fs::remove_all(work_root.path_cstr()) != 0 + && b_fs::remove_all(change_root.path_cstr()) != 0 + && b_fs::remove_all(tmp_root.path_cstr()) != 0) { ret = true; } } catch (...) { @@ -400,10 +407,9 @@ UnionfsCstore::teardownSession() bool UnionfsCstore::inSession() { - string wstr = work_root.file_string(); + string wstr = work_root.path_cstr(); return (!wstr.empty() && wstr.find(C_DEF_WORK_PREFIX) == 0 - && path_exists(work_root.file_string().c_str()) - && path_is_directory(work_root.file_string().c_str())); + && path_exists(work_root) && path_is_directory(work_root)); } @@ -414,11 +420,11 @@ UnionfsCstore::inSession() bool UnionfsCstore::tmpl_node_exists() { - return (path_exists(tmpl_path.file_string().c_str()) - && path_is_directory(tmpl_path.file_string().c_str())); + return (path_exists(tmpl_path) && path_is_directory(tmpl_path)); } -typedef Cstore::MapT<string, tr1::shared_ptr<vtw_def> > ParsedTmplCacheT; +typedef Cstore::MapT<FsPath, tr1::shared_ptr<vtw_def>, FsPathHash> + ParsedTmplCacheT; static ParsedTmplCacheT _parsed_tmpl_cache; /* parse template at current tmpl_path and return an allocated Ctemplate @@ -427,14 +433,14 @@ static ParsedTmplCacheT _parsed_tmpl_cache; Ctemplate * UnionfsCstore::tmpl_parse() { - b_fs::path tp = tmpl_path / C_DEF_NAME; - if (!path_exists(tp.file_string().c_str()) - || !path_is_regular(tp.file_string().c_str())) { + FsPath tp = tmpl_path; + tp.push(C_DEF_NAME); + if (!path_exists(tp) || !path_is_regular(tp)) { // invalid return 0; } - ParsedTmplCacheT::iterator p = _parsed_tmpl_cache.find(tp.file_string()); + ParsedTmplCacheT::iterator p = _parsed_tmpl_cache.find(tp); if (p != _parsed_tmpl_cache.end()) { // found in cache return (new Ctemplate(p->second)); @@ -443,9 +449,9 @@ UnionfsCstore::tmpl_parse() // new template => parse tr1::shared_ptr<vtw_def> def(new vtw_def); vtw_def *_def = def.get(); - if (_def && parse_def(_def, tp.file_string().c_str(), 0) == 0) { + if (_def && parse_def(_def, tp.path_cstr(), 0) == 0) { // succes => cache and return - _parsed_tmpl_cache[tp.file_string()] = def; + _parsed_tmpl_cache[tp] = def; return (new Ctemplate(def)); } return 0; @@ -454,9 +460,8 @@ UnionfsCstore::tmpl_parse() bool UnionfsCstore::cfg_node_exists(bool active_cfg) { - b_fs::path p = (active_cfg ? get_active_path() : get_work_path()); - return (path_exists(p.file_string().c_str()) - && path_is_directory(p.file_string().c_str())); + FsPath p = (active_cfg ? get_active_path() : get_work_path()); + return (path_exists(p) && path_is_directory(p)); } bool @@ -464,7 +469,7 @@ UnionfsCstore::add_node() { bool ret = true; try { - if (!b_fs::create_directory(get_work_path())) { + if (!b_fs::create_directory(get_work_path().path_cstr())) { // already exists. shouldn't call this function. ret = false; } @@ -473,7 +478,7 @@ UnionfsCstore::add_node() } if (!ret) { output_internal("failed to add node [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); } return ret; } @@ -481,15 +486,15 @@ UnionfsCstore::add_node() bool UnionfsCstore::remove_node() { - if (!path_exists(get_work_path().file_string().c_str()) - || !path_is_directory(get_work_path().file_string().c_str())) { + if (!path_exists(get_work_path()) + || !path_is_directory(get_work_path())) { output_internal("remove non-existent node [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } bool ret = false; try { - if (b_fs::remove_all(get_work_path()) != 0) { + if (b_fs::remove_all(get_work_path().path_cstr()) != 0) { ret = true; } } catch (...) { @@ -497,7 +502,7 @@ UnionfsCstore::remove_node() } if (!ret) { output_internal("failed to remove node [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); } return ret; } @@ -506,7 +511,7 @@ void UnionfsCstore::get_all_child_node_names_impl(vector<string>& cnodes, bool active_cfg) { - b_fs::path p = (active_cfg ? get_active_path() : get_work_path()); + FsPath p = (active_cfg ? get_active_path() : get_work_path()); get_all_child_dir_names(p, cnodes); /* XXX special cases to emulate original perl API behavior. @@ -530,8 +535,8 @@ UnionfsCstore::get_all_child_node_names_impl(vector<string>& cnodes, bool UnionfsCstore::read_value_vec(vector<string>& vvec, bool active_cfg) { - b_fs::path vpath = (active_cfg ? get_active_path() : get_work_path()); - vpath /= C_VAL_NAME; + FsPath vpath = (active_cfg ? get_active_path() : get_work_path()); + vpath.push(C_VAL_NAME); string ostr; if (!read_whole_file(vpath, ostr)) { @@ -564,14 +569,13 @@ UnionfsCstore::read_value_vec(vector<string>& vvec, bool active_cfg) bool UnionfsCstore::write_value_vec(const vector<string>& vvec, bool active_cfg) { - b_fs::path wp = (active_cfg ? get_active_path() : get_work_path()); - wp /= C_VAL_NAME; + FsPath wp = (active_cfg ? get_active_path() : get_work_path()); + wp.push(C_VAL_NAME); - if (path_exists(wp.file_string().c_str()) - && !path_is_regular(wp.file_string().c_str())) { + if (path_exists(wp) && !path_is_regular(wp)) { // not a file output_internal("failed to write node value (file) [%s]\n", - wp.file_string().c_str()); + wp.path_cstr()); return false; } @@ -584,9 +588,9 @@ UnionfsCstore::write_value_vec(const vector<string>& vvec, bool active_cfg) ostr += vvec[i]; } - if (!write_file(wp.file_string().c_str(), ostr)) { + if (!write_file(wp, ostr)) { output_internal("failed to write node value (write) [%s]\n", - wp.file_string().c_str()); + wp.path_cstr()); return false; } @@ -594,16 +598,16 @@ UnionfsCstore::write_value_vec(const vector<string>& vvec, bool active_cfg) } bool -UnionfsCstore::rename_child_node(const string& oname, const string& nname) +UnionfsCstore::rename_child_node(const char *oname, const char *nname) { - b_fs::path opath = get_work_path() / oname; - b_fs::path npath = get_work_path() / nname; - if (!path_exists(opath.file_string().c_str()) - || !path_is_directory(opath.file_string().c_str()) - || path_exists(npath.file_string().c_str())) { + FsPath opath = get_work_path(); + opath.push(oname); + FsPath npath = get_work_path(); + npath.push(nname); + if (!path_exists(opath) || !path_is_directory(opath) + || path_exists(npath)) { output_internal("cannot rename node [%s,%s,%s]\n", - get_work_path().file_string().c_str(), - oname.c_str(), nname.c_str()); + get_work_path().path_cstr(), oname, nname); return false; } bool ret = true; @@ -614,39 +618,37 @@ UnionfsCstore::rename_child_node(const string& oname, const string& nname) * do it the hard way. */ recursive_copy_dir(opath, npath); - if (b_fs::remove_all(opath) == 0) { + if (b_fs::remove_all(opath.path_cstr()) == 0) { ret = false; } } catch (...) { ret = false; } if (!ret) { - output_internal("failed to rename node [%s,%s]\n", - opath.file_string().c_str(), - npath.file_string().c_str()); + output_internal("failed to rename node [%s,%s]\n", opath.path_cstr(), + npath.path_cstr()); } return ret; } bool -UnionfsCstore::copy_child_node(const string& oname, const string& nname) +UnionfsCstore::copy_child_node(const char *oname, const char *nname) { - b_fs::path opath = get_work_path() / oname; - b_fs::path npath = get_work_path() / nname; - if (!path_exists(opath.file_string().c_str()) - || !path_is_directory(opath.file_string().c_str()) - || path_exists(npath.file_string().c_str())) { + FsPath opath = get_work_path(); + opath.push(oname); + FsPath npath = get_work_path(); + npath.push(nname); + if (!path_exists(opath) || !path_is_directory(opath) + || path_exists(npath)) { output_internal("cannot copy node [%s,%s,%s]\n", - get_work_path().file_string().c_str(), - oname.c_str(), nname.c_str()); + get_work_path().path_cstr(), oname, nname); return false; } try { recursive_copy_dir(opath, npath); } catch (...) { output_internal("failed to copy node [%s,%s,%s]\n", - get_work_path().file_string().c_str(), - oname.c_str(), nname.c_str()); + get_work_path().path_cstr(), oname, nname); return false; } return true; @@ -655,14 +657,15 @@ UnionfsCstore::copy_child_node(const string& oname, const string& nname) bool UnionfsCstore::mark_display_default() { - b_fs::path marker = get_work_path() / C_MARKER_DEF_VALUE; - if (path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEF_VALUE); + if (path_exists(marker)) { // already marked. treat as success. return true; } - if (!create_file(marker.file_string())) { + if (!create_file(marker)) { output_internal("failed to mark default [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -671,16 +674,17 @@ UnionfsCstore::mark_display_default() bool UnionfsCstore::unmark_display_default() { - b_fs::path marker = get_work_path() / C_MARKER_DEF_VALUE; - if (!path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEF_VALUE); + if (!path_exists(marker)) { // not marked. treat as success. return true; } try { - b_fs::remove(marker); + b_fs::remove(marker.path_cstr()); } catch (...) { output_internal("failed to unmark default [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -689,30 +693,31 @@ UnionfsCstore::unmark_display_default() bool UnionfsCstore::marked_display_default(bool active_cfg) { - b_fs::path marker = (active_cfg ? get_active_path() : get_work_path()) - / C_MARKER_DEF_VALUE; - return path_exists(marker.file_string().c_str()); + FsPath marker = (active_cfg ? get_active_path() : get_work_path()); + marker.push(C_MARKER_DEF_VALUE); + return path_exists(marker); } bool UnionfsCstore::marked_deactivated(bool active_cfg) { - b_fs::path p = (active_cfg ? get_active_path() : get_work_path()); - b_fs::path marker = p / C_MARKER_DEACTIVATE; - return path_exists(marker.file_string().c_str()); + FsPath marker = (active_cfg ? get_active_path() : get_work_path()); + marker.push(C_MARKER_DEACTIVATE); + return path_exists(marker); } bool UnionfsCstore::mark_deactivated() { - b_fs::path marker = get_work_path() / C_MARKER_DEACTIVATE; - if (path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEACTIVATE); + if (path_exists(marker)) { // already marked. treat as success. return true; } - if (!create_file(marker.file_string())) { + if (!create_file(marker)) { output_internal("failed to mark deactivated [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -721,16 +726,17 @@ UnionfsCstore::mark_deactivated() bool UnionfsCstore::unmark_deactivated() { - b_fs::path marker = get_work_path() / C_MARKER_DEACTIVATE; - if (!path_exists(marker.file_string().c_str())) { + FsPath marker = get_work_path(); + marker.push(C_MARKER_DEACTIVATE); + if (!path_exists(marker)) { // not deactivated. treat as success. return true; } try { - b_fs::remove(marker); + b_fs::remove(marker.path_cstr()); } catch (...) { output_internal("failed to unmark deactivated [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -742,20 +748,21 @@ UnionfsCstore::unmark_deactivated_descendants() bool ret = false; do { // sanity check - if (!path_is_directory(get_work_path().file_string().c_str())) { + if (!path_is_directory(get_work_path())) { break; } try { vector<b_fs::path> markers; - b_fs::recursive_directory_iterator di(get_work_path()); + b_fs::recursive_directory_iterator di(get_work_path().path_cstr()); for (; di != b_fs::recursive_directory_iterator(); ++di) { if (!path_is_regular(di->path().file_string().c_str()) || di->path().filename() != C_MARKER_DEACTIVATE) { // not marker continue; } - if (di->path().parent_path() == get_work_path()) { + const char *ppath = di->path().parent_path().file_string().c_str(); + if (strcmp(ppath, get_work_path().path_cstr()) == 0) { // don't unmark the node itself continue; } @@ -771,7 +778,7 @@ UnionfsCstore::unmark_deactivated_descendants() } while (0); if (!ret) { output_internal("failed to unmark deactivated descendants [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); } return ret; } @@ -780,29 +787,27 @@ UnionfsCstore::unmark_deactivated_descendants() bool UnionfsCstore::mark_changed_with_ancestors() { - b_fs::path opath = mutable_cfg_path; // use a copy + FsPath opath = mutable_cfg_path; // use a copy bool done = false; while (!done) { - b_fs::path marker = work_root; + FsPath marker = work_root; if (opath.has_parent_path()) { marker /= opath; pop_path(opath); } else { done = true; } - if (!path_exists(marker.file_string().c_str()) - || !path_is_directory(marker.file_string().c_str())) { + if (!path_exists(marker) || !path_is_directory(marker)) { // don't do anything if the node is not there continue; } - marker /= C_MARKER_CHANGED; - if (path_exists(marker.file_string().c_str())) { + marker.push(C_MARKER_CHANGED); + if (path_exists(marker)) { // reached a node already marked => done break; } - if (!create_file(marker.file_string())) { - output_internal("failed to mark changed [%s]\n", - marker.file_string().c_str()); + if (!create_file(marker)) { + output_internal("failed to mark changed [%s]\n", marker.path_cstr()); return false; } } @@ -817,7 +822,7 @@ UnionfsCstore::unmark_changed_with_descendants() { try { vector<b_fs::path> markers; - b_fs::recursive_directory_iterator di(get_work_path()); + b_fs::recursive_directory_iterator di(get_work_path().path_cstr()); for (; di != b_fs::recursive_directory_iterator(); ++di) { if (!path_is_regular(di->path().file_string().c_str()) || di->path().filename() != C_MARKER_CHANGED) { @@ -831,7 +836,7 @@ UnionfsCstore::unmark_changed_with_descendants() } } catch (...) { output_internal("failed to unmark changed with descendants [%s]\n", - get_work_path().file_string().c_str()); + get_work_path().path_cstr()); return false; } return true; @@ -841,15 +846,15 @@ UnionfsCstore::unmark_changed_with_descendants() bool UnionfsCstore::remove_comment() { - b_fs::path cfile = get_work_path() / C_COMMENT_FILE; - if (!path_exists(cfile.file_string().c_str())) { + FsPath cfile = get_work_path(); + cfile.push(C_COMMENT_FILE); + if (!path_exists(cfile)) { return false; } try { - b_fs::remove(cfile); + b_fs::remove(cfile.path_cstr()); } catch (...) { - output_internal("failed to remove comment [%s]\n", - cfile.file_string().c_str()); + output_internal("failed to remove comment [%s]\n", cfile.path_cstr()); return false; } return true; @@ -859,8 +864,9 @@ UnionfsCstore::remove_comment() bool UnionfsCstore::set_comment(const string& comment) { - b_fs::path cfile = get_work_path() / C_COMMENT_FILE; - return write_file(cfile.file_string(), comment); + FsPath cfile = get_work_path(); + cfile.push(C_COMMENT_FILE); + return write_file(cfile, comment); } // discard all changes in working config @@ -875,7 +881,7 @@ UnionfsCstore::discard_changes(unsigned long long& num_removed) vector<b_fs::path> directories; try { // iterate through all entries in change root - b_fs::directory_iterator di(change_root); + b_fs::directory_iterator di(change_root.path_cstr()); for (; di != b_fs::directory_iterator(); ++di) { if (path_is_directory(di->path().file_string().c_str())) { directories.push_back(di->path()); @@ -894,8 +900,7 @@ UnionfsCstore::discard_changes(unsigned long long& num_removed) num_removed += b_fs::remove_all(directories[i]); } } catch (...) { - output_internal("discard failed [%s]\n", - change_root.file_string().c_str()); + output_internal("discard failed [%s]\n", change_root.path_cstr()); ret = false; } @@ -911,8 +916,8 @@ UnionfsCstore::discard_changes(unsigned long long& num_removed) bool UnionfsCstore::get_comment(string& comment, bool active_cfg) { - b_fs::path cfile = (active_cfg ? get_active_path() : get_work_path()); - cfile /= C_COMMENT_FILE; + FsPath cfile = (active_cfg ? get_active_path() : get_work_path()); + cfile.push(C_COMMENT_FILE); return read_whole_file(cfile, comment); } @@ -920,8 +925,9 @@ UnionfsCstore::get_comment(string& comment, bool active_cfg) bool UnionfsCstore::cfg_node_changed() { - b_fs::path marker = get_work_path() / C_MARKER_CHANGED; - return path_exists(marker.file_string().c_str()); + FsPath marker = get_work_path(); + marker.push(C_MARKER_CHANGED); + return path_exists(marker); } /* XXX currently "committed marking" is done inside commit. @@ -934,14 +940,17 @@ UnionfsCstore::cfg_node_changed() * be only one operation on the path). */ bool -UnionfsCstore::marked_committed(const Ctemplate *def, bool is_set) +UnionfsCstore::marked_committed(const tr1::shared_ptr<Ctemplate>& def, + bool is_set) { - b_fs::path cpath = mutable_cfg_path; - string com_str = cpath.file_string() + "/"; + FsPath cpath = mutable_cfg_path; + string com_str = cpath.path_cstr(); + com_str += "/"; if (def->isLeafValue()) { // path includes leaf value. construct the right string. - string val = _unescape_path_name(cpath.filename()); - cpath = cpath.parent_path(); + string val; + cpath.pop(val); + val = _unescape_path_name(val); /* XXX current commit implementation escapes value strings for * single-value nodes but not for multi-value nodes for some * reason. the following match current behavior. @@ -949,14 +958,17 @@ UnionfsCstore::marked_committed(const Ctemplate *def, bool is_set) if (!def->isMulti()) { val = _escape_path_name(val); } - com_str = cpath.file_string() + "/value:" + val; + com_str = cpath.path_cstr(); + com_str += "/value:"; + com_str += val; } com_str = (is_set ? "+ " : "- ") + com_str; return committed_marker_exists(com_str); } bool -UnionfsCstore::validate_val_impl(const Ctemplate *def, char *value) +UnionfsCstore::validate_val_impl(const tr1::shared_ptr<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. @@ -971,16 +983,23 @@ UnionfsCstore::validate_val_impl(const Ctemplate *def, char *value) } void -UnionfsCstore::get_edit_level(vector<string>& pcomps) { - b_fs::path opath = mutable_cfg_path; // use a copy +UnionfsCstore::get_edit_level(Cpath& pcomps) { + FsPath opath = mutable_cfg_path; // use a copy + vector<string> tmp; while (opath.has_parent_path()) { - pcomps.insert(pcomps.begin(), pop_path(opath)); + string last; + pop_path(opath, last); + tmp.push_back(last); + } + while (tmp.size() > 0) { + pcomps.push(tmp.back()); + tmp.pop_back(); } } string UnionfsCstore::cfg_path_to_str() { - string cpath = mutable_cfg_path.file_string(); + string cpath = mutable_cfg_path.path_cstr(); if (cpath.length() == 0) { cpath = "/"; } @@ -990,8 +1009,8 @@ UnionfsCstore::cfg_path_to_str() { string UnionfsCstore::tmpl_path_to_str() { // return only the mutable part - string tpath = tmpl_path.file_string(); - tpath.erase(0, tmpl_root.file_string().length()); + string tpath = tmpl_path.path_cstr(); + tpath.erase(0, tmpl_root.length()); if (tpath.length() == 0) { tpath = "/"; } @@ -1001,33 +1020,35 @@ UnionfsCstore::tmpl_path_to_str() { ////// private functions void -UnionfsCstore::push_path(b_fs::path& old_path, const string& new_comp) +UnionfsCstore::push_path(FsPath& old_path, const char *new_comp) { string comp = _escape_path_name(new_comp); - old_path /= comp; + old_path.push(comp); } -string -UnionfsCstore::pop_path(b_fs::path& path) +void +UnionfsCstore::pop_path(FsPath& path) { - string ret = _unescape_path_name(path.filename()); - /* note: contrary to documentation, remove_filename() does not remove - * trailing slash. - */ - path = path.parent_path(); - return ret; + path.pop(); } void -UnionfsCstore::get_all_child_dir_names(b_fs::path root, vector<string>& nodes) +UnionfsCstore::pop_path(FsPath& path, string& last) { - if (!path_exists(root.file_string().c_str()) - || !path_is_directory(root.file_string().c_str())) { + path.pop(last); + last = _unescape_path_name(last); +} + +void +UnionfsCstore::get_all_child_dir_names(const FsPath& root, + vector<string>& nodes) +{ + if (!path_exists(root) || !path_is_directory(root)) { // not a valid root. nop. return; } try { - b_fs::directory_iterator di(root); + b_fs::directory_iterator di(root.path_cstr()); for (; di != b_fs::directory_iterator(); ++di) { // must be directory if (!path_is_directory(di->path().file_string().c_str())) { @@ -1047,7 +1068,7 @@ UnionfsCstore::get_all_child_dir_names(b_fs::path root, vector<string>& nodes) } bool -UnionfsCstore::write_file(const string& file, const string& data) +UnionfsCstore::write_file(const FsPath& file, const string& data) { if (data.size() > C_UNIONFS_MAX_FILE_SIZE) { output_internal("write_file too large\n"); @@ -1055,13 +1076,14 @@ UnionfsCstore::write_file(const string& file, const string& data) } try { // make sure the path exists - b_fs::path fpath(file); - b_fs::create_directories(fpath.parent_path()); + FsPath ppath(file); + ppath.pop(); + b_fs::create_directories(ppath.path_cstr()); // write the file ofstream fout; fout.exceptions(ofstream::failbit | ofstream::badbit); - fout.open(file.c_str(), ios_base::out | ios_base::trunc); + fout.open(file.path_cstr(), ios_base::out | ios_base::trunc); fout << data; fout.close(); } catch (...) { @@ -1071,23 +1093,22 @@ UnionfsCstore::write_file(const string& file, const string& data) } bool -UnionfsCstore::read_whole_file(const b_fs::path& fpath, string& data) +UnionfsCstore::read_whole_file(const FsPath& fpath, string& data) { /* must exist, be a regular file, and smaller than limit (we're going * to read the whole thing). */ - if (!path_exists(fpath.file_string().c_str()) - || !path_is_regular(fpath.file_string().c_str())) { + if (!path_exists(fpath) || !path_is_regular(fpath)) { return false; } try { - if (b_fs::file_size(fpath) > C_UNIONFS_MAX_FILE_SIZE) { + if (b_fs::file_size(fpath.path_cstr()) > C_UNIONFS_MAX_FILE_SIZE) { output_internal("read_whole_file too large\n"); return false; } stringbuf sbuf; - ifstream fin(fpath.file_string().c_str()); + ifstream fin(fpath.path_cstr()); fin >> &sbuf; fin.close(); /* note: if file contains just a newline => (eof() && fail()) @@ -1132,22 +1153,21 @@ UnionfsCstore::committed_marker_exists(const string& marker) * will throw exception (from b_fs) if fail. */ void -UnionfsCstore::recursive_copy_dir(const b_fs::path& src, const b_fs::path& dst) +UnionfsCstore::recursive_copy_dir(const FsPath& src, const FsPath& dst) { - string src_str = src.file_string(); - string dst_str = dst.file_string(); - b_fs::create_directory(dst); + string src_str = src.path_cstr(); + string dst_str = dst.path_cstr(); + b_fs::create_directory(dst.path_cstr()); - b_fs::recursive_directory_iterator di(src); + b_fs::recursive_directory_iterator di(src_str); for (; di != b_fs::recursive_directory_iterator(); ++di) { - b_fs::path opath = di->path(); - string nname = opath.file_string(); + const char *oname = di->path().file_string().c_str(); + string nname = oname; nname.replace(0, src_str.length(), dst_str); - b_fs::path npath = nname; - if (path_is_directory(opath.file_string().c_str())) { - b_fs::create_directory(npath); + if (path_is_directory(oname)) { + b_fs::create_directory(nname); } else { - b_fs::copy_file(opath, npath); + b_fs::copy_file(oname, nname); } } } @@ -1182,3 +1202,6 @@ UnionfsCstore::path_is_regular(const char *path) return b_fs::is_regular(result); } +} // end namespace unionfs +} // end namespace cstore + diff --git a/src/cstore/unionfs/cstore-unionfs.hpp b/src/cstore/unionfs/cstore-unionfs.hpp index 53c6396..afb65a6 100644 --- a/src/cstore/unionfs/cstore-unionfs.hpp +++ b/src/cstore/unionfs/cstore-unionfs.hpp @@ -28,8 +28,10 @@ #include <cli_cstore.h> #include <cstore/cstore.hpp> +#include <cstore/unionfs/fspath.hpp> namespace cstore { // begin namespace cstore +namespace unionfs { // begin namespace unionfs namespace b_fs = boost::filesystem; namespace b_s = boost::system; @@ -80,21 +82,19 @@ private: static const size_t C_UNIONFS_MAX_FILE_SIZE = 262144; // root dirs (constant) - b_fs::path work_root; // working root (union) - b_fs::path active_root; // active root (readonly part of union) - b_fs::path change_root; // change root (r/w part of union) - b_fs::path tmp_root; // temp root - b_fs::path tmpl_root; // template root + FsPath work_root; // working root (union) + FsPath active_root; // active root (readonly part of union) + FsPath change_root; // change root (r/w part of union) + FsPath tmp_root; // temp root + FsPath tmpl_root; // template root // path buffers - b_fs::path mutable_cfg_path; // mutable part of config path - b_fs::path tmpl_path; // whole template path - Cstore::MapT<const void *, pair<b_fs::path, b_fs::path> > saved_paths; - // saved mutable part of cfg path and whole template path + FsPath mutable_cfg_path; // mutable part of config path + FsPath tmpl_path; // whole template path ////// virtual functions defined in base class // begin path modifiers - void push_tmpl_path(const string& new_comp) { + void push_tmpl_path(const char *new_comp) { push_path(tmpl_path, new_comp); }; void push_tmpl_path_tag() { @@ -105,18 +105,24 @@ private: * however, since current C_TAG_NAME doesn't contain any escape * sequences, this cannot happen for now. */ - tmpl_path /= C_TAG_NAME; + tmpl_path.push(C_TAG_NAME); }; - string pop_tmpl_path() { - return pop_path(tmpl_path); + void pop_tmpl_path() { + pop_path(tmpl_path); }; - void push_cfg_path(const string& new_comp) { + void pop_tmpl_path(string& last) { + pop_path(tmpl_path, last); + }; + void push_cfg_path(const char *new_comp) { push_path(mutable_cfg_path, new_comp); }; - string pop_cfg_path() { - return pop_path(mutable_cfg_path); + void pop_cfg_path() { + pop_path(mutable_cfg_path); + }; + void pop_cfg_path(string& last) { + pop_path(mutable_cfg_path, last); }; - void append_cfg_path(const vector<string>& path_comps) { + void append_cfg_path(const Cpath& path_comps) { for (size_t i = 0; i < path_comps.size(); i++) { push_cfg_path(path_comps[i]); } @@ -125,27 +131,31 @@ private: tmpl_path = tmpl_root; mutable_cfg_path = ""; }; - void save_paths(const void *handle = NULL) { - pair<b_fs::path, b_fs::path> p; - p.first = mutable_cfg_path; - p.second = tmpl_path; - saved_paths[handle] = p; - }; - void restore_paths(const void *handle = NULL) { - Cstore::MapT<const void *, pair<b_fs::path, b_fs::path> >::iterator it - = saved_paths.find(handle); - if (it == saved_paths.end()) { - exit_internal("restore_paths: handle not found\n"); - } - pair<b_fs::path, b_fs::path> p = it->second; - mutable_cfg_path = p.first; - tmpl_path = p.second; + + class UnionfsSavePaths : public SavePaths { + public: + UnionfsSavePaths(UnionfsCstore *cs) + : cstore(cs), cpath(cs->mutable_cfg_path), tpath(cs->tmpl_path) {}; + + ~UnionfsSavePaths() { + cstore->mutable_cfg_path = cpath; + cstore->tmpl_path = tpath; + }; + + private: + UnionfsCstore *cstore; + FsPath cpath; + FsPath tpath; }; + auto_ptr<SavePaths> create_save_paths() { + return auto_ptr<SavePaths>(new UnionfsSavePaths(this)); + }; + bool cfg_path_at_root() { return (!mutable_cfg_path.has_parent_path()); }; bool tmpl_path_at_root() { - return (tmpl_path.file_string() == tmpl_root.file_string()); + return (tmpl_path == tmpl_root); }; // end path modifiers @@ -161,8 +171,8 @@ private: get_all_child_dir_names(tmpl_path, cnodes); }; bool write_value_vec(const vector<string>& vvec, bool active_cfg); - bool rename_child_node(const string& oname, const string& nname); - bool copy_child_node(const string& oname, const string& nname); + bool rename_child_node(const char *oname, const char *nname); + bool copy_child_node(const char *oname, const char *nname); bool mark_display_default(); bool unmark_display_default(); bool mark_deactivated(); @@ -185,10 +195,10 @@ private: bool marked_display_default(bool active_cfg); // observers during commit operation - bool marked_committed(const Ctemplate *def, bool is_set); + bool marked_committed(const tr1::shared_ptr<Ctemplate>& def, bool is_set); // these operate on both current tmpl and work paths - bool validate_val_impl(const Ctemplate *def, char *value); + bool validate_val_impl(const tr1::shared_ptr<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. @@ -198,7 +208,7 @@ private: string get_tmpl_level_path() { return tmpl_path_to_str(); }; - void get_edit_level(vector<string>& path_comps); + void get_edit_level(Cpath& path_comps); bool edit_level_at_root() { return cfg_path_at_root(); }; @@ -208,19 +218,20 @@ private: string tmpl_path_to_str(); ////// private functions - b_fs::path get_work_path() { return (work_root / mutable_cfg_path); }; - b_fs::path get_active_path() { return (active_root / mutable_cfg_path); }; - b_fs::path get_change_path() { return (change_root / mutable_cfg_path); }; - void push_path(b_fs::path& old_path, const string& new_comp); - string pop_path(b_fs::path& path); - void get_all_child_dir_names(b_fs::path root, vector<string>& nodes); - bool write_file(const string& file, const string& data); - bool create_file(const string& file) { + FsPath get_work_path() { return (work_root / mutable_cfg_path); }; + FsPath get_active_path() { return (active_root / mutable_cfg_path); }; + FsPath get_change_path() { return (change_root / mutable_cfg_path); }; + void push_path(FsPath& old_path, const char *new_comp); + void pop_path(FsPath& path); + void pop_path(FsPath& path, string& last); + void get_all_child_dir_names(const FsPath& root, vector<string>& nodes); + bool write_file(const FsPath& file, const string& data); + bool create_file(const FsPath& file) { return write_file(file, ""); }; - bool read_whole_file(const b_fs::path& file, string& data); + bool read_whole_file(const FsPath& file, string& data); bool committed_marker_exists(const string& marker); - void recursive_copy_dir(const b_fs::path& src, const b_fs::path& dst); + void recursive_copy_dir(const FsPath& src, const FsPath& dst); // boost fs operations wrappers bool b_fs_get_file_status(const char *path, b_fs::file_status& fs) { @@ -229,10 +240,20 @@ private: return (!ec); }; bool path_exists(const char *path); + bool path_exists(const FsPath& path) { + return path_exists(path.path_cstr()); + }; bool path_is_directory(const char *path); + bool path_is_directory(const FsPath& path) { + return path_is_directory(path.path_cstr()); + }; bool path_is_regular(const char *path); + bool path_is_regular(const FsPath& path) { + return path_is_regular(path.path_cstr()); + }; }; +} // end namespace unionfs } // end namespace cstore #endif /* _CSTORE_UNIONFS_H_ */ diff --git a/src/cstore/unionfs/fspath.hpp b/src/cstore/unionfs/fspath.hpp new file mode 100644 index 0000000..35985ed --- /dev/null +++ b/src/cstore/unionfs/fspath.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 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 _FSPATH_HPP_ +#define _FSPATH_HPP_ +#include <string> + +#include <cstore/svector.hpp> + +namespace cstore { // begin namespace cstore +namespace unionfs { // begin namespace unionfs + +class FsPath { +public: + FsPath() : _data() {}; + explicit FsPath(const char *full_path) : _data() { operator=(full_path); }; + explicit FsPath(const std::string& full_path) : _data() { + operator=(full_path); + }; + FsPath(const FsPath& p) : _data() { operator=(p); }; + ~FsPath() {}; + + void push(const char *comp) { _data.push_back(comp); }; + void push(const std::string& comp) { _data.push_back(comp.c_str()); }; + void pop() { _data.pop_back(); }; + void pop(std::string& last) { _data.pop_back(last); }; + + FsPath& operator=(const char *full_path) { + _data = full_path; + return *this; + }; + FsPath& operator=(const std::string& full_path) { + _data = full_path; + return *this; + }; + FsPath& operator=(const FsPath& p) { + _data = p._data; + return *this; + }; + FsPath& operator/=(const FsPath& p) { + _data /= p._data; + return *this; + } + FsPath operator/(const FsPath& rhs) { + FsPath lhs(*this); + lhs /= rhs; + return lhs; + }; + + bool operator==(const FsPath& rhs) const { + return (_data == rhs._data); + }; + + size_t length() const { return _data.length(); }; + bool has_parent_path() const { return (_data.size() > 0); }; + const char *path_cstr() const { return _data.get_cstr(); }; + size_t hash() const { return _data.hash(); }; + +private: + struct FsPathParams { + static const char separator = '/'; + static const size_t static_num_elems = 24; + static const size_t static_buf_len = 256; + }; + + cstore::svector<FsPathParams> _data; +}; + +struct FsPathHash { + inline size_t operator()(const FsPath& p) const { + return p.hash(); + }; +}; + +} // end namespace unionfs +} // end namespace cstore + +#endif /* _FSPATH_HPP_ */ + |