mirror of https://github.com/tstack/lnav
[jsonptr] initial impl
parent
7e0a218dc0
commit
1974e1f1ae
@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file json-extension-functions.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "sqlite3.h"
|
||||
|
||||
#include "json_op.hh"
|
||||
|
||||
#include "sqlite-extension-func.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class sql_json_op : public json_op {
|
||||
public:
|
||||
sql_json_op(json_ptr &ptr) : json_op(ptr), sjo_type(-1) { };
|
||||
|
||||
int sjo_type;
|
||||
string sjo_str;
|
||||
int sjo_int;
|
||||
};
|
||||
|
||||
static void printer(void *ctx, const char *numberVal, size_t numberLen)
|
||||
{
|
||||
string &str = *(string *)ctx;
|
||||
|
||||
str.append(numberVal, numberLen);
|
||||
}
|
||||
|
||||
static void null_or_default(sqlite3_context *context, int argc, sqlite3_value **argv)
|
||||
{
|
||||
if (argc > 2) {
|
||||
sqlite3_result_value(context, argv[2]);
|
||||
}
|
||||
else {
|
||||
sqlite3_result_null(context);
|
||||
}
|
||||
}
|
||||
|
||||
static int gen_handle_null(void *ctx)
|
||||
{
|
||||
sql_json_op *sjo = (sql_json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)sjo->jo_ptr_data;
|
||||
|
||||
if (sjo->jo_ptr.jp_state == json_ptr::MS_DONE) {
|
||||
sjo->sjo_type = SQLITE_NULL;
|
||||
}
|
||||
else {
|
||||
sjo->jo_ptr_error_code = yajl_gen_null(gen);
|
||||
}
|
||||
|
||||
return sjo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_boolean(void *ctx, int boolVal)
|
||||
{
|
||||
sql_json_op *sjo = (sql_json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)sjo->jo_ptr_data;
|
||||
|
||||
if (sjo->jo_ptr.jp_state == json_ptr::MS_DONE) {
|
||||
sjo->sjo_type = SQLITE_INTEGER;
|
||||
sjo->sjo_int = boolVal;
|
||||
}
|
||||
else {
|
||||
sjo->jo_ptr_error_code = yajl_gen_bool(gen, boolVal);
|
||||
}
|
||||
|
||||
return sjo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_string(void *ctx, const unsigned char * stringVal, size_t len)
|
||||
{
|
||||
sql_json_op *sjo = (sql_json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)sjo->jo_ptr_data;
|
||||
|
||||
if (sjo->jo_ptr.jp_state == json_ptr::MS_DONE) {
|
||||
sjo->sjo_type = SQLITE3_TEXT;
|
||||
sjo->sjo_str = string((char *)stringVal, len);
|
||||
}
|
||||
else {
|
||||
sjo->jo_ptr_error_code = yajl_gen_string(gen, stringVal, len);
|
||||
}
|
||||
|
||||
return sjo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static void sql_jget(sqlite3_context *context,
|
||||
int argc, sqlite3_value **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
sqlite3_result_error(context, "expecting JSON value and pointer", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
|
||||
null_or_default(context, argc, argv);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *json_in = (const char *)sqlite3_value_text(argv[0]);
|
||||
|
||||
if (sqlite3_value_type(argv[1]) == SQLITE_NULL) {
|
||||
sqlite3_result_text(context, json_in, -1, SQLITE_TRANSIENT);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *ptr_in = (const char *)sqlite3_value_text(argv[1]);
|
||||
json_ptr jp(ptr_in);
|
||||
sql_json_op jo(jp);
|
||||
auto_mem<yajl_gen_t> gen(yajl_gen_free);
|
||||
auto_mem<yajl_handle_t> handle(yajl_free);
|
||||
const unsigned char *err;
|
||||
string result;
|
||||
|
||||
gen = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(gen.in(), yajl_gen_print_callback, printer, &result);
|
||||
yajl_gen_config(gen.in(), yajl_gen_beautify, false);
|
||||
|
||||
jo.jo_ptr_callbacks = json_op::gen_callbacks;
|
||||
jo.jo_ptr_callbacks.yajl_null = gen_handle_null;
|
||||
jo.jo_ptr_callbacks.yajl_boolean = gen_handle_boolean;
|
||||
jo.jo_ptr_callbacks.yajl_string = gen_handle_string;
|
||||
jo.jo_ptr_data = gen.in();
|
||||
|
||||
handle.reset(yajl_alloc(&json_op::ptr_callbacks, NULL, &jo));
|
||||
switch (yajl_parse(handle.in(), (const unsigned char *)json_in, strlen(json_in))) {
|
||||
case yajl_status_error:
|
||||
err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in));
|
||||
sqlite3_result_error(context, (const char *)err, -1);
|
||||
return;
|
||||
case yajl_status_client_canceled:
|
||||
if (jo.jo_ptr.jp_state == json_ptr::MS_ERR_INVALID_ESCAPE) {
|
||||
sqlite3_result_error(context, jo.jo_ptr.error_msg().c_str(), -1);
|
||||
}
|
||||
else {
|
||||
null_or_default(context, argc, argv);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (yajl_complete_parse(handle.in())) {
|
||||
case yajl_status_error:
|
||||
err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in));
|
||||
sqlite3_result_error(context, (const char *)err, -1);
|
||||
return;
|
||||
case yajl_status_client_canceled:
|
||||
if (jo.jo_ptr.jp_state == json_ptr::MS_ERR_INVALID_ESCAPE) {
|
||||
sqlite3_result_error(context, jo.jo_ptr.error_msg().c_str(), -1);
|
||||
}
|
||||
else {
|
||||
null_or_default(context, argc, argv);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (jo.sjo_type) {
|
||||
case SQLITE3_TEXT:
|
||||
sqlite3_result_text(context, jo.sjo_str.c_str(), jo.sjo_str.size(), SQLITE_TRANSIENT);
|
||||
return;
|
||||
case SQLITE_NULL:
|
||||
sqlite3_result_null(context);
|
||||
return;
|
||||
case SQLITE_INTEGER:
|
||||
sqlite3_result_int(context, jo.sjo_int);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.empty()) {
|
||||
null_or_default(context, argc, argv);
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3_result_text(context, result.c_str(), result.size(), SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
int json_extension_functions(const struct FuncDef **basic_funcs,
|
||||
const struct FuncDefAgg **agg_funcs)
|
||||
{
|
||||
static const struct FuncDef fs_funcs[] = {
|
||||
{ "jget", -1, 0, SQLITE_UTF8, 0, sql_jget },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
*basic_funcs = fs_funcs;
|
||||
*agg_funcs = NULL;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
@ -0,0 +1,295 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file json_op.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "json_op.hh"
|
||||
#include "lnav_log.hh"
|
||||
|
||||
static int gen_handle_start_map(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_map_open(gen);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_map_key(void *ctx, const unsigned char * key, size_t len)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_string(gen, key, len);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_end_map(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_map_close(gen);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_null(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_null(gen);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_boolean(void *ctx, int boolVal)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_bool(gen, boolVal);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_number(void *ctx, const char *numberVal, size_t numberLen)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_number(gen, numberVal, numberLen);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_string(void *ctx, const unsigned char * stringVal, size_t len)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_string(gen, stringVal, len);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_start_array(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_array_open(gen);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static int gen_handle_end_array(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
jo->jo_ptr_error_code = yajl_gen_array_close(gen);
|
||||
|
||||
return jo->jo_ptr_error_code == yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
const yajl_callbacks json_op::gen_callbacks = {
|
||||
gen_handle_null,
|
||||
gen_handle_boolean,
|
||||
NULL,
|
||||
NULL,
|
||||
gen_handle_number,
|
||||
gen_handle_string,
|
||||
gen_handle_start_map,
|
||||
gen_handle_map_key,
|
||||
gen_handle_end_map,
|
||||
gen_handle_start_array,
|
||||
gen_handle_end_array,
|
||||
};
|
||||
|
||||
const yajl_callbacks json_op::ptr_callbacks = {
|
||||
handle_null,
|
||||
handle_boolean,
|
||||
NULL,
|
||||
NULL,
|
||||
handle_number,
|
||||
handle_string,
|
||||
handle_start_map,
|
||||
handle_map_key,
|
||||
handle_end_map,
|
||||
handle_start_array,
|
||||
handle_end_array,
|
||||
};
|
||||
|
||||
int json_op::handle_null(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index()) {
|
||||
if (jo->jo_ptr_callbacks.yajl_null != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_null(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_boolean(void *ctx, int boolVal)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index()) {
|
||||
if (jo->jo_ptr_callbacks.yajl_boolean != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_boolean(ctx, boolVal);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_number(void *ctx, const char *numberVal, size_t numberLen)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index()) {
|
||||
if (jo->jo_ptr_callbacks.yajl_number != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_number(ctx, numberVal, numberLen);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_string(void *ctx, const unsigned char *stringVal, size_t stringLen)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index()) {
|
||||
if (jo->jo_ptr_callbacks.yajl_string != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_string(ctx, stringVal, stringLen);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_start_map(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index(false)) {
|
||||
if (jo->jo_ptr_callbacks.yajl_start_map != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_start_map(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!jo->jo_ptr.expect_map(jo->jo_depth)) {
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_map_key(void *ctx, const unsigned char * key, size_t len)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index(false)) {
|
||||
if (jo->jo_ptr_callbacks.yajl_map_key != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_map_key(ctx, key, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!jo->jo_ptr.at_key(jo->jo_depth, (const char *)key, len)) {
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_end_map(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index()) {
|
||||
if (jo->jo_ptr_callbacks.yajl_end_map != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_end_map(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
jo->jo_ptr.exit_container(jo->jo_depth, jo->jo_array_index);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_start_array(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index(false)) {
|
||||
if (jo->jo_ptr_callbacks.yajl_start_array != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_start_array(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if (!jo->jo_ptr.expect_array(jo->jo_depth, jo->jo_array_index)) {
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int json_op::handle_end_array(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
int retval = 1;
|
||||
|
||||
if (jo->check_index()) {
|
||||
if (jo->jo_ptr_callbacks.yajl_end_array != NULL) {
|
||||
retval = jo->jo_ptr_callbacks.yajl_end_array(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
jo->jo_ptr.exit_container(jo->jo_depth, jo->jo_array_index);
|
||||
|
||||
return retval;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file json_op.hh
|
||||
*/
|
||||
|
||||
#ifndef __json_op_hh
|
||||
#define __json_op_hh
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "json_ptr.hh"
|
||||
#include "yajlpp.hh"
|
||||
|
||||
class json_op {
|
||||
static int handle_null(void *ctx);
|
||||
static int handle_boolean(void *ctx, int boolVal);
|
||||
static int handle_number(void *ctx, const char *numberVal, size_t numberLen);
|
||||
static int handle_string(void *ctx, const unsigned char * stringVal, size_t len);
|
||||
static int handle_start_map(void *ctx);
|
||||
static int handle_map_key(void *ctx, const unsigned char * key, size_t len);
|
||||
static int handle_end_map(void *ctx);
|
||||
static int handle_start_array(void *ctx);
|
||||
static int handle_end_array(void *ctx);
|
||||
|
||||
public:
|
||||
|
||||
const static yajl_callbacks gen_callbacks;
|
||||
const static yajl_callbacks ptr_callbacks;
|
||||
|
||||
json_op(json_ptr &ptr)
|
||||
: jo_depth(0),
|
||||
jo_array_index(-1),
|
||||
jo_ptr(ptr),
|
||||
jo_ptr_data(NULL),
|
||||
jo_ptr_error_code(0) {
|
||||
memset(&this->jo_ptr_callbacks, 0, sizeof(this->jo_ptr_callbacks));
|
||||
};
|
||||
|
||||
bool check_index(bool primitive = true) {
|
||||
return this->jo_ptr.at_index(this->jo_depth, this->jo_array_index, primitive);
|
||||
};
|
||||
|
||||
int jo_depth;
|
||||
int jo_array_index;
|
||||
|
||||
json_ptr jo_ptr;
|
||||
yajl_callbacks jo_ptr_callbacks;
|
||||
void *jo_ptr_data;
|
||||
std::string jo_ptr_error;
|
||||
int jo_ptr_error_code;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file json_ptr.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "json_ptr.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int handle_null(void *ctx)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), "null"));
|
||||
jpw->inc_array_index();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_boolean(void *ctx, int boolVal)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), boolVal ? "true" : "false"));
|
||||
jpw->inc_array_index();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_number(void *ctx, const char *numberVal, size_t numberLen)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), string(numberVal, numberLen)));
|
||||
jpw->inc_array_index();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void appender(void *ctx, const char *strVal, size_t strLen)
|
||||
{
|
||||
string &str = *(string *)ctx;
|
||||
|
||||
str.append(strVal, strLen);
|
||||
}
|
||||
|
||||
static int handle_string(void *ctx, const unsigned char * stringVal, size_t len)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
auto_mem<yajl_gen_t> gen(yajl_gen_free);
|
||||
string str;
|
||||
|
||||
gen = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(gen.in(), yajl_gen_print_callback, appender, &str);
|
||||
yajl_gen_string(gen.in(), stringVal, len);
|
||||
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), str));
|
||||
jpw->inc_array_index();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_start_map(void *ctx)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_keys.push_back("");
|
||||
jpw->jpw_array_indexes.push_back(-1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_map_key(void *ctx, const unsigned char * key, size_t len)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
char partially_encoded_key[len + 32];
|
||||
size_t required_len;
|
||||
|
||||
jpw->jpw_keys.pop_back();
|
||||
|
||||
required_len = json_ptr::encode(partially_encoded_key, sizeof(partially_encoded_key),
|
||||
(const char *)key, len);
|
||||
if (required_len < sizeof(partially_encoded_key)) {
|
||||
jpw->jpw_keys.push_back(string(partially_encoded_key, required_len));
|
||||
}
|
||||
else {
|
||||
char fully_encoded_key[required_len];
|
||||
|
||||
json_ptr::encode(fully_encoded_key, sizeof(fully_encoded_key),
|
||||
(const char *)key, len);
|
||||
jpw->jpw_keys.push_back(string(fully_encoded_key, required_len));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_end_map(void *ctx)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_keys.pop_back();
|
||||
jpw->jpw_array_indexes.pop_back();
|
||||
|
||||
jpw->inc_array_index();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_start_array(void *ctx)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_keys.push_back("");
|
||||
jpw->jpw_array_indexes.push_back(0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_end_array(void *ctx)
|
||||
{
|
||||
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
|
||||
|
||||
jpw->jpw_keys.pop_back();
|
||||
jpw->jpw_array_indexes.pop_back();
|
||||
jpw->inc_array_index();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const yajl_callbacks json_ptr_walk::callbacks = {
|
||||
handle_null,
|
||||
handle_boolean,
|
||||
NULL,
|
||||
NULL,
|
||||
handle_number,
|
||||
handle_string,
|
||||
handle_start_map,
|
||||
handle_map_key,
|
||||
handle_end_map,
|
||||
handle_start_array,
|
||||
handle_end_array
|
||||
};
|
@ -0,0 +1,380 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file json_ptr.hh
|
||||
*/
|
||||
|
||||
#ifndef __json_ptr_hh
|
||||
#define __json_ptr_hh
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "yajlpp.hh"
|
||||
#include "lnav_log.hh"
|
||||
|
||||
class json_ptr_walk {
|
||||
public:
|
||||
const static yajl_callbacks callbacks;
|
||||
|
||||
json_ptr_walk() : jpw_handle(yajl_free) {
|
||||
this->jpw_handle = yajl_alloc(&callbacks, NULL, this);
|
||||
};
|
||||
|
||||
yajl_status parse(const char *buffer, ssize_t len) {
|
||||
yajl_status retval;
|
||||
|
||||
retval = yajl_parse(this->jpw_handle, (const unsigned char *)buffer, len);
|
||||
this->update_error_msg(retval, buffer, len);
|
||||
return retval;
|
||||
};
|
||||
|
||||
yajl_status complete_parse() {
|
||||
yajl_status retval;
|
||||
|
||||
retval = yajl_complete_parse(this->jpw_handle);
|
||||
this->update_error_msg(retval, NULL, -1);
|
||||
return retval;
|
||||
};
|
||||
|
||||
void update_error_msg(yajl_status status, const char *buffer, ssize_t len) {
|
||||
switch (status) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
this->jpw_error_msg = "internal error";
|
||||
break;
|
||||
case yajl_status_error:
|
||||
this->jpw_error_msg = std::string((const char *)yajl_get_error(
|
||||
this->jpw_handle, 1, (const unsigned char *)buffer, len));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void clear() {
|
||||
this->jpw_values.clear();
|
||||
};
|
||||
|
||||
void inc_array_index() {
|
||||
if (!this->jpw_array_indexes.empty() &&
|
||||
this->jpw_array_indexes.back() != -1) {
|
||||
this->jpw_array_indexes.back() += 1;
|
||||
}
|
||||
};
|
||||
|
||||
std::string current_ptr() {
|
||||
std::string retval;
|
||||
|
||||
for (int lpc = 0; lpc < this->jpw_array_indexes.size(); lpc++) {
|
||||
retval.append("/");
|
||||
if (this->jpw_array_indexes[lpc] == -1) {
|
||||
retval.append(this->jpw_keys[lpc]);
|
||||
}
|
||||
else {
|
||||
char num[64];
|
||||
|
||||
snprintf(num, sizeof(num), "%d", this->jpw_array_indexes[lpc]);
|
||||
retval.append(num);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
typedef std::vector<std::pair<std::string, std::string> > pair_list_t;
|
||||
|
||||
auto_mem<yajl_handle_t> jpw_handle;
|
||||
std::string jpw_error_msg;
|
||||
pair_list_t jpw_values;
|
||||
std::vector<std::string> jpw_keys;
|
||||
std::vector<int32_t> jpw_array_indexes;
|
||||
};
|
||||
|
||||
class json_ptr {
|
||||
public:
|
||||
enum match_state_t {
|
||||
MS_DONE,
|
||||
MS_VALUE,
|
||||
MS_ELEMENT,
|
||||
MS_ERR_INVALID_TYPE,
|
||||
MS_ERR_NO_SLASH,
|
||||
MS_ERR_INVALID_ESCAPE,
|
||||
MS_ERR_INVALID_INDEX,
|
||||
};
|
||||
|
||||
static size_t encode(char *dst, size_t dst_len, const char *src, size_t src_len = -1) {
|
||||
size_t retval = 0;
|
||||
|
||||
if (src_len == -1) {
|
||||
src_len = strlen(src);
|
||||
}
|
||||
|
||||
for (size_t lpc = 0; lpc < src_len; lpc++) {
|
||||
switch (src[lpc]) {
|
||||
case '/':
|
||||
case '~':
|
||||
if (retval < dst_len) {
|
||||
dst[retval] = '~';
|
||||
retval += 1;
|
||||
if (src[lpc] == '~') {
|
||||
dst[retval] = '0';
|
||||
}
|
||||
else {
|
||||
dst[retval] = '1';
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval += 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (retval < dst_len) {
|
||||
dst[retval] = src[lpc];
|
||||
}
|
||||
break;
|
||||
}
|
||||
retval += 1;
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
json_ptr(const char *value)
|
||||
: jp_value(value), jp_pos(value), jp_depth(0), jp_array_index(-1),
|
||||
jp_state(MS_VALUE) {
|
||||
|
||||
};
|
||||
|
||||
bool expect_map(int32_t &depth) {
|
||||
bool retval;
|
||||
|
||||
if (this->jp_state == MS_DONE) {
|
||||
retval = true;
|
||||
}
|
||||
else if (depth != this->jp_depth) {
|
||||
retval = true;
|
||||
}
|
||||
else if (this->reached_end()) {
|
||||
retval = true;
|
||||
}
|
||||
else if (this->jp_state == MS_VALUE) {
|
||||
if (this->jp_pos[0] == '/') {
|
||||
this->jp_pos += 1;
|
||||
this->jp_depth += 1;
|
||||
this->jp_state = MS_ELEMENT;
|
||||
retval = true;
|
||||
}
|
||||
else {
|
||||
this->jp_state = MS_ERR_NO_SLASH;
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval = true;
|
||||
}
|
||||
depth += 1;
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
bool at_key(int32_t depth, const char *component, ssize_t len = -1) {
|
||||
const char *component_end;
|
||||
int lpc;
|
||||
|
||||
if (this->jp_state == MS_DONE || depth != this->jp_depth) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (len == -1) {
|
||||
len = strlen(component);
|
||||
}
|
||||
component_end = component + len;
|
||||
|
||||
for (lpc = 0; component < component_end; lpc++, component++) {
|
||||
char ch = this->jp_pos[lpc];
|
||||
|
||||
if (this->jp_pos[lpc] == '~') {
|
||||
switch (this->jp_pos[lpc + 1]) {
|
||||
case '0':
|
||||
ch = '~';
|
||||
break;
|
||||
case '1':
|
||||
ch = '/';
|
||||
break;
|
||||
default:
|
||||
this->jp_state = MS_ERR_INVALID_ESCAPE;
|
||||
return false;
|
||||
}
|
||||
lpc += 1;
|
||||
}
|
||||
else if (this->jp_pos[lpc] == '/') {
|
||||
ch = '\0';
|
||||
}
|
||||
|
||||
if (ch != *component) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this->jp_pos += lpc;
|
||||
this->jp_state = MS_VALUE;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
void exit_container(int32_t &depth, int32_t &index) {
|
||||
depth -= 1;
|
||||
if (this->jp_state == MS_VALUE && depth == this->jp_depth) {
|
||||
this->jp_state = MS_DONE;
|
||||
index = -1;
|
||||
}
|
||||
};
|
||||
|
||||
bool expect_array(int32_t &depth, int32_t &index) {
|
||||
bool retval;
|
||||
|
||||
if (this->jp_state == MS_DONE) {
|
||||
retval = true;
|
||||
}
|
||||
else if (depth != this->jp_depth) {
|
||||
retval = true;
|
||||
}
|
||||
else if (this->reached_end()) {
|
||||
retval = true;
|
||||
}
|
||||
else if (this->jp_pos[0] == '/') {
|
||||
int offset;
|
||||
|
||||
this->jp_depth += 1;
|
||||
|
||||
if (sscanf(this->jp_pos, "/%d%n", &this->jp_array_index, &offset) != 1) {
|
||||
this->jp_state = MS_ERR_INVALID_INDEX;
|
||||
retval = false;
|
||||
}
|
||||
else if (this->jp_pos[offset] != '\0' && this->jp_pos[offset] != '/') {
|
||||
this->jp_state = MS_ERR_INVALID_INDEX;
|
||||
retval = false;
|
||||
}
|
||||
else {
|
||||
index = 0;
|
||||
this->jp_pos += offset;
|
||||
this->jp_state = MS_ELEMENT;
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this->jp_state = MS_ERR_NO_SLASH;
|
||||
retval = false;
|
||||
}
|
||||
|
||||
depth += 1;
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
bool at_index(int32_t &depth, int32_t &index, bool primitive = true) {
|
||||
bool retval;
|
||||
|
||||
if (this->jp_state == MS_DONE) {
|
||||
retval = false;
|
||||
}
|
||||
else if (depth < this->jp_depth) {
|
||||
retval = false;
|
||||
}
|
||||
else if (depth == this->jp_depth) {
|
||||
if (index == -1) {
|
||||
if (this->jp_array_index == -1) {
|
||||
retval = this->reached_end();
|
||||
if (primitive && retval) {
|
||||
this->jp_state = MS_DONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else if (index == this->jp_array_index) {
|
||||
retval = this->reached_end();
|
||||
index = -1;
|
||||
if (primitive && retval) {
|
||||
this->jp_state = MS_DONE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
index += 1;
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else if (index == -1) {
|
||||
retval = this->reached_end();
|
||||
}
|
||||
else {
|
||||
retval = false;
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
bool reached_end() {
|
||||
return this->jp_pos[0] == '\0';
|
||||
};
|
||||
|
||||
std::string error_msg() const {
|
||||
std::string retval;
|
||||
|
||||
switch (this->jp_state) {
|
||||
case MS_ERR_INVALID_ESCAPE:
|
||||
retval = ("invalid escape sequence near -- " + std::string(this->jp_pos));
|
||||
break;
|
||||
case MS_ERR_INVALID_INDEX:
|
||||
retval = ("expecting array index at -- " + std::string(this->jp_pos));
|
||||
break;
|
||||
case MS_ERR_INVALID_TYPE:
|
||||
retval = ("expecting container at -- " + std::string(
|
||||
this->jp_value, this->jp_pos - this->jp_value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
const char *jp_value;
|
||||
const char *jp_pos;
|
||||
int32_t jp_depth;
|
||||
int32_t jp_array_index;
|
||||
match_state_t jp_state;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file drive_json_op.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "json_op.hh"
|
||||
|
||||
static void printer(void *ctx, const char *numberVal, size_t numberLen)
|
||||
{
|
||||
write(STDOUT_FILENO, numberVal, numberLen);
|
||||
}
|
||||
|
||||
static int handle_start_map(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_map_open(gen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_map_key(void *ctx, const unsigned char * key, size_t len)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_string(gen, key, len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_end_map(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_map_close(gen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_null(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_null(gen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_boolean(void *ctx, int boolVal)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_bool(gen, boolVal);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_number(void *ctx, const char *numberVal, size_t numberLen)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_number(gen, numberVal, numberLen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_string(void *ctx, const unsigned char * stringVal, size_t len)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_string(gen, stringVal, len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_start_array(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_array_open(gen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int handle_end_array(void *ctx)
|
||||
{
|
||||
json_op *jo = (json_op *)ctx;
|
||||
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
|
||||
|
||||
yajl_gen_array_close(gen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
log_argv(argc, argv);
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "error: expecting operation and json-pointer\n");
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
else if (strcmp(argv[1], "get") == 0) {
|
||||
unsigned char buffer[1024];
|
||||
json_ptr jptr(argv[2]);
|
||||
json_op jo(jptr);
|
||||
yajl_handle handle;
|
||||
yajl_status status;
|
||||
yajl_gen gen;
|
||||
ssize_t rc;
|
||||
|
||||
gen = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(gen, yajl_gen_print_callback, printer, NULL);
|
||||
yajl_gen_config(gen, yajl_gen_beautify, true);
|
||||
|
||||
jo.jo_ptr_callbacks.yajl_start_map = handle_start_map;
|
||||
jo.jo_ptr_callbacks.yajl_map_key = handle_map_key;
|
||||
jo.jo_ptr_callbacks.yajl_end_map = handle_end_map;
|
||||
jo.jo_ptr_callbacks.yajl_start_array = handle_start_array;
|
||||
jo.jo_ptr_callbacks.yajl_end_array = handle_end_array;
|
||||
jo.jo_ptr_callbacks.yajl_null = handle_null;
|
||||
jo.jo_ptr_callbacks.yajl_boolean = handle_boolean;
|
||||
jo.jo_ptr_callbacks.yajl_number = handle_number;
|
||||
jo.jo_ptr_callbacks.yajl_string = handle_string;
|
||||
jo.jo_ptr_data = gen;
|
||||
|
||||
handle = yajl_alloc(&json_op::ptr_callbacks, NULL, &jo);
|
||||
while ((rc = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
|
||||
status = yajl_parse(handle, buffer, rc);
|
||||
if (status == yajl_status_error) {
|
||||
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
|
||||
yajl_get_error(handle, 1, buffer, rc));
|
||||
retval = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
else if (status == yajl_status_client_canceled) {
|
||||
fprintf(stderr, "client cancel\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = yajl_complete_parse(handle);
|
||||
if (status == yajl_status_error) {
|
||||
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
|
||||
yajl_get_error(handle, 1, buffer, rc));
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
else if (status == yajl_status_client_canceled) {
|
||||
fprintf(stderr, "client cancel\n");
|
||||
}
|
||||
yajl_free(handle);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "error: unknown operation -- %s\n", argv[1]);
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file drive_json_ptr_dump.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "json_ptr.hh"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
char buffer[1024];
|
||||
yajl_status status;
|
||||
json_ptr_walk jpw;
|
||||
ssize_t rc;
|
||||
|
||||
log_argv(argc, argv);
|
||||
|
||||
while ((rc = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
|
||||
status = jpw.parse(buffer, rc);
|
||||
if (status == yajl_status_error) {
|
||||
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
|
||||
jpw.jpw_error_msg.c_str());
|
||||
retval = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
else if (status == yajl_status_client_canceled) {
|
||||
fprintf(stderr, "client cancel\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
status = jpw.complete_parse();
|
||||
if (status == yajl_status_error) {
|
||||
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
|
||||
jpw.jpw_error_msg.c_str());
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
else if (status == yajl_status_client_canceled) {
|
||||
fprintf(stderr, "client cancel\n");
|
||||
}
|
||||
|
||||
for (json_ptr_walk::pair_list_t::iterator iter = jpw.jpw_values.begin();
|
||||
iter != jpw.jpw_values.end();
|
||||
++iter) {
|
||||
printf("%s = %s\n", iter->first.c_str(), iter->second.c_str());
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
#! /bin/bash
|
||||
|
||||
run_test ./drive_json_op get "" <<EOF
|
||||
3
|
||||
EOF
|
||||
|
||||
check_output "cannot read root number value" <<EOF
|
||||
3
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get "" <<EOF
|
||||
null
|
||||
EOF
|
||||
|
||||
check_output "cannot read root null value" <<EOF
|
||||
null
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get "" <<EOF
|
||||
true
|
||||
EOF
|
||||
|
||||
check_output "cannot read root bool value" <<EOF
|
||||
true
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get "" <<EOF
|
||||
"str"
|
||||
EOF
|
||||
|
||||
check_output "cannot read root string value" <<EOF
|
||||
"str"
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get "" <<EOF
|
||||
{ "val" : 3, "other" : 2 }
|
||||
EOF
|
||||
|
||||
check_output "cannot read root map value" <<EOF
|
||||
{
|
||||
"val": 3,
|
||||
"other": 2
|
||||
}
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get /val <<EOF
|
||||
{ "val" : 3 }
|
||||
EOF
|
||||
|
||||
check_output "cannot read top-level value" <<EOF
|
||||
3
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get /val <<EOF
|
||||
{ "other" : { "val" : 5 }, "val" : 3 }
|
||||
EOF
|
||||
|
||||
check_output "read wrong value" <<EOF
|
||||
3
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get /other <<EOF
|
||||
{ "other" : { "val" : 5 }, "val" : 3 }
|
||||
EOF
|
||||
|
||||
check_output "cannot read map" <<EOF
|
||||
{
|
||||
"val": 5
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
run_test ./drive_json_op get "" <<EOF
|
||||
[0, 1]
|
||||
EOF
|
||||
|
||||
check_output "cannot read root array value" <<EOF
|
||||
[
|
||||
0,
|
||||
1
|
||||
]
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get "/6" <<EOF
|
||||
[null, true, 1, "str", {"sub":[10, 11]}, [21, [33, 34], 66], 2]
|
||||
EOF
|
||||
|
||||
check_output "cannot read array value" <<EOF
|
||||
2
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_op get "/ID" <<EOF
|
||||
{"ID":"P1","ProcessID":"P1","Name":"VxWorks","CanSuspend":true,"CanResume":1,"IsContainer":true,"WordSize":4,"CanTerminate":true,"CanDetach":true,"RCGroup":"P1","SymbolsGroup":"P1","CPUGroup":"P1","DiagnosticTestProcess":true}
|
||||
EOF
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Timothy Stack
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @file test_json_ptr.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "json_ptr.hh"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
int32_t depth, index;
|
||||
|
||||
{
|
||||
json_ptr jptr("");
|
||||
|
||||
depth = 0;
|
||||
index = -1;
|
||||
assert(jptr.at_index(depth, index));
|
||||
}
|
||||
|
||||
{
|
||||
json_ptr jptr("/");
|
||||
|
||||
depth = 0;
|
||||
index = -1;
|
||||
assert(!jptr.at_index(depth, index));
|
||||
assert(jptr.expect_map(depth));
|
||||
assert(jptr.at_index(depth, index));
|
||||
}
|
||||
|
||||
{
|
||||
json_ptr jptr("/foo/bar");
|
||||
|
||||
depth = 0;
|
||||
index = -1;
|
||||
assert(jptr.expect_map(depth));
|
||||
assert(jptr.at_key(depth, "foo"));
|
||||
assert(jptr.expect_map(depth));
|
||||
assert(jptr.at_key(depth, "bar"));
|
||||
assert(jptr.at_index(depth, index));
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
#! /bin/bash
|
||||
|
||||
run_test ./drive_json_ptr_walk <<EOF
|
||||
{ "foo" : 1 }
|
||||
EOF
|
||||
|
||||
check_output "simple object" <<EOF
|
||||
/foo = 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_ptr_walk <<EOF
|
||||
{ "~tstack/julia" : 1 }
|
||||
EOF
|
||||
|
||||
check_output "escaped object" <<EOF
|
||||
/~0tstack~1julia = 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_ptr_walk <<EOF
|
||||
1
|
||||
EOF
|
||||
|
||||
check_output "root value" <<EOF
|
||||
= 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_ptr_walk <<EOF
|
||||
[1, 2, 3]
|
||||
EOF
|
||||
|
||||
check_output "array" <<EOF
|
||||
/0 = 1
|
||||
/1 = 2
|
||||
/2 = 3
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_ptr_walk <<EOF
|
||||
[1, 2, 3, [4, 5, 6]]
|
||||
EOF
|
||||
|
||||
check_output "nested array" <<EOF
|
||||
/0 = 1
|
||||
/1 = 2
|
||||
/2 = 3
|
||||
/3/0 = 4
|
||||
/3/1 = 5
|
||||
/3/2 = 6
|
||||
EOF
|
||||
|
||||
run_test ./drive_json_ptr_walk <<EOF
|
||||
[null, true, 123.0, "foo", { "bar" : { "baz" : [1, 2, 3]} }, ["a", null]]
|
||||
EOF
|
||||
|
||||
check_error_output "" <<EOF
|
||||
EOF
|
||||
|
||||
check_output "complex" <<EOF
|
||||
/0 = null
|
||||
/1 = true
|
||||
/2 = 123.0
|
||||
/3 = "foo"
|
||||
/4/bar/baz/0 = 1
|
||||
/4/bar/baz/1 = 2
|
||||
/4/bar/baz/2 = 3
|
||||
/5/0 = "a"
|
||||
/5/1 = null
|
||||
EOF
|
@ -0,0 +1,55 @@
|
||||
#! /bin/bash
|
||||
|
||||
run_test ./drive_sql "select jget('4', '')"
|
||||
|
||||
check_output "jget root does not work" <<EOF
|
||||
Row 0:
|
||||
Column jget('4', ''): 4
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select jget('4', null)"
|
||||
|
||||
check_output "jget null does not work" <<EOF
|
||||
Row 0:
|
||||
Column jget('4', null): 4
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/3')"
|
||||
|
||||
check_error_output "" <<EOF
|
||||
EOF
|
||||
|
||||
check_output "jget null does not work" <<EOF
|
||||
Row 0:
|
||||
Column jget('[null, true, 20, 30, 40]', '/3'): 30
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/abc')"
|
||||
|
||||
check_error_output "" <<EOF
|
||||
EOF
|
||||
|
||||
check_output "jget for array does not work" <<EOF
|
||||
Row 0:
|
||||
Column jget('[null, true, 20, 30, 40]', '/abc'): (null)
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/abc', 1)"
|
||||
|
||||
check_error_output "" <<EOF
|
||||
EOF
|
||||
|
||||
check_output "jget for array does not work" <<EOF
|
||||
Row 0:
|
||||
Column jget('[null, true, 20, 30, 40]', '/abc', 1): 1
|
||||
EOF
|
||||
|
||||
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/0/foo')"
|
||||
|
||||
check_error_output "" <<EOF
|
||||
EOF
|
||||
|
||||
check_output "jget for array does not work" <<EOF
|
||||
Row 0:
|
||||
Column jget('[null, true, 20, 30, 40]', '/0/foo'): (null)
|
||||
EOF
|
Loading…
Reference in New Issue