summaryrefslogtreecommitdiffstats
path: root/src/yajlpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yajlpp')
-rw-r--r--src/yajlpp/CMakeLists.txt2
-rw-r--r--src/yajlpp/Makefile.am2
-rw-r--r--src/yajlpp/json_ptr.cc46
-rw-r--r--src/yajlpp/json_ptr.hh11
-rw-r--r--src/yajlpp/yajlpp.cc82
-rw-r--r--src/yajlpp/yajlpp.hh63
-rw-r--r--src/yajlpp/yajlpp_def.hh467
7 files changed, 567 insertions, 106 deletions
diff --git a/src/yajlpp/CMakeLists.txt b/src/yajlpp/CMakeLists.txt
index 73168ba..260e6e1 100644
--- a/src/yajlpp/CMakeLists.txt
+++ b/src/yajlpp/CMakeLists.txt
@@ -13,7 +13,7 @@ add_library(
target_include_directories(yajlpp PUBLIC . .. ../fmtlib
${CMAKE_CURRENT_BINARY_DIR}/..)
-target_link_libraries(yajlpp pcrepp yajl ncurses::libcurses)
+target_link_libraries(yajlpp pcrepp yajl ncurses::libcurses datepp)
add_executable(test_yajlpp test_yajlpp.cc)
target_link_libraries(test_yajlpp yajlpp base ${lnav_LIBS})
diff --git a/src/yajlpp/Makefile.am b/src/yajlpp/Makefile.am
index cc6bcf6..35688a0 100644
--- a/src/yajlpp/Makefile.am
+++ b/src/yajlpp/Makefile.am
@@ -11,6 +11,7 @@ AM_CPPFLAGS = \
$(PCRE_CFLAGS) \
-I$(top_srcdir)/src/ \
-I$(top_srcdir)/src/fmtlib \
+ -I$(top_srcdir)/src/third-party/date/include \
-I$(top_srcdir)/src/third-party/scnlib/include
AM_LDFLAGS = \
@@ -53,6 +54,7 @@ LDADD = \
libyajlpp.a \
$(top_builddir)/src/base/libbase.a \
$(top_builddir)/src/fmtlib/libcppfmt.a \
+ $(top_builddir)/src/third-party/date/src/libdatepp.a \
$(top_builddir)/src/third-party/scnlib/src/libscnlib.a \
$(top_builddir)/src/pcrepp/libpcrepp.a \
$(top_builddir)/src/yajl/libyajl.a
diff --git a/src/yajlpp/json_ptr.cc b/src/yajlpp/json_ptr.cc
index 4cc0273..3336f4e 100644
--- a/src/yajlpp/json_ptr.cc
+++ b/src/yajlpp/json_ptr.cc
@@ -226,6 +226,19 @@ json_ptr::encode(char* dst, size_t dst_len, const char* src, size_t src_len)
return retval;
}
+std::string
+json_ptr::encode_str(const char* src, size_t src_len)
+{
+ if (src_len == (size_t) -1) {
+ src_len = strlen(src);
+ }
+
+ char retval[src_len * 2 + 1];
+ auto rc = encode(retval, sizeof(retval), src, src_len);
+
+ return std::string(retval, rc);
+}
+
size_t
json_ptr::decode(char* dst, const char* src, ssize_t src_len)
{
@@ -268,6 +281,39 @@ json_ptr::decode(char* dst, const char* src, ssize_t src_len)
return retval;
}
+std::string
+json_ptr::decode(const string_fragment& sf)
+{
+ std::string retval;
+ auto in_escape = false;
+
+ retval.reserve(sf.length());
+ for (const auto ch : sf) {
+ if (in_escape) {
+ switch (ch) {
+ case '0':
+ retval.push_back('~');
+ break;
+ case '1':
+ retval.push_back('/');
+ break;
+ case '2':
+ retval.push_back('#');
+ break;
+ default:
+ break;
+ }
+ in_escape = false;
+ } else if (ch == '~') {
+ in_escape = true;
+ } else {
+ retval.push_back(ch);
+ }
+ }
+
+ return retval;
+}
+
bool
json_ptr::expect_map(int32_t& depth, int32_t& index)
{
diff --git a/src/yajlpp/json_ptr.hh b/src/yajlpp/json_ptr.hh
index f7822ab..463048c 100644
--- a/src/yajlpp/json_ptr.hh
+++ b/src/yajlpp/json_ptr.hh
@@ -41,6 +41,7 @@
#include <sys/types.h>
#include "base/auto_mem.hh"
+#include "base/intern_string.hh"
#include "yajl/api/yajl_parse.h"
#include "yajl/api/yajl_tree.h"
@@ -64,7 +65,8 @@ public:
void inc_array_index()
{
if (!this->jpw_array_indexes.empty()
- && this->jpw_array_indexes.back() != -1) {
+ && this->jpw_array_indexes.back() != -1)
+ {
this->jpw_array_indexes.back() += 1;
}
}
@@ -108,7 +110,14 @@ public:
const char* src,
size_t src_len = -1);
+ static std::string encode_str(const char* src, size_t src_len = -1);
+ static std::string encode_str(const std::string& src)
+ {
+ return encode_str(src.c_str(), src.size());
+ }
+
static size_t decode(char* dst, const char* src, ssize_t src_len = -1);
+ static std::string decode(const string_fragment& sf);
json_ptr(const char* value) : jp_value(value), jp_pos(value) {}
diff --git a/src/yajlpp/yajlpp.cc b/src/yajlpp/yajlpp.cc
index b1362ab..0fc0001 100644
--- a/src/yajlpp/yajlpp.cc
+++ b/src/yajlpp/yajlpp.cc
@@ -34,8 +34,6 @@
#include "yajlpp.hh"
-#include "base/fs_util.hh"
-#include "base/snippet_highlighters.hh"
#include "config.h"
#include "fmt/format.h"
#include "ghc/filesystem.hpp"
@@ -213,10 +211,7 @@ json_path_handler_base::gen(yajlpp_gen_context& ygc, yajl_gen handle) const
if (this->jph_children) {
for (const auto& lpath : local_paths) {
- std::string full_path = lpath;
- if (this->jph_path_provider) {
- full_path += "/";
- }
+ std::string full_path = json_ptr::encode_str(lpath);
int start_depth = ygc.ygc_depth;
yajl_gen_string(handle, lpath);
@@ -455,8 +450,8 @@ json_path_handler_base::gen_schema_type(yajlpp_gen_context& ygc) const
void
json_path_handler_base::walk(
- const std::function<
- void(const json_path_handler_base&, const std::string&, void*)>& cb,
+ const std::function<void(
+ const json_path_handler_base&, const std::string&, const void*)>& cb,
void* root,
const std::string& base) const
{
@@ -465,11 +460,11 @@ json_path_handler_base::walk(
if (this->jph_path_provider) {
this->jph_path_provider(root, local_paths);
- for (auto& lpath : local_paths) {
+ for (const auto& lpath : local_paths) {
cb(*this,
fmt::format(FMT_STRING("{}{}{}"),
base,
- lpath,
+ json_ptr::encode_str(lpath),
this->jph_children ? "/" : ""),
nullptr);
}
@@ -477,6 +472,12 @@ json_path_handler_base::walk(
local_paths.clear();
this->jph_path_provider(root, local_paths);
}
+ if (this->jph_field_getter) {
+ const auto* field = this->jph_field_getter(root, nonstd::nullopt);
+ if (field != nullptr) {
+ cb(*this, base, field);
+ }
+ }
} else {
local_paths.emplace_back(this->jph_property);
@@ -484,6 +485,7 @@ json_path_handler_base::walk(
if (this->jph_children) {
full_path += "/";
}
+
cb(*this, full_path, nullptr);
}
@@ -493,7 +495,7 @@ json_path_handler_base::walk(
static const intern_string_t POSS_SRC
= intern_string::lookup("possibilities");
- std::string full_path = base + lpath;
+ std::string full_path = base + json_ptr::encode_str(lpath);
if (this->jph_children) {
full_path += "/";
}
@@ -509,13 +511,18 @@ json_path_handler_base::walk(
static thread_local auto md
= lnav::pcre2pp::match_data::unitialized();
- std::string full_path = lpath + "/";
+ const auto short_path = json_ptr::encode_str(lpath) + "/";
- if (!this->jph_regex->capture_from(full_path)
+ if (!this->jph_regex->capture_from(short_path)
.into(md)
.matches()
.ignore_error())
{
+ log_error(
+ "path-handler regex (%s) does not match path: "
+ "%s",
+ this->jph_regex->get_pattern().c_str(),
+ full_path.c_str());
ensure(false);
}
child_root = this->jph_obj_provider(
@@ -527,7 +534,7 @@ json_path_handler_base::walk(
}
} else {
for (auto& lpath : local_paths) {
- void* field = nullptr;
+ const void* field = nullptr;
if (this->jph_field_getter) {
field = this->jph_field_getter(root, lpath);
@@ -1370,6 +1377,33 @@ json_path_handler_base::report_pattern_error(yajlpp_parse_context* ypc,
.with_help(this->get_help_text(ypc)));
}
+void
+json_path_handler_base::report_tz_error(yajlpp_parse_context* ypc,
+ const std::string& value_str,
+ const char* msg) const
+{
+ auto help_al = attr_line_t()
+ .append(lnav::roles::h2("Available time zones"))
+ .append("\n");
+
+ try {
+ for (const auto& tz : date::get_tzdb().zones) {
+ help_al.append(" ")
+ .append(lnav::roles::symbol(tz.name()))
+ .append("\n");
+ }
+ } catch (const std::runtime_error& e) {
+ log_error("unable to load timezones: %s", e.what());
+ }
+
+ ypc->report_error(lnav::console::user_message::error(
+ attr_line_t().append_quoted(value_str).append(
+ " is not a valid timezone"))
+ .with_snippet(ypc->get_snippet())
+ .with_reason(msg)
+ .with_help(help_al));
+}
+
attr_line_t
json_path_handler_base::get_help_text(const std::string& full_path) const
{
@@ -1495,6 +1529,7 @@ json_path_container::gen_schema(yajlpp_gen_context& ygc) const
void
json_path_container::gen_properties(yajlpp_gen_context& ygc) const
{
+ static const auto FWD_SLASH = lnav::pcre2pp::code::from_const(R"(\[\^/\])");
auto pattern_count = count_if(
this->jpc_children.begin(), this->jpc_children.end(), [](auto& jph) {
return jph.jph_is_pattern_property;
@@ -1524,7 +1559,10 @@ json_path_container::gen_properties(yajlpp_gen_context& ygc) const
if (!child_handler.jph_is_pattern_property) {
continue;
}
- properties.gen(child_handler.jph_property);
+
+ auto pattern = child_handler.jph_property;
+ pattern = FWD_SLASH.replace(pattern, ".");
+ properties.gen(fmt::format(FMT_STRING("^{}$"), pattern));
child_handler.gen_schema(ygc);
}
}
@@ -1572,3 +1610,17 @@ yajlpp_gen::to_string_fragment()
return string_fragment::from_bytes(buf, len);
}
+
+namespace yajlpp {
+
+auto_mem<yajl_handle_t>
+alloc_handle(const yajl_callbacks* cb, void* cu)
+{
+ auto_mem<yajl_handle_t> retval(yajl_free);
+
+ retval = yajl_alloc(cb, nullptr, cu);
+
+ return retval;
+}
+
+} // namespace yajlpp \ No newline at end of file
diff --git a/src/yajlpp/yajlpp.hh b/src/yajlpp/yajlpp.hh
index 7632329..ecf9734 100644
--- a/src/yajlpp/yajlpp.hh
+++ b/src/yajlpp/yajlpp.hh
@@ -112,6 +112,14 @@ struct factory_container : public positioned_property<std::shared_ptr<T>> {
return Err(
lnav::console::to_user_message(src, from_res.unwrapErr()));
}
+
+ std::string to_string() const
+ {
+ if (this->pp_value != nullptr) {
+ return this->pp_value->to_string();
+ }
+ return "";
+ }
};
template<typename... Args>
@@ -131,6 +139,14 @@ struct factory_container : public positioned_property<std::shared_ptr<T>> {
return Err(lnav::console::to_user_message(src, from_res.unwrapErr()));
}
+
+ std::string to_string() const
+ {
+ if (this->pp_value != nullptr) {
+ return this->pp_value->to_string();
+ }
+ return "";
+ }
};
class yajlpp_gen_context;
@@ -228,11 +244,11 @@ struct json_path_handler_base {
yajl_gen_status gen(yajlpp_gen_context& ygc, yajl_gen handle) const;
yajl_gen_status gen_schema(yajlpp_gen_context& ygc) const;
yajl_gen_status gen_schema_type(yajlpp_gen_context& ygc) const;
- void walk(
- const std::function<
- void(const json_path_handler_base&, const std::string&, void*)>& cb,
- void* root = nullptr,
- const std::string& base = "/") const;
+ void walk(const std::function<void(const json_path_handler_base&,
+ const std::string&,
+ const void*)>& cb,
+ void* root = nullptr,
+ const std::string& base = "/") const;
enum class schema_type_t : std::uint32_t {
ANY,
@@ -255,7 +271,7 @@ struct json_path_handler_base {
std::function<void(yajlpp_parse_context& ypc,
const json_path_handler_base& jph)>
jph_validator;
- std::function<void*(void* root, nonstd::optional<std::string> name)>
+ std::function<const void*(void* root, nonstd::optional<std::string> name)>
jph_field_getter;
std::function<void*(const yajlpp_provider_context& pe, void* root)>
jph_obj_provider;
@@ -283,8 +299,7 @@ struct json_path_handler_base {
std::function<int(yajlpp_parse_context*, int)> jph_bool_cb;
std::function<int(yajlpp_parse_context*, long long)> jph_integer_cb;
std::function<int(yajlpp_parse_context*, double)> jph_double_cb;
- std::function<int(
- yajlpp_parse_context*, const unsigned char* str, size_t len)>
+ std::function<int(yajlpp_parse_context*, const string_fragment& sf)>
jph_str_cb;
void validate_string(yajlpp_parse_context& ypc, string_fragment sf) const;
@@ -301,6 +316,9 @@ struct json_path_handler_base {
void report_error(yajlpp_parse_context* ypc,
const std::string& value_str,
lnav::console::user_message um) const;
+ void report_tz_error(yajlpp_parse_context* ypc,
+ const std::string& value_str,
+ const char* msg) const;
attr_line_t get_help_text(const std::string& full_path) const;
attr_line_t get_help_text(yajlpp_parse_context* ypc) const;
@@ -452,6 +470,16 @@ public:
return obj->*MEM;
}
+ void fill_in_source()
+ {
+ if (this->ypc_locations != nullptr) {
+ (*this->ypc_locations)[this->get_full_path()] = source_location{
+ this->ypc_source,
+ this->get_line_number(),
+ };
+ }
+ }
+
const intern_string_t ypc_source;
int ypc_line_number{1};
const struct json_path_container* ypc_handlers;
@@ -673,10 +701,29 @@ struct json_string {
memcpy((void*) this->js_content.in(), buf, this->js_len);
}
+ explicit json_string(auto_buffer&& buf)
+ {
+ auto buf_pair = buf.release();
+
+ this->js_content = (const unsigned char*) buf_pair.first;
+ this->js_len = buf_pair.second;
+ }
+
+ string_fragment to_string_fragment() const
+ {
+ return string_fragment::from_bytes(this->js_content, this->js_len);
+ }
+
auto_mem<const unsigned char> js_content;
size_t js_len{0};
};
void dump_schema_to(const json_path_container& jpc, const char* internals_dir);
+namespace yajlpp {
+
+auto_mem<yajl_handle_t> alloc_handle(const yajl_callbacks* cb, void* cu);
+
+} // namespace yajlpp
+
#endif
diff --git a/src/yajlpp/yajlpp_def.hh b/src/yajlpp/yajlpp_def.hh
index 22454b1..7bcb687 100644
--- a/src/yajlpp/yajlpp_def.hh
+++ b/src/yajlpp/yajlpp_def.hh
@@ -241,11 +241,13 @@ struct json_path_handler : public json_path_handler_base {
static int null_field_cb(yajlpp_parse_context* ypc)
{
+ ypc->fill_in_source();
return ypc->ypc_current_handler->jph_null_cb(ypc);
}
static int bool_field_cb(yajlpp_parse_context* ypc, int val)
{
+ ypc->fill_in_source();
return ypc->ypc_current_handler->jph_bool_cb(ypc, val);
}
@@ -253,20 +255,36 @@ struct json_path_handler : public json_path_handler_base {
const unsigned char* str,
size_t len)
{
- return ypc->ypc_current_handler->jph_str_cb(ypc, str, len);
+ ypc->fill_in_source();
+ return ypc->ypc_current_handler->jph_str_cb(
+ ypc, string_fragment::from_bytes(str, len));
}
static int int_field_cb(yajlpp_parse_context* ypc, long long val)
{
+ ypc->fill_in_source();
return ypc->ypc_current_handler->jph_integer_cb(ypc, val);
}
static int dbl_field_cb(yajlpp_parse_context* ypc, double val)
{
+ ypc->fill_in_source();
return ypc->ypc_current_handler->jph_double_cb(ypc, val);
}
template<typename T, typename U>
+ static inline U& get_field(T& input, std::shared_ptr<U>(T::*field))
+ {
+ auto& ptr = input.*field;
+
+ if (ptr.get() == nullptr) {
+ ptr = std::make_shared<U>();
+ }
+
+ return *ptr;
+ }
+
+ template<typename T, typename U>
static inline U& get_field(T& input, U(T::*field))
{
return input.*field;
@@ -366,11 +384,64 @@ struct json_path_handler : public json_path_handler_base {
};
template<typename T, typename U>
+ struct LastIsVector<std::shared_ptr<std::vector<U>> T::*> {
+ using value_type = U;
+ static constexpr bool value = true;
+ };
+
+ template<typename T, typename U>
struct LastIsVector<U T::*> {
using value_type = void;
static constexpr bool value = false;
};
+ template<typename T, typename... Args>
+ struct LastIsIntegerVector {
+ using value_type = typename LastIsIntegerVector<Args...>::value_type;
+ static constexpr bool value = LastIsIntegerVector<Args...>::value;
+ };
+
+ template<typename T, typename U>
+ struct LastIsIntegerVector<std::vector<U> T::*> {
+ using value_type = U;
+ static constexpr bool value
+ = std::is_integral<U>::value && !std::is_same<U, bool>::value;
+ };
+
+ template<typename T, typename U>
+ struct LastIsIntegerVector<U T::*> {
+ using value_type = void;
+ static constexpr bool value = false;
+ };
+
+ template<typename T, typename... Args>
+ struct LastIsMap {
+ using key_type = typename LastIsMap<Args...>::key_type;
+ using value_type = typename LastIsMap<Args...>::value_type;
+ static constexpr bool value = LastIsMap<Args...>::value;
+ };
+
+ template<typename T, typename K, typename U>
+ struct LastIsMap<std::shared_ptr<std::map<K, U>> T::*> {
+ using key_type = K;
+ using value_type = U;
+ static constexpr bool value = true;
+ };
+
+ template<typename T, typename K, typename U>
+ struct LastIsMap<std::map<K, U> T::*> {
+ using key_type = K;
+ using value_type = U;
+ static constexpr bool value = true;
+ };
+
+ template<typename T, typename U>
+ struct LastIsMap<U T::*> {
+ using key_type = void;
+ using value_type = void;
+ static constexpr bool value = false;
+ };
+
template<typename T>
static bool is_field_set(const nonstd::optional<T>& field)
{
@@ -434,15 +505,13 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto value_str = std::string((const char*) str, len);
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
jph->validate_string(*ypc, value_str);
json_path_handler::get_field(obj, args...)
- .emplace_back(std::move(value_str));
+ .emplace_back(value_str.to_string());
return 1;
};
@@ -450,10 +519,33 @@ struct json_path_handler : public json_path_handler_base {
}
template<typename... Args,
+ std::enable_if_t<LastIsIntegerVector<Args...>::value, bool> = true>
+ json_path_handler& for_field(Args... args)
+ {
+ this->add_cb(int_field_cb);
+ this->jph_integer_cb
+ = [args...](yajlpp_parse_context* ypc, long long val) {
+ const auto* jph = ypc->ypc_current_handler;
+ auto* obj = ypc->ypc_obj_stack.top();
+
+ if (val < jph->jph_min_value) {
+ jph->report_min_value_error(ypc, val);
+ return 1;
+ }
+
+ json_path_handler::get_field(obj, args...).emplace_back(val);
+
+ return 1;
+ };
+ return *this;
+ }
+
+ template<typename... Args,
std::enable_if_t<LastIsVector<Args...>::value, bool> = true,
std::enable_if_t<
!std::is_same<typename LastIsVector<Args...>::value_type,
- std::string>::value,
+ std::string>::value
+ && !LastIsIntegerVector<Args...>::value,
bool>
= true>
json_path_handler& for_field(Args... args)
@@ -515,16 +607,37 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
auto key = ypc->get_path_fragment(-1);
json_path_handler::get_field(obj, args...)[key]
- = std::string((const char*) str, len);
+ = value_str.to_string();
return 1;
};
+ this->jph_path_provider =
+ [args...](void* root, std::vector<std::string>& paths_out) {
+ const auto& field = json_path_handler::get_field(root, args...);
+
+ for (const auto& pair : field) {
+ paths_out.emplace_back(pair.first);
+ }
+ };
+ this->jph_field_getter
+ = [args...](void* root,
+ nonstd::optional<std::string> name) -> const void* {
+ const auto& field = json_path_handler::get_field(root, args...);
+ if (!name) {
+ return &field;
+ }
+
+ auto iter = field.find(name.value());
+ if (iter == field.end()) {
+ return nullptr;
+ }
+ return (void*) &iter->second;
+ };
this->jph_gen_callback = [args...](yajlpp_gen_context& ygc,
const json_path_handler_base& jph,
yajl_gen handle) {
@@ -555,6 +668,70 @@ struct json_path_handler : public json_path_handler_base {
}
template<typename... Args,
+ std::enable_if_t<LastIsMap<Args...>::value, bool> = true,
+ std::enable_if_t<
+ std::is_same<intern_string_t,
+ typename LastIsMap<Args...>::key_type>::value,
+ bool>
+ = true>
+ json_path_handler& for_field(Args... args)
+ {
+ this->jph_path_provider =
+ [args...](void* root, std::vector<std::string>& paths_out) {
+ const auto& field = json_path_handler::get_field(root, args...);
+
+ for (const auto& pair : field) {
+ paths_out.emplace_back(std::to_string(pair.first));
+ }
+ };
+ this->jph_obj_provider
+ = [args...](const yajlpp_provider_context& ypc, void* root) {
+ auto& field = json_path_handler::get_field(root, args...);
+
+ return &(field[ypc.get_substr_i(0)]);
+ };
+ return *this;
+ }
+
+ template<
+ typename... Args,
+ std::enable_if_t<LastIsMap<Args...>::value, bool> = true,
+ std::enable_if_t<
+ std::is_same<std::string,
+ typename LastIsMap<Args...>::key_type>::value,
+ bool>
+ = true,
+ std::enable_if_t<
+ !std::is_same<json_any_t,
+ typename LastIsMap<Args...>::value_type>::value
+ && !std::is_same<std::string,
+ typename LastIsMap<Args...>::value_type>::value
+ && !std::is_same<
+ nonstd::optional<std::string>,
+ typename LastIsMap<Args...>::value_type>::value,
+ bool>
+ = true>
+ json_path_handler& for_field(Args... args)
+ {
+ this->jph_path_provider =
+ [args...](void* root, std::vector<std::string>& paths_out) {
+ const auto& field = json_path_handler::get_field(root, args...);
+
+ for (const auto& pair : field) {
+ paths_out.emplace_back(pair.first);
+ }
+ };
+ this->jph_obj_provider
+ = [args...](const yajlpp_provider_context& ypc, void* root) {
+ auto& field = json_path_handler::get_field(root, args...);
+ auto key = ypc.get_substr(0);
+
+ return &(field[key]);
+ };
+ return *this;
+ }
+
+ template<typename... Args,
std::enable_if_t<
LastIs<std::map<std::string, nonstd::optional<std::string>>,
Args...>::value,
@@ -564,13 +741,12 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
+ const string_fragment& value_str) {
auto obj = ypc->ypc_obj_stack.top();
auto key = ypc->get_path_fragment(-1);
json_path_handler::get_field(obj, args...)[key]
- = std::string((const char*) str, len);
+ = value_str.to_string();
return 1;
};
@@ -642,13 +818,12 @@ struct json_path_handler : public json_path_handler_base {
};
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
+ const string_fragment& value_str) {
auto* obj = ypc->ypc_obj_stack.top();
auto key = ypc->get_path_fragment(-1);
json_path_handler::get_field(obj, args...)[key]
- = std::string((const char*) str, len);
+ = value_str.to_string();
return 1;
};
@@ -691,14 +866,12 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto value_str = std::string((const char*) str, len);
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
jph->validate_string(*ypc, value_str);
- json_path_handler::get_field(obj, args...) = std::move(value_str);
+ json_path_handler::get_field(obj, args...) = value_str.to_string();
return 1;
};
@@ -738,23 +911,22 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
date_time_scanner dts;
timeval tv{};
exttm tm;
- if (dts.scan((char*) str, len, nullptr, &tm, tv) == nullptr) {
- ypc->report_error(
- lnav::console::user_message::error(
- attr_line_t("unrecognized timestamp ")
- .append_quoted(
- string_fragment::from_bytes(str, len)))
- .with_snippet(ypc->get_snippet())
- .with_help(jph->get_help_text(ypc)));
+ if (dts.scan(value_str.data(), value_str.length(), nullptr, &tm, tv)
+ == nullptr)
+ {
+ ypc->report_error(lnav::console::user_message::error(
+ attr_line_t("unrecognized timestamp ")
+ .append_quoted(value_str))
+ .with_snippet(ypc->get_snippet())
+ .with_help(jph->get_help_text(ypc)));
} else {
json_path_handler::get_field(obj, args...) = tv;
}
@@ -804,14 +976,20 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto value_str = std::string((const char*) str, len);
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
jph->validate_string(*ypc, value_str);
- json_path_handler::get_field(obj, args...) = std::move(value_str);
+ json_path_handler::get_field(obj, args...) = value_str.to_string();
+
+ return 1;
+ };
+ this->add_cb(null_field_cb);
+ this->jph_null_cb = [args...](yajlpp_parse_context* ypc) {
+ auto* obj = ypc->ypc_obj_stack.top();
+
+ json_path_handler::get_field(obj, args...) = nonstd::nullopt;
return 1;
};
@@ -858,11 +1036,9 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto value_str = std::string((const char*) str, len);
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
jph->validate_string(*ypc, value_str);
auto& field = json_path_handler::get_field(obj, args...);
@@ -870,7 +1046,7 @@ struct json_path_handler : public json_path_handler_base {
field.pp_path = ypc->get_full_path();
field.pp_location.sl_source = ypc->ypc_source;
field.pp_location.sl_line_number = ypc->get_line_number();
- field.pp_value = std::move(value_str);
+ field.pp_value = value_str.to_string();
return 1;
};
@@ -897,6 +1073,10 @@ struct json_path_handler : public json_path_handler_base {
return gen(field.pp_value);
};
+ this->jph_field_getter
+ = [args...](void* root, nonstd::optional<std::string> name) {
+ return (void*) &json_path_handler::get_field(root, args...);
+ };
return *this;
}
@@ -907,11 +1087,9 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto value_str = std::string((const char*) str, len);
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
jph->validate_string(*ypc, value_str);
json_path_handler::get_field(obj, args...)
@@ -945,6 +1123,60 @@ struct json_path_handler : public json_path_handler_base {
return *this;
}
+ template<
+ typename... Args,
+ std::enable_if_t<
+ LastIs<positioned_property<const date::time_zone*>, Args...>::value,
+ bool>
+ = true>
+ json_path_handler& for_field(Args... args)
+ {
+ this->add_cb(str_field_cb2);
+ this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
+
+ try {
+ const auto* tz
+ = date::get_tzdb().locate_zone(value_str.to_string());
+ auto& field = json_path_handler::get_field(obj, args...);
+ field.pp_path = ypc->get_full_path();
+ field.pp_location.sl_source = ypc->ypc_source;
+ field.pp_location.sl_line_number = ypc->get_line_number();
+ field.pp_value = tz;
+ } catch (const std::runtime_error& e) {
+ jph->report_tz_error(ypc, value_str.to_string(), e.what());
+ }
+
+ return 1;
+ };
+ this->jph_gen_callback = [args...](yajlpp_gen_context& ygc,
+ const json_path_handler_base& jph,
+ yajl_gen handle) {
+ const auto& field = json_path_handler::get_field(
+ ygc.ygc_obj_stack.top(), args...);
+
+ if (!ygc.ygc_default_stack.empty()) {
+ const auto& field_def = json_path_handler::get_field(
+ ygc.ygc_default_stack.top(), args...);
+
+ if (field.pp_value == field_def.pp_value) {
+ return yajl_gen_status_ok;
+ }
+ }
+
+ if (ygc.ygc_depth) {
+ yajl_gen_string(handle, jph.jph_property);
+ }
+
+ yajlpp_generator gen(handle);
+
+ return gen(field.pp_value->name());
+ };
+ return *this;
+ }
+
template<typename... Args,
std::enable_if_t<
LastIs<positioned_property<intern_string_t>, Args...>::value,
@@ -954,11 +1186,9 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto value_str = std::string((const char*) str, len);
- auto jph = ypc->ypc_current_handler;
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* jph = ypc->ypc_current_handler;
jph->validate_string(*ypc, value_str);
auto& field = json_path_handler::get_field(obj, args...);
@@ -997,7 +1227,7 @@ struct json_path_handler : public json_path_handler_base {
template<typename>
struct int_ {
- typedef int type;
+ using type = int;
};
template<
typename C,
@@ -1009,11 +1239,10 @@ struct json_path_handler : public json_path_handler_base {
json_path_handler& for_field(Args... args, T C::*ptr_arg)
{
this->add_cb(str_field_cb2);
- this->jph_str_cb = [args..., ptr_arg](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
+ this->jph_str_cb = [args..., ptr_arg](
+ yajlpp_parse_context* ypc,
+ const string_fragment& value_frag) {
auto* obj = ypc->ypc_obj_stack.top();
- auto value_frag = string_fragment::from_bytes(str, len);
const auto* jph = ypc->ypc_current_handler;
auto loc = source_location{ypc->ypc_source, ypc->get_line_number()};
@@ -1028,6 +1257,30 @@ struct json_path_handler : public json_path_handler_base {
return 1;
};
+ this->jph_gen_callback
+ = [args..., ptr_arg](yajlpp_gen_context& ygc,
+ const json_path_handler_base& jph,
+ yajl_gen handle) {
+ const auto& field = json_path_handler::get_field(
+ ygc.ygc_obj_stack.top(), args..., ptr_arg);
+
+ if (!ygc.ygc_default_stack.empty()) {
+ const auto& field_def = json_path_handler::get_field(
+ ygc.ygc_default_stack.top(), args..., ptr_arg);
+
+ if (field.pp_value == field_def.pp_value) {
+ return yajl_gen_status_ok;
+ }
+ }
+
+ if (ygc.ygc_depth) {
+ yajl_gen_string(handle, jph.jph_property);
+ }
+
+ yajlpp_generator gen(handle);
+
+ return gen(field.to_string());
+ };
return *this;
}
@@ -1038,7 +1291,7 @@ struct json_path_handler : public json_path_handler_base {
this->add_cb(int_field_cb);
this->jph_integer_cb
= [args...](yajlpp_parse_context* ypc, long long val) {
- auto jph = ypc->ypc_current_handler;
+ const auto* jph = ypc->ypc_current_handler;
auto* obj = ypc->ypc_obj_stack.top();
if (val < jph->jph_min_value) {
@@ -1091,7 +1344,7 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(dbl_field_cb);
this->jph_double_cb = [args...](yajlpp_parse_context* ypc, double val) {
- auto jph = ypc->ypc_current_handler;
+ const auto* jph = ypc->ypc_current_handler;
auto* obj = ypc->ypc_obj_stack.top();
if (val < jph->jph_min_value) {
@@ -1146,18 +1399,16 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto handler = ypc->ypc_current_handler;
- auto parse_res = relative_time::from_str(
- string_fragment::from_bytes(str, len));
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* handler = ypc->ypc_current_handler;
+ auto parse_res = relative_time::from_str(value_str);
if (parse_res.isErr()) {
auto parse_error = parse_res.unwrapErr();
- auto value_str = std::string((const char*) str, len);
- handler->report_duration_error(ypc, value_str, parse_error);
+ handler->report_duration_error(
+ ypc, value_str.to_string(), parse_error);
return 1;
}
@@ -1204,18 +1455,16 @@ struct json_path_handler : public json_path_handler_base {
{
this->add_cb(str_field_cb2);
this->jph_str_cb = [args...](yajlpp_parse_context* ypc,
- const unsigned char* str,
- size_t len) {
- auto obj = ypc->ypc_obj_stack.top();
- auto handler = ypc->ypc_current_handler;
- auto res = handler->to_enum_value(string_fragment(str, 0, len));
+ const string_fragment& value_str) {
+ auto* obj = ypc->ypc_obj_stack.top();
+ const auto* handler = ypc->ypc_current_handler;
+ auto res = handler->to_enum_value(value_str);
if (res) {
json_path_handler::get_field(obj, args...)
= (typename LastIsEnum<Args...>::value_type) res.value();
} else {
- handler->report_enum_error(ypc,
- std::string((const char*) str, len));
+ handler->report_enum_error(ypc, value_str.to_string());
}
return 1;
@@ -1325,11 +1574,34 @@ public:
return *this;
}
+ Result<void, std::vector<lnav::console::user_message>> consume(
+ const string_fragment& json)
+ {
+ if (this->yp_parse_context.parse(json) == yajl_status_ok) {
+ if (this->yp_errors.empty()) {
+ return Ok();
+ }
+ }
+
+ return Err(std::move(this->yp_errors));
+ }
+
+ Result<T, std::vector<lnav::console::user_message>> complete()
+ {
+ if (this->yp_parse_context.complete_parse() == yajl_status_ok) {
+ return Ok(std::move(this->yp_obj));
+ }
+
+ return Err(std::move(this->yp_errors));
+ }
+
Result<T, std::vector<lnav::console::user_message>> of(
const string_fragment& json)
{
if (this->yp_parse_context.parse_doc(json)) {
- return Ok(std::move(this->yp_obj));
+ if (this->yp_errors.empty()) {
+ return Ok(std::move(this->yp_obj));
+ }
}
return Err(std::move(this->yp_errors));
@@ -1343,6 +1615,34 @@ private:
};
template<typename T>
+struct typed_json_path_container;
+
+template<typename T>
+struct yajlpp_formatter {
+ const T& yf_obj;
+ const typed_json_path_container<T>& yf_container;
+ yajlpp_gen yf_gen;
+
+ template<typename... Args>
+ yajlpp_formatter<T> with_config(Args... args) &&
+ {
+ yajl_gen_config(this->yf_gen.get_handle(), args...);
+
+ return std::move(*this);
+ }
+
+ std::string to_string() &&
+ {
+ yajlpp_gen_context ygc(this->yf_gen, this->yf_container);
+ ygc.template with_obj(this->yf_obj);
+ ygc.ygc_depth = 1;
+ ygc.gen();
+
+ return this->yf_gen.to_string_fragment().to_string();
+ }
+};
+
+template<typename T>
struct typed_json_path_container : public json_path_container {
typed_json_path_container(std::initializer_list<json_path_handler> children)
: json_path_container(children)
@@ -1366,6 +1666,11 @@ struct typed_json_path_container : public json_path_container {
return yajlpp_parser<T>{src, this};
}
+ yajlpp_formatter<T> formatter_for(const T& obj) const
+ {
+ return yajlpp_formatter<T>{obj, *this};
+ }
+
std::string to_string(const T& obj) const
{
yajlpp_gen gen;