ioc/dbStatic: Add JSON parsing of field values

The parsing removes all white-space outside of quotes from the JSON.
dbRecordField() now strips quotes from simple string values itself.
This commit is contained in:
Andrew Johnson
2016-05-19 01:15:33 -05:00
parent efb5ba27ae
commit 28b3b1678c
3 changed files with 111 additions and 13 deletions

View File

@@ -1,11 +1,12 @@
/*************************************************************************\
* Copyright (c) 2009 UChicago Argonne LLC, as Operator of Argonne
* Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
newline "\n"
backslash "\\"
doublequote "\""
@@ -15,6 +16,18 @@ escape {backslash}.
stringchar [^"\n\\]
bareword [a-zA-Z0-9_\-+:.\[\]<>;]
punctuation [:,\[\]{}]
normalchar [^"\\\0-\x1f]
escapedchar ({backslash}["\\/bfnrt])
hexdigit [0-9a-fA-F]
unicodechar ({backslash}"u"{hexdigit}{4})
jsonchar ({normalchar}|{escapedchar}|{unicodechar})
jsondqstr ({doublequote}{jsonchar}*{doublequote})
int ("-"?([0-9]|[1-9][0-9]+))
frac ("."[0-9]+)
exp ([eE][+-]?[0-9]+)
number ({int}{frac}?{exp}?)
%{
#undef YY_INPUT
#define YY_INPUT(b,r,ms) (r=(*db_yyinput)((char *)b,ms))
@@ -27,6 +40,8 @@ static int yyreset(void)
%}
%x JSON
%%
"include" return(tokenINCLUDE);
@@ -49,18 +64,18 @@ static int yyreset(void)
"variable" return(tokenVARIABLE);
{bareword}+ { /* unquoted string or number */
yylval.Str = dbmfStrdup(yytext);
yylval.Str = dbmfStrdup((char *) yytext);
return(tokenSTRING);
}
{doublequote}({stringchar}|{escape})*{doublequote} { /* quoted string */
yylval.Str = dbmfStrdup(yytext+1);
yylval.Str = dbmfStrdup((char *) yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(tokenSTRING);
}
%.* { /*C definition in recordtype*/
yylval.Str = dbmfStrdup(yytext+1);
yylval.Str = dbmfStrdup((char *) yytext+1);
return(tokenCDEFS);
}
@@ -71,13 +86,30 @@ static int yyreset(void)
"," return(yytext[0]);
{comment}.* ;
{whitespace} ;
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
yyerrorAbort("Newline in string, closing quote missing");
}
. {
<JSON>"null" return jsonNULL;
<JSON>"true" return jsonTRUE;
<JSON>"false" return jsonFALSE;
<JSON>{punctuation} return yytext[0];
<JSON>{jsondqstr} {
yylval.Str = dbmfStrdup((char *) yytext);
return jsonSTRING;
}
<JSON>{number} {
yylval.Str = dbmfStrdup((char *) yytext);
return jsonNUMBER;
}
<INITIAL,JSON>{whitespace} ;
<INITIAL,JSON>. {
char message[40];
YY_BUFFER_STATE *dummy=0;

View File

@@ -1048,6 +1048,11 @@ static void dbRecordField(char *name,char *value)
yyerror(NULL);
return;
}
if (*value == '"') {
/* jsonSTRING values still have their quotes */
value++;
value[strlen(value) - 1] = 0;
}
dbTranslateEscape(value, value); /* yuck: in-place, but safe */
status = dbPutString(pdbentry,value);
if(status) {

View File

@@ -17,6 +17,11 @@ static int yyAbort = 0;
%start database
%union
{
char *Str;
}
%token tokenINCLUDE tokenPATH tokenADDPATH
%token tokenALIAS tokenMENU tokenCHOICE tokenRECORDTYPE
%token tokenFIELD tokenINFO tokenREGISTRAR
@@ -24,10 +29,10 @@ static int yyAbort = 0;
%token tokenRECORD tokenGRECORD tokenVARIABLE tokenFUNCTION
%token <Str> tokenSTRING tokenCDEFS
%union
{
char *Str;
}
%token jsonNULL jsonTRUE jsonFALSE
%token <Str> jsonNUMBER jsonSTRING
%type <Str> json_value json_object json_array
%type <Str> json_members json_pair json_elements
%%
@@ -247,10 +252,11 @@ record_body: /* empty */
record_field_list: record_field_list record_field
| record_field;
record_field: tokenFIELD '(' tokenSTRING ',' tokenSTRING ')'
record_field: tokenFIELD '(' tokenSTRING ','
{ BEGIN JSON; } json_value { BEGIN INITIAL; } ')'
{
if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$5);
dbRecordField($3,$5); dbmfFree($3); dbmfFree($5);
if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$6);
dbRecordField($3,$6); dbmfFree($3); dbmfFree($6);
}
| tokenINFO '(' tokenSTRING ',' tokenSTRING ')'
{
@@ -270,6 +276,61 @@ alias: tokenALIAS '(' tokenSTRING ',' tokenSTRING ')'
dbAlias($3,$5); dbmfFree($3); dbmfFree($5);
};
json_object: '{' '}'
{
$$ = "{}";
if (dbStaticDebug>2) printf("json %s\n", $$);
}
| '{' json_members '}'
{
$$ = dbmfStrcat3("{", $2, "}");
dbmfFree($2);
if (dbStaticDebug>2) printf("json %s\n", $$);
};
json_members: json_pair
| json_pair ',' json_members
{
$$ = dbmfStrcat3($1, ",", $3);
dbmfFree($1); dbmfFree($3);
if (dbStaticDebug>2) printf("json %s\n", $$);
};
json_pair: jsonSTRING ':' json_value
{
$$ = dbmfStrcat3($1, ":", $3);
dbmfFree($1); dbmfFree($3);
if (dbStaticDebug>2) printf("json %s\n", $$);
};
json_array: '[' ']'
{
$$ = "[]";
if (dbStaticDebug>2) printf("json %s\n", $$);
}
| '[' json_elements ']'
{
$$ = dbmfStrcat3("[", $2, "]");
dbmfFree($2);
if (dbStaticDebug>2) printf("json %s\n", $$);
};
json_elements: json_value
| json_value ',' json_elements
{
$$ = dbmfStrcat3($1, ",", $3);
dbmfFree($1); dbmfFree($3);
if (dbStaticDebug>2) printf("json %s\n", $$);
};
json_value: jsonNULL { $$ = "null"; }
| jsonTRUE { $$ = "true"; }
| jsonFALSE { $$ = "false"; }
| jsonNUMBER
| jsonSTRING
| json_array
| json_object ;
%%