diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ebbe998..11ffa9b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,18 +96,18 @@ Developers may need to change their code * `clixon_cli2file()` - Print internal tree as CLI format to file * `clixon_txt2file()` - Print internal tree as text format to file * As developer, you need to replace the old functions to the new API as follows: - * `clicon_xml2file(f, x, l, p)` -> `clixon_xml2file(f, x, l, p, NULL, 0)` - * `clicon_xml2file_cb(f, x, l, p, fn)` -> `clixon_xml2file(f, x, l, p, fn, 0)` - * `cli_xml2file(x, l, p, fn)` -> `clixon_xml2file(stdout, x, l, p, fn, 0)` + * `clicon_xml2file(f, x, l, p)` -> `clixon_xml2file(f, x, l, p, NULL, 0, 0)` + * `clicon_xml2file_cb(f, x, l, p, fn)` -> `clixon_xml2file(f, x, l, p, fn, 0, 0)` + * `cli_xml2file(x, l, p, fn)` -> `clixon_xml2file(stdout, x, l, p, fn, 0, 0)` * `clicon_xml2cbuf(c, x, l, p, d)` -> `clixon_xml2cbuf(c, x, l, p, d, 0)` * `clicon_xml2str(x)` -> Rewrite using cbufs and `clixon_xml2cbuf()` - * `xml2json(f, x, p)` -> `clixon_json2file(f, x, p, NULL, 0)` - * `xml2json_cb(f, x, p, fn)` -> `clixon_json2file(f, x, p, fn, 0)` - * `xml2json_cbuf(c, x, p)` -> `clixon_json2cbuf(c, x, p, 0)` + * `xml2json(f, x, p)` -> `clixon_json2file(f, x, p, NULL, 0, 0)` + * `xml2json_cb(f, x, p, fn)` -> `clixon_json2file(f, x, p, fn, 0, 0)` + * `xml2json_cbuf(c, x, p)` -> `clixon_json2cbuf(c, x, p, 0, 0)` * `xml2cli(h, f, x, p, fn)` -> `clixon_cli2file(h, f, x, p, fn, 0)` - * `cli_xml2txt(x, fn, l)` -> `clixon_txt2file(stdout, x, l, NULL, 0)` - * `xml2txt(f, x, l)` -> `clixon_txt2file(f, x, l, NULL, 0)` - * `xml2txt_cb(f, x, fn)` -> `clixon_txt2file(f, x, 0, NULL, 0)` + * `cli_xml2txt(x, fn, l)` -> `clixon_txt2file(stdout, x, l, NULL, 0, 0)` + * `xml2txt(f, x, l)` -> `clixon_txt2file(f, x, l, NULL, 0, 0)` + * `xml2txt_cb(f, x, fn)` -> `clixon_txt2file(f, x, 0, NULL, 0, 0)` ### Minor features @@ -122,6 +122,7 @@ Developers may need to change their code ### Corrected Bugs +* Fixed: ["autocli:hide-show" extension cause bug in xmldb_put method #343](https://github.com/clicon/clixon/issues/343) * Fixed: [Schema Ambiguity Error with openconfig-system re: NTP](https://github.com/clicon/clixon/issues/334) * Fixed: [YANG mandatory statements within case nodes do not work](https://github.com/clicon/clixon/issues/344) * Fixed: [Nested YANG choice does not work](https://github.com/clicon/clixon/issues/342) diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index c0d14d68..8f771bd8 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -452,17 +452,17 @@ cli_auto_show(clicon_handle h, /* Print configuration according to format */ switch (format){ case FORMAT_XML: - if (clixon_xml2file(stdout, xp, 0, pretty, cligen_output, skiproot) < 0) + if (clixon_xml2file(stdout, xp, 0, pretty, cligen_output, skiproot, 1) < 0) goto done; fprintf(stdout, "\n"); break; case FORMAT_JSON: - if (clixon_json2file(stdout, xp, pretty, cligen_output, skiproot) < 0) + if (clixon_json2file(stdout, xp, pretty, cligen_output, skiproot, 1) < 0) goto done; fprintf(stdout, "\n"); break; case FORMAT_TEXT: - if (clixon_txt2file(stdout, xp, 0, cligen_output, skiproot) < 0) + if (clixon_txt2file(stdout, xp, 0, cligen_output, skiproot, 1) < 0) goto done; break; case FORMAT_CLI: @@ -474,7 +474,7 @@ cli_auto_show(clicon_handle h, NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR); if (pretty) fprintf(stdout, "\n"); - if (clixon_xml2file(stdout, xp, 2, pretty, cligen_output, skiproot) < 0) + if (clixon_xml2file(stdout, xp, 2, pretty, cligen_output, skiproot, 1) < 0) goto done; fprintf(stdout, "]]>]]>\n"); break; diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 430868cc..cb34e4f8 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -696,12 +696,12 @@ compare_xmls(cxobj *xc1, goto done; switch(format){ case FORMAT_TEXT: - if (clixon_txt2file(f, xc1, 0, cligen_output, 1) < 0) + if (clixon_txt2file(f, xc1, 0, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_XML: default: - if (clixon_xml2file(f, xc1, 0, 1, cligen_output, 1) < 0) + if (clixon_xml2file(f, xc1, 0, 1, cligen_output, 1, 1) < 0) goto done; break; } @@ -717,12 +717,12 @@ compare_xmls(cxobj *xc1, switch(format){ case FORMAT_TEXT: - if (clixon_txt2file(f, xc2, 0, cligen_output, 1) < 0) + if (clixon_txt2file(f, xc2, 0, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_XML: default: - if (clixon_xml2file(f, xc2, 0, 1, cligen_output, 1) < 0) + if (clixon_xml2file(f, xc2, 0, 1, cligen_output, 1, 1) < 0) goto done; break; } @@ -1048,15 +1048,15 @@ save_config_file(clicon_handle h, } switch (format){ case FORMAT_XML: - if (clixon_xml2file(f, xt, 0, pretty, fprintf, 0) < 0) + if (clixon_xml2file(f, xt, 0, pretty, fprintf, 0, 1) < 0) goto done; break; case FORMAT_JSON: - if (clixon_json2file(f, xt, pretty, fprintf, 0) < 0) + if (clixon_json2file(f, xt, pretty, fprintf, 0, 1) < 0) goto done; break; case FORMAT_TEXT: - if (clixon_txt2file(f, xt, 0, fprintf, 0) < 0) + if (clixon_txt2file(f, xt, 0, fprintf, 0, 1) < 0) goto done; break; case FORMAT_CLI: @@ -1067,7 +1067,7 @@ save_config_file(clicon_handle h, fprintf(f, "", NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR); fprintf(f, "\n"); - if (clixon_xml2file(f, xt, 0, pretty, fprintf, 0) < 0) + if (clixon_xml2file(f, xt, 0, pretty, fprintf, 0, 1) < 0) goto done; fprintf(f, "]]>]]>\n"); break; @@ -1171,14 +1171,14 @@ cli_notification_cb(int s, } switch (format){ case FORMAT_JSON: - if (clixon_json2file(stdout, xt, 1, cligen_output, 1) < 0) + if (clixon_json2file(stdout, xt, 1, cligen_output, 1, 1) < 0) goto done; case FORMAT_TEXT: - if (clixon_txt2file(stdout, xt, 0, cligen_output, 1) < 0) + if (clixon_txt2file(stdout, xt, 0, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_XML: - if (clixon_xml2file(stdout, xt, 0, 1, cligen_output, 1) < 0) + if (clixon_xml2file(stdout, xt, 0, 1, cligen_output, 1, 1) < 0) goto done; break; default: diff --git a/apps/cli/cli_show.c b/apps/cli/cli_show.c index d9e4b503..8b71ea6d 100644 --- a/apps/cli/cli_show.c +++ b/apps/cli/cli_show.c @@ -494,15 +494,15 @@ cli_show_config1(clicon_handle h, /* Print configuration according to format */ switch (format){ case FORMAT_XML: - if (clixon_xml2file(stdout, xt, 0, 1, cligen_output, 1) < 0) + if (clixon_xml2file(stdout, xt, 0, 1, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_JSON: - if (clixon_json2file(stdout, xt, 1, cligen_output, 0) < 0) + if (clixon_json2file(stdout, xt, 1, cligen_output, 0, 1) < 0) goto done; break; case FORMAT_TEXT: - if (clixon_txt2file(stdout, xt, 0, cligen_output, 1) < 0) + if (clixon_txt2file(stdout, xt, 0, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_CLI: @@ -512,7 +512,7 @@ cli_show_config1(clicon_handle h, case FORMAT_NETCONF: cligen_output(stdout, "\n", NETCONF_BASE_NAMESPACE, NETCONF_MESSAGE_ID_ATTR); - if (clixon_xml2file(stdout, xt, 2, 1, cligen_output, 1) < 0) + if (clixon_xml2file(stdout, xt, 2, 1, cligen_output, 1, 1) < 0) goto done; cligen_output(stdout, "]]>]]>\n"); break; @@ -647,7 +647,7 @@ show_conf_xpath(clicon_handle h, if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0) goto done; for (i=0; i\n"); - if (clixon_xml2file(stdout, xp, 2, 1, fprintf, 0) < 0) + if (clixon_xml2file(stdout, xp, 2, 1, fprintf, 0, 1) < 0) goto done; fprintf(stdout, "]]>]]>\n"); break; case FORMAT_JSON: - if (clixon_json2file(stdout, xp, 1, cligen_output, 1) < 0) // XXX helper? + if (clixon_json2file(stdout, xp, 1, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_TEXT: - if (clixon_txt2file(stdout, xp, 0, cligen_output, 1) < 0) // XXX helper? + if (clixon_txt2file(stdout, xp, 0, cligen_output, 1, 1) < 0) goto done; break; case FORMAT_XML: - if (clixon_xml2file(stdout, xp, 0, 1, fprintf, 0) < 0) // XXX helper? + if (clixon_xml2file(stdout, xp, 0, 1, fprintf, 0, 1) < 0) goto done; break; } @@ -970,15 +970,15 @@ cli_pagination(clicon_handle h, xc = xvec[j]; switch (format){ case FORMAT_XML: - if (clixon_xml2file(stdout, xc, 0, 1, cligen_output, 0) < 0) + if (clixon_xml2file(stdout, xc, 0, 1, cligen_output, 0, 1) < 0) goto done; break; case FORMAT_JSON: - if (clixon_json2file(stdout, xc, 1, cligen_output, 0) < 0) + if (clixon_json2file(stdout, xc, 1, cligen_output, 0, 1) < 0) goto done; break; case FORMAT_TEXT: - if (clixon_txt2file(stdout, xc, 0, cligen_output, 0) < 0) + if (clixon_txt2file(stdout, xc, 0, cligen_output, 0, 1) < 0) goto done; break; case FORMAT_CLI: diff --git a/apps/restconf/restconf_err.c b/apps/restconf/restconf_err.c index c786db89..35c7277b 100644 --- a/apps/restconf/restconf_err.c +++ b/apps/restconf/restconf_err.c @@ -295,14 +295,14 @@ api_return_err(clicon_handle h, clicon_debug(1, "%s code:%d", __FUNCTION__, code); if (pretty){ cprintf(cb, "{\n\"ietf-restconf:errors\" : "); - if (clixon_json2cbuf(cb, xerr, pretty, 0) < 0) + if (clixon_json2cbuf(cb, xerr, pretty, 0, 0) < 0) goto done; cprintf(cb, "\n}\r\n"); } else{ cprintf(cb, "{"); cprintf(cb, "\"ietf-restconf:errors\":"); - if (clixon_json2cbuf(cb, xerr, pretty, 0) < 0) + if (clixon_json2cbuf(cb, xerr, pretty, 0, 0) < 0) goto done; cprintf(cb, "}\r\n"); } diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c index 464fde4d..9161c9e8 100644 --- a/apps/restconf/restconf_methods_get.c +++ b/apps/restconf/restconf_methods_get.c @@ -229,7 +229,7 @@ api_data_get2(clicon_handle h, goto done; break; case YANG_DATA_JSON: - if (clixon_json2cbuf(cbx, xret, pretty, 0) < 0) + if (clixon_json2cbuf(cbx, xret, pretty, 0, 0) < 0) goto done; break; default: diff --git a/apps/restconf/restconf_methods_patch.c b/apps/restconf/restconf_methods_patch.c index 33c39d82..56e9531b 100644 --- a/apps/restconf/restconf_methods_patch.c +++ b/apps/restconf/restconf_methods_patch.c @@ -119,7 +119,7 @@ yang_patch_xml2json_modified_cbuf(cxobj *x_simple_patch) if (json_simple_patch == NULL) return NULL; cb = cbuf_new(); - if (clixon_json2cbuf(cb, x_simple_patch, 0) < 0) + if (clixon_json2cbuf(cb, x_simple_patch, 0, 0) < 0) goto done; // Insert a '[' after the first '{' to get the JSON to match what api_data_post/write() expect @@ -267,7 +267,7 @@ yang_patch_do_replace(clicon_handle h, } } // Convert the data to json - if (clixon_json2cbuf(json_simple_patch, x_simple_patch, 0) < 0) + if (clixon_json2cbuf(json_simple_patch, x_simple_patch, 0, 0) < 0) goto done; // Send the POST request @@ -329,7 +329,7 @@ yang_patch_do_create(clicon_handle h, xml_addsub(x_simple_patch, value_vec_tmp); } } - if (clixon_json2cbuf(cb, x_simple_patch, 0) < 0) + if (clixon_json2cbuf(cb, x_simple_patch, 0, 0) < 0) goto done; if (api_data_post(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, @@ -479,7 +479,7 @@ yang_patch_do_merge(clicon_handle h, xml_addsub(x_simple_patch, value_vec_tmp); } cbuf_reset(cb); /* reuse cb */ - if (clixon_json2cbuf(cb, x_simple_patch, 0) < 0) + if (clixon_json2cbuf(cb, x_simple_patch, 0, 0) < 0) goto done; if ((json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch)) == NULL) diff --git a/apps/restconf/restconf_methods_post.c b/apps/restconf/restconf_methods_post.c index ee4b78f9..69cf7ad9 100644 --- a/apps/restconf/restconf_methods_post.c +++ b/apps/restconf/restconf_methods_post.c @@ -879,7 +879,7 @@ api_operations_post(clicon_handle h, /* xoutput should now look: 0 */ break; case YANG_DATA_JSON: - if (clixon_json2cbuf(cbret, xoutput, pretty, 0) < 0) + if (clixon_json2cbuf(cbret, xoutput, pretty, 0, 0) < 0) goto done; /* xoutput should now look: {"example:output": {"x":0,"y":42}} */ break; diff --git a/apps/restconf/restconf_root.c b/apps/restconf/restconf_root.c index 686981b8..1cb8730f 100644 --- a/apps/restconf/restconf_root.c +++ b/apps/restconf/restconf_root.c @@ -209,7 +209,7 @@ api_root_restconf_exact(clicon_handle h, break; case YANG_DATA_JSON: case YANG_PATCH_JSON: - if (clixon_json2cbuf(cb, xt, pretty, 0) < 0) + if (clixon_json2cbuf(cb, xt, pretty, 0, 0) < 0) goto done; break; default: @@ -293,7 +293,7 @@ api_yang_library_version(clicon_handle h, break; case YANG_DATA_JSON: case YANG_PATCH_JSON: - if (clixon_json2cbuf(cb, xt, pretty, 0) < 0) + if (clixon_json2cbuf(cb, xt, pretty, 0, 0) < 0) goto done; break; default: diff --git a/example/main/example_cli.c b/example/main/example_cli.c index 688a8153..d7dec97d 100644 --- a/example/main/example_cli.c +++ b/example/main/example_cli.c @@ -74,7 +74,7 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv) nsc, &xret) < 0) goto done; - if (clixon_xml2file(stdout, xret, 0, 1, cligen_output, 0) < 0) + if (clixon_xml2file(stdout, xret, 0, 1, cligen_output, 0, 1) < 0) goto done; retval = 0; done: @@ -119,7 +119,7 @@ example_client_rpc(clicon_handle h, goto done; } /* Print result */ - if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 0, cligen_output, 0) < 0) + if (clixon_xml2file(stdout, xml_child_i(xret, 0), 0, 0, cligen_output, 0, 1) < 0) goto done; fprintf(stdout,"\n"); diff --git a/lib/clixon/clixon_json.h b/lib/clixon/clixon_json.h index 31562317..bd8cdfec 100644 --- a/lib/clixon/clixon_json.h +++ b/lib/clixon/clixon_json.h @@ -44,9 +44,9 @@ * Prototypes */ int json2xml_decode(cxobj *x, cxobj **xerr); -int clixon_json2cbuf(cbuf *cb, cxobj *x, int pretty, int skiptop); +int clixon_json2cbuf(cbuf *cb, cxobj *x, int pretty, int skiptop, int autocliext); int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty); -int clixon_json2file(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn, int skiptop); +int clixon_json2file(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn, int skiptop, int autocliext); int json_print(FILE *f, cxobj *x); int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty); int clixon_json_parse_string(char *str, int rfc7951, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xret); diff --git a/lib/clixon/clixon_text_syntax.h b/lib/clixon/clixon_text_syntax.h index 79778e9c..e19d0509 100644 --- a/lib/clixon/clixon_text_syntax.h +++ b/lib/clixon/clixon_text_syntax.h @@ -39,7 +39,7 @@ /* * Prototypes */ -int clixon_txt2file(FILE *f, cxobj *xn, int level, clicon_output_cb *fn, int skiptop); +int clixon_txt2file(FILE *f, cxobj *xn, int level, clicon_output_cb *fn, int skiptop, int autocliext); int clixon_text_syntax_parse_string(char *str, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr); int clixon_text_syntax_parse_file(FILE *fp, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xerr); diff --git a/lib/clixon/clixon_xml_io.h b/lib/clixon/clixon_xml_io.h index f2e3323f..ce465895 100644 --- a/lib/clixon/clixon_xml_io.h +++ b/lib/clixon/clixon_xml_io.h @@ -43,7 +43,7 @@ /* * Prototypes */ -int clixon_xml2file(FILE *f, cxobj *xn, int level, int pretty, clicon_output_cb *fn, int skiptop); +int clixon_xml2file(FILE *f, cxobj *xn, int level, int pretty, clicon_output_cb *fn, int skiptop, int autocliext); int xml_print(FILE *f, cxobj *xn); int xml_dump(FILE *f, cxobj *x); int clixon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, int32_t depth, int skiptop); diff --git a/lib/src/clixon_datastore_read.c b/lib/src/clixon_datastore_read.c index 5061ed84..5e0c0ae8 100644 --- a/lib/src/clixon_datastore_read.c +++ b/lib/src/clixon_datastore_read.c @@ -745,7 +745,7 @@ xmldb_get_nocache(clicon_handle h, clicon_log(LOG_NOTICE, "%s: sort verify failed #2", __FUNCTION__); #endif if (clicon_debug_get()>1) - if (clixon_xml2file(stderr, xt, 0, 1, fprintf, 0) < 0) + if (clixon_xml2file(stderr, xt, 0, 1, fprintf, 0, 0) < 0) goto done; *xtop = xt; xt = NULL; @@ -917,7 +917,7 @@ xmldb_get_cache(clicon_handle h, * If cache was empty, also update to datastore cache */ if (clicon_debug_get()>1) - if (clixon_xml2file(stderr, x1t, 0, 1, fprintf, 0) < 0) + if (clixon_xml2file(stderr, x1t, 0, 1, fprintf, 0, 0) < 0) goto done; *xtop = x1t; retval = 1; @@ -1019,7 +1019,7 @@ xmldb_get_zerocopy(clicon_handle h, goto done; } if (clicon_debug_get() > 1) - if (clixon_xml2file(stderr, x0t, 0, 1, fprintf, 0) < 0) + if (clixon_xml2file(stderr, x0t, 0, 1, fprintf, 0, 0) < 0) goto done; *xtop = x0t; retval = 1; diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index f522b9db..c1d4df18 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -1244,10 +1244,10 @@ xmldb_put(clicon_handle h, } pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY"); if (strcmp(format,"json")==0){ - if (clixon_json2file(f, x0, pretty, fprintf, 0) < 0) + if (clixon_json2file(f, x0, pretty, fprintf, 0, 0) < 0) goto done; } - else if (clixon_xml2file(f, x0, 0, pretty, fprintf, 0) < 0) + else if (clixon_xml2file(f, x0, 0, pretty, fprintf, 0, 0) < 0) goto done; /* Remove modules state after writing to file */ @@ -1302,10 +1302,10 @@ xmldb_dump(clicon_handle h, } pretty = clicon_option_bool(h, "CLICON_XMLDB_PRETTY"); if (strcmp(format,"json")==0){ - if (clixon_json2file(f, xt, pretty, fprintf, 0) < 0) + if (clixon_json2file(f, xt, pretty, fprintf, 0, 0) < 0) goto done; } - else if (clixon_xml2file(f, xt, 0, pretty, fprintf, 0) < 0) + else if (clixon_xml2file(f, xt, 0, pretty, fprintf, 0, 0) < 0) goto done; retval = 0; done: diff --git a/lib/src/clixon_json.c b/lib/src/clixon_json.c index 60ba1f62..21afce16 100644 --- a/lib/src/clixon_json.c +++ b/lib/src/clixon_json.c @@ -1043,6 +1043,7 @@ xml2json1_cbuf(cbuf *cb, * @param[in,out] cb Cligen buffer to write to * @param[in] x XML tree to translate from * @param[in] pretty Set if output is pretty-printed + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow * @retval 0 OK * @retval -1 Error * @@ -1052,18 +1053,27 @@ xml2json1_cbuf(cbuf *cb, static int xml2json_cbuf1(cbuf *cb, cxobj *x, - int pretty) + int pretty, + int autocliext) { int retval = 1; int level = 0; yang_stmt *y; enum array_element_type arraytype = NO_ARRAY; + int exist = 0; + y = xml_spec(x); + if (autocliext && y != NULL) { + if (yang_extension_value(y, "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0) + goto done; + if (exist) + goto ok; + } cprintf(cb, "%*s{%s", pretty?level*JSON_INDENT:0,"", pretty?"\n":""); - if ((y = xml_spec(x)) != NULL){ + if (y != NULL){ switch (yang_keyword_get(y)){ case Y_LEAF_LIST: case Y_LIST: @@ -1087,6 +1097,7 @@ xml2json_cbuf1(cbuf *cb, pretty?"\n":"", pretty?level*JSON_INDENT:0,"", pretty?"\n":""); + ok: retval = 0; done: return retval; @@ -1101,6 +1112,7 @@ xml2json_cbuf1(cbuf *cb, * @param[in] xt Top-level xml object * @param[in] pretty Set if output is pretty-printed * @param[in] skiptop 0: Include top object 1: Skip top-object, only children, + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow * @retval 0 OK * @retval -1 Error * @code @@ -1115,7 +1127,8 @@ int clixon_json2cbuf(cbuf *cb, cxobj *xt, int pretty, - int skiptop) + int skiptop, + int autocliext) { int retval = -1; cxobj *xc; @@ -1123,11 +1136,11 @@ clixon_json2cbuf(cbuf *cb, if (skiptop){ xc = NULL; while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL) - if (xml2json_cbuf1(cb, xc, pretty) < 0) + if (xml2json_cbuf1(cb, xc, pretty, autocliext) < 0) goto done; } else { - if (xml2json_cbuf1(cb, xt, pretty) < 0) + if (xml2json_cbuf1(cb, xt, pretty, autocliext) < 0) goto done; } retval = 0; @@ -1206,13 +1219,14 @@ xml2json_cbuf_vec(cbuf *cb, * @param[in] pretty Set if output is pretty-printed * @param[in] fn File print function (if NULL, use fprintf) * @param[in] skiptop 0: Include top object 1: Skip top-object, only children, + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow * @retval 0 OK * @retval -1 Error * * @note yang is necessary to translate to one-member lists, * eg if a is a yang LIST 0 -> {"a":["0"]} and not {"a":"0"} * @code - * if (clixon_json2file(stderr, xn, 0, fprintf, 0) < 0) + * if (clixon_json2file(stderr, xn, 0, fprintf, 0, 0) < 0) * goto err; * @endcode */ @@ -1221,7 +1235,8 @@ clixon_json2file(FILE *f, cxobj *xn, int pretty, clicon_output_cb *fn, - int skiptop) + int skiptop, + int autocliext) { int retval = 1; cbuf *cb = NULL; @@ -1232,7 +1247,7 @@ clixon_json2file(FILE *f, clicon_err(OE_XML, errno, "cbuf_new"); goto done; } - if (clixon_json2cbuf(cb, xn, pretty, skiptop) < 0) + if (clixon_json2cbuf(cb, xn, pretty, skiptop, autocliext) < 0) goto done; (*fn)(f, "%s", cbuf_get(cb)); retval = 0; @@ -1251,7 +1266,7 @@ int json_print(FILE *f, cxobj *x) { - return clixon_json2file(f, x, 1, fprintf, 0); + return clixon_json2file(f, x, 1, fprintf, 0, 0); } /*! Translate a vector of xml objects to JSON File. diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 9caadd4d..2a7eb9ce 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -1998,7 +1998,7 @@ netconf_output(int s, if (clicon_debug_get() > 1){ /* XXX: below only works to stderr, clicon_debug may log to syslog */ cxobj *xt = NULL; if (clixon_xml_parse_string(buf, YB_NONE, NULL, &xt, NULL) == 0){ - if (clixon_xml2file(stderr, xml_child_i(xt, 0), 0, 0, fprintf, 0) < 0) + if (clixon_xml2file(stderr, xml_child_i(xt, 0), 0, 0, fprintf, 0, 0) < 0) goto done; fprintf(stderr, "\n"); xml_free(xt); diff --git a/lib/src/clixon_text_syntax.c b/lib/src/clixon_text_syntax.c index 4398e90e..cba69917 100644 --- a/lib/src/clixon_text_syntax.c +++ b/lib/src/clixon_text_syntax.c @@ -101,6 +101,7 @@ tleaf(cxobj *x) * @param[in] fn Callback to make print function * @param[in] f File to print to * @param[in] level Print 4 spaces per level in front of each line + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow * @param[in,out] leafl Leaflist state for keeping track of when [] ends * @param[in,out] leaflname Leaflist state for [] * leaflist state: @@ -112,8 +113,10 @@ xml2txt1(cxobj *xn, clicon_output_cb *fn, FILE *f, int level, + int autocliext, int *leafl, char **leaflname) + { cxobj *xc = NULL; int children=0; @@ -134,10 +137,12 @@ xml2txt1(cxobj *xn, goto done; } if ((yn = xml_spec(xn)) != NULL){ - if (yang_extension_value(yn, "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0) - goto done; - if (exist) - goto ok; + if (autocliext){ + if (yang_extension_value(yn, "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0) + goto done; + if (exist) + goto ok; + } /* Find out prefix if needed: topmost or new module a la API-PATH */ if (ys_real_module(yn, &ymod) < 0) goto done; @@ -230,7 +235,7 @@ xml2txt1(cxobj *xn, if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY){ if (yn && yang_key_match(yn, xml_name(xc), NULL)) continue; /* Skip keys, already printed */ - if (xml2txt1(xc, fn, f, level+1, leafl, leaflname) < 0) + if (xml2txt1(xc, fn, f, level+1, autocliext, leafl, leaflname) < 0) break; } } @@ -256,6 +261,7 @@ xml2txt1(cxobj *xn, * @param[in] level Print 4 spaces per level in front of each line * @param[in] fn File print function (if NULL, use fprintf) * @param[in] skiptop 0: Include top object 1: Skip top-object, only children, + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow * @retval 0 OK * @retval -1 Error */ @@ -264,7 +270,8 @@ clixon_txt2file(FILE *f, cxobj *xn, int level, clicon_output_cb *fn, - int skiptop) + int skiptop, + int autocliext) { int retval = 1; cxobj *xc; @@ -276,11 +283,11 @@ clixon_txt2file(FILE *f, if (skiptop){ xc = NULL; while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL) - if (xml2txt1(xc, fn, f, level, &leafl, &leaflname) < 0) + if (xml2txt1(xc, fn, f, level, autocliext, &leafl, &leaflname) < 0) goto done; } else { - if (xml2txt1(xn, fn, f, level, &leafl, &leaflname) < 0) + if (xml2txt1(xn, fn, f, level, autocliext, &leafl, &leaflname) < 0) goto done; } retval = 0; diff --git a/lib/src/clixon_xml_io.c b/lib/src/clixon_xml_io.c index 23e95569..5f9d49ea 100644 --- a/lib/src/clixon_xml_io.c +++ b/lib/src/clixon_xml_io.c @@ -89,21 +89,26 @@ /*! Print an XML tree structure to an output stream and encode chars "<>&" * - * @param[in] f UNIX output stream - * @param[in] xn Clicon xml tree - * @param[in] level How many spaces to insert before each line - * @param[in] pretty Insert \n and spaces to make the xml more readable. - * @param[in] fn Callback to make print function + * @param[in] f UNIX output stream + * @param[in] xn Clicon xml tree + * @param[in] level How many spaces to insert before each line + * @param[in] pretty Insert \n and spaces to make the xml more readable. + * @param[in] fn Callback to make print function + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow + * @retval 0 OK + * @retval -1 Error * @see clixon_xml2cbuf * One can use clixon_xml2cbuf to get common code, but using fprintf is * much faster than using cbuf and then printing that,... + * */ -int +static int xml2file_recurse(FILE *f, cxobj *x, int level, int pretty, - clicon_output_cb *fn) + clicon_output_cb *fn, + int autocliext) { int retval = -1; char *name; @@ -114,13 +119,17 @@ xml2file_recurse(FILE *f, char *val; char *encstr = NULL; /* xml encoded string */ int exist = 0; + yang_stmt *y; if (x == NULL) goto ok; - if (yang_extension_value(xml_spec(x), "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0) - goto done; - if (exist) - goto ok; + if (autocliext && + (y = xml_spec(x)) != NULL){ + if (yang_extension_value(y, "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0) + goto done; + if (exist) + goto ok; + } name = xml_name(x); namespace = xml_prefix(x); switch(xml_type(x)){ @@ -149,7 +158,7 @@ xml2file_recurse(FILE *f, while ((xc = xml_child_each(x, xc, -1)) != NULL) { switch (xml_type(xc)){ case CX_ATTR: - if (xml2file_recurse(f, xc, level+1, pretty, fn) <0) + if (xml2file_recurse(f, xc, level+1, pretty, fn, autocliext) <0) goto done; break; case CX_BODY: @@ -174,7 +183,7 @@ xml2file_recurse(FILE *f, xc = NULL; while ((xc = xml_child_each(x, xc, -1)) != NULL) { if (xml_type(xc) != CX_ATTR) - if (xml2file_recurse(f, xc, level+1, pretty, fn) <0) + if (xml2file_recurse(f, xc, level+1, pretty, fn, autocliext) <0) goto done; } if (pretty && hasbody==0) @@ -206,9 +215,12 @@ xml2file_recurse(FILE *f, * @param[in] pretty Insert \n and spaces to make the xml more readable. * @param[in] fn File print function (if NULL, use fprintf) * @param[in] skiptop 0: Include top object 1: Skip top-object, only children, + * @param[in] autocliext How to handle autocli extensions: 0: ignore 1: follow * @retval 0 OK * @retval -1 Error * @see clixon_xml2cbuf print to a cbuf string + * @note There is a slight "layer violation" with the autocli parameter: it should normally be set + * for CLI calls, but not for others. */ int clixon_xml2file(FILE *f, @@ -216,7 +228,8 @@ clixon_xml2file(FILE *f, int level, int pretty, clicon_output_cb *fn, - int skiptop) + int skiptop, + int autocliext) { int retval = 1; cxobj *xc; @@ -226,11 +239,11 @@ clixon_xml2file(FILE *f, if (skiptop){ xc = NULL; while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL) - if (xml2file_recurse(f, xc, level, pretty, fn) < 0) + if (xml2file_recurse(f, xc, level, pretty, fn, autocliext) < 0) goto done; } else { - if (xml2file_recurse(f, xn, level, pretty, fn) < 0) + if (xml2file_recurse(f, xn, level, pretty, fn, autocliext) < 0) goto done; } retval = 0; @@ -241,8 +254,7 @@ clixon_xml2file(FILE *f, /*! Print an XML tree structure to an output stream * - * Uses clixon_xml2file internally - * + * Utility function eg in gdb. For code, use clixon_xml2file * @param[in] f UNIX output stream * @param[in] xn clicon xml tree * @see clixon_xml2cbuf @@ -252,7 +264,7 @@ int xml_print(FILE *f, cxobj *x) { - return xml2file_recurse(f, x, 0, 1, fprintf); + return xml2file_recurse(f, x, 0, 1, fprintf, 0); } /*! Dump cxobj structure with pointers and flags for debugging, internal function diff --git a/lib/src/clixon_xml_vec.c b/lib/src/clixon_xml_vec.c index d5be0034..ab4b5003 100644 --- a/lib/src/clixon_xml_vec.c +++ b/lib/src/clixon_xml_vec.c @@ -377,7 +377,7 @@ clixon_xvec_print(FILE *f, int i; for (i=0; ixv_len; i++) - if (clixon_xml2file(f, xv->xv_vec[i], 0, 1, fprintf, 0) < 0) + if (clixon_xml2file(f, xv->xv_vec[i], 0, 1, fprintf, 0, 0) < 0) return -1; return 0; } diff --git a/test/test_autocli_extension.sh b/test/test_autocli_extension.sh index 3dee8756..d6e58e57 100755 --- a/test/test_autocli_extension.sh +++ b/test/test_autocli_extension.sh @@ -8,6 +8,8 @@ s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi APPNAME=example +: ${clixon_util_datastore:=clixon_util_datastore} + fin=$dir/in cfg=$dir/conf_yang.xml fyang=$dir/example.yang @@ -113,20 +115,6 @@ module example-augment { } EOF -new "test params: -f $cfg" -if [ $BE -ne 0 ]; then - new "kill old backend" - sudo clixon_backend -z -f $cfg - if [ $? -ne 0 ]; then - err - fi - new "start backend -s init -f $cfg" - start_backend -s init -f $cfg -fi - -new "wait backend" -wait_backend - function testparam() { # Try hidden parameter list @@ -138,7 +126,16 @@ set table parameter x show config xml EOF new "set table parameter hidden" - expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "set table parameter x" "
" + expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "set table parameter x" "
" + + XML="x
" + + new "check datastore using netconf" + expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "$XML" + + new "check datastore direct access" + expectpart "$($clixon_util_datastore -d candidate -b $dir -y $fyang -Y ${YANG_INSTALLDIR} -Y $dir get /)" 0 "$XML" + } function testvalue() @@ -157,8 +154,33 @@ show config xml EOF new "set table parameter hidden leaf2" expectpart "$(cat $fin | $clixon_cli -f $cfg 2>&1)" 0 "x
" + + XML="x42
" + + new "check datastore using netconf" + expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "$XML" + + new "check datastore direct access" + expectpart "$($clixon_util_datastore -d candidate -b $dir -y $fyang -Y ${YANG_INSTALLDIR} -Y $dir get /)" 0 "$XML" + } +new "test params: -f $cfg" +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -z -f $cfg + if [ $? -ne 0 ]; then + err + fi + new "start backend -s init -f $cfg" + start_backend -s init -f $cfg +fi + +new "wait backend" +wait_backend + +sudo chmod a+r $dir/candidate_db + # INLINE MODE new "Test hidden parameter in table/param inline" diff --git a/util/clixon_util_datastore.c b/util/clixon_util_datastore.c index b74b96e3..cd1b6e0a 100644 --- a/util/clixon_util_datastore.c +++ b/util/clixon_util_datastore.c @@ -66,7 +66,7 @@ #include /* Command line options to be passed to getopt(3) */ -#define DATASTORE_OPTS "hDd:b:f:x:y:" +#define DATASTORE_OPTS "hDd:b:f:x:y:Y:" /*! usage */ @@ -74,29 +74,30 @@ static void usage(char *argv0) { fprintf(stderr, "usage:%s * []\n" - "where options are\n" - "\t-h\t\tHelp\n" - "\t-D\t\tDebug\n" - "\t-d \t\tDatabase name. Default: running. Alt: candidate,startup\n" - "\t-b \tDatabase directory. Mandatory\n" - "\t-f \tDatabase format: xml or json\n" - "\t-x \tXML file. Alternative to put argument\n" - "\t-y \tYang file. Mandatory\n" - "and command is either:\n" - "\tget []\n" - "\tmget []\n" - "\tput (merge|replace|create|delete|remove) []\n" - "\tcopy \n" - "\tlock \n" - "\tunlock\n" - "\tunlock_all \n" - "\tislocked\n" - "\texists\n" - "\tdelete\n" - "\tinit\n" - , - argv0 - ); + "where options are\n" + "\t-h\t\tHelp\n" + "\t-D\t\tDebug\n" + "\t-d \t\tDatabase name. Default: running. Alt: candidate,startup\n" + "\t-b \tDatabase directory. Mandatory\n" + "\t-f \tDatabase format: xml or json\n" + "\t-x \tXML file. Alternative to put argument\n" + "\t-y \tYang file. Mandatory\n" + "\t-Y \tYang dirs (can be several)\n" + "and command is either:\n" + "\tget []\n" + "\tmget []\n" + "\tput (merge|replace|create|delete|remove) []\n" + "\tcopy \n" + "\tlock \n" + "\tunlock\n" + "\tunlock_all \n" + "\tislocked\n" + "\texists\n" + "\tdelete\n" + "\tinit\n" + , + argv0 + ); exit(0); } @@ -122,6 +123,7 @@ main(int argc, char **argv) cbuf *cbret = NULL; int dbg = 0; cxobj *xerr = NULL; + cxobj *xcfg = NULL; /* In the startup, logs to stderr & debug flag set later */ clicon_log_init(__FILE__, LOG_INFO, CLICON_LOG_STDERR); @@ -130,6 +132,10 @@ main(int argc, char **argv) /* Defaults */ if ((h = clicon_handle_init()) == NULL) goto done; + if ((xcfg = xml_new("clixon-config", NULL, CX_ELMNT)) == NULL) + goto done; + if (clicon_conf_xml_set(h, xcfg) < 0) + goto done; /* getopt in two steps, first find config-file before over-riding options. */ clicon_option_str_set(h, "CLICON_XMLDB_FORMAT", "xml"); /* default */ while ((c = getopt(argc, argv, DATASTORE_OPTS)) != -1) @@ -166,6 +172,10 @@ main(int argc, char **argv) usage(argv0); yangfilename = optarg; break; + case 'Y': + if (clicon_option_add(h, "CLICON_YANG_DIR", optarg) < 0) + goto done; + break; } /* * Logs, error and debug to stderr, set debug level @@ -206,7 +216,7 @@ main(int argc, char **argv) xpath = "/"; if (xmldb_get(h, db, NULL, xpath, &xt) < 0) goto done; - if (clixon_xml2file(stdout, xt, 0, 0, fprintf, 0) < 0) + if (clixon_xml2file(stdout, xt, 0, 0, fprintf, 0, 0) < 0) goto done; fprintf(stdout, "\n"); if (xt){ @@ -230,7 +240,7 @@ main(int argc, char **argv) clicon_err(OE_DB, 0, "xt is NULL"); goto done; } - if (clixon_xml2file(stdout, xt, 0, 0, fprintf, 0) < 0) + if (clixon_xml2file(stdout, xt, 0, 0, fprintf, 0, 0) < 0) goto done; if (xt){ xml_free(xt); @@ -341,6 +351,8 @@ main(int argc, char **argv) goto done; retval = 0; done: + if (xcfg) + xml_free(xcfg); if (cbret) cbuf_free(cbret); if (xt) diff --git a/util/clixon_util_json.c b/util/clixon_util_json.c index 8797d4a1..6882d129 100644 --- a/util/clixon_util_json.c +++ b/util/clixon_util_json.c @@ -144,7 +144,7 @@ main(int argc, goto done; } if (json){ - if (clixon_json2cbuf(cb, xt, pretty, 1) < 0) + if (clixon_json2cbuf(cb, xt, pretty, 1, 0) < 0) goto done; } else if (clixon_xml2cbuf(cb, xt, 0, pretty, -1, 1) < 0) diff --git a/util/clixon_util_path.c b/util/clixon_util_path.c index 9a8c382f..a1d2dfdf 100644 --- a/util/clixon_util_path.c +++ b/util/clixon_util_path.c @@ -281,7 +281,7 @@ main(int argc, for (i = 0; i < xlen; i++){ xc = xvec[i]; fprintf(stdout, "%d: ", i); - clixon_xml2file(stdout, xc, 0, 0, fprintf, 0); + clixon_xml2file(stdout, xc, 0, 0, fprintf, 0, 0); fprintf(stdout, "\n"); fflush(stdout); } diff --git a/util/clixon_util_xml.c b/util/clixon_util_xml.c index 65e68855..5733c651 100644 --- a/util/clixon_util_xml.c +++ b/util/clixon_util_xml.c @@ -334,11 +334,11 @@ main(int argc, /* 4. Output data (xml/json/text) */ if (output){ if (textout){ - if (clixon_txt2file(stdout, xt, 0, fprintf, 1) < 0) + if (clixon_txt2file(stdout, xt, 0, fprintf, 1, 0) < 0) goto done; } else if (jsonout){ - if (clixon_json2cbuf(cb, xt, pretty, 1) < 0) + if (clixon_json2cbuf(cb, xt, pretty, 1, 0) < 0) goto done; } else if (clixon_xml2cbuf(cb, xt, 0, pretty, -1, 1) < 0) diff --git a/util/clixon_util_xml_mod.c b/util/clixon_util_xml_mod.c index a009c99f..94b60a92 100644 --- a/util/clixon_util_xml_mod.c +++ b/util/clixon_util_xml_mod.c @@ -282,11 +282,11 @@ main(int argc, char **argv) if (sort) xml_sort_recurse(xb); if (strcmp(xml_name(xb),"top")==0){ - if (clixon_xml2file(stdout, xb, 0, 0, fprintf, 1) < 0) + if (clixon_xml2file(stdout, xb, 0, 0, fprintf, 1, 0) < 0) goto done; } else{ - if (clixon_xml2file(stdout, xb, 0, 0, fprintf, 0) < 0) + if (clixon_xml2file(stdout, xb, 0, 0, fprintf, 0, 0) < 0) goto done; } fprintf(stdout, "\n");