mirror of
https://github.com/tstack/lnav.git
synced 2024-08-17 00:40:30 +03:00
[jsonptr] initial impl
This commit is contained in:
parent
7e0a218dc0
commit
1974e1f1ae
@ -29,6 +29,9 @@ test_num=0
|
||||
lnav_test="${top_builddir}/src/lnav-test"
|
||||
export lnav_test
|
||||
|
||||
LNAV_LOG_PATH="${top_builddir}/test/test.log"
|
||||
export LNAV_LOG_PATH
|
||||
|
||||
## BEGIN Functions
|
||||
|
||||
LAST_TEST=""
|
||||
|
4
configure
vendored
4
configure
vendored
@ -3986,8 +3986,8 @@ fi
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -D_ISOC99_SOURCE -D__STDC_LIMIT_MACROS"
|
||||
|
||||
CFLAGS=`echo $CFLAGS | sed 's/-O2//g'`
|
||||
CXXFLAGS=`echo $CXXFLAGS | sed 's/-O2//g'`
|
||||
# CFLAGS=`echo $CFLAGS | sed 's/-O2//g'`
|
||||
# CXXFLAGS=`echo $CXXFLAGS | sed 's/-O2//g'`
|
||||
|
||||
# Check whether --enable-profiling was given.
|
||||
if test "${enable_profiling+set}" = set; then :
|
||||
|
@ -41,8 +41,8 @@ AC_PROG_CXX
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -D_ISOC99_SOURCE -D__STDC_LIMIT_MACROS"
|
||||
|
||||
CFLAGS=`echo $CFLAGS | sed 's/-O2//g'`
|
||||
CXXFLAGS=`echo $CXXFLAGS | sed 's/-O2//g'`
|
||||
# CFLAGS=`echo $CFLAGS | sed 's/-O2//g'`
|
||||
# CXXFLAGS=`echo $CXXFLAGS | sed 's/-O2//g'`
|
||||
|
||||
AC_ARG_ENABLE([profiling],
|
||||
AS_HELP_STRING([--enable-profiling],
|
||||
|
@ -83,6 +83,8 @@ noinst_HEADERS = \
|
||||
hist_source.hh \
|
||||
init.sql \
|
||||
init-sql.hh \
|
||||
json_op.hh \
|
||||
json_ptr.hh \
|
||||
k_merge_tree.h \
|
||||
line_buffer.hh \
|
||||
listview_curses.hh \
|
||||
@ -148,6 +150,9 @@ libdiag_a_SOURCES = \
|
||||
fs-extension-functions.cc \
|
||||
grep_proc.cc \
|
||||
hist_source.cc \
|
||||
json-extension-functions.cc \
|
||||
json_op.cc \
|
||||
json_ptr.cc \
|
||||
line_buffer.cc \
|
||||
listview_curses.cc \
|
||||
lnav_commands.cc \
|
||||
|
@ -113,11 +113,13 @@ am_libdiag_a_OBJECTS = ansi_scrubber.$(OBJEXT) bookmarks.$(OBJEXT) \
|
||||
collation-functions.$(OBJEXT) db_sub_source.$(OBJEXT) \
|
||||
extension-functions.$(OBJEXT) fs-extension-functions.$(OBJEXT) \
|
||||
grep_proc.$(OBJEXT) hist_source.$(OBJEXT) \
|
||||
line_buffer.$(OBJEXT) listview_curses.$(OBJEXT) \
|
||||
lnav_commands.$(OBJEXT) lnav_config.$(OBJEXT) \
|
||||
lnav_log.$(OBJEXT) lnav_util.$(OBJEXT) log_accel.$(OBJEXT) \
|
||||
log_format.$(OBJEXT) log_format_loader.$(OBJEXT) \
|
||||
logfile.$(OBJEXT) logfile_sub_source.$(OBJEXT) \
|
||||
json-extension-functions.$(OBJEXT) json_op.$(OBJEXT) \
|
||||
json_ptr.$(OBJEXT) line_buffer.$(OBJEXT) \
|
||||
listview_curses.$(OBJEXT) lnav_commands.$(OBJEXT) \
|
||||
lnav_config.$(OBJEXT) lnav_log.$(OBJEXT) lnav_util.$(OBJEXT) \
|
||||
log_accel.$(OBJEXT) log_format.$(OBJEXT) \
|
||||
log_format_loader.$(OBJEXT) logfile.$(OBJEXT) \
|
||||
logfile_sub_source.$(OBJEXT) \
|
||||
network-extension-functions.$(OBJEXT) data_scanner.$(OBJEXT) \
|
||||
data_parser.$(OBJEXT) ptimec_rt.$(OBJEXT) \
|
||||
readline_curses.$(OBJEXT) readline_highlighters.$(OBJEXT) \
|
||||
@ -412,6 +414,8 @@ noinst_HEADERS = \
|
||||
hist_source.hh \
|
||||
init.sql \
|
||||
init-sql.hh \
|
||||
json_op.hh \
|
||||
json_ptr.hh \
|
||||
k_merge_tree.h \
|
||||
line_buffer.hh \
|
||||
listview_curses.hh \
|
||||
@ -477,6 +481,9 @@ libdiag_a_SOURCES = \
|
||||
fs-extension-functions.cc \
|
||||
grep_proc.cc \
|
||||
hist_source.cc \
|
||||
json-extension-functions.cc \
|
||||
json_op.cc \
|
||||
json_ptr.cc \
|
||||
line_buffer.cc \
|
||||
listview_curses.cc \
|
||||
lnav_commands.cc \
|
||||
@ -730,6 +737,9 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fs-extension-functions.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grep_proc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hist_source.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json-extension-functions.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_op.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json_ptr.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/line_buffer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listview_curses.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnav.Po@am__quote@
|
||||
|
@ -387,7 +387,7 @@
|
||||
],
|
||||
"regex" : {
|
||||
"std" : {
|
||||
"pattern" : "^TCF (?<timestamp>\\d{2}:\\d{2}.\\d{3}): (?:Server-Properties: |channel server|\\w+: (?<dir>--->|<---) (?<type>\\w)(?: (?<token>\\w+))?(?: (?<service>\\w+))?(?: (?<name>\\w+))? )(?<body>.*)"
|
||||
"pattern" : "^TCF (?<timestamp>\\d{2}:\\d{2}.\\d{3}): (?:Server-Properties: (?:.*)|channel server|\\w+: (?<dir>--->|<---) (?<type>\\w)(?: (?<token>\\w+))?(?: (?<service>\\w+))?(?: (?<name>\\w+))?(?: (?<msg>.*))?(?: <eom>))$"
|
||||
}
|
||||
},
|
||||
"value" : {
|
||||
@ -409,6 +409,9 @@
|
||||
"name" : {
|
||||
"kind" : "string",
|
||||
"identifier" : true
|
||||
},
|
||||
"msg" : {
|
||||
"kind" : "json"
|
||||
}
|
||||
},
|
||||
"sample" : [
|
||||
|
@ -29,6 +29,8 @@
|
||||
* @file fs-extension-functions.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
228
src/json-extension-functions.cc
Normal file
228
src/json-extension-functions.cc
Normal file
@ -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;
|
||||
}
|
295
src/json_op.cc
Normal file
295
src/json_op.cc
Normal file
@ -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;
|
||||
}
|
81
src/json_op.hh
Normal file
81
src/json_op.hh
Normal file
@ -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
|
169
src/json_ptr.cc
Normal file
169
src/json_ptr.cc
Normal file
@ -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
|
||||
};
|
380
src/json_ptr.hh
Normal file
380
src/json_ptr.hh
Normal file
@ -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
|
248
src/lnav.cc
248
src/lnav.cc
@ -215,6 +215,7 @@ public:
|
||||
size_t list_overlay_count(const listview_curses &lv)
|
||||
{
|
||||
logfile_sub_source &lss = lnav_data.ld_log_source;
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
if (!this->fos_active) {
|
||||
return 0;
|
||||
@ -231,13 +232,13 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->fos_key_size = 0;
|
||||
this->fos_known_key_size = 0;
|
||||
|
||||
for (std::vector<logline_value>::iterator iter =
|
||||
this->fos_log_helper.ldh_line_values.begin();
|
||||
iter != this->fos_log_helper.ldh_line_values.end();
|
||||
++iter) {
|
||||
this->fos_key_size = max(this->fos_key_size,
|
||||
this->fos_known_key_size = max(this->fos_known_key_size,
|
||||
(int)iter->lv_name.length());
|
||||
}
|
||||
|
||||
@ -249,127 +250,134 @@ public:
|
||||
iter->e_sub_elements->front());
|
||||
|
||||
colname = this->fos_log_helper.ldh_namer->add_column(colname);
|
||||
this->fos_key_size = max(this->fos_key_size, (int)colname.length());
|
||||
this->fos_unknown_key_size = max(
|
||||
this->fos_unknown_key_size, (int)colname.length());
|
||||
}
|
||||
|
||||
return 1 +
|
||||
1 +
|
||||
this->fos_log_helper.ldh_line_values.size() +
|
||||
1 +
|
||||
this->fos_log_helper.ldh_parser->dp_pairs.size();
|
||||
this->fos_lines.clear();
|
||||
|
||||
char old_timestamp[64], curr_timestamp[64];
|
||||
struct timeval curr_tv, offset_tv, orig_tv;
|
||||
char log_time[256];
|
||||
|
||||
sql_strftime(curr_timestamp, sizeof(curr_timestamp),
|
||||
this->fos_log_helper.ldh_line->get_time(),
|
||||
this->fos_log_helper.ldh_line->get_millis(),
|
||||
'T');
|
||||
curr_tv = this->fos_log_helper.ldh_line->get_timeval();
|
||||
offset_tv = this->fos_log_helper.ldh_file->get_time_offset();
|
||||
timersub(&curr_tv, &offset_tv, &orig_tv);
|
||||
sql_strftime(old_timestamp, sizeof(old_timestamp),
|
||||
orig_tv.tv_sec, orig_tv.tv_usec / 1000,
|
||||
'T');
|
||||
snprintf(log_time, sizeof(log_time),
|
||||
" Current Time: %s Original Time: %s Offset: %+d.%03d",
|
||||
curr_timestamp,
|
||||
old_timestamp,
|
||||
(int)offset_tv.tv_sec, offset_tv.tv_usec / 1000);
|
||||
this->fos_lines.push_back(log_time);
|
||||
|
||||
if (this->fos_log_helper.ldh_line_values.empty()) {
|
||||
this->fos_lines.push_back(" No known message fields");
|
||||
}
|
||||
else{
|
||||
this->fos_lines.push_back(" Known message fields:");
|
||||
}
|
||||
|
||||
for (size_t lpc = 0; lpc < this->fos_log_helper.ldh_line_values.size(); lpc++) {
|
||||
logline_value &lv = this->fos_log_helper.ldh_line_values[lpc];
|
||||
attr_line_t al;
|
||||
string str;
|
||||
|
||||
str = " " + lv.lv_name;
|
||||
str.append(this->fos_known_key_size - lv.lv_name.size() + 3, ' ');
|
||||
str += " = " + lv.to_string();
|
||||
|
||||
|
||||
al.with_string(str)
|
||||
.with_attr(string_attr(
|
||||
line_range(3, 3 + lv.lv_name.length()),
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(lv.lv_name)));
|
||||
|
||||
this->fos_lines.push_back(al);
|
||||
this->add_key_line_attrs(this->fos_known_key_size);
|
||||
}
|
||||
|
||||
std::map<std::string, json_ptr_walk::pair_list_t>::iterator json_iter;
|
||||
|
||||
if (!this->fos_log_helper.ldh_json_pairs.empty()) {
|
||||
this->fos_lines.push_back(" JSON fields:");
|
||||
}
|
||||
|
||||
for (json_iter = this->fos_log_helper.ldh_json_pairs.begin();
|
||||
json_iter != this->fos_log_helper.ldh_json_pairs.end();
|
||||
++json_iter) {
|
||||
json_ptr_walk::pair_list_t &jpairs = json_iter->second;
|
||||
|
||||
for (size_t lpc = 0; lpc < jpairs.size(); lpc++) {
|
||||
this->fos_lines.push_back(" " +
|
||||
this->fos_log_helper.format_json_getter(json_iter->first, lpc) + " = " +
|
||||
jpairs[lpc].second);
|
||||
this->add_key_line_attrs(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
|
||||
this->fos_lines.push_back(" No discovered message fields");
|
||||
}
|
||||
else {
|
||||
this->fos_lines.push_back(" Discovered message fields:");
|
||||
}
|
||||
|
||||
data_parser::element_list_t::iterator iter;
|
||||
|
||||
iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
||||
for (size_t lpc = 0;
|
||||
lpc < this->fos_log_helper.ldh_parser->dp_pairs.size(); lpc++, ++iter) {
|
||||
string &name = this->fos_log_helper.ldh_namer->cn_names[lpc];
|
||||
string val = this->fos_log_helper.ldh_parser->get_element_string(
|
||||
iter->e_sub_elements->back());
|
||||
attr_line_t al(" " + name + " = " + val);
|
||||
|
||||
al.with_attr(string_attr(
|
||||
line_range(3, 3 + name.length()),
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(name)));
|
||||
|
||||
this->fos_lines.push_back(al);
|
||||
this->add_key_line_attrs(this->fos_unknown_key_size,
|
||||
lpc == (this->fos_log_helper.ldh_parser->dp_pairs.size() - 1));
|
||||
}
|
||||
|
||||
return this->fos_lines.size();
|
||||
};
|
||||
|
||||
void add_key_line_attrs(int key_size, bool last_line = false) {
|
||||
string_attrs_t &sa = this->fos_lines.back().get_attrs();
|
||||
struct line_range lr(1, 2);
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE));
|
||||
|
||||
lr.lr_start = 3 + key_size + 3;
|
||||
lr.lr_end = -1;
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE, A_BOLD));
|
||||
};
|
||||
|
||||
bool list_value_for_overlay(const listview_curses &lv,
|
||||
vis_line_t y,
|
||||
attr_line_t &value_out)
|
||||
{
|
||||
view_colors &vc = view_colors::singleton();
|
||||
|
||||
if (!this->fos_active || this->fos_log_helper.ldh_parser.get() == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t total_count = (1 +
|
||||
1 +
|
||||
this->fos_log_helper.ldh_line_values.size() +
|
||||
1 +
|
||||
this->fos_log_helper.ldh_parser->dp_pairs.size());
|
||||
int row = (int)y - 1;
|
||||
bool last_line = (row == (int)(total_count - 1));
|
||||
|
||||
if (row < 0 || row >= (int)total_count) {
|
||||
if (row < 0 || row >= (int)this->fos_lines.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string &str = value_out.get_string();
|
||||
|
||||
if (row == 0) {
|
||||
char old_timestamp[64], curr_timestamp[64];
|
||||
struct timeval curr_tv, offset_tv, orig_tv;
|
||||
char log_time[256];
|
||||
|
||||
sql_strftime(curr_timestamp, sizeof(curr_timestamp),
|
||||
this->fos_log_helper.ldh_line->get_time(),
|
||||
this->fos_log_helper.ldh_line->get_millis(),
|
||||
'T');
|
||||
curr_tv = this->fos_log_helper.ldh_line->get_timeval();
|
||||
offset_tv = this->fos_log_helper.ldh_file->get_time_offset();
|
||||
timersub(&curr_tv, &offset_tv, &orig_tv);
|
||||
sql_strftime(old_timestamp, sizeof(old_timestamp),
|
||||
orig_tv.tv_sec, orig_tv.tv_usec / 1000,
|
||||
'T');
|
||||
snprintf(log_time, sizeof(log_time),
|
||||
" Current Time: %s Original Time: %s Offset: %+d.%03d",
|
||||
curr_timestamp,
|
||||
old_timestamp,
|
||||
(int)offset_tv.tv_sec, offset_tv.tv_usec / 1000);
|
||||
str = log_time;
|
||||
return true;
|
||||
}
|
||||
row -= 1;
|
||||
if (row == 0) {
|
||||
if (this->fos_log_helper.ldh_line_values.empty()) {
|
||||
str = " No known message fields";
|
||||
}
|
||||
else{
|
||||
str = " Known message fields:";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
row -= 1;
|
||||
if (row == (int)this->fos_log_helper.ldh_line_values.size()) {
|
||||
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
|
||||
str = " No discovered message fields";
|
||||
}
|
||||
else{
|
||||
str = " Discovered message fields:";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (row < (int)this->fos_log_helper.ldh_line_values.size()) {
|
||||
string &name = this->fos_log_helper.ldh_line_values[row].lv_name;
|
||||
|
||||
str = " " + name;
|
||||
|
||||
int padding = this->fos_key_size - str.length() + 3;
|
||||
|
||||
value_out.get_attrs().push_back(string_attr(
|
||||
line_range(3, 3 + name.length()),
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(name)));
|
||||
str.append(padding, ' ');
|
||||
str += " = " + this->fos_log_helper.ldh_line_values[row].to_string();
|
||||
}
|
||||
else {
|
||||
data_parser::element_list_t::iterator iter;
|
||||
|
||||
row -= this->fos_log_helper.ldh_line_values.size() + 1;
|
||||
|
||||
iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
||||
std::advance(iter, row);
|
||||
|
||||
string &name = this->fos_log_helper.ldh_namer->cn_names[row];
|
||||
|
||||
str = " " + name;
|
||||
int padding = this->fos_key_size - str.length() + 3;
|
||||
|
||||
value_out.get_attrs().push_back(string_attr(
|
||||
line_range(3, 3 + name.length()),
|
||||
&view_curses::VC_STYLE,
|
||||
vc.attrs_for_ident(name)));
|
||||
str.append(padding, ' ');
|
||||
str += " = " + this->fos_log_helper.ldh_parser->get_element_string(
|
||||
iter->e_sub_elements->back());
|
||||
}
|
||||
|
||||
string_attrs_t & sa = value_out.get_attrs();
|
||||
struct line_range lr(1, 2);
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE));
|
||||
|
||||
lr.lr_start = 3 + this->fos_key_size + 3;
|
||||
lr.lr_end = -1;
|
||||
sa.push_back(string_attr(lr, &view_curses::VC_STYLE, A_BOLD));
|
||||
value_out = this->fos_lines[row];
|
||||
|
||||
return true;
|
||||
};
|
||||
@ -377,7 +385,9 @@ public:
|
||||
bool fos_active;
|
||||
bool fos_active_prev;
|
||||
log_data_helper fos_log_helper;
|
||||
int fos_key_size;
|
||||
int fos_known_key_size;
|
||||
int fos_unknown_key_size;
|
||||
vector<attr_line_t> fos_lines;
|
||||
};
|
||||
|
||||
static int handle_collation_list(void *ptr,
|
||||
@ -552,6 +562,11 @@ bool setup_logline_table()
|
||||
textview_curses &log_view = lnav_data.ld_views[LNV_LOG];
|
||||
bool retval = false;
|
||||
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
lnav_data.ld_rl_view->clear_possibilities(LNM_SQL, "*");
|
||||
add_view_text_possibilities(LNM_SQL, &log_view);
|
||||
}
|
||||
|
||||
if (log_view.get_inner_height()) {
|
||||
vis_line_t vl = log_view.get_top();
|
||||
content_line_t cl = lnav_data.ld_log_source.at_base(vl);
|
||||
@ -559,15 +574,28 @@ bool setup_logline_table()
|
||||
lnav_data.ld_vtab_manager->unregister_vtab("logline");
|
||||
lnav_data.ld_vtab_manager->register_vtab(new log_data_table(cl));
|
||||
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
log_data_helper ldh(lnav_data.ld_log_source);
|
||||
|
||||
ldh.parse_line(cl);
|
||||
|
||||
std::map<std::string, json_ptr_walk::pair_list_t>::const_iterator pair_iter;
|
||||
for (pair_iter = ldh.ldh_json_pairs.begin();
|
||||
pair_iter != ldh.ldh_json_pairs.end();
|
||||
++pair_iter) {
|
||||
for (int lpc = 0; lpc < pair_iter->second.size(); lpc++) {
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*",
|
||||
ldh.format_json_getter(pair_iter->first, lpc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = true;
|
||||
}
|
||||
|
||||
lnav_data.ld_db_key_names.clear();
|
||||
|
||||
if (lnav_data.ld_rl_view != NULL) {
|
||||
lnav_data.ld_rl_view->clear_possibilities(LNM_SQL, "*");
|
||||
|
||||
add_view_text_possibilities(LNM_SQL, &log_view);
|
||||
add_env_possibilities(LNM_SQL);
|
||||
|
||||
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", sql_keywords);
|
||||
|
@ -133,6 +133,20 @@ static char *log_alloc(void)
|
||||
return &log_ring.lr_data[log_ring.lr_length];
|
||||
}
|
||||
|
||||
void log_argv(int argc, char *argv[])
|
||||
{
|
||||
const char *log_path = getenv("LNAV_LOG_PATH");
|
||||
|
||||
if (log_path != NULL) {
|
||||
lnav_log_file = fopen(log_path, "a");
|
||||
}
|
||||
|
||||
log_info("argv[%d] =", argc);
|
||||
for (int lpc = 0; lpc < argc; lpc++) {
|
||||
log_info(" [%d] = %s", lpc, argv[lpc]);
|
||||
}
|
||||
}
|
||||
|
||||
void log_host_info(void)
|
||||
{
|
||||
struct utsname un;
|
||||
|
@ -48,6 +48,7 @@ enum lnav_log_level_t {
|
||||
LOG_LEVEL_ERROR,
|
||||
};
|
||||
|
||||
void log_argv(int argc, char *argv[]);
|
||||
void log_host_info(void);
|
||||
void log_msg(enum lnav_log_level_t level, const char *src_file, int line_number,
|
||||
const char *fmt, ...);
|
||||
|
@ -32,12 +32,18 @@
|
||||
#ifndef __log_data_helper_hh
|
||||
#define __log_data_helper_hh
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "logfile_sub_source.hh"
|
||||
#include "data_parser.hh"
|
||||
#include "column_namer.hh"
|
||||
#include "json_ptr.hh"
|
||||
#include "lnav_log.hh"
|
||||
#include "sql_util.hh"
|
||||
|
||||
class log_data_helper
|
||||
{
|
||||
@ -50,6 +56,7 @@ public:
|
||||
this->ldh_parser.reset();
|
||||
this->ldh_scanner.reset();
|
||||
this->ldh_namer.reset();
|
||||
this->ldh_json_pairs.clear();
|
||||
};
|
||||
|
||||
bool parse_line(vis_line_t line, bool allow_middle = false) {
|
||||
@ -74,6 +81,7 @@ public:
|
||||
this->ldh_parser.reset();
|
||||
this->ldh_scanner.reset();
|
||||
this->ldh_namer.reset();
|
||||
this->ldh_json_pairs.clear();
|
||||
}
|
||||
else {
|
||||
log_format *format = this->ldh_file->get_format();
|
||||
@ -94,6 +102,24 @@ public:
|
||||
this->ldh_parser.reset(new data_parser(this->ldh_scanner.get()));
|
||||
this->ldh_parser->parse();
|
||||
this->ldh_namer.reset(new column_namer());
|
||||
this->ldh_json_pairs.clear();
|
||||
|
||||
for (std::vector<logline_value>::iterator iter =
|
||||
this->ldh_line_values.begin();
|
||||
iter != this->ldh_line_values.end();
|
||||
++iter) {
|
||||
switch (iter->lv_kind) {
|
||||
case logline_value::VALUE_JSON: {
|
||||
json_ptr_walk jpw;
|
||||
|
||||
jpw.parse(iter->lv_sbr.get_data(), iter->lv_sbr.length());
|
||||
this->ldh_json_pairs[iter->lv_name] = jpw.jpw_values;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
retval = true;
|
||||
}
|
||||
@ -134,6 +160,19 @@ public:
|
||||
'\n');
|
||||
};
|
||||
|
||||
std::string format_json_getter(std::string field, int index) {
|
||||
auto_mem<char, sqlite3_free> qname;
|
||||
auto_mem<char, sqlite3_free> jget;
|
||||
std::string retval;
|
||||
|
||||
qname = sql_quote_ident(field.c_str());
|
||||
jget = sqlite3_mprintf("jget(%s,%Q)", qname.in(),
|
||||
this->ldh_json_pairs[field][index].first.c_str());
|
||||
retval = std::string(jget);
|
||||
|
||||
return retval;
|
||||
};
|
||||
|
||||
logfile_sub_source &ldh_log_source;
|
||||
content_line_t ldh_source_line;
|
||||
logfile *ldh_file;
|
||||
@ -145,6 +184,7 @@ public:
|
||||
std::auto_ptr<data_parser> ldh_parser;
|
||||
std::auto_ptr<column_namer> ldh_namer;
|
||||
std::vector<logline_value> ldh_line_values;
|
||||
std::map<std::string, json_ptr_walk::pair_list_t> ldh_json_pairs;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -171,7 +171,8 @@ const char *logline_value::value_names[VALUE__MAX] = {
|
||||
"text",
|
||||
"int",
|
||||
"float",
|
||||
"bool"
|
||||
"bool",
|
||||
"json"
|
||||
};
|
||||
|
||||
logline_value::kind_t logline_value::string2kind(const char *kindstr)
|
||||
@ -188,6 +189,9 @@ logline_value::kind_t logline_value::string2kind(const char *kindstr)
|
||||
else if (strcmp(kindstr, "boolean") == 0) {
|
||||
return VALUE_BOOLEAN;
|
||||
}
|
||||
else if (strcmp(kindstr, "json") == 0) {
|
||||
return VALUE_JSON;
|
||||
}
|
||||
|
||||
return VALUE_UNKNOWN;
|
||||
}
|
||||
@ -448,6 +452,7 @@ static int json_array_end(void *ctx)
|
||||
|
||||
jlu->jlu_format->jlf_line_values.push_back(
|
||||
logline_value(field_name, tsb.tsb_ref));
|
||||
jlu->jlu_format->jlf_line_values.back().lv_kind = logline_value::VALUE_JSON;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -1136,6 +1141,7 @@ public:
|
||||
switch (vd.vd_kind) {
|
||||
case logline_value::VALUE_NULL:
|
||||
case logline_value::VALUE_TEXT:
|
||||
case logline_value::VALUE_JSON:
|
||||
type = SQLITE3_TEXT;
|
||||
break;
|
||||
case logline_value::VALUE_FLOAT:
|
||||
|
@ -343,6 +343,7 @@ public:
|
||||
VALUE_INTEGER,
|
||||
VALUE_FLOAT,
|
||||
VALUE_BOOLEAN,
|
||||
VALUE_JSON,
|
||||
|
||||
VALUE__MAX
|
||||
};
|
||||
@ -378,6 +379,7 @@ public:
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case VALUE_JSON:
|
||||
case VALUE_TEXT:
|
||||
this->lv_sbr = sbr;
|
||||
break;
|
||||
@ -429,6 +431,7 @@ public:
|
||||
case VALUE_NULL:
|
||||
return "null";
|
||||
|
||||
case VALUE_JSON:
|
||||
case VALUE_TEXT:
|
||||
return std::string(this->lv_sbr.get_data(), this->lv_sbr.length());
|
||||
|
||||
|
@ -169,7 +169,7 @@ static int read_value_def(yajlpp_parse_context *ypc, const unsigned char *str, s
|
||||
|
||||
if ((kind = logline_value::string2kind(val.c_str())) ==
|
||||
logline_value::VALUE_UNKNOWN) {
|
||||
fprintf(stderr, "unknown value kind %s\n", val.c_str());
|
||||
fprintf(stderr, "error: unknown value kind %s\n", val.c_str());
|
||||
return 0;
|
||||
}
|
||||
elf->elf_value_defs[value_name].vd_kind = kind;
|
||||
|
@ -381,6 +381,7 @@ static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
|
||||
case logline_value::VALUE_NULL:
|
||||
sqlite3_result_null(ctx);
|
||||
break;
|
||||
case logline_value::VALUE_JSON:
|
||||
case logline_value::VALUE_TEXT: {
|
||||
const char *text_value = lv_iter->lv_sbr.get_data();
|
||||
|
||||
|
@ -29,6 +29,8 @@
|
||||
* @file nextwork-extension-functions.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <pcrecpp.h>
|
||||
|
||||
#include "auto_mem.hh"
|
||||
@ -519,3 +519,45 @@ void sql_install_logger(void)
|
||||
{
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, sqlite_logger, NULL);
|
||||
}
|
||||
|
||||
char *sql_quote_ident(const char *ident)
|
||||
{
|
||||
char *quote = (char *)ident;
|
||||
size_t quote_count = 0;
|
||||
char *retval;
|
||||
|
||||
while ((quote = strchr(quote, '"')) != NULL) {
|
||||
quote_count += 1;
|
||||
quote += 1;
|
||||
}
|
||||
|
||||
if ((retval = (char *)sqlite3_malloc(
|
||||
strlen(ident) + quote_count * 2 + (quote_count ? 2: 0))) == NULL) {
|
||||
retval = NULL;
|
||||
}
|
||||
else {
|
||||
char *curr = retval;
|
||||
|
||||
if (quote_count) {
|
||||
curr[0] = '"';
|
||||
curr += 1;
|
||||
}
|
||||
for (size_t lpc = 0; ident[lpc] != '\0'; lpc++) {
|
||||
switch (ident[lpc]) {
|
||||
case '"':
|
||||
curr[0] = '"';
|
||||
curr += 1;
|
||||
default:
|
||||
curr[0] = ident[lpc];
|
||||
break;
|
||||
}
|
||||
curr += 1;
|
||||
}
|
||||
if (quote_count) {
|
||||
curr[0] = '"';
|
||||
curr += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -75,4 +75,6 @@ inline void sql_strftime(char *buffer, size_t buffer_size,
|
||||
|
||||
void sql_install_logger(void);
|
||||
|
||||
char *sql_quote_ident(const char *ident);
|
||||
|
||||
#endif
|
||||
|
@ -42,6 +42,7 @@ sqlite_registration_func_t sqlite_registration_funcs[] = {
|
||||
string_extension_functions,
|
||||
network_extension_functions,
|
||||
fs_extension_functions,
|
||||
json_extension_functions,
|
||||
|
||||
NULL
|
||||
};
|
||||
|
@ -75,6 +75,9 @@ int network_extension_functions(const struct FuncDef **basic_funcs,
|
||||
int fs_extension_functions(const struct FuncDef **basic_funcs,
|
||||
const struct FuncDefAgg **agg_funcs);
|
||||
|
||||
int json_extension_functions(const struct FuncDef **basic_funcs,
|
||||
const struct FuncDefAgg **agg_funcs);
|
||||
|
||||
extern sqlite_registration_func_t sqlite_registration_funcs[];
|
||||
|
||||
int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs);
|
||||
|
@ -29,6 +29,8 @@
|
||||
* @file state-extension-functions.cc
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -293,10 +293,15 @@ public:
|
||||
attr_line_t() {
|
||||
this->al_attrs.reserve(RESERVE_SIZE);
|
||||
};
|
||||
|
||||
attr_line_t(const std::string &str) : al_string(str) {
|
||||
this->al_attrs.reserve(RESERVE_SIZE);
|
||||
};
|
||||
|
||||
attr_line_t(const char *str) : al_string(str) {
|
||||
this->al_attrs.reserve(RESERVE_SIZE);
|
||||
};
|
||||
|
||||
/** @return The string itself. */
|
||||
std::string &get_string() { return this->al_string; };
|
||||
|
||||
@ -315,8 +320,6 @@ public:
|
||||
|
||||
size_t length() const { return this->al_string.length(); };
|
||||
|
||||
void operator=(const std::string &rhs) { this->al_string = rhs; };
|
||||
|
||||
/** Clear the string and the attributes for the string. */
|
||||
attr_line_t &clear()
|
||||
{
|
||||
|
@ -142,23 +142,6 @@ struct json_path_handler : public json_path_handler_base {
|
||||
|
||||
class yajlpp_parse_context {
|
||||
public:
|
||||
|
||||
struct json_path_element {
|
||||
json_path_element(int index = 0) : jpe_index(index) { };
|
||||
json_path_element(const std::string &name)
|
||||
: jpe_name(name), jpe_index(0) {};
|
||||
json_path_element(const unsigned char *name)
|
||||
: jpe_name((const char *)name), jpe_index(0) {};
|
||||
|
||||
void set_name(const unsigned char *name, size_t len)
|
||||
{
|
||||
this->jpe_name = std::string((const char *)name, len);
|
||||
};
|
||||
|
||||
std::string jpe_name;
|
||||
int jpe_index;
|
||||
};
|
||||
|
||||
yajlpp_parse_context(std::string source,
|
||||
struct json_path_handler *handlers = NULL)
|
||||
: ypc_source(source), ypc_handlers(handlers), ypc_ignore_unused(false)
|
||||
|
@ -17,6 +17,8 @@ check_PROGRAMS = \
|
||||
drive_data_scanner \
|
||||
drive_line_buffer \
|
||||
drive_grep_proc \
|
||||
drive_json_op \
|
||||
drive_json_ptr_walk \
|
||||
drive_listview \
|
||||
drive_logfile \
|
||||
drive_mvwattrline \
|
||||
@ -35,6 +37,7 @@ check_PROGRAMS = \
|
||||
test_date_time_scanner \
|
||||
test_grep_proc2 \
|
||||
test_hist_source \
|
||||
test_json_ptr \
|
||||
test_line_buffer2 \
|
||||
test_log_accel \
|
||||
test_pcrepp \
|
||||
@ -86,12 +89,21 @@ test_yajlpp_LDADD = ../src/libdiag.a
|
||||
test_concise_SOURCES = test_concise.cc
|
||||
test_concise_LDADD = ../src/libdiag.a
|
||||
|
||||
test_json_ptr_SOURCES = test_json_ptr.cc
|
||||
test_json_ptr_LDADD = ../src/libdiag.a
|
||||
|
||||
drive_line_buffer_SOURCES = drive_line_buffer.cc
|
||||
drive_line_buffer_LDADD = ../src/libdiag.a $(CURSES_LIB) -lz
|
||||
|
||||
drive_grep_proc_SOURCES = drive_grep_proc.cc
|
||||
drive_grep_proc_LDADD = ../src/libdiag.a $(PCRE_LIBS) -lz
|
||||
|
||||
drive_json_op_SOURCES = drive_json_op.cc
|
||||
drive_json_op_LDADD = ../src/libdiag.a $(PCRE_LIBS) -lz
|
||||
|
||||
drive_json_ptr_walk_SOURCES = drive_json_ptr_walk.cc
|
||||
drive_json_ptr_walk_LDADD = ../src/libdiag.a $(PCRE_LIBS) -lz
|
||||
|
||||
drive_listview_SOURCES = drive_listview.cc
|
||||
drive_listview_LDADD = ../src/libdiag.a $(CURSES_LIB) -lz
|
||||
|
||||
@ -160,6 +172,7 @@ dist_noinst_SCRIPTS = \
|
||||
test_sessions.sh \
|
||||
test_sql.sh \
|
||||
test_sql_coll_func.sh \
|
||||
test_sql_json_func.sh \
|
||||
test_sql_str_func.sh \
|
||||
test_sql_fs_func.sh \
|
||||
test_view_colors.sh \
|
||||
@ -233,12 +246,15 @@ TESTS = \
|
||||
test_grep_proc2 \
|
||||
test_hist_source \
|
||||
test_json_format.sh \
|
||||
test_json_op.sh \
|
||||
test_json_ptr_walk.sh \
|
||||
test_log_accel \
|
||||
test_logfile.sh \
|
||||
test_pcrepp \
|
||||
test_sessions.sh \
|
||||
test_sql.sh \
|
||||
test_sql_coll_func.sh \
|
||||
test_sql_json_func.sh \
|
||||
test_sql_fs_func.sh \
|
||||
test_sql_str_func.sh \
|
||||
test_view_colors.sh \
|
||||
|
@ -81,6 +81,7 @@ build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
check_PROGRAMS = drive_data_scanner$(EXEEXT) \
|
||||
drive_line_buffer$(EXEEXT) drive_grep_proc$(EXEEXT) \
|
||||
drive_json_op$(EXEEXT) drive_json_ptr_walk$(EXEEXT) \
|
||||
drive_listview$(EXEEXT) drive_logfile$(EXEEXT) \
|
||||
drive_mvwattrline$(EXEEXT) drive_sequencer$(EXEEXT) \
|
||||
drive_sql$(EXEEXT) drive_view_colors$(EXEEXT) \
|
||||
@ -89,18 +90,20 @@ check_PROGRAMS = drive_data_scanner$(EXEEXT) \
|
||||
test_auto_fd$(EXEEXT) test_auto_mem$(EXEEXT) \
|
||||
test_bookmarks$(EXEEXT) test_concise$(EXEEXT) \
|
||||
test_date_time_scanner$(EXEEXT) test_grep_proc2$(EXEEXT) \
|
||||
test_hist_source$(EXEEXT) test_line_buffer2$(EXEEXT) \
|
||||
test_log_accel$(EXEEXT) test_pcrepp$(EXEEXT) \
|
||||
test_top_status$(EXEEXT) test_yajlpp$(EXEEXT)
|
||||
test_hist_source$(EXEEXT) test_json_ptr$(EXEEXT) \
|
||||
test_line_buffer2$(EXEEXT) test_log_accel$(EXEEXT) \
|
||||
test_pcrepp$(EXEEXT) test_top_status$(EXEEXT) \
|
||||
test_yajlpp$(EXEEXT)
|
||||
TESTS = test_ansi_scrubber$(EXEEXT) test_auto_fd$(EXEEXT) \
|
||||
test_auto_mem$(EXEEXT) test_bookmarks$(EXEEXT) \
|
||||
test_date_time_scanner$(EXEEXT) test_cmds.sh \
|
||||
test_concise$(EXEEXT) test_line_buffer2$(EXEEXT) \
|
||||
test_line_buffer.sh test_listview.sh test_mvwattrline.sh \
|
||||
test_grep_proc.sh test_grep_proc2$(EXEEXT) \
|
||||
test_hist_source$(EXEEXT) test_json_format.sh \
|
||||
test_log_accel$(EXEEXT) test_logfile.sh test_pcrepp$(EXEEXT) \
|
||||
test_sessions.sh test_sql.sh test_sql_coll_func.sh \
|
||||
test_hist_source$(EXEEXT) test_json_format.sh test_json_op.sh \
|
||||
test_json_ptr_walk.sh test_log_accel$(EXEEXT) test_logfile.sh \
|
||||
test_pcrepp$(EXEEXT) test_sessions.sh test_sql.sh \
|
||||
test_sql_coll_func.sh test_sql_json_func.sh \
|
||||
test_sql_fs_func.sh test_sql_str_func.sh test_view_colors.sh \
|
||||
test_vt52_curses.sh test_top_status$(EXEEXT) \
|
||||
test_data_parser.sh test_yajlpp$(EXEEXT)
|
||||
@ -129,6 +132,13 @@ drive_data_scanner_DEPENDENCIES = ../src/libdiag.a \
|
||||
am_drive_grep_proc_OBJECTS = drive_grep_proc.$(OBJEXT)
|
||||
drive_grep_proc_OBJECTS = $(am_drive_grep_proc_OBJECTS)
|
||||
drive_grep_proc_DEPENDENCIES = ../src/libdiag.a $(am__DEPENDENCIES_1)
|
||||
am_drive_json_op_OBJECTS = drive_json_op.$(OBJEXT)
|
||||
drive_json_op_OBJECTS = $(am_drive_json_op_OBJECTS)
|
||||
drive_json_op_DEPENDENCIES = ../src/libdiag.a $(am__DEPENDENCIES_1)
|
||||
am_drive_json_ptr_walk_OBJECTS = drive_json_ptr_walk.$(OBJEXT)
|
||||
drive_json_ptr_walk_OBJECTS = $(am_drive_json_ptr_walk_OBJECTS)
|
||||
drive_json_ptr_walk_DEPENDENCIES = ../src/libdiag.a \
|
||||
$(am__DEPENDENCIES_1)
|
||||
am_drive_line_buffer_OBJECTS = drive_line_buffer.$(OBJEXT)
|
||||
drive_line_buffer_OBJECTS = $(am_drive_line_buffer_OBJECTS)
|
||||
drive_line_buffer_DEPENDENCIES = ../src/libdiag.a \
|
||||
@ -200,6 +210,9 @@ test_grep_proc2_DEPENDENCIES = ../src/libdiag.a $(am__DEPENDENCIES_1)
|
||||
am_test_hist_source_OBJECTS = test_hist_source.$(OBJEXT)
|
||||
test_hist_source_OBJECTS = $(am_test_hist_source_OBJECTS)
|
||||
test_hist_source_DEPENDENCIES = ../src/libdiag.a $(am__DEPENDENCIES_1)
|
||||
am_test_json_ptr_OBJECTS = test_json_ptr.$(OBJEXT)
|
||||
test_json_ptr_OBJECTS = $(am_test_json_ptr_OBJECTS)
|
||||
test_json_ptr_DEPENDENCIES = ../src/libdiag.a
|
||||
am_test_line_buffer2_OBJECTS = test_line_buffer2.$(OBJEXT)
|
||||
test_line_buffer2_OBJECTS = $(am_test_line_buffer2_OBJECTS)
|
||||
test_line_buffer2_DEPENDENCIES = ../src/libdiag.a
|
||||
@ -247,6 +260,7 @@ am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
|
||||
am__v_CXXLD_0 = @echo " CXXLD " $@;
|
||||
am__v_CXXLD_1 =
|
||||
SOURCES = $(drive_data_scanner_SOURCES) $(drive_grep_proc_SOURCES) \
|
||||
$(drive_json_op_SOURCES) $(drive_json_ptr_walk_SOURCES) \
|
||||
$(drive_line_buffer_SOURCES) $(drive_listview_SOURCES) \
|
||||
$(drive_logfile_SOURCES) $(drive_mvwattrline_SOURCES) \
|
||||
$(drive_readline_curses_SOURCES) $(drive_sequencer_SOURCES) \
|
||||
@ -256,11 +270,13 @@ SOURCES = $(drive_data_scanner_SOURCES) $(drive_grep_proc_SOURCES) \
|
||||
$(test_auto_fd_SOURCES) $(test_auto_mem_SOURCES) \
|
||||
$(test_bookmarks_SOURCES) $(test_concise_SOURCES) \
|
||||
$(test_date_time_scanner_SOURCES) $(test_grep_proc2_SOURCES) \
|
||||
$(test_hist_source_SOURCES) $(test_line_buffer2_SOURCES) \
|
||||
$(test_log_accel_SOURCES) $(test_pcrepp_SOURCES) \
|
||||
$(test_top_status_SOURCES) $(test_yajlpp_SOURCES)
|
||||
$(test_hist_source_SOURCES) $(test_json_ptr_SOURCES) \
|
||||
$(test_line_buffer2_SOURCES) $(test_log_accel_SOURCES) \
|
||||
$(test_pcrepp_SOURCES) $(test_top_status_SOURCES) \
|
||||
$(test_yajlpp_SOURCES)
|
||||
DIST_SOURCES = $(drive_data_scanner_SOURCES) \
|
||||
$(drive_grep_proc_SOURCES) $(drive_line_buffer_SOURCES) \
|
||||
$(drive_grep_proc_SOURCES) $(drive_json_op_SOURCES) \
|
||||
$(drive_json_ptr_walk_SOURCES) $(drive_line_buffer_SOURCES) \
|
||||
$(drive_listview_SOURCES) $(drive_logfile_SOURCES) \
|
||||
$(drive_mvwattrline_SOURCES) $(drive_readline_curses_SOURCES) \
|
||||
$(drive_sequencer_SOURCES) $(drive_sql_SOURCES) \
|
||||
@ -270,9 +286,9 @@ DIST_SOURCES = $(drive_data_scanner_SOURCES) \
|
||||
$(test_auto_mem_SOURCES) $(test_bookmarks_SOURCES) \
|
||||
$(test_concise_SOURCES) $(test_date_time_scanner_SOURCES) \
|
||||
$(test_grep_proc2_SOURCES) $(test_hist_source_SOURCES) \
|
||||
$(test_line_buffer2_SOURCES) $(test_log_accel_SOURCES) \
|
||||
$(test_pcrepp_SOURCES) $(test_top_status_SOURCES) \
|
||||
$(test_yajlpp_SOURCES)
|
||||
$(test_json_ptr_SOURCES) $(test_line_buffer2_SOURCES) \
|
||||
$(test_log_accel_SOURCES) $(test_pcrepp_SOURCES) \
|
||||
$(test_top_status_SOURCES) $(test_yajlpp_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
@ -664,10 +680,16 @@ test_yajlpp_SOURCES = test_yajlpp.cc
|
||||
test_yajlpp_LDADD = ../src/libdiag.a
|
||||
test_concise_SOURCES = test_concise.cc
|
||||
test_concise_LDADD = ../src/libdiag.a
|
||||
test_json_ptr_SOURCES = test_json_ptr.cc
|
||||
test_json_ptr_LDADD = ../src/libdiag.a
|
||||
drive_line_buffer_SOURCES = drive_line_buffer.cc
|
||||
drive_line_buffer_LDADD = ../src/libdiag.a $(CURSES_LIB) -lz
|
||||
drive_grep_proc_SOURCES = drive_grep_proc.cc
|
||||
drive_grep_proc_LDADD = ../src/libdiag.a $(PCRE_LIBS) -lz
|
||||
drive_json_op_SOURCES = drive_json_op.cc
|
||||
drive_json_op_LDADD = ../src/libdiag.a $(PCRE_LIBS) -lz
|
||||
drive_json_ptr_walk_SOURCES = drive_json_ptr_walk.cc
|
||||
drive_json_ptr_walk_LDADD = ../src/libdiag.a $(PCRE_LIBS) -lz
|
||||
drive_listview_SOURCES = drive_listview.cc
|
||||
drive_listview_LDADD = ../src/libdiag.a $(CURSES_LIB) -lz
|
||||
drive_logfile_SOURCES = drive_logfile.cc
|
||||
@ -730,6 +752,7 @@ dist_noinst_SCRIPTS = \
|
||||
test_sessions.sh \
|
||||
test_sql.sh \
|
||||
test_sql_coll_func.sh \
|
||||
test_sql_json_func.sh \
|
||||
test_sql_str_func.sh \
|
||||
test_sql_fs_func.sh \
|
||||
test_view_colors.sh \
|
||||
@ -844,6 +867,14 @@ drive_grep_proc$(EXEEXT): $(drive_grep_proc_OBJECTS) $(drive_grep_proc_DEPENDENC
|
||||
@rm -f drive_grep_proc$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(drive_grep_proc_OBJECTS) $(drive_grep_proc_LDADD) $(LIBS)
|
||||
|
||||
drive_json_op$(EXEEXT): $(drive_json_op_OBJECTS) $(drive_json_op_DEPENDENCIES) $(EXTRA_drive_json_op_DEPENDENCIES)
|
||||
@rm -f drive_json_op$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(drive_json_op_OBJECTS) $(drive_json_op_LDADD) $(LIBS)
|
||||
|
||||
drive_json_ptr_walk$(EXEEXT): $(drive_json_ptr_walk_OBJECTS) $(drive_json_ptr_walk_DEPENDENCIES) $(EXTRA_drive_json_ptr_walk_DEPENDENCIES)
|
||||
@rm -f drive_json_ptr_walk$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(drive_json_ptr_walk_OBJECTS) $(drive_json_ptr_walk_LDADD) $(LIBS)
|
||||
|
||||
drive_line_buffer$(EXEEXT): $(drive_line_buffer_OBJECTS) $(drive_line_buffer_DEPENDENCIES) $(EXTRA_drive_line_buffer_DEPENDENCIES)
|
||||
@rm -f drive_line_buffer$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(drive_line_buffer_OBJECTS) $(drive_line_buffer_LDADD) $(LIBS)
|
||||
@ -920,6 +951,10 @@ test_hist_source$(EXEEXT): $(test_hist_source_OBJECTS) $(test_hist_source_DEPEND
|
||||
@rm -f test_hist_source$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(test_hist_source_OBJECTS) $(test_hist_source_LDADD) $(LIBS)
|
||||
|
||||
test_json_ptr$(EXEEXT): $(test_json_ptr_OBJECTS) $(test_json_ptr_DEPENDENCIES) $(EXTRA_test_json_ptr_DEPENDENCIES)
|
||||
@rm -f test_json_ptr$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(test_json_ptr_OBJECTS) $(test_json_ptr_LDADD) $(LIBS)
|
||||
|
||||
test_line_buffer2$(EXEEXT): $(test_line_buffer2_OBJECTS) $(test_line_buffer2_DEPENDENCIES) $(EXTRA_test_line_buffer2_DEPENDENCIES)
|
||||
@rm -f test_line_buffer2$(EXEEXT)
|
||||
$(AM_V_CXXLD)$(CXXLINK) $(test_line_buffer2_OBJECTS) $(test_line_buffer2_LDADD) $(LIBS)
|
||||
@ -948,6 +983,8 @@ distclean-compile:
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_data_scanner.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_grep_proc.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_json_op.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_json_ptr_walk.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_line_buffer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_listview.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drive_logfile.Po@am__quote@
|
||||
@ -967,6 +1004,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_date_time_scanner.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_grep_proc2.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_hist_source.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_json_ptr.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_line_buffer2.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_log_accel.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_pcrepp.Po@am__quote@
|
||||
@ -1287,6 +1325,20 @@ test_json_format.sh.log: test_json_format.sh
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
test_json_op.sh.log: test_json_op.sh
|
||||
@p='test_json_op.sh'; \
|
||||
b='test_json_op.sh'; \
|
||||
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
test_json_ptr_walk.sh.log: test_json_ptr_walk.sh
|
||||
@p='test_json_ptr_walk.sh'; \
|
||||
b='test_json_ptr_walk.sh'; \
|
||||
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
test_log_accel.log: test_log_accel$(EXEEXT)
|
||||
@p='test_log_accel$(EXEEXT)'; \
|
||||
b='test_log_accel'; \
|
||||
@ -1329,6 +1381,13 @@ test_sql_coll_func.sh.log: test_sql_coll_func.sh
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
test_sql_json_func.sh.log: test_sql_json_func.sh
|
||||
@p='test_sql_json_func.sh'; \
|
||||
b='test_sql_json_func.sh'; \
|
||||
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
|
||||
--log-file $$b.log --trs-file $$b.trs \
|
||||
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
|
||||
"$$tst" $(AM_TESTS_FD_REDIRECT)
|
||||
test_sql_fs_func.sh.log: test_sql_fs_func.sh
|
||||
@p='test_sql_fs_func.sh'; \
|
||||
b='test_sql_fs_func.sh'; \
|
||||
|
198
test/drive_json_op.cc
Normal file
198
test/drive_json_op.cc
Normal file
@ -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;
|
||||
}
|
79
test/drive_json_ptr_walk.cc
Normal file
79
test/drive_json_ptr_walk.cc
Normal file
@ -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;
|
||||
}
|
@ -37,6 +37,8 @@ int main(int argc, char *argv[])
|
||||
int retval = EXIT_SUCCESS;
|
||||
auto_mem<sqlite3> db(sqlite3_close);
|
||||
|
||||
log_argv(argc, argv);
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "error: expecting an SQL statement\n");
|
||||
retval = EXIT_FAILURE;
|
||||
|
94
test/test_json_op.sh
Normal file
94
test/test_json_op.sh
Normal file
@ -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
|
73
test/test_json_ptr.cc
Normal file
73
test/test_json_ptr.cc
Normal file
@ -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));
|
||||
}
|
||||
}
|
67
test/test_json_ptr_walk.sh
Normal file
67
test/test_json_ptr_walk.sh
Normal file
@ -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
|
55
test/test_sql_json_func.sh
Normal file
55
test/test_sql_json_func.sh
Normal file
@ -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
Block a user