[jsonptr] initial impl

pull/111/head
Timothy Stack 10 years ago
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

@ -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>

@ -0,0 +1,228 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file json-extension-functions.cc
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include <string>
#include "sqlite3.h"
#include "json_op.hh"
#include "sqlite-extension-func.h"
using namespace std;
class sql_json_op : public json_op {
public:
sql_json_op(json_ptr &ptr) : json_op(ptr), sjo_type(-1) { };
int sjo_type;
string sjo_str;
int sjo_int;
};
static void printer(void *ctx, const char *numberVal, size_t numberLen)
{
string &str = *(string *)ctx;
str.append(numberVal, numberLen);
}
static void null_or_default(sqlite3_context *context, int argc, sqlite3_value **argv)
{
if (argc > 2) {
sqlite3_result_value(context, argv[2]);
}
else {
sqlite3_result_null(context);
}
}
static int gen_handle_null(void *ctx)
{
sql_json_op *sjo = (sql_json_op *)ctx;
yajl_gen gen = (yajl_gen)sjo->jo_ptr_data;
if (sjo->jo_ptr.jp_state == json_ptr::MS_DONE) {
sjo->sjo_type = SQLITE_NULL;
}
else {
sjo->jo_ptr_error_code = yajl_gen_null(gen);
}
return sjo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_boolean(void *ctx, int boolVal)
{
sql_json_op *sjo = (sql_json_op *)ctx;
yajl_gen gen = (yajl_gen)sjo->jo_ptr_data;
if (sjo->jo_ptr.jp_state == json_ptr::MS_DONE) {
sjo->sjo_type = SQLITE_INTEGER;
sjo->sjo_int = boolVal;
}
else {
sjo->jo_ptr_error_code = yajl_gen_bool(gen, boolVal);
}
return sjo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_string(void *ctx, const unsigned char * stringVal, size_t len)
{
sql_json_op *sjo = (sql_json_op *)ctx;
yajl_gen gen = (yajl_gen)sjo->jo_ptr_data;
if (sjo->jo_ptr.jp_state == json_ptr::MS_DONE) {
sjo->sjo_type = SQLITE3_TEXT;
sjo->sjo_str = string((char *)stringVal, len);
}
else {
sjo->jo_ptr_error_code = yajl_gen_string(gen, stringVal, len);
}
return sjo->jo_ptr_error_code == yajl_gen_status_ok;
}
static void sql_jget(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
if (argc < 2) {
sqlite3_result_error(context, "expecting JSON value and pointer", -1);
return;
}
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
null_or_default(context, argc, argv);
return;
}
const char *json_in = (const char *)sqlite3_value_text(argv[0]);
if (sqlite3_value_type(argv[1]) == SQLITE_NULL) {
sqlite3_result_text(context, json_in, -1, SQLITE_TRANSIENT);
return;
}
const char *ptr_in = (const char *)sqlite3_value_text(argv[1]);
json_ptr jp(ptr_in);
sql_json_op jo(jp);
auto_mem<yajl_gen_t> gen(yajl_gen_free);
auto_mem<yajl_handle_t> handle(yajl_free);
const unsigned char *err;
string result;
gen = yajl_gen_alloc(NULL);
yajl_gen_config(gen.in(), yajl_gen_print_callback, printer, &result);
yajl_gen_config(gen.in(), yajl_gen_beautify, false);
jo.jo_ptr_callbacks = json_op::gen_callbacks;
jo.jo_ptr_callbacks.yajl_null = gen_handle_null;
jo.jo_ptr_callbacks.yajl_boolean = gen_handle_boolean;
jo.jo_ptr_callbacks.yajl_string = gen_handle_string;
jo.jo_ptr_data = gen.in();
handle.reset(yajl_alloc(&json_op::ptr_callbacks, NULL, &jo));
switch (yajl_parse(handle.in(), (const unsigned char *)json_in, strlen(json_in))) {
case yajl_status_error:
err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in));
sqlite3_result_error(context, (const char *)err, -1);
return;
case yajl_status_client_canceled:
if (jo.jo_ptr.jp_state == json_ptr::MS_ERR_INVALID_ESCAPE) {
sqlite3_result_error(context, jo.jo_ptr.error_msg().c_str(), -1);
}
else {
null_or_default(context, argc, argv);
}
return;
default:
break;
}
switch (yajl_complete_parse(handle.in())) {
case yajl_status_error:
err = yajl_get_error(handle.in(), 0, (const unsigned char *)json_in, strlen(json_in));
sqlite3_result_error(context, (const char *)err, -1);
return;
case yajl_status_client_canceled:
if (jo.jo_ptr.jp_state == json_ptr::MS_ERR_INVALID_ESCAPE) {
sqlite3_result_error(context, jo.jo_ptr.error_msg().c_str(), -1);
}
else {
null_or_default(context, argc, argv);
}
return;
default:
break;
}
switch (jo.sjo_type) {
case SQLITE3_TEXT:
sqlite3_result_text(context, jo.sjo_str.c_str(), jo.sjo_str.size(), SQLITE_TRANSIENT);
return;
case SQLITE_NULL:
sqlite3_result_null(context);
return;
case SQLITE_INTEGER:
sqlite3_result_int(context, jo.sjo_int);
return;
}
if (result.empty()) {
null_or_default(context, argc, argv);
return;
}
sqlite3_result_text(context, result.c_str(), result.size(), SQLITE_TRANSIENT);
}
int json_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs)
{
static const struct FuncDef fs_funcs[] = {
{ "jget", -1, 0, SQLITE_UTF8, 0, sql_jget },
{ NULL }
};
*basic_funcs = fs_funcs;
*agg_funcs = NULL;
return SQLITE_OK;
}

@ -0,0 +1,295 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file json_op.cc
*/
#include "config.h"
#include "json_op.hh"
#include "lnav_log.hh"
static int gen_handle_start_map(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_map_open(gen);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_map_key(void *ctx, const unsigned char * key, size_t len)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_string(gen, key, len);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_end_map(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_map_close(gen);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_null(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_null(gen);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_boolean(void *ctx, int boolVal)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_bool(gen, boolVal);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_number(void *ctx, const char *numberVal, size_t numberLen)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_number(gen, numberVal, numberLen);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_string(void *ctx, const unsigned char * stringVal, size_t len)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_string(gen, stringVal, len);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_start_array(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_array_open(gen);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
static int gen_handle_end_array(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
jo->jo_ptr_error_code = yajl_gen_array_close(gen);
return jo->jo_ptr_error_code == yajl_gen_status_ok;
}
const yajl_callbacks json_op::gen_callbacks = {
gen_handle_null,
gen_handle_boolean,
NULL,
NULL,
gen_handle_number,
gen_handle_string,
gen_handle_start_map,
gen_handle_map_key,
gen_handle_end_map,
gen_handle_start_array,
gen_handle_end_array,
};
const yajl_callbacks json_op::ptr_callbacks = {
handle_null,
handle_boolean,
NULL,
NULL,
handle_number,
handle_string,
handle_start_map,
handle_map_key,
handle_end_map,
handle_start_array,
handle_end_array,
};
int json_op::handle_null(void *ctx)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index()) {
if (jo->jo_ptr_callbacks.yajl_null != NULL) {
retval = jo->jo_ptr_callbacks.yajl_null(ctx);
}
}
return retval;
}
int json_op::handle_boolean(void *ctx, int boolVal)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index()) {
if (jo->jo_ptr_callbacks.yajl_boolean != NULL) {
retval = jo->jo_ptr_callbacks.yajl_boolean(ctx, boolVal);
}
}
return retval;
}
int json_op::handle_number(void *ctx, const char *numberVal, size_t numberLen)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index()) {
if (jo->jo_ptr_callbacks.yajl_number != NULL) {
retval = jo->jo_ptr_callbacks.yajl_number(ctx, numberVal, numberLen);
}
}
return retval;
}
int json_op::handle_string(void *ctx, const unsigned char *stringVal, size_t stringLen)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index()) {
if (jo->jo_ptr_callbacks.yajl_string != NULL) {
retval = jo->jo_ptr_callbacks.yajl_string(ctx, stringVal, stringLen);
}
}
return retval;
}
int json_op::handle_start_map(void *ctx)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index(false)) {
if (jo->jo_ptr_callbacks.yajl_start_map != NULL) {
retval = jo->jo_ptr_callbacks.yajl_start_map(ctx);
}
}
if (!jo->jo_ptr.expect_map(jo->jo_depth)) {
retval = 0;
}
return retval;
}
int json_op::handle_map_key(void *ctx, const unsigned char * key, size_t len)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index(false)) {
if (jo->jo_ptr_callbacks.yajl_map_key != NULL) {
retval = jo->jo_ptr_callbacks.yajl_map_key(ctx, key, len);
}
}
if (!jo->jo_ptr.at_key(jo->jo_depth, (const char *)key, len)) {
retval = 0;
}
return retval;
}
int json_op::handle_end_map(void *ctx)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index()) {
if (jo->jo_ptr_callbacks.yajl_end_map != NULL) {
retval = jo->jo_ptr_callbacks.yajl_end_map(ctx);
}
}
jo->jo_ptr.exit_container(jo->jo_depth, jo->jo_array_index);
return retval;
}
int json_op::handle_start_array(void *ctx)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index(false)) {
if (jo->jo_ptr_callbacks.yajl_start_array != NULL) {
retval = jo->jo_ptr_callbacks.yajl_start_array(ctx);
}
}
if (!jo->jo_ptr.expect_array(jo->jo_depth, jo->jo_array_index)) {
retval = 0;
}
return retval;
}
int json_op::handle_end_array(void *ctx)
{
json_op *jo = (json_op *)ctx;
int retval = 1;
if (jo->check_index()) {
if (jo->jo_ptr_callbacks.yajl_end_array != NULL) {
retval = jo->jo_ptr_callbacks.yajl_end_array(ctx);
}
}
jo->jo_ptr.exit_container(jo->jo_depth, jo->jo_array_index);
return retval;
}

@ -0,0 +1,81 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file json_op.hh
*/
#ifndef __json_op_hh
#define __json_op_hh
#include <sys/types.h>
#include <string>
#include "json_ptr.hh"
#include "yajlpp.hh"
class json_op {
static int handle_null(void *ctx);
static int handle_boolean(void *ctx, int boolVal);
static int handle_number(void *ctx, const char *numberVal, size_t numberLen);
static int handle_string(void *ctx, const unsigned char * stringVal, size_t len);
static int handle_start_map(void *ctx);
static int handle_map_key(void *ctx, const unsigned char * key, size_t len);
static int handle_end_map(void *ctx);
static int handle_start_array(void *ctx);
static int handle_end_array(void *ctx);
public:
const static yajl_callbacks gen_callbacks;
const static yajl_callbacks ptr_callbacks;
json_op(json_ptr &ptr)
: jo_depth(0),
jo_array_index(-1),
jo_ptr(ptr),
jo_ptr_data(NULL),
jo_ptr_error_code(0) {
memset(&this->jo_ptr_callbacks, 0, sizeof(this->jo_ptr_callbacks));
};
bool check_index(bool primitive = true) {
return this->jo_ptr.at_index(this->jo_depth, this->jo_array_index, primitive);
};
int jo_depth;
int jo_array_index;
json_ptr jo_ptr;
yajl_callbacks jo_ptr_callbacks;
void *jo_ptr_data;
std::string jo_ptr_error;
int jo_ptr_error_code;
};
#endif

@ -0,0 +1,169 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file json_ptr.cc
*/
#include "config.h"
#include "json_ptr.hh"
using namespace std;
static int handle_null(void *ctx)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), "null"));
jpw->inc_array_index();
return 1;
}
static int handle_boolean(void *ctx, int boolVal)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), boolVal ? "true" : "false"));
jpw->inc_array_index();
return 1;
}
static int handle_number(void *ctx, const char *numberVal, size_t numberLen)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), string(numberVal, numberLen)));
jpw->inc_array_index();
return 1;
}
static void appender(void *ctx, const char *strVal, size_t strLen)
{
string &str = *(string *)ctx;
str.append(strVal, strLen);
}
static int handle_string(void *ctx, const unsigned char * stringVal, size_t len)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
auto_mem<yajl_gen_t> gen(yajl_gen_free);
string str;
gen = yajl_gen_alloc(NULL);
yajl_gen_config(gen.in(), yajl_gen_print_callback, appender, &str);
yajl_gen_string(gen.in(), stringVal, len);
jpw->jpw_values.push_back(make_pair(jpw->current_ptr(), str));
jpw->inc_array_index();
return 1;
}
static int handle_start_map(void *ctx)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_keys.push_back("");
jpw->jpw_array_indexes.push_back(-1);
return 1;
}
static int handle_map_key(void *ctx, const unsigned char * key, size_t len)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
char partially_encoded_key[len + 32];
size_t required_len;
jpw->jpw_keys.pop_back();
required_len = json_ptr::encode(partially_encoded_key, sizeof(partially_encoded_key),
(const char *)key, len);
if (required_len < sizeof(partially_encoded_key)) {
jpw->jpw_keys.push_back(string(partially_encoded_key, required_len));
}
else {
char fully_encoded_key[required_len];
json_ptr::encode(fully_encoded_key, sizeof(fully_encoded_key),
(const char *)key, len);
jpw->jpw_keys.push_back(string(fully_encoded_key, required_len));
}
return 1;
}
static int handle_end_map(void *ctx)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_keys.pop_back();
jpw->jpw_array_indexes.pop_back();
jpw->inc_array_index();
return 1;
}
static int handle_start_array(void *ctx)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_keys.push_back("");
jpw->jpw_array_indexes.push_back(0);
return 1;
}
static int handle_end_array(void *ctx)
{
json_ptr_walk *jpw = (json_ptr_walk *)ctx;
jpw->jpw_keys.pop_back();
jpw->jpw_array_indexes.pop_back();
jpw->inc_array_index();
return 1;
}
const yajl_callbacks json_ptr_walk::callbacks = {
handle_null,
handle_boolean,
NULL,
NULL,
handle_number,
handle_string,
handle_start_map,
handle_map_key,
handle_end_map,
handle_start_array,
handle_end_array
};

@ -0,0 +1,380 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file json_ptr.hh
*/
#ifndef __json_ptr_hh
#define __json_ptr_hh
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <string>
#include <vector>
#include "yajlpp.hh"
#include "lnav_log.hh"
class json_ptr_walk {
public:
const static yajl_callbacks callbacks;
json_ptr_walk() : jpw_handle(yajl_free) {
this->jpw_handle = yajl_alloc(&callbacks, NULL, this);
};
yajl_status parse(const char *buffer, ssize_t len) {
yajl_status retval;
retval = yajl_parse(this->jpw_handle, (const unsigned char *)buffer, len);
this->update_error_msg(retval, buffer, len);
return retval;
};
yajl_status complete_parse() {
yajl_status retval;
retval = yajl_complete_parse(this->jpw_handle);
this->update_error_msg(retval, NULL, -1);
return retval;
};
void update_error_msg(yajl_status status, const char *buffer, ssize_t len) {
switch (status) {
case yajl_status_ok:
break;
case yajl_status_client_canceled:
this->jpw_error_msg = "internal error";
break;
case yajl_status_error:
this->jpw_error_msg = std::string((const char *)yajl_get_error(
this->jpw_handle, 1, (const unsigned char *)buffer, len));
break;
}
};
void clear() {
this->jpw_values.clear();
};
void inc_array_index() {
if (!this->jpw_array_indexes.empty() &&
this->jpw_array_indexes.back() != -1) {
this->jpw_array_indexes.back() += 1;
}
};
std::string current_ptr() {
std::string retval;
for (int lpc = 0; lpc < this->jpw_array_indexes.size(); lpc++) {
retval.append("/");
if (this->jpw_array_indexes[lpc] == -1) {
retval.append(this->jpw_keys[lpc]);
}
else {
char num[64];
snprintf(num, sizeof(num), "%d", this->jpw_array_indexes[lpc]);
retval.append(num);
}
}
return retval;
};
typedef std::vector<std::pair<std::string, std::string> > pair_list_t;
auto_mem<yajl_handle_t> jpw_handle;
std::string jpw_error_msg;
pair_list_t jpw_values;
std::vector<std::string> jpw_keys;
std::vector<int32_t> jpw_array_indexes;
};
class json_ptr {
public:
enum match_state_t {
MS_DONE,
MS_VALUE,
MS_ELEMENT,
MS_ERR_INVALID_TYPE,
MS_ERR_NO_SLASH,
MS_ERR_INVALID_ESCAPE,
MS_ERR_INVALID_INDEX,
};
static size_t encode(char *dst, size_t dst_len, const char *src, size_t src_len = -1) {
size_t retval = 0;
if (src_len == -1) {
src_len = strlen(src);
}
for (size_t lpc = 0; lpc < src_len; lpc++) {
switch (src[lpc]) {
case '/':
case '~':
if (retval < dst_len) {
dst[retval] = '~';
retval += 1;
if (src[lpc] == '~') {
dst[retval] = '0';
}
else {
dst[retval] = '1';
}
}
else {
retval += 1;
}
break;
default:
if (retval < dst_len) {
dst[retval] = src[lpc];
}
break;
}
retval += 1;
}
return retval;
};
json_ptr(const char *value)
: jp_value(value), jp_pos(value), jp_depth(0), jp_array_index(-1),
jp_state(MS_VALUE) {
};
bool expect_map(int32_t &depth) {
bool retval;
if (this->jp_state == MS_DONE) {
retval = true;
}
else if (depth != this->jp_depth) {
retval = true;
}
else if (this->reached_end()) {
retval = true;
}
else if (this->jp_state == MS_VALUE) {
if (this->jp_pos[0] == '/') {
this->jp_pos += 1;
this->jp_depth += 1;
this->jp_state = MS_ELEMENT;
retval = true;
}
else {
this->jp_state = MS_ERR_NO_SLASH;
retval = false;
}
}
else {
retval = true;
}
depth += 1;
return retval;
};
bool at_key(int32_t depth, const char *component, ssize_t len = -1) {
const char *component_end;
int lpc;
if (this->jp_state == MS_DONE || depth != this->jp_depth) {
return true;
}
if (len == -1) {
len = strlen(component);
}
component_end = component + len;
for (lpc = 0; component < component_end; lpc++, component++) {
char ch = this->jp_pos[lpc];
if (this->jp_pos[lpc] == '~') {
switch (this->jp_pos[lpc + 1]) {
case '0':
ch = '~';
break;
case '1':
ch = '/';
break;
default:
this->jp_state = MS_ERR_INVALID_ESCAPE;
return false;
}
lpc += 1;
}
else if (this->jp_pos[lpc] == '/') {
ch = '\0';
}
if (ch != *component) {
return true;
}
}
this->jp_pos += lpc;
this->jp_state = MS_VALUE;
return true;
};
void exit_container(int32_t &depth, int32_t &index) {
depth -= 1;
if (this->jp_state == MS_VALUE && depth == this->jp_depth) {
this->jp_state = MS_DONE;
index = -1;
}
};
bool expect_array(int32_t &depth, int32_t &index) {
bool retval;
if (this->jp_state == MS_DONE) {
retval = true;
}
else if (depth != this->jp_depth) {
retval = true;
}
else if (this->reached_end()) {
retval = true;
}
else if (this->jp_pos[0] == '/') {
int offset;
this->jp_depth += 1;
if (sscanf(this->jp_pos, "/%d%n", &this->jp_array_index, &offset) != 1) {
this->jp_state = MS_ERR_INVALID_INDEX;
retval = false;
}
else if (this->jp_pos[offset] != '\0' && this->jp_pos[offset] != '/') {
this->jp_state = MS_ERR_INVALID_INDEX;
retval = false;
}
else {
index = 0;
this->jp_pos += offset;
this->jp_state = MS_ELEMENT;
retval = true;
}
}
else {
this->jp_state = MS_ERR_NO_SLASH;
retval = false;
}
depth += 1;
return retval;
};
bool at_index(int32_t &depth, int32_t &index, bool primitive = true) {
bool retval;
if (this->jp_state == MS_DONE) {
retval = false;
}
else if (depth < this->jp_depth) {
retval = false;
}
else if (depth == this->jp_depth) {
if (index == -1) {
if (this->jp_array_index == -1) {
retval = this->reached_end();
if (primitive && retval) {
this->jp_state = MS_DONE;
}
}
else {
retval = false;
}
}
else if (index == this->jp_array_index) {
retval = this->reached_end();
index = -1;
if (primitive && retval) {
this->jp_state = MS_DONE;
}
}
else {
index += 1;
retval = false;
}
}
else if (index == -1) {
retval = this->reached_end();
}
else {
retval = false;
}
return retval;
};
bool reached_end() {
return this->jp_pos[0] == '\0';
};
std::string error_msg() const {
std::string retval;
switch (this->jp_state) {
case MS_ERR_INVALID_ESCAPE:
retval = ("invalid escape sequence near -- " + std::string(this->jp_pos));
break;
case MS_ERR_INVALID_INDEX:
retval = ("expecting array index at -- " + std::string(this->jp_pos));
break;
case MS_ERR_INVALID_TYPE:
retval = ("expecting container at -- " + std::string(
this->jp_value, this->jp_pos - this->jp_value));
break;
default:
break;
}
return retval;
};
const char *jp_value;
const char *jp_pos;
int32_t jp_depth;
int32_t jp_array_index;
match_state_t jp_state;
};
#endif

@ -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());
}
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:");
}
return 1 +
1 +
this->fos_log_helper.ldh_line_values.size() +
1 +
this->fos_log_helper.ldh_parser->dp_pairs.size();
};
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;
bool list_value_for_overlay(const listview_curses &lv,
vis_line_t y,
attr_line_t &value_out)
{
view_colors &vc = view_colors::singleton();
str = " " + lv.lv_name;
str.append(this->fos_known_key_size - lv.lv_name.size() + 3, ' ');
str += " = " + lv.to_string();
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));
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)));
if (row < 0 || row >= (int)total_count) {
return false;
this->fos_lines.push_back(al);
this->add_key_line_attrs(this->fos_known_key_size);
}
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;
}
std::map<std::string, json_ptr_walk::pair_list_t>::iterator json_iter;
if (row < (int)this->fos_log_helper.ldh_line_values.size()) {
string &name = this->fos_log_helper.ldh_line_values[row].lv_name;
if (!this->fos_log_helper.ldh_json_pairs.empty()) {
this->fos_lines.push_back(" JSON fields:");
}
str = " " + name;
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;
int padding = this->fos_key_size - str.length() + 3;
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);
}
}
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();
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
this->fos_lines.push_back(" No discovered message fields");
}
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);
this->fos_lines.push_back(" Discovered message fields:");
}
string &name = this->fos_log_helper.ldh_namer->cn_names[row];
data_parser::element_list_t::iterator iter;
str = " " + name;
int padding = this->fos_key_size - str.length() + 3;
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);
value_out.get_attrs().push_back(string_attr(
al.with_attr(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());
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));
}
string_attrs_t & sa = value_out.get_attrs();
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 + this->fos_key_size + 3;
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)
{
if (!this->fos_active || this->fos_log_helper.ldh_parser.get() == NULL) {
return false;
}
int row = (int)y - 1;
if (row < 0 || row >= (int)this->fos_lines.size()) {
return false;
}
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'; \

@ -0,0 +1,198 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file drive_json_op.cc
*/
#include "config.h"
#include <stdlib.h>
#include "json_op.hh"
static void printer(void *ctx, const char *numberVal, size_t numberLen)
{
write(STDOUT_FILENO, numberVal, numberLen);
}
static int handle_start_map(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_map_open(gen);
return 1;
}
static int handle_map_key(void *ctx, const unsigned char * key, size_t len)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_string(gen, key, len);
return 1;
}
static int handle_end_map(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_map_close(gen);
return 1;
}
static int handle_null(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_null(gen);
return 1;
}
static int handle_boolean(void *ctx, int boolVal)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_bool(gen, boolVal);
return 1;
}
static int handle_number(void *ctx, const char *numberVal, size_t numberLen)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_number(gen, numberVal, numberLen);
return 1;
}
static int handle_string(void *ctx, const unsigned char * stringVal, size_t len)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_string(gen, stringVal, len);
return 1;
}
static int handle_start_array(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_array_open(gen);
return 1;
}
static int handle_end_array(void *ctx)
{
json_op *jo = (json_op *)ctx;
yajl_gen gen = (yajl_gen)jo->jo_ptr_data;
yajl_gen_array_close(gen);
return 1;
}
int main(int argc, char *argv[])
{
int retval = EXIT_SUCCESS;
log_argv(argc, argv);
if (argc != 3) {
fprintf(stderr, "error: expecting operation and json-pointer\n");
retval = EXIT_FAILURE;
}
else if (strcmp(argv[1], "get") == 0) {
unsigned char buffer[1024];
json_ptr jptr(argv[2]);
json_op jo(jptr);
yajl_handle handle;
yajl_status status;
yajl_gen gen;
ssize_t rc;
gen = yajl_gen_alloc(NULL);
yajl_gen_config(gen, yajl_gen_print_callback, printer, NULL);
yajl_gen_config(gen, yajl_gen_beautify, true);
jo.jo_ptr_callbacks.yajl_start_map = handle_start_map;
jo.jo_ptr_callbacks.yajl_map_key = handle_map_key;
jo.jo_ptr_callbacks.yajl_end_map = handle_end_map;
jo.jo_ptr_callbacks.yajl_start_array = handle_start_array;
jo.jo_ptr_callbacks.yajl_end_array = handle_end_array;
jo.jo_ptr_callbacks.yajl_null = handle_null;
jo.jo_ptr_callbacks.yajl_boolean = handle_boolean;
jo.jo_ptr_callbacks.yajl_number = handle_number;
jo.jo_ptr_callbacks.yajl_string = handle_string;
jo.jo_ptr_data = gen;
handle = yajl_alloc(&json_op::ptr_callbacks, NULL, &jo);
while ((rc = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
status = yajl_parse(handle, buffer, rc);
if (status == yajl_status_error) {
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
yajl_get_error(handle, 1, buffer, rc));
retval = EXIT_FAILURE;
break;
}
else if (status == yajl_status_client_canceled) {
fprintf(stderr, "client cancel\n");
break;
}
}
status = yajl_complete_parse(handle);
if (status == yajl_status_error) {
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
yajl_get_error(handle, 1, buffer, rc));
retval = EXIT_FAILURE;
}
else if (status == yajl_status_client_canceled) {
fprintf(stderr, "client cancel\n");
}
yajl_free(handle);
}
else {
fprintf(stderr, "error: unknown operation -- %s\n", argv[1]);
retval = EXIT_FAILURE;
}
return retval;
}

@ -0,0 +1,79 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file drive_json_ptr_dump.cc
*/
#include "config.h"
#include <stdlib.h>
#include "json_ptr.hh"
int main(int argc, char *argv[])
{
int retval = EXIT_SUCCESS;
char buffer[1024];
yajl_status status;
json_ptr_walk jpw;
ssize_t rc;
log_argv(argc, argv);
while ((rc = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
status = jpw.parse(buffer, rc);
if (status == yajl_status_error) {
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
jpw.jpw_error_msg.c_str());
retval = EXIT_FAILURE;
break;
}
else if (status == yajl_status_client_canceled) {
fprintf(stderr, "client cancel\n");
break;
}
}
status = jpw.complete_parse();
if (status == yajl_status_error) {
fprintf(stderr, "error:cannot parse JSON input -- %s\n",
jpw.jpw_error_msg.c_str());
retval = EXIT_FAILURE;
}
else if (status == yajl_status_client_canceled) {
fprintf(stderr, "client cancel\n");
}
for (json_ptr_walk::pair_list_t::iterator iter = jpw.jpw_values.begin();
iter != jpw.jpw_values.end();
++iter) {
printf("%s = %s\n", iter->first.c_str(), iter->second.c_str());
}
return retval;
}

@ -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;

@ -0,0 +1,94 @@
#! /bin/bash
run_test ./drive_json_op get "" <<EOF
3
EOF
check_output "cannot read root number value" <<EOF
3
EOF
run_test ./drive_json_op get "" <<EOF
null
EOF
check_output "cannot read root null value" <<EOF
null
EOF
run_test ./drive_json_op get "" <<EOF
true
EOF
check_output "cannot read root bool value" <<EOF
true
EOF
run_test ./drive_json_op get "" <<EOF
"str"
EOF
check_output "cannot read root string value" <<EOF
"str"
EOF
run_test ./drive_json_op get "" <<EOF
{ "val" : 3, "other" : 2 }
EOF
check_output "cannot read root map value" <<EOF
{
"val": 3,
"other": 2
}
EOF
run_test ./drive_json_op get /val <<EOF
{ "val" : 3 }
EOF
check_output "cannot read top-level value" <<EOF
3
EOF
run_test ./drive_json_op get /val <<EOF
{ "other" : { "val" : 5 }, "val" : 3 }
EOF
check_output "read wrong value" <<EOF
3
EOF
run_test ./drive_json_op get /other <<EOF
{ "other" : { "val" : 5 }, "val" : 3 }
EOF
check_output "cannot read map" <<EOF
{
"val": 5
}
EOF
run_test ./drive_json_op get "" <<EOF
[0, 1]
EOF
check_output "cannot read root array value" <<EOF
[
0,
1
]
EOF
run_test ./drive_json_op get "/6" <<EOF
[null, true, 1, "str", {"sub":[10, 11]}, [21, [33, 34], 66], 2]
EOF
check_output "cannot read array value" <<EOF
2
EOF
run_test ./drive_json_op get "/ID" <<EOF
{"ID":"P1","ProcessID":"P1","Name":"VxWorks","CanSuspend":true,"CanResume":1,"IsContainer":true,"WordSize":4,"CanTerminate":true,"CanDetach":true,"RCGroup":"P1","SymbolsGroup":"P1","CPUGroup":"P1","DiagnosticTestProcess":true}
EOF

@ -0,0 +1,73 @@
/**
* Copyright (c) 2014, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TIMOTHY STACK AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file test_json_ptr.cc
*/
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "json_ptr.hh"
int main(int argc, const char *argv[])
{
int32_t depth, index;
{
json_ptr jptr("");
depth = 0;
index = -1;
assert(jptr.at_index(depth, index));
}
{
json_ptr jptr("/");
depth = 0;
index = -1;
assert(!jptr.at_index(depth, index));
assert(jptr.expect_map(depth));
assert(jptr.at_index(depth, index));
}
{
json_ptr jptr("/foo/bar");
depth = 0;
index = -1;
assert(jptr.expect_map(depth));
assert(jptr.at_key(depth, "foo"));
assert(jptr.expect_map(depth));
assert(jptr.at_key(depth, "bar"));
assert(jptr.at_index(depth, index));
}
}

@ -0,0 +1,67 @@
#! /bin/bash
run_test ./drive_json_ptr_walk <<EOF
{ "foo" : 1 }
EOF
check_output "simple object" <<EOF
/foo = 1
EOF
run_test ./drive_json_ptr_walk <<EOF
{ "~tstack/julia" : 1 }
EOF
check_output "escaped object" <<EOF
/~0tstack~1julia = 1
EOF
run_test ./drive_json_ptr_walk <<EOF
1
EOF
check_output "root value" <<EOF
= 1
EOF
run_test ./drive_json_ptr_walk <<EOF
[1, 2, 3]
EOF
check_output "array" <<EOF
/0 = 1
/1 = 2
/2 = 3
EOF
run_test ./drive_json_ptr_walk <<EOF
[1, 2, 3, [4, 5, 6]]
EOF
check_output "nested array" <<EOF
/0 = 1
/1 = 2
/2 = 3
/3/0 = 4
/3/1 = 5
/3/2 = 6
EOF
run_test ./drive_json_ptr_walk <<EOF
[null, true, 123.0, "foo", { "bar" : { "baz" : [1, 2, 3]} }, ["a", null]]
EOF
check_error_output "" <<EOF
EOF
check_output "complex" <<EOF
/0 = null
/1 = true
/2 = 123.0
/3 = "foo"
/4/bar/baz/0 = 1
/4/bar/baz/1 = 2
/4/bar/baz/2 = 3
/5/0 = "a"
/5/1 = null
EOF

@ -0,0 +1,55 @@
#! /bin/bash
run_test ./drive_sql "select jget('4', '')"
check_output "jget root does not work" <<EOF
Row 0:
Column jget('4', ''): 4
EOF
run_test ./drive_sql "select jget('4', null)"
check_output "jget null does not work" <<EOF
Row 0:
Column jget('4', null): 4
EOF
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/3')"
check_error_output "" <<EOF
EOF
check_output "jget null does not work" <<EOF
Row 0:
Column jget('[null, true, 20, 30, 40]', '/3'): 30
EOF
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/abc')"
check_error_output "" <<EOF
EOF
check_output "jget for array does not work" <<EOF
Row 0:
Column jget('[null, true, 20, 30, 40]', '/abc'): (null)
EOF
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/abc', 1)"
check_error_output "" <<EOF
EOF
check_output "jget for array does not work" <<EOF
Row 0:
Column jget('[null, true, 20, 30, 40]', '/abc', 1): 1
EOF
run_test ./drive_sql "select jget('[null, true, 20, 30, 40]', '/0/foo')"
check_error_output "" <<EOF
EOF
check_output "jget for array does not work" <<EOF
Row 0:
Column jget('[null, true, 20, 30, 40]', '/0/foo'): (null)
EOF
Loading…
Cancel
Save