Generalized template and variable substitution functions
Modified api-path-fmt to uri-encoded only =restval
This commit is contained in:
parent
278def125c
commit
01938b7a64
6 changed files with 153 additions and 85 deletions
|
|
@ -196,13 +196,15 @@ xpath_append(cbuf *cb0,
|
||||||
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
||||||
* @param[in] argv Arguments given at the callback:
|
* @param[in] argv Arguments given at the callback:
|
||||||
* <db> Name of datastore, such as "running"
|
* <db> Name of datastore, such as "running"
|
||||||
* <api_path_fmt> Generated API PATH (this is added implicitly, not actually given in the cvv)
|
* <api_path_fmt> Generated API PATH (this is sometimes added implicitly)
|
||||||
* [<mt-point>] Optional YANG path-arg/xpath from mount-point
|
* [<mt-point>] Optional YANG path-arg/xpath from mount-point
|
||||||
* @param[out] commands vector of function pointers to callback functions
|
* @param[out] commands vector of function pointers to callback functions
|
||||||
* @param[out] helptxt vector of pointers to helptexts
|
* @param[out] helptxt vector of pointers to helptexts
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* @see cli_expand_var_generate where api_path_fmt + mt-point are generated
|
* @see cli_expand_var_generate where api_path_fmt + mt-point are generated
|
||||||
|
* The syntax of <api_path_fmt> is of RFC8040 api-path with the following extension:
|
||||||
|
* "%s" represents the values of cvv in order starting from element 1
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
expand_dbvar(void *h,
|
expand_dbvar(void *h,
|
||||||
|
|
@ -451,24 +453,29 @@ expand_dbvar(void *h,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Completion callback of variable for yang schema list or container nodes
|
/*! Completion callback of variable for yang schema list nodes
|
||||||
*
|
*
|
||||||
* Typical yang:
|
* Typical yang:
|
||||||
* container foo { list bar; }
|
* container foo { list bar; }
|
||||||
|
* modA:
|
||||||
|
* augment foo bar;
|
||||||
|
* modB:
|
||||||
* augment foo fie;
|
* augment foo fie;
|
||||||
* This function expands to bar, fie...
|
* This function expands foo to: bar, fie...
|
||||||
|
* Or (if <module> is true): modA:bar, modB:fie...
|
||||||
* @param[in] h clicon handle
|
* @param[in] h clicon handle
|
||||||
* @param[in] name Name of this function
|
* @param[in] name Name of this function
|
||||||
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
* @param[in] cvv The command so far. Eg: cvec [0]:"a 5 b"; [1]: x=5;
|
||||||
* @param[in] argv Arguments given at the callback:
|
* @param[in] argv Arguments given at the callback:
|
||||||
* <schemanode> Absolute YANG schema-node (eg: /ctrl:services)
|
* <schemanode> Absolute YANG schema-node (eg: /ctrl:services)
|
||||||
|
* <modname> true|false: Show with api-path module-name, eg moda:foo, modb:fie
|
||||||
* @param[out] commands vector of function pointers to callback functions
|
* @param[out] commands vector of function pointers to callback functions
|
||||||
* @param[out] helptxt vector of pointers to helptexts
|
* @param[out] helptxt vector of pointers to helptexts
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
expand_yang(void *h,
|
expand_yang_list(void *h,
|
||||||
char *name,
|
char *name,
|
||||||
cvec *cvv,
|
cvec *cvv,
|
||||||
cvec *argv,
|
cvec *argv,
|
||||||
|
|
@ -483,9 +490,12 @@ expand_yang(void *h,
|
||||||
yang_stmt *yres = NULL;
|
yang_stmt *yres = NULL;
|
||||||
yang_stmt *yn = NULL;
|
yang_stmt *yn = NULL;
|
||||||
yang_stmt *ydesc;
|
yang_stmt *ydesc;
|
||||||
|
yang_stmt *ymod;
|
||||||
|
int modname = 0;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
if (argv == NULL || cvec_len(argv) != 1){
|
if (argv == NULL || cvec_len(argv) < 1 || cvec_len(argv) > 2){
|
||||||
clixon_err(OE_PLUGIN, EINVAL, "requires arguments: <schemanode>");
|
clixon_err(OE_PLUGIN, EINVAL, "requires arguments: <schemanode> [<modname>]");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((cv = cvec_i(argv, argc++)) == NULL){
|
if ((cv = cvec_i(argv, argc++)) == NULL){
|
||||||
|
|
@ -493,17 +503,32 @@ expand_yang(void *h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
schema_nodeid = cv_string_get(cv);
|
schema_nodeid = cv_string_get(cv);
|
||||||
|
if (cvec_len(argv) > argc){
|
||||||
|
if (cli_show_option_bool(argv, argc++, &modname) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if ((yspec0 = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec0 = clicon_dbspec_yang(h)) == NULL){
|
||||||
clixon_err(OE_FATAL, 0, "No DB_SPEC");
|
clixon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (yang_abs_schema_nodeid(yspec0, schema_nodeid, &yres) < 0)
|
if (yang_abs_schema_nodeid(yspec0, schema_nodeid, &yres) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
if ((cb = cbuf_new()) == NULL){
|
||||||
|
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
yn = NULL;
|
yn = NULL;
|
||||||
while ((yn = yn_each(yres, yn)) != NULL) {
|
while ((yn = yn_each(yres, yn)) != NULL) {
|
||||||
if (yang_keyword_get(yn) != Y_LIST && yang_keyword_get(yn) != Y_CONTAINER)
|
if (yang_keyword_get(yn) != Y_LIST)
|
||||||
continue;
|
continue;
|
||||||
cvec_add_string(commands, NULL, yang_argument_get(yn));
|
cbuf_reset(cb);
|
||||||
|
if (modname){
|
||||||
|
if (ys_real_module(yn, &ymod) < 0)
|
||||||
|
goto done;
|
||||||
|
cprintf(cb, "%s:", yang_argument_get(ymod));
|
||||||
|
}
|
||||||
|
cprintf(cb, "%s", yang_argument_get(yn));
|
||||||
|
cvec_add_string(commands, NULL, cbuf_get(cb));
|
||||||
if ((ydesc = yang_find(yn, Y_DESCRIPTION, NULL)) != NULL)
|
if ((ydesc = yang_find(yn, Y_DESCRIPTION, NULL)) != NULL)
|
||||||
cvec_add_string(helptexts, NULL, yang_argument_get(ydesc));
|
cvec_add_string(helptexts, NULL, yang_argument_get(ydesc));
|
||||||
else
|
else
|
||||||
|
|
@ -511,6 +536,8 @@ expand_yang(void *h,
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ int cli_process_control(clixon_handle h, cvec *vars, cvec *argv);
|
||||||
/* In cli_show.c */
|
/* In cli_show.c */
|
||||||
int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
|
int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
|
||||||
cvec *commands, cvec *helptexts);
|
cvec *commands, cvec *helptexts);
|
||||||
int expand_yang(void *h, char *name, cvec *cvv, cvec *argv,
|
int expand_yang_list(void *h, char *name, cvec *cvv, cvec *argv,
|
||||||
cvec *commands, cvec *helptexts);
|
cvec *commands, cvec *helptexts);
|
||||||
int clixon_cli2file(clixon_handle h, FILE *f, cxobj *xn, char *prepend, clicon_output_cb *fn, int skiptop);
|
int clixon_cli2file(clixon_handle h, FILE *f, cxobj *xn, char *prepend, clicon_output_cb *fn, int skiptop);
|
||||||
int clixon_cli2cbuf(clixon_handle h, cbuf *cb, cxobj *xn, char *prepend, int skiptop);
|
int clixon_cli2cbuf(clixon_handle h, cbuf *cb, cxobj *xn, char *prepend, int skiptop);
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ char *clixon_trim(char *str);
|
||||||
char *clixon_trim2(char *str, char *trims);
|
char *clixon_trim2(char *str, char *trims);
|
||||||
int clicon_strcmp(char *s1, char *s2);
|
int clicon_strcmp(char *s1, char *s2);
|
||||||
int clixon_unicode2utf8(char *ucstr, char *utfstr, size_t utflen);
|
int clixon_unicode2utf8(char *ucstr, char *utfstr, size_t utflen);
|
||||||
|
int clixon_str_subst(char *str, cvec *cvv, cbuf *cb);
|
||||||
|
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *clicon_strndup (const char *, size_t);
|
char *clicon_strndup (const char *, size_t);
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ yang2api_path_fmt(yang_stmt *ys,
|
||||||
* cvv: foo, bar
|
* cvv: foo, bar
|
||||||
* api_path: /subif-entry=foo,bar/subid
|
* api_path: /subif-entry=foo,bar/subid
|
||||||
*
|
*
|
||||||
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3 (note only =%s)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
api_path_fmt2api_path(const char *api_path_fmt,
|
api_path_fmt2api_path(const char *api_path_fmt,
|
||||||
|
|
@ -476,7 +476,9 @@ api_path_fmt2api_path(const char *api_path_fmt,
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char c;
|
char c;
|
||||||
int esc=0;
|
char cprev;
|
||||||
|
int esc = 0;
|
||||||
|
int uri_encode = 0;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
|
@ -491,15 +493,13 @@ api_path_fmt2api_path(const char *api_path_fmt,
|
||||||
}
|
}
|
||||||
j = 1; /* j==0 is cli string */
|
j = 1; /* j==0 is cli string */
|
||||||
len = strlen(api_path_fmt);
|
len = strlen(api_path_fmt);
|
||||||
|
cprev = 0;
|
||||||
for (i=0; i<len; i++){
|
for (i=0; i<len; i++){
|
||||||
c = api_path_fmt[i];
|
c = api_path_fmt[i];
|
||||||
if (esc){
|
if (esc){
|
||||||
esc = 0;
|
esc = 0;
|
||||||
if (c!='s')
|
if (c == 's' && /* Only accept "%s" no other types */
|
||||||
continue;
|
j != cvec_len(cvv)) { /* last element */
|
||||||
if (j == cvec_len(cvv)) /* last element */
|
|
||||||
;
|
|
||||||
else{
|
|
||||||
if ((cv = cvec_i(cvv, j++)) == NULL){
|
if ((cv = cvec_i(cvv, j++)) == NULL){
|
||||||
clixon_err(OE_XML, 0, "Number of elements in cvv does not match api_path_fmt string");
|
clixon_err(OE_XML, 0, "Number of elements in cvv does not match api_path_fmt string");
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -508,22 +508,35 @@ api_path_fmt2api_path(const char *api_path_fmt,
|
||||||
clixon_err(OE_UNIX, errno, "cv2str_dup");
|
clixon_err(OE_UNIX, errno, "cv2str_dup");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (uri_encode){
|
||||||
|
/* Only if restval, ie =%s, not if eg /%s/ */
|
||||||
if (uri_percent_encode(&strenc, "%s", str) < 0)
|
if (uri_percent_encode(&strenc, "%s", str) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "%s", strenc);
|
cprintf(cb, "%s", strenc);
|
||||||
free(strenc); strenc = NULL;
|
if (strenc){
|
||||||
free(str); str = NULL;
|
free(strenc);
|
||||||
|
strenc = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (c == '%')
|
cprintf(cb, "%s", str);
|
||||||
|
if (str) {
|
||||||
|
free(str);
|
||||||
|
str = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uri_encode = 0;
|
||||||
|
}
|
||||||
|
else if (c == '%'){
|
||||||
esc++;
|
esc++;
|
||||||
else{
|
if (cprev == '=')
|
||||||
if ((c == '=' || c == ',') && api_path_fmt[i+1]=='%' && j == cvec_len(cvv))
|
uri_encode++;
|
||||||
|
}
|
||||||
|
else if ((c == '=' || c == ',') && api_path_fmt[i+1]=='%' && j == cvec_len(cvv))
|
||||||
; /* skip */
|
; /* skip */
|
||||||
else
|
else
|
||||||
cprintf(cb, "%c", c);
|
cprintf(cb, "%c", c);
|
||||||
}
|
cprev = c;
|
||||||
}
|
}
|
||||||
if ((*api_path = strdup(cbuf_get(cb))) == NULL){
|
if ((*api_path = strdup(cbuf_get(cb))) == NULL){
|
||||||
clixon_err(OE_UNIX, errno, "strdup");
|
clixon_err(OE_UNIX, errno, "strdup");
|
||||||
|
|
|
||||||
|
|
@ -1212,6 +1212,59 @@ clixon_unicode2utf8(char *ucstr,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Substitute ${var} in string with variables in cvv
|
||||||
|
*
|
||||||
|
* @param[in] str Input string
|
||||||
|
* @param[in] cvv Variable name/value vector
|
||||||
|
* @param[out] cb Result buffer
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clixon_str_subst(char *str,
|
||||||
|
cvec *cvv,
|
||||||
|
cbuf *cb)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char **vec = NULL;
|
||||||
|
int nvec = 0;
|
||||||
|
int i;
|
||||||
|
cg_var *cv;
|
||||||
|
char *var;
|
||||||
|
char *varname;
|
||||||
|
char *varval;
|
||||||
|
|
||||||
|
if (clixon_strsep2(str, "${", "}", &vec, &nvec) < 0)
|
||||||
|
goto done;
|
||||||
|
if (nvec > 1){
|
||||||
|
i = 0;
|
||||||
|
while (i < nvec){
|
||||||
|
cprintf(cb, "%s", vec[i++]);
|
||||||
|
if (i == nvec)
|
||||||
|
break;
|
||||||
|
var = vec[i++];
|
||||||
|
cv = NULL;
|
||||||
|
while ((cv = cvec_each(cvv, cv)) != NULL){
|
||||||
|
if ((varname = cv_name_get(cv)) == NULL)
|
||||||
|
continue;
|
||||||
|
if (strcmp(varname, var) != 0)
|
||||||
|
continue;
|
||||||
|
varval = cv_string_get(cv);
|
||||||
|
cprintf(cb, "%s", varval);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cprintf(cb, "%s", str);
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (vec)
|
||||||
|
free(vec);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! strndup() for systems without it, such as xBSD
|
/*! strndup() for systems without it, such as xBSD
|
||||||
*/
|
*/
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
|
|
|
||||||
|
|
@ -2107,12 +2107,16 @@ clixon_compare_xmls(cxobj *xc1,
|
||||||
|
|
||||||
/*! XML apply function: replace ${} variables with values from cligen variable vector
|
/*! XML apply function: replace ${} variables with values from cligen variable vector
|
||||||
*
|
*
|
||||||
|
* Example: x=<a>${name}</a>, cvv=["name","bert"] --> <a>bert</a>
|
||||||
* @param[in] x XML node
|
* @param[in] x XML node
|
||||||
* @param[in] arg cvv: vector of name/value pairs
|
* @param[in] arg cvv: vector of name/value pairs
|
||||||
* @retval -1 Error, aborted at first error encounter, return -1 to end user
|
|
||||||
* @retval 0 OK, continue
|
|
||||||
* @retval 1 Abort, dont continue with others, return 1 to end user
|
|
||||||
* @retval 2 Locally abort this subtree, continue with others
|
* @retval 2 Locally abort this subtree, continue with others
|
||||||
|
* @retval 1 Abort, dont continue with others, return 1 to end user
|
||||||
|
* @retval 0 OK, continue
|
||||||
|
* @retval -1 Error, aborted at first error encounter, return -1 to end user
|
||||||
|
* @code
|
||||||
|
* xml_apply(xtmpl, CX_ELMNT, xml_template_apply, cvv);
|
||||||
|
* @endcode
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_template_apply(cxobj *x,
|
xml_template_apply(cxobj *x,
|
||||||
|
|
@ -2122,50 +2126,20 @@ xml_template_apply(cxobj *x,
|
||||||
cvec *cvv = (cvec *)arg;
|
cvec *cvv = (cvec *)arg;
|
||||||
cxobj *xb;
|
cxobj *xb;
|
||||||
char *b;
|
char *b;
|
||||||
char *var;
|
|
||||||
char *varname;
|
|
||||||
char *varval;
|
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
int i;
|
|
||||||
char **vec = NULL;
|
|
||||||
int nvec = 0;
|
|
||||||
cg_var *cv = NULL;
|
|
||||||
|
|
||||||
if ((xb = xml_body_get(x)) != NULL &&
|
if ((xb = xml_body_get(x)) != NULL &&
|
||||||
(b = xml_value(xb)) != NULL){
|
(b = xml_value(xb)) != NULL){
|
||||||
if (clixon_strsep2(b, "${", "}", &vec, &nvec) < 0)
|
|
||||||
goto done;
|
|
||||||
assert(nvec%2 == 1); /* Must be odd */
|
|
||||||
if (nvec > 1){
|
|
||||||
if ((cb = cbuf_new()) == NULL){
|
if ((cb = cbuf_new()) == NULL){
|
||||||
clixon_err(OE_UNIX, errno, "cbuf_new");
|
clixon_err(OE_UNIX, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
i = 0;
|
if (clixon_str_subst(b, cvv, cb) < 0)
|
||||||
while (i < nvec){
|
goto done;
|
||||||
cprintf(cb, "%s", vec[i++]);
|
|
||||||
if (i == nvec)
|
|
||||||
break;
|
|
||||||
var = vec[i++];
|
|
||||||
assert(i < nvec); /* Must be odd */
|
|
||||||
cv = NULL;
|
|
||||||
while ((cv = cvec_each(cvv, cv)) != NULL){
|
|
||||||
if ((varname = cv_name_get(cv)) == NULL)
|
|
||||||
continue;
|
|
||||||
if (strcmp(varname, var) != 0)
|
|
||||||
continue;
|
|
||||||
varval = cv_string_get(cv);
|
|
||||||
cprintf(cb, "%s", varval);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xml_value_set(xb, cbuf_get(cb));
|
xml_value_set(xb, cbuf_get(cb));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (vec)
|
|
||||||
free(vec);
|
|
||||||
if (cb)
|
if (cb)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue