Enhanced for client-side functionality:

- parse of yang from string, not only file
- Decode of xml encoding, not only decoding
This commit is contained in:
Olof Hagsand 2023-01-02 21:25:49 +01:00
parent 0df023c70e
commit 99c6f61637
7 changed files with 158 additions and 7 deletions

View file

@ -95,6 +95,7 @@ int uri_str2cvec(char *string, char delim1, char delim2, int decode, cvec **c
int uri_percent_encode(char **encp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
int xml_chardata_encode(char **escp, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3)));
int xml_chardata_cbuf_append(cbuf *cb, char *str);
int xml_chardata_decode(char **escp, const char *fmt,...);
int uri_percent_decode(char *enc, char **str);
const char *clicon_int2str(const map_str2int *mstab, int i);

View file

@ -55,6 +55,7 @@ yang_stmt *yang_parse_file(FILE *fp, const char *name, yang_stmt *ysp);
yang_stmt *yang_parse_filename(const char *filename, yang_stmt *ysp);
int yang_spec_parse_module(clicon_handle h, const char *module,
const char *revision, yang_stmt *yspec);
yang_stmt *yang_parse_str(char *str, const char *name, yang_stmt *yspec);
int yang_spec_parse_file(clicon_handle h, char *filename, yang_stmt *yspec);
int yang_spec_load_dir(clicon_handle h, char *dir, yang_stmt *yspec);
int ys_parse_date_arg(char *datearg, uint32_t *dateint);

View file

@ -1270,7 +1270,7 @@ clicon_rpc_validate(clicon_handle h,
/*! Commit changes send a commit request to backend daemon
* @param[in] h CLICON handle
* @param[in] confirmed If set, send commit/confirmed
* @param[in] cancel If set, send cancle-commit
* @param[in] cancel If set, send cancel-commit
* @param[in] timeout For confirmed, a timeout in seconds (default 600s)
* @param[in] persist A persist identifier to use
* @param[in] persist_id If cancel or confirmed, the persist id

View file

@ -387,7 +387,7 @@ uri_percent_decode(char *enc,
return retval;
}
/*! Escape characters according to XML definition
/*! Encode escape characters according to XML definition
* @param[out] encp Encoded malloced output string
* @param[in] fmt Not-encoded input string (stdarg format string)
* @param[in] ... stdarg variable parameters
@ -410,6 +410,7 @@ uri_percent_decode(char *enc,
* @see uri_percent_encode
* @see AMPERSAND mode in clixon_xml_parse.l, implicit decoding
* @see xml_chardata_cbuf_append for a specialized version
* @see xml_chardata_decode for decoding
*/
int
xml_chardata_encode(char **escp,
@ -587,6 +588,147 @@ xml_chardata_cbuf_append(cbuf *cb,
return retval;
}
/*! xml decode &...;
*
* @param[in] str Input string on the form &..; with & stripped
* @param[out] ch Decoded character
* @param[in,out] ip
* @retval 1 OK and identified a decoding
* @retval 0 OK No identified decoding
* @retval -1 Error
*/
static int
xml_chardata_decode_ampersand(char *str,
char *ch,
int *ip)
{
int retval = -1;
char *semi;
char *p;
size_t len;
uint32_t code;
cbuf *cb = NULL;
int ret;
if ((semi = index(str, ';')) == NULL)
goto fail;
*semi = '\0';
len = strlen(str);
p = str;
if (strcmp(p, "amp") == 0)
*ch = '&';
else if (strcmp(p, "lt") == 0)
*ch = '<';
else if (strcmp(p, "gt") == 0)
*ch = '>';
else if (strcmp(p, "apos") == 0)
*ch = '\'';
else if (strcmp(p, "quot") == 0)
*ch = '"';
else if (len > 0 && *p == '#'){
p++;
if ((cb = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "parse_uint32");
goto done;
}
if (len > 1 && *p == 'x'){
cprintf(cb, "0x");
p++;
}
cprintf(cb, "%s", p);
if ((ret = parse_uint32(cbuf_get(cb), &code, NULL)) < 0){
clicon_err(OE_UNIX, errno, "parse_uint32");
goto done;
}
if (ret == 0){
goto fail;
}
*ch = code;
}
else
goto fail;
*ip += len+1;
retval = 1;
done:
if (cb)
cbuf_free(cb);
return retval;
fail:
retval = 0;
if (semi)
*semi = ';';
goto done;
}
/*! Decode escape characters according to XML definition
* @param[out] decp Decoded malloced output string
* @param[in] fmt Encoded input string (stdarg format string)
* @see xml_chardata_encode for encoding
*/
int
xml_chardata_decode(char **decp,
const char *fmt,...)
{
int retval = -1;
char *str = NULL; /* Expanded encoded format string w stdarg */
char *dec = NULL;
int fmtlen;
va_list args;
size_t slen;
int i;
int j;
char ch;
int ret;
/* Two steps: (1) read in the complete format string */
va_start(args, fmt); /* dryrun */
fmtlen = vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args);
if ((str = malloc(fmtlen)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
memset(str, 0, fmtlen);
va_start(args, fmt); /* real */
fmtlen = vsnprintf(str, fmtlen, fmt, args) + 1;
va_end(args);
/* Now str is the combined fmt + ... */
/* Step (2) decode str --> dec
* First allocate decoded string, encoded is always >= larger */
slen = strlen(str);
if ((dec = malloc(slen+1)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
j = 0;
memset(dec, 0, slen+1);
for (i=0; i<slen; i++){
ch = str[i];
switch (ch){
case '&':
if ((ret = xml_chardata_decode_ampersand(&str[i+1], &ch, &i)) < 0)
goto done;
if (ret == 0)
dec[j++] = str[i];
else
dec[j++] = ch;
break;
default:
dec[j++] = str[i];
}
}
*decp = dec;
retval = 0;
done:
if (str)
free(str);
if (retval < 0 && dec)
free(dec);
return retval;
}
/*! Split a string into a cligen variable vector using 1st and 2nd delimiter
*
* (1) Split a string into elements delimited by delim1,

View file

@ -146,8 +146,8 @@ ncname {namestart}{namechar}*
<AMPERSAND>"gt;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = ">"; return CHARDATA;}
<AMPERSAND>"apos;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;}
<AMPERSAND>"quot;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;}
<AMPERSAND>"#"[0-9]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA; /* ISO/IEC 10646 */ }
<AMPERSAND>"#x"[0-9a-fA-F]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;}
<AMPERSAND>"#"[0-9]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = yytext; return ENCODED; /* ISO/IEC 10646 */ }
<AMPERSAND>"#x"[0-9a-fA-F]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = yytext; return ENCODED;}
<CDATA>\n { clixon_xml_parselval.string = yytext;_XY->xy_linenum++; return (CHARDATA);}
<CDATA>"]]>" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;}

View file

@ -45,7 +45,7 @@
%start document
%token <string> NAME CHARDATA WHITESPACE STRING
%token <string> NAME CHARDATA ENCODED WHITESPACE STRING
%token MY_EOF
%token VER ENC SD
%token BSLASH ESLASH
@ -104,12 +104,14 @@ clixon_xml_parseerror(void *_xy,
/*! Parse XML content, eg chars between >...<
* @param[in] xy
* @param[in] encoded set if ampersand encoded
* @param[in] str Body string, direct pointer (copy before use, dont free)
* Note that we dont handle escaped characters correctly
* there may also be some leakage here on NULL return
*/
static int
xml_parse_content(clixon_xml_yacc *xy,
int encoded,
char *str)
{
cxobj *xn = xy->xy_xelement;
@ -121,6 +123,9 @@ xml_parse_content(clixon_xml_yacc *xy,
if ((xn = xml_new("body", xp, CX_BODY)) == NULL)
goto done;
}
if (encoded)
if (xml_value_append(xn, "&") < 0)
goto done;
if (xml_value_append(xn, str) < 0)
goto done;
xy->xy_xelement = xn;
@ -446,8 +451,10 @@ elist : elist content { _PARSE_DEBUG("elist -> elist content"); }
content : element { _PARSE_DEBUG("content -> element"); }
| comment { _PARSE_DEBUG("content -> comment"); }
| pi { _PARSE_DEBUG("content -> pi"); }
| CHARDATA { if (xml_parse_content(_XY, $1) < 0) YYABORT;
| CHARDATA { if (xml_parse_content(_XY, 0, $1) < 0) YYABORT;
_PARSE_DEBUG("content -> CHARDATA"); }
| ENCODED { if (xml_parse_content(_XY, 1, $1) < 0) YYABORT;
_PARSE_DEBUG("content -> ENCODED"); }
| WHITESPACE { if (xml_parse_whitespace(_XY, $1) < 0) YYABORT;
_PARSE_DEBUG("content -> WHITESPACE"); }
| { _PARSE_DEBUG("content -> "); }

View file

@ -759,7 +759,7 @@ yang_expand_grouping(yang_stmt *yn)
* @retval NULL Error encountered
* See top of file for diagram of calling order
*/
static yang_stmt *
yang_stmt *
yang_parse_str(char *str,
const char *name, /* just for errs */
yang_stmt *yspec)