handle yajl 2.1.0 API changes

This commit is contained in:
Michael Davidsaver
2017-10-31 17:45:40 -05:00
parent e247a2c4eb
commit 51cbe538e8
5 changed files with 79 additions and 25 deletions

View File

@@ -15,6 +15,8 @@
#include "pv/json.h"
namespace pvd = epics::pvData;
using pvd::yajl::integer_arg;
using pvd::yajl::size_arg;
namespace {
@@ -77,7 +79,7 @@ int jtree_boolean(void * ctx, int boolVal)
}CATCH()
}
int jtree_integer(void * ctx, long integerVal)
int jtree_integer(void * ctx, integer_arg integerVal)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare value not supported");
@@ -130,7 +132,7 @@ int jtree_double(void * ctx, double doubleVal)
}
int jtree_string(void * ctx, const unsigned char * stringVal,
unsigned int stringLen)
size_arg stringLen)
{
TRY {
if(self->depth==0) throw std::runtime_error("Bare value not supported");
@@ -172,7 +174,7 @@ int jtree_start_map(void * ctx)
}
int jtree_map_key(void * ctx, const unsigned char * key,
unsigned int stringLen)
size_arg stringLen)
{
TRY {
if(!self->key.empty())
@@ -254,16 +256,24 @@ namespace epics{namespace pvData{
epics::pvData::PVStructure::shared_pointer
parseJSON(std::istream& strm)
{
#ifndef EPICS_YAJL_VERSION
yajl_parser_config conf;
memset(&conf, 0, sizeof(conf));
conf.allowComments = 1;
conf.checkUTF8 = 1;
#endif
context ctxt;
#ifndef EPICS_YAJL_VERSION
handler handle(yajl_alloc(&jtree_cbs, &conf, NULL, &ctxt));
#else
handler handle(yajl_alloc(&jtree_cbs, NULL, &ctxt));
if(!yajl_parse_helper(strm, handle, conf))
yajl_config(handle, yajl_allow_comments, 1);
#endif
if(!yajl_parse_helper(strm, handle))
throw std::runtime_error(ctxt.msg);
return ctxt.cur->buildPVStructure();

View File

@@ -15,7 +15,7 @@
namespace {
void check_trailing(const std::string& line, bool commentok)
void check_trailing(const std::string& line)
{
size_t idx = line.find_first_not_of(" \t\n\r");
if(idx==line.npos) return;
@@ -29,37 +29,46 @@ void check_trailing(const std::string& line, bool commentok)
namespace epics{namespace pvData{
bool yajl_parse_helper(std::istream& src,
yajl_handle handle,
const yajl_parser_config& config)
yajl_handle handle)
{
unsigned linenum=0;
#ifndef EPICS_YAJL_VERSION
bool done = false;
#endif
std::string line;
while(std::getline(src, line)) {
linenum++;
#ifndef EPICS_YAJL_VERSION
if(done) {
check_trailing(line, config.allowComments);
check_trailing(line);
continue;
}
#endif
yajl_status sts = yajl_parse(handle, (const unsigned char*)line.c_str(), line.size());
switch(sts) {
case yajl_status_ok: {
size_t consumed = yajl_get_bytes_consumed(handle);
if(consumed<line.size()) {
check_trailing(line.substr(consumed), config.allowComments);
check_trailing(line.substr(consumed));
}
#ifndef EPICS_YAJL_VERSION
done = true;
#endif
break;
}
case yajl_status_client_canceled:
return false;
#ifndef EPICS_YAJL_VERSION
case yajl_status_insufficient_data:
// continue with next line
break;
#endif
case yajl_status_error:
{
std::ostringstream msg;
@@ -85,15 +94,24 @@ bool yajl_parse_helper(std::istream& src,
msg<<"I/O error after line "<<linenum;
throw std::runtime_error(msg.str());
} else if(!done) switch(yajl_parse_complete(handle)) {
case yajl_status_ok:
break;
case yajl_status_client_canceled:
return false;
case yajl_status_insufficient_data:
throw std::runtime_error("unexpected end of input");
case yajl_status_error:
throw std::runtime_error("Error while completing parsing");
#ifndef EPICS_YAJL_VERSION
} else if(!done) {
switch(yajl_parse_complete(handle)) {
#else
} else {
switch(yajl_complete_parse(handle)) {
#endif
case yajl_status_ok:
break;
case yajl_status_client_canceled:
return false;
#ifndef EPICS_YAJL_VERSION
case yajl_status_insufficient_data:
throw std::runtime_error("unexpected end of input");
#endif
case yajl_status_error:
throw std::runtime_error("Error while completing parsing");
}
}
return true;

View File

@@ -17,6 +17,8 @@
#include "pv/json.h"
namespace pvd = epics::pvData;
using pvd::yajl::integer_arg;
using pvd::yajl::size_arg;
namespace {
struct context {
@@ -148,7 +150,7 @@ int jtree_boolean(void * ctx, int boolVal)
}CATCH()
}
int jtree_integer(void * ctx, long integerVal)
int jtree_integer(void * ctx, integer_arg integerVal)
{
TRY {
valueAssign<pvd::PVLong, pvd::PVLongArray>(self, integerVal);
@@ -165,7 +167,7 @@ int jtree_double(void * ctx, double doubleVal)
}
int jtree_string(void * ctx, const unsigned char * stringVal,
unsigned int stringLen)
size_arg stringLen)
{
TRY {
std::string val((const char*)stringVal, stringLen);
@@ -200,7 +202,7 @@ int jtree_start_map(void * ctx)
}
int jtree_map_key(void * ctx, const unsigned char * key,
unsigned int stringLen)
size_arg stringLen)
{
TRY {
assert(!self->stack.empty());
@@ -309,16 +311,25 @@ void parseJSON(std::istream& strm,
const PVField::shared_pointer& dest,
BitSet *assigned)
{
#ifndef EPICS_YAJL_VERSION
yajl_parser_config conf;
memset(&conf, 0, sizeof(conf));
conf.allowComments = 1;
conf.checkUTF8 = 1;
#endif
context ctxt(dest, assigned);
#ifndef EPICS_YAJL_VERSION
handler handle(yajl_alloc(&jtree_cbs, &conf, NULL, &ctxt));
#else
handler handle(yajl_alloc(&jtree_cbs, NULL, &ctxt));
if(!yajl_parse_helper(strm, handle, conf))
yajl_config(handle, yajl_allow_comments, 1);
#endif
if(!yajl_parse_helper(strm, handle))
throw std::runtime_error(ctxt.msg);
if(!ctxt.stack.empty())

View File

@@ -96,14 +96,25 @@ void parseJSON(std::istream& strm,
*
* @param src The stream from which input charactors are read
* @param handle A parser handle previously allocated with yajl_alloc(). Not free'd on success or failure.
* @param config The same configuration passed to yajl_alloc(). Used to decide if trailing comments are allowed
*
* @returns true if parsing completes successfully. false if parsing cancelled by callback. throws other errors
*
* @note The form of this call depends on EPICS_YAJL_VERSION
*/
epicsShareFunc
bool yajl_parse_helper(std::istream& src,
yajl_handle handle,
const yajl_parser_config& config);
yajl_handle handle);
namespace yajl {
// undef implies API version 0
#ifndef EPICS_YAJL_VERSION
typedef long integer_arg;
typedef unsigned size_arg;
#else
typedef long long integer_arg;
typedef size_t size_arg;
#endif
} // namespace epics::pvData::yajl
/** @} */

View File

@@ -97,12 +97,16 @@ void testparseanyjunk()
{
testThrows(std::runtime_error, std::istringstream strm("{} x"); std::cout<<pvd::parseJSON(strm) );
}
#ifndef EPICS_YAJL_VERSION
{
testThrows(std::runtime_error, std::istringstream strm("{} /* y */"); std::cout<<pvd::parseJSON(strm) );
}
{
testThrows(std::runtime_error, std::istringstream strm("{} /* y *"); std::cout<<pvd::parseJSON(strm) );
}
#else
testSkip(2, "yajl >= 2.1.0 handles trailing comments for us");
#endif
{
testThrows(std::runtime_error, std::istringstream strm("{}\n\n{}"); std::cout<<pvd::parseJSON(strm) );
}