diff --git a/CHANGELOG.md b/CHANGELOG.md index fd173d97..d6fa4508 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,7 @@ Users may have to change how they access the system ### Minor features +* JSON errors are now labelled with JSON and not XML * Restconf native HTTP/2: * Added option `CLICON_RESTCONF_HTTP2_PLAIN` for non-TLS http * Default disabled, set to true to enable HTTP/2 direct and switch/upgrade HTTP/1->HTTP/2 @@ -78,6 +79,7 @@ Users may have to change how they access the system ### Corrected Bugs +* Fixed: [Performance issue when parsing large JSON param](https://github.com/clicon/clixon/issues/266) * Fixed: [Duplicate lines emitted by cli_show_config (cli output style) when yang list element has composite key](https://github.com/clicon/clixon/issues/258) * Fixed: [JSON leaf-list output single element leaf-list does not use array](https://github.com/clicon/clixon/issues/261) * Fixed: Netconf diff callback did not work with choice and same value replace diff --git a/apps/cli/cli_auto.c b/apps/cli/cli_auto.c index fe33128a..7b0cce6b 100644 --- a/apps/cli/cli_auto.c +++ b/apps/cli/cli_auto.c @@ -521,6 +521,7 @@ cli_auto_up(clicon_handle h, char *api_path = NULL; int i; int j; + size_t len; if (cvec_len(argv) != 1){ clicon_err(OE_PLUGIN, EINVAL, "Usage: %s()", __FUNCTION__); @@ -551,7 +552,8 @@ cli_auto_up(clicon_handle h, /* Find diff of 0 and 1 (how many variables differ?) and trunc cvv0 by that amount */ cvv0 = clicon_data_cvec_get(h, "cli-edit-cvv"); j=0; /* count diffs */ - for (i=strlen(api_path_fmt1); i "); @@ -1241,8 +1242,9 @@ cli_copy_config(clicon_handle h, goto done; } /* Sanity check that xpath contains exactly two %s, ie [%s='%s'] */ + len = strlen(xpath); j = 0; - for (i=0; i J_FALSE @@ -89,8 +90,8 @@ object. %token J_CHAR %token J_NUMBER -%type string -%type ustring +%type string +%type ustring %type number %lex-param {void *_jy} /* Add this argument to parse() and lex() function */ @@ -102,7 +103,7 @@ object. /* typecast macro */ #define _JY ((clixon_json_yacc *)_jy) -#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_json_parsetext, _JY->jy_linenum); YYERROR;} +#define _YYERROR(msg) {clicon_err(OE_JSON, 0, "YYERROR %s '%s' %d", (msg), clixon_json_parsetext, _JY->jy_linenum); YYERROR;} /* add _yy to error parameters */ #define YY_(msgid) msgid @@ -150,7 +151,7 @@ void clixon_json_parseerror(void *_jy, char *s) { - clicon_err(OE_XML, XMLPARSE_ERRNO, "json_parse: line %d: %s at or before: '%s'", + clicon_err(OE_JSON, XMLPARSE_ERRNO, "json_parse: line %d: %s at or before: '%s'", _JY->jy_linenum , s, clixon_json_parsetext); @@ -265,7 +266,7 @@ value : J_TRUE { json_current_body(_JY, "true"); _PARSE_DEBUG("va | object { _PARSE_DEBUG("value->object"); } | array { _PARSE_DEBUG("value->array"); } | number { json_current_body(_JY, $1); free($1); _PARSE_DEBUG("value->number");} - | string { json_current_body(_JY, $1); free($1); _PARSE_DEBUG("value->string");} + | string { json_current_body(_JY, cbuf_get($1)); cbuf_free($1); _PARSE_DEBUG("value->string");} ; @@ -277,7 +278,7 @@ objlist : pair { _PARSE_DEBUG("objlist->pair");} | objlist ',' pair { _PARSE_DEBUG("objlist->objlist , pair");} ; -pair : string { json_current_new(_JY, $1);free($1);} ':' +pair : string { json_current_new(_JY, cbuf_get($1));cbuf_free($1);} ':' value { json_current_pop(_JY);}{ _PARSE_DEBUG("pair->string : value");} ; @@ -292,19 +293,16 @@ valuelist : value { _PARSE_DEBUG("valuelist->value"); } /* quoted string */ string : J_DQ ustring J_DQ { _PARSE_DEBUG("string->\" ustring \"");$$=$2; } - | J_DQ J_DQ { _PARSE_DEBUG("string->\" \"");$$=strdup(""); } + | J_DQ J_DQ { _PARSE_DEBUG("string->\" \"");$$=cbuf_new(); } ; /* unquoted string: can be optimized by reading whole string in lex */ ustring : ustring J_CHAR { - int len = strlen($1); - $$ = realloc($1, len+strlen($2) + 1); - sprintf($$+len, "%s", $2); - free($2); + cbuf_append_str($1,$2); $$=$1; free($2); } | J_CHAR - {$$=$1;} + { cbuf *cb = cbuf_new(); cbuf_append_str(cb,$1); $$=cb; free($1);} ; number : J_NUMBER { $$ = $1; } diff --git a/lib/src/clixon_path.c b/lib/src/clixon_path.c index b7127939..b8c8d4fd 100644 --- a/lib/src/clixon_path.c +++ b/lib/src/clixon_path.c @@ -460,13 +460,15 @@ api_path_fmt2api_path(const char *api_path_fmt, char *str; char *strenc=NULL; cg_var *cv; + size_t len; if ((cb = cbuf_new()) == NULL){ clicon_err(OE_UNIX, errno, "cbuf_new"); goto done; } j = 1; /* j==0 is cli string */ - for (i=0; i 2 && isxdigit(enc[i+1]) && isxdigit(enc[i+2])){ hstr[0] = enc[i+1]; @@ -386,6 +388,7 @@ xml_chardata_encode(char **escp, int i, j; int cdata; /* when set, skip encoding */ va_list args; + size_t slen; /* Two steps: (1) read in the complete format string */ va_start(args, fmt); /* dryrun */ @@ -404,7 +407,8 @@ xml_chardata_encode(char **escp, /* Step (2) encode and expand str --> enc */ /* First compute length (do nothing) */ len = 0; cdata = 0; - for (i=0; i", strlen("]]>")) == 0) cdata = 0; @@ -440,7 +444,8 @@ xml_chardata_encode(char **escp, /* Same code again, but now actually encode into output buffer */ j = 0; cdata = 0; - for (i=0; i", strlen("]]>")) == 0){ cdata = 0; @@ -503,12 +508,15 @@ xml_chardata_cbuf_append(cbuf *cb, int retval = -1; int i; int cdata; /* when set, skip encoding */ + size_t len; /* The orignal of this code is in xml_chardata_encode */ /* Step: encode and expand str --> enc */ /* Same code again, but now actually encode into output buffer */ cdata = 0; - for (i=0; i", strlen("]]>")) == 0){ cdata = 0; diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 43845787..29084fb6 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -75,7 +75,6 @@ #include #include #include -#include /* cligen */ #include @@ -538,6 +537,7 @@ xpath_parse(const char *xpath, clicon_log(LOG_NOTICE, "XPATH error: on line %d", xpy.xpy_linenum); if (clicon_errno == 0) clicon_err(OE_XML, 0, "XPATH parser error with no error code (should not happen)"); + xpath_scan_exit(&xpy); goto done; } if (clicon_debug_get() > 1){ diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index 825203aa..5619344a 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -126,6 +126,20 @@ #include "clixon_xpath_parse.h" +/* Best debugging is to enable PARSE_DEBUG below and add -d to the LEX compile statement in the Makefile + * And then run the testcase with -D 1 + * Disable it to stop any calls to clicon_debug. Having it on by default would mean very large debug outputs. + */ +#if 0 +#define _PARSE_DEBUG(s) clicon_debug(1,(s)) +#define _PARSE_DEBUG1(s, s1) clicon_debug(1,(s), (s1)) +#define _PARSE_DEBUG2(s, s1, s2) clicon_debug(1,(s), (s1), (s2)) +#else +#define _PARSE_DEBUG(s) +#define _PARSE_DEBUG1(s, s1) +#define _PARSE_DEBUG2(s, s1, s2) +#endif + extern int clixon_xpath_parseget_lineno (void); /*XXX obsolete ? */ /* @@ -366,92 +380,92 @@ xp_nodetest_function(clixon_xpath_yacc *xpy, /* */ -start : expr X_EOF { _XPY->xpy_top=$1;clicon_debug(3,"start->expr"); YYACCEPT; } - | locationpath X_EOF { _XPY->xpy_top=$1;clicon_debug(3,"start->locationpath"); YYACCEPT; } +start : expr X_EOF { _XPY->xpy_top=$1;_PARSE_DEBUG("start->expr"); YYACCEPT; } + | locationpath X_EOF { _XPY->xpy_top=$1;_PARSE_DEBUG("start->locationpath"); YYACCEPT; } ; -expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,NULL,NULL,NULL,$1, $3);clicon_debug(3,"expr->expr or andexpr"); } - | andexpr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"expr-> andexpr"); } +expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("expr->expr or andexpr"); } + | andexpr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL);_XPY->xpy_top=$$;_PARSE_DEBUG("expr-> andexpr"); } ; -andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,NULL,NULL,NULL,$1, $3);clicon_debug(3,"andexpr-> andexpr and relexpr"); } - | relexpr { $$=xp_new(XP_AND,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"andexpr-> relexpr"); } +andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("andexpr-> andexpr and relexpr"); } + | relexpr { $$=xp_new(XP_AND,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("andexpr-> relexpr"); } ; -relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,NULL,NULL,NULL,$1, $3);clicon_debug(3,"relexpr-> relexpr relop addexpr"); } - | addexpr { $$=xp_new(XP_RELEX,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"relexpr-> addexpr"); } +relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("relexpr-> relexpr relop addexpr"); } + | addexpr { $$=xp_new(XP_RELEX,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("relexpr-> addexpr"); } ; -addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,NULL,NULL,NULL,$1, $3);clicon_debug(3,"addexpr-> addexpr ADDOP unionexpr"); } - | unionexpr { $$=xp_new(XP_ADD,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"addexpr-> unionexpr"); } +addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("addexpr-> addexpr ADDOP unionexpr"); } + | unionexpr { $$=xp_new(XP_ADD,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("addexpr-> unionexpr"); } ; /* node-set */ -unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,XO_UNION,NULL,NULL,NULL,$1, $3);clicon_debug(3,"unionexpr-> unionexpr | pathexpr"); } - | pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"unionexpr-> pathexpr"); } +unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,XO_UNION,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("unionexpr-> unionexpr | pathexpr"); } + | pathexpr { $$=xp_new(XP_UNION,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("unionexpr-> pathexpr"); } ; -pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"pathexpr-> locationpath"); } - | filterexpr { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"pathexpr-> filterexpr"); } - | filterexpr '/' rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("/"),NULL,$1, $3);clicon_debug(3,"pathexpr-> filterexpr / rellocpath"); } - | filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);clicon_debug(3,"pathexpr-> filterexpr // rellocpath"); } +pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("pathexpr-> locationpath"); } + | filterexpr { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("pathexpr-> filterexpr"); } + | filterexpr '/' rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("/"),NULL,$1, $3);_PARSE_DEBUG("pathexpr-> filterexpr / rellocpath"); } + | filterexpr DOUBLESLASH rellocpath { $$=xp_new(XP_PATHEXPR,A_NAN,NULL,strdup("//"),NULL,$1, $3);_PARSE_DEBUG("pathexpr-> filterexpr // rellocpath"); } ; -filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);clicon_debug(3,"filterexpr-> primaryexpr"); } +filterexpr : primaryexpr { $$=xp_new(XP_FILTEREXPR,A_NAN,NULL,NULL,NULL,$1, NULL);_PARSE_DEBUG("filterexpr-> primaryexpr"); } /* Filterexpr predicate */ ; /* location path returns a node-set */ -locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(3,"locationpath-> rellocpath"); } - | abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(3,"locationpath-> abslocpath"); } +locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("locationpath-> rellocpath"); } + | abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("locationpath-> abslocpath"); } ; -abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,NULL, NULL);clicon_debug(3,"abslocpath-> /"); } - | '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,$2, NULL);clicon_debug(3,"abslocpath->/ rellocpath");} +abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,NULL, NULL);_PARSE_DEBUG("abslocpath-> /"); } + | '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,NULL,NULL,NULL,$2, NULL);_PARSE_DEBUG("abslocpath->/ rellocpath");} /* // is short for /descendant-or-self::node()/ */ - | DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$2, NULL); clicon_debug(3,"abslocpath-> // rellocpath"); } + | DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$2, NULL); _PARSE_DEBUG("abslocpath-> // rellocpath"); } ; -rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); clicon_debug(3,"rellocpath-> step"); } - | rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, $3);clicon_debug(3,"rellocpath-> rellocpath / step"); } - | rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); clicon_debug(3,"rellocpath-> rellocpath // step"); } +rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, NULL); _PARSE_DEBUG("rellocpath-> step"); } + | rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,NULL,NULL,NULL,$1, $3);_PARSE_DEBUG("rellocpath-> rellocpath / step"); } + | rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,NULL,NULL,NULL,$1, $3); _PARSE_DEBUG("rellocpath-> rellocpath // step"); } ; -step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,NULL, NULL, NULL, $2, $3);clicon_debug(3,"step->axisspec(%d) nodetest", $1); } - | '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); clicon_debug(3,"step-> ."); } - | DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); clicon_debug(3,"step-> .."); } +step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,NULL, NULL, NULL, $2, $3);_PARSE_DEBUG1("step->axisspec(%d) nodetest", $1); } + | '.' predicates { $$=xp_new(XP_STEP,A_SELF, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> ."); } + | DOUBLEDOT predicates { $$=xp_new(XP_STEP, A_PARENT, NULL,NULL, NULL, NULL, $2); _PARSE_DEBUG("step-> .."); } ; -axisspec : AXISNAME { clicon_debug(3,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;} - | '@' { $$=A_ATTRIBUTE; clicon_debug(3,"axisspec-> @"); } - | { clicon_debug(3,"axisspec-> "); $$=A_CHILD;} +axisspec : AXISNAME { _PARSE_DEBUG1("axisspec-> AXISNAME(%d) ::", $1); $$=$1;} + | '@' { $$=A_ATTRIBUTE; _PARSE_DEBUG("axisspec-> @"); } + | { _PARSE_DEBUG("axisspec-> "); $$=A_CHILD;} ; -nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, NULL, NULL, NULL); clicon_debug(3,"nodetest-> *"); } - | NAME { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL); clicon_debug(3,"nodetest-> name(%s)",$1); } - | NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);clicon_debug(3,"nodetest-> name(%s) : name(%s)", $1, $3); } - | NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);clicon_debug(3,"nodetest-> name(%s) : *", $1); } - | FUNCTIONNAME ')' { if (($$ = xp_nodetest_function(_XPY, $1, NULL)) == NULL) YYERROR;; clicon_debug(3,"nodetest-> nodetype():%s", $1); } +nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, NULL, NULL, NULL); _PARSE_DEBUG("nodetest-> *"); } + | NAME { $$=xp_new(XP_NODE,A_NAN,NULL, NULL, $1, NULL, NULL); _PARSE_DEBUG1("nodetest-> name(%s)",$1); } + | NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,NULL, $1, $3, NULL, NULL);_PARSE_DEBUG2("nodetest-> name(%s) : name(%s)", $1, $3); } + | NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,NULL, $1, NULL, NULL, NULL);_PARSE_DEBUG1("nodetest-> name(%s) : *", $1); } + | FUNCTIONNAME ')' { if (($$ = xp_nodetest_function(_XPY, $1, NULL)) == NULL) YYERROR;; _PARSE_DEBUG1("nodetest-> nodetype():%s", $1); } ; /* evaluates to boolean */ -predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, $1, $3); clicon_debug(3,"predicates-> [ expr ]"); } - | { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); clicon_debug(3,"predicates->"); } +predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, $1, $3); _PARSE_DEBUG("predicates-> [ expr ]"); } + | { $$=xp_new(XP_PRED,A_NAN,NULL, NULL, NULL, NULL, NULL); _PARSE_DEBUG("predicates->"); } ; -primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); clicon_debug(3,"primaryexpr-> ( expr )"); } - | NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(3,"primaryexpr-> NUMBER(%s)", $1); /*XXX*/} - | QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);clicon_debug(3,"primaryexpr-> \" string \""); } - | QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);clicon_debug(3,"primaryexpr-> \" \""); } - | APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);clicon_debug(3,"primaryexpr-> ' string '"); } - | APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);clicon_debug(3,"primaryexpr-> ' '"); } - | FUNCTIONNAME ')' { if (($$ = xp_primary_function(_XPY, $1, NULL)) == NULL) YYERROR; clicon_debug(3,"primaryexpr-> functionname ()"); } - | FUNCTIONNAME args ')' { if (($$ = xp_primary_function(_XPY, $1, $2)) == NULL) YYERROR; clicon_debug(3,"primaryexpr-> functionname (arguments)"); } +primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,NULL, NULL, NULL, $2, NULL); _PARSE_DEBUG("primaryexpr-> ( expr )"); } + | NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);_PARSE_DEBUG1("primaryexpr-> NUMBER(%s)", $1); /*XXX*/} + | QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> \" string \""); } + | QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> \" \""); } + | APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, $2, NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> ' string '"); } + | APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,NULL, strdup(""), NULL, NULL, NULL);_PARSE_DEBUG("primaryexpr-> ' '"); } + | FUNCTIONNAME ')' { if (($$ = xp_primary_function(_XPY, $1, NULL)) == NULL) YYERROR; _PARSE_DEBUG("primaryexpr-> functionname ()"); } + | FUNCTIONNAME args ')' { if (($$ = xp_primary_function(_XPY, $1, $2)) == NULL) YYERROR; _PARSE_DEBUG("primaryexpr-> functionname (arguments)"); } ; args : args ',' expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, $3); - clicon_debug(3,"args -> args expr");} + _PARSE_DEBUG("args -> args expr");} | expr { $$=xp_new(XP_EXP,A_NAN,NULL,NULL,NULL,$1, NULL); - clicon_debug(3,"args -> expr "); } + _PARSE_DEBUG("args -> expr "); } ; string : string CHARS { @@ -459,9 +473,9 @@ string : string CHARS { $$ = realloc($1, len+strlen($2) + 1); sprintf($$+len, "%s", $2); free($2); - clicon_debug(3,"string-> string CHAR"); + _PARSE_DEBUG("string-> string CHAR"); } - | CHARS { clicon_debug(3,"string-> "); } + | CHARS { _PARSE_DEBUG("string-> "); } ; diff --git a/test/test_perf_json.sh b/test/test_perf_json.sh new file mode 100755 index 00000000..3dfab307 --- /dev/null +++ b/test/test_perf_json.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# JSON performance test: +# 1. parse a long string + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +: ${clixon_util_json:="clixon_util_json"} + +# Number of list/leaf-list entries in file +: ${perfnr:=20000} + +fjson=$dir/long.json + +new "generate long file $fjson" +echo -n '{"foo": "' > $fjson +for (( i=0; i<$perfnr; i++ )); do + echo -n "a" >> $fjson +done +echo '"}' >> $fjson +echo "$fjson" + +new "json parse long string" +expecteof_file "time -p $clixon_util_json" 0 "$fjson" 2>&1 | awk '/real/ {print $2}' + +rm -rf $dir + +# unset conditional parameters +unset clixon_util_xml +unset perfnr + +new "endtest" +endtest