handle yajl 2.1.0 API changes
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -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) );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user