From b0589d14d91d6cb401ba6e4f7c3ed3791d1697c0 Mon Sep 17 00:00:00 2001 From: Tim Stack Date: Tue, 25 Jul 2023 20:45:12 -0700 Subject: [PATCH] [tidy] use factory_container for theme highlights And... a bunch of other stuff --- NEWS.md | 2 + src/base/string_attr_type.hh | 8 + src/environ_vtab.cc | 26 +- src/json-extension-functions.cc | 63 ++-- src/lnav.cc | 24 +- src/lnav_commands.cc | 6 +- src/lnav_config.cc | 17 +- src/log_format.cc | 4 +- src/log_format.hh | 11 +- src/log_format_ext.hh | 11 + src/log_format_impls.cc | 154 ++++++--- src/log_format_loader.cc | 4 +- src/log_vtab_impl.cc | 11 +- src/pcrepp/pcre2pp.hh | 2 + src/readline_possibilities.cc | 4 +- src/regexp_vtab.cc | 22 +- src/session_data.cc | 308 ++++++++---------- src/session_data.hh | 13 +- src/static_file_vtab.cc | 2 +- src/styling.cc | 48 +-- src/styling.hh | 3 +- src/text_format.cc | 16 +- src/textfile_sub_source.cc | 4 +- src/textview_curses.cc | 16 +- src/views_vtab.cc | 55 ++-- src/vtab_module.hh | 9 +- src/xpath_vtab.cc | 2 +- src/yajlpp/yajlpp.cc | 14 + src/yajlpp/yajlpp.hh | 25 +- src/yajlpp/yajlpp_def.hh | 183 ++++++----- .../configs/invalid-theme/config.json | 5 + test/expected/expected.am | 10 + ...907769aba112d628e7ebe39c4ec252e5e0bc69.err | 13 +- ...ab03afda2c9331a289fcbd1abdbc1c37b2e87b.err | 0 ...ab03afda2c9331a289fcbd1abdbc1c37b2e87b.out | 11 + ...7697be4d81ac8e5b2b2fa84f919b2d494978f3.err | 0 ...7697be4d81ac8e5b2b2fa84f919b2d494978f3.out | 11 + ...6077f4d573ee034467065b7e4f1878bdd4e2f2.err | 5 +- ...4f5dfa938a1ac7721f924beb16bbceec127a1b.err | 5 +- ...9a579cf7744fa08ab79fadd08b521b2f18a661.err | 7 + ...9a579cf7744fa08ab79fadd08b521b2f18a661.out | 0 ...10798fefdacd8d0179a4b17cd757d00fb731be.err | 7 + ...10798fefdacd8d0179a4b17cd757d00fb731be.out | 0 ...bc869850f5b7e53353fc2506fea0c8e96f29c5.err | 2 +- ...a7fd577f710aa8b0ad5a94fdfb35daea75e06c.err | 4 + ...a7fd577f710aa8b0ad5a94fdfb35daea75e06c.out | 0 ...51bdf3ba2f56fac5a216457b2d11a109e77f03.err | 4 +- test/test_sessions.sh | 16 + test/test_sql_regexp.sh | 6 + test/test_sql_views_vtab.sh | 4 + 50 files changed, 680 insertions(+), 497 deletions(-) create mode 100644 test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.err create mode 100644 test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.out create mode 100644 test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.err create mode 100644 test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.out create mode 100644 test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.err create mode 100644 test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.out create mode 100644 test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.err create mode 100644 test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.out create mode 100644 test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.err create mode 100644 test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.out diff --git a/NEWS.md b/NEWS.md index 186c72e0..3166af38 100644 --- a/NEWS.md +++ b/NEWS.md @@ -50,6 +50,8 @@ Bug Fixes: as if it was in a file that was passed on the command-line. * The `-I` option is now recognized in the management CLI (i.e. when you run **lnav** with the `-m` flag). +* Fields in the bro and w3c log formats that were hidden are + now saved in the session and restored. Interface changes: * The DB view now uses the "alt-text" theme style to draw diff --git a/src/base/string_attr_type.hh b/src/base/string_attr_type.hh index 5bff3458..f1a1ee95 100644 --- a/src/base/string_attr_type.hh +++ b/src/base/string_attr_type.hh @@ -342,6 +342,14 @@ identifier(S str) VC_ROLE.template value(role_t::VCR_IDENTIFIER)); } +template +inline std::pair +string(S str) +{ + return std::make_pair(std::move(str), + VC_ROLE.template value(role_t::VCR_STRING)); +} + template inline std::pair hr(S str) diff --git a/src/environ_vtab.cc b/src/environ_vtab.cc index 1265f4ca..0b89b761 100644 --- a/src/environ_vtab.cc +++ b/src/environ_vtab.cc @@ -71,7 +71,7 @@ vt_create(sqlite3* db, /* Allocate the sqlite3_vtab/vtab structure itself */ p_vt = (env_vtab*) sqlite3_malloc(sizeof(*p_vt)); - if (p_vt == NULL) { + if (p_vt == nullptr) { return SQLITE_NOMEM; } @@ -126,11 +126,11 @@ vt_open(sqlite3_vtab* p_svt, sqlite3_vtab_cursor** pp_cursor) { env_vtab* p_vt = (env_vtab*) p_svt; - p_vt->base.zErrMsg = NULL; + p_vt->base.zErrMsg = nullptr; env_vtab_cursor* p_cur = (env_vtab_cursor*) new env_vtab_cursor(); - if (p_cur == NULL) { + if (p_cur == nullptr) { return SQLITE_NOMEM; } else { *pp_cursor = (sqlite3_vtab_cursor*) p_cur; @@ -158,7 +158,7 @@ vt_eof(sqlite3_vtab_cursor* cur) { env_vtab_cursor* vc = (env_vtab_cursor*) cur; - return vc->env_cursor[0] == NULL; + return vc->env_cursor[0] == nullptr; } static int @@ -166,7 +166,7 @@ vt_next(sqlite3_vtab_cursor* cur) { env_vtab_cursor* vc = (env_vtab_cursor*) cur; - if (vc->env_cursor[0] != NULL) { + if (vc->env_cursor[0] != nullptr) { vc->env_cursor += 1; } @@ -309,11 +309,11 @@ static sqlite3_module vtab_module = { vt_column, /* xColumn - read data */ vt_rowid, /* xRowid - read data */ vt_update, /* xUpdate - write data */ - NULL, /* xBegin - begin transaction */ - NULL, /* xSync - sync transaction */ - NULL, /* xCommit - commit transaction */ - NULL, /* xRollback - rollback transaction */ - NULL, /* xFindFunction - function overloading */ + nullptr, /* xBegin - begin transaction */ + nullptr, /* xSync - sync transaction */ + nullptr, /* xCommit - commit transaction */ + nullptr, /* xRollback - rollback transaction */ + nullptr, /* xFindFunction - function overloading */ }; int @@ -322,13 +322,13 @@ register_environ_vtab(sqlite3* db) auto_mem errmsg; int rc; - rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL); + rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, nullptr); ensure(rc == SQLITE_OK); if ((rc = sqlite3_exec( db, "CREATE VIRTUAL TABLE environ USING environ_vtab_impl()", - NULL, - NULL, + nullptr, + nullptr, errmsg.out())) != SQLITE_OK) { diff --git a/src/json-extension-functions.cc b/src/json-extension-functions.cc index 36dc2906..4f1aaa70 100644 --- a/src/json-extension-functions.cc +++ b/src/json-extension-functions.cc @@ -43,8 +43,6 @@ #include "yajlpp/json_op.hh" #include "yajlpp/yajlpp.hh" -using namespace mapbox; - #define JSON_SUBTYPE 74 /* Ascii for "J" */ class sql_json_op : public json_op { @@ -68,7 +66,8 @@ null_or_default(sqlite3_context* context, int argc, sqlite3_value* argv[]) } struct contains_userdata { - util::variant cu_match_value{false}; + mapbox::util::variant cu_match_value{ + false}; size_t cu_depth{0}; bool cu_result{false}; }; @@ -119,12 +118,10 @@ json_contains(vtab_types::nullable nullable_json_in, } const auto* json_in = nullable_json_in.n_value; - auto_mem handle(yajl_free); - yajl_callbacks cb; - contains_userdata cu; - memset(&cb, 0, sizeof(cb)); - handle = yajl_alloc(&cb, nullptr, &cu); + yajl_callbacks cb{}; + contains_userdata cu; + auto handle = yajlpp::alloc_handle(&cb, &cu); cb.yajl_start_array = +[](void* ctx) { auto& cu = *((contains_userdata*) ctx); @@ -266,17 +263,16 @@ sql_jget(sqlite3_context* context, int argc, sqlite3_value** argv) return; } - const char* json_in = (const char*) sqlite3_value_text(argv[0]); + const auto json_in = from_sqlite()(argc, argv, 0); if (sqlite3_value_type(argv[1]) == SQLITE_NULL) { - sqlite3_result_text(context, json_in, -1, SQLITE_TRANSIENT); + sqlite3_result_text(context, json_in.data(), -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 handle(yajl_free); unsigned char* err; yajlpp_gen gen; @@ -289,16 +285,15 @@ sql_jget(sqlite3_context* context, int argc, sqlite3_value** argv) jo.jo_ptr_callbacks.yajl_number = gen_handle_number; jo.jo_ptr_data = gen.get_handle(); - handle.reset(yajl_alloc(&json_op::ptr_callbacks, nullptr, &jo)); - switch (yajl_parse( - handle.in(), (const unsigned char*) json_in, strlen(json_in))) - { + auto handle = yajlpp::alloc_handle(&json_op::ptr_callbacks, &jo); + switch (yajl_parse(handle.in(), json_in.udata(), json_in.length())) { case yajl_status_error: { - err = yajl_get_error(handle.in(), - 1, - (const unsigned char*) json_in, - strlen(json_in)); - sqlite3_result_error(context, (const char*) err, -1); + err = yajl_get_error( + handle.in(), 1, json_in.udata(), json_in.length()); + auto um = lnav::console::user_message::error("invalid JSON") + .with_reason((const char*) err); + + to_sqlite(context, um); yajl_free_error(handle.in(), err); return; } @@ -318,11 +313,12 @@ sql_jget(sqlite3_context* context, int argc, sqlite3_value** argv) switch (yajl_complete_parse(handle.in())) { case yajl_status_error: { - err = yajl_get_error(handle.in(), - 1, - (const unsigned char*) json_in, - strlen(json_in)); - sqlite3_result_error(context, (const char*) err, -1); + err = yajl_get_error( + handle.in(), 1, json_in.udata(), json_in.length()); + auto um = lnav::console::user_message::error("invalid JSON") + .with_reason((const char*) err); + + to_sqlite(context, um); yajl_free_error(handle.in(), err); return; } @@ -342,10 +338,7 @@ sql_jget(sqlite3_context* context, int argc, sqlite3_value** argv) switch (jo.sjo_type) { case SQLITE3_TEXT: - sqlite3_result_text(context, - jo.sjo_str.c_str(), - jo.sjo_str.size(), - SQLITE_TRANSIENT); + to_sqlite(context, jo.sjo_str); return; case SQLITE_NULL: sqlite3_result_null(context); @@ -358,7 +351,7 @@ sql_jget(sqlite3_context* context, int argc, sqlite3_value** argv) return; } - string_fragment result = gen.to_string_fragment(); + const auto result = gen.to_string_fragment(); if (result.empty()) { null_or_default(context, argc, argv); @@ -468,7 +461,6 @@ concat_gen_end_array(void* ctx) static void concat_gen_elements(yajl_gen gen, const unsigned char* text, size_t len) { - auto_mem handle(yajl_free); yajl_callbacks callbacks = {nullptr}; concat_context cc{gen}; @@ -482,7 +474,7 @@ concat_gen_elements(yajl_gen gen, const unsigned char* text, size_t len) callbacks.yajl_start_array = concat_gen_start_array; callbacks.yajl_end_array = concat_gen_end_array; - handle = yajl_alloc(&callbacks, nullptr, &cc); + auto handle = yajlpp::alloc_handle(&callbacks, &cc); yajl_config(handle, yajl_allow_comments, 1); if (yajl_parse(handle, (const unsigned char*) text, len) != yajl_status_ok || yajl_complete_parse(handle) != yajl_status_ok) @@ -600,7 +592,7 @@ sql_json_group_object_step(sqlite3_context* context, return; } - json_agg_context* jac = (json_agg_context*) sqlite3_aggregate_context( + auto* jac = (json_agg_context*) sqlite3_aggregate_context( context, sizeof(json_agg_context)); if (jac->jac_yajl_gen == nullptr) { @@ -662,8 +654,7 @@ sql_json_group_object_step(sqlite3_context* context, static void sql_json_group_object_final(sqlite3_context* context) { - json_agg_context* jac - = (json_agg_context*) sqlite3_aggregate_context(context, 0); + auto* jac = (json_agg_context*) sqlite3_aggregate_context(context, 0); if (jac == nullptr) { sqlite3_result_text(context, "{}", -1, SQLITE_STATIC); @@ -686,7 +677,7 @@ sql_json_group_array_step(sqlite3_context* context, int argc, sqlite3_value** argv) { - json_agg_context* jac = (json_agg_context*) sqlite3_aggregate_context( + auto* jac = (json_agg_context*) sqlite3_aggregate_context( context, sizeof(json_agg_context)); if (jac->jac_yajl_gen == nullptr) { diff --git a/src/lnav.cc b/src/lnav.cc index 062e68e6..d1bce0d8 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -1924,29 +1924,7 @@ looper() || lnav_data.ld_text_source.text_line_count() > 0 || !lnav_data.ld_active_files.fc_other_files.empty())) { - log_debug("restoring view states"); - for (size_t view_index = 0; view_index < LNV__MAX; - view_index++) - { - const auto& vs - = session_data.sd_view_states[view_index]; - auto& tview = lnav_data.ld_views[view_index]; - - if (vs.vs_top >= 0 - && (view_index == LNV_LOG - || tview.get_top() == 0_vl)) - { - log_info("restoring %s view top: %d", - lnav_view_strings[view_index], - vs.vs_top); - lnav_data.ld_views[view_index].set_top( - vis_line_t(vs.vs_top)); - if (vs.vs_selection) { - lnav_data.ld_views[view_index].set_selection( - vis_line_t(vs.vs_selection.value())); - } - } - } + lnav::session::restore_view_states(); if (lnav_data.ld_mode == ln_mode_t::FILES) { if (lnav_data.ld_active_files.fc_name_to_errors.empty()) { diff --git a/src/lnav_commands.cc b/src/lnav_commands.cc index 1ab8837d..d33f83e5 100644 --- a/src/lnav_commands.cc +++ b/src/lnav_commands.cc @@ -918,15 +918,14 @@ json_write_row(yajl_gen handle, case SQLITE_TEXT: switch (hm.hm_sub_type) { case 74: { - auto_mem parse_handle(yajl_free); unsigned char* err; json_ptr jp(""); json_op jo(jp); jo.jo_ptr_callbacks = json_op::gen_callbacks; jo.jo_ptr_data = handle; - parse_handle.reset( - yajl_alloc(&json_op::ptr_callbacks, nullptr, &jo)); + auto parse_handle = yajlpp::alloc_handle( + &json_op::ptr_callbacks, &jo); const unsigned char* json_in = (const unsigned char*) dls.dls_rows[row][col]; @@ -3770,6 +3769,7 @@ com_load_session(exec_context& ec, if (args.empty()) { } else if (!ec.ec_dry_run) { load_session(); + lnav::session::restore_view_states(); lnav_data.ld_views[LNV_LOG].reload_data(); } diff --git a/src/lnav_config.cc b/src/lnav_config.cc index 364fea8b..45d9068e 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -1348,10 +1348,10 @@ read_id(yajlpp_parse_context* ypc, const unsigned char* str, size_t len) } ypc->report_error( lnav::console::user_message::error( - attr_line_t("'") - .append(lnav::roles::symbol(file_id)) + attr_line_t() + .append_quoted(lnav::roles::symbol(file_id)) .append( - "' is not a supported configuration $schema version")) + " is not a supported configuration $schema version")) .with_snippet(ypc->get_snippet()) .with_note(notes) .with_help(handler->get_help_text(ypc))); @@ -1458,11 +1458,10 @@ load_config_from(_lnav_config& lconfig, .with_errno_reason()); } } else { - auto_mem handle(yajl_free); char buffer[2048]; ssize_t rc = -1; - handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc); + auto handle = yajlpp::alloc_handle(&ypc.ypc_callbacks, &ypc); yajl_config(handle, yajl_allow_comments, 1); yajl_config(handle, yajl_allow_multiple_values, 1); ypc.ypc_handle = handle; @@ -1498,10 +1497,10 @@ load_default_config(struct _lnav_config& config_obj, { yajlpp_parse_context ypc_builtin(intern_string::lookup(bsf.get_name()), &lnav_config_handlers); - auto_mem handle(yajl_free); struct config_userdata ud(errors); - handle = yajl_alloc(&ypc_builtin.ypc_callbacks, nullptr, &ypc_builtin); + auto handle + = yajlpp::alloc_handle(&ypc_builtin.ypc_callbacks, &ypc_builtin); ypc_builtin.ypc_locations = &lnav_config_locations; ypc_builtin.with_handle(handle); ypc_builtin.with_obj(config_obj); @@ -1515,9 +1514,7 @@ load_default_config(struct _lnav_config& config_obj, yajl_config(handle, yajl_allow_comments, 1); yajl_config(handle, yajl_allow_multiple_values, 1); - if (ypc_builtin.parse(bsf.to_string_fragment()) == yajl_status_ok) { - ypc_builtin.complete_parse(); - } + ypc_builtin.parse_doc(bsf.to_string_fragment()); return path == "*" || ypc_builtin.ypc_active_paths.empty(); } diff --git a/src/log_format.cc b/src/log_format.cc index f8183dba..e9bec8e2 100644 --- a/src/log_format.cc +++ b/src/log_format.cc @@ -280,7 +280,7 @@ next_format( } bool -log_format::next_format(pcre_format* fmt, int& index, int& locked_index) +log_format::next_format(const pcre_format* fmt, int& index, int& locked_index) { bool retval = true; @@ -301,7 +301,7 @@ log_format::next_format(pcre_format* fmt, int& index, int& locked_index) const char* log_format::log_scanf(uint32_t line_number, string_fragment line, - pcre_format* fmt, + const pcre_format* fmt, const char* time_fmt[], struct exttm* tm_out, struct timeval* tv_out, diff --git a/src/log_format.hh b/src/log_format.hh index f4cf88da..88f459a2 100644 --- a/src/log_format.hh +++ b/src/log_format.hh @@ -450,6 +450,11 @@ public: return false; } + virtual std::map get_field_states() + { + return {}; + } + const char* const* get_timestamp_formats() const { if (this->lf_timestamp_format.empty()) { @@ -555,11 +560,13 @@ protected: int pf_timestamp_index{-1}; }; - static bool next_format(pcre_format* fmt, int& index, int& locked_index); + static bool next_format(const pcre_format* fmt, + int& index, + int& locked_index); const char* log_scanf(uint32_t line_number, string_fragment line, - pcre_format* fmt, + const pcre_format* fmt, const char* time_fmt[], struct exttm* tm_out, struct timeval* tv_out, diff --git a/src/log_format_ext.hh b/src/log_format_ext.hh index a72ca1ec..ea6a88dd 100644 --- a/src/log_format_ext.hh +++ b/src/log_format_ext.hh @@ -169,6 +169,17 @@ public: bool hide_field(const intern_string_t field_name, bool val) override; + std::map get_field_states() override + { + std::map retval; + + for (const auto& vd : this->elf_value_defs) { + retval.emplace(vd.first, vd.second->vd_meta); + } + + return retval; + } + std::shared_ptr specialized(int fmt_lock) override; const logline_value_stats* stats_for_value( diff --git a/src/log_format_impls.cc b/src/log_format_impls.cc index 96d37f53..6d5b91a4 100644 --- a/src/log_format_impls.cc +++ b/src/log_format_impls.cc @@ -41,13 +41,14 @@ #include "config.h" #include "formats/logfmt/logfmt.parser.hh" #include "log_vtab_impl.hh" +#include "scn/scn.h" #include "sql_util.hh" #include "yajlpp/yajlpp.hh" class generic_log_format : public log_format { - static pcre_format* get_pcre_log_formats() + static const pcre_format* get_pcre_log_formats() { - static pcre_format log_fmt[] = { + static const pcre_format log_fmt[] = { pcre_format( "^(?:\\*\\*\\*\\s+)?(?@[0-9a-zA-Z]{16,24})(.*)"), pcre_format( @@ -88,7 +89,10 @@ class generic_log_format : public log_format { const intern_string_t get_name() const override { - return intern_string::lookup("generic_log"); + static const intern_string_t RETVAL + = intern_string::lookup("generic_log"); + + return RETVAL; } scan_result_t scan(logfile& lf, @@ -140,7 +144,7 @@ class generic_log_format : public log_format { { auto& line = values.lvv_sbr; int pat_index = this->pattern_index_for_line(line_number); - auto& fmt = get_pcre_log_formats()[pat_index]; + const auto& fmt = get_pcre_log_formats()[pat_index]; int prefix_len = 0; auto md = fmt.pcre->create_match_data(); auto match_res = fmt.pcre->capture_from(line.to_string_fragment()) @@ -324,13 +328,15 @@ class bro_log_format : public log_format { public: struct field_def { logline_value_meta fd_meta; + logline_value_meta* fd_root_meta; std::string fd_collator; nonstd::optional fd_numeric_index; explicit field_def(const intern_string_t name, int col, log_format* format) - : fd_meta(name, value_kind_t::VALUE_TEXT, col, format) + : fd_meta(name, value_kind_t::VALUE_TEXT, col, format), + fd_root_meta(&FIELD_META.find(name)->second) { } @@ -351,6 +357,9 @@ public: } }; + static std::unordered_map + FIELD_META; + bro_log_format() { this->lf_is_self_describing = true; @@ -410,13 +419,13 @@ public: found_ts = true; } } else if (STATUS_CODE == fd.fd_meta.lvm_name) { - string_fragment sf = *iter; + const auto sf = *iter; if (!sf.empty() && sf[0] >= '4') { level = LEVEL_ERROR; } } else if (UID == fd.fd_meta.lvm_name) { - string_fragment sf = *iter; + const auto sf = *iter; opid = hash_str(sf.data(), sf.length()); } @@ -425,14 +434,11 @@ public: switch (fd.fd_meta.lvm_kind) { case value_kind_t::VALUE_INTEGER: case value_kind_t::VALUE_FLOAT: { - string_fragment sf = *iter; - char field_copy[sf.length() + 1]; - double val; - - if (sscanf(sf.to_string(field_copy), "%lf", &val) == 1) - { + const auto sv = (*iter).to_string_view(); + auto scan_float_res = scn::scan_value(sv); + if (scan_float_res) { this->lf_value_stats[fd.fd_numeric_index.value()] - .add_value(val); + .add_value(scan_float_res.value()); } break; } @@ -531,10 +537,18 @@ public: this->blf_format_name = intern_string::lookup(full_name); } else if (directive == "#fields" && this->blf_field_defs.empty()) { do { + auto field_name + = intern_string::lookup("bro_" + sql_safe_ident(*iter)); + auto common_iter = FIELD_META.find(field_name); + if (common_iter == FIELD_META.end()) { + FIELD_META.emplace(field_name, + logline_value_meta{ + field_name, + value_kind_t::VALUE_TEXT, + }); + } this->blf_field_defs.emplace_back( - intern_string::lookup("bro_" + sql_safe_ident(*iter)), - this->blf_field_defs.size(), - this); + field_name, this->blf_field_defs.size(), this); ++iter; } while (iter != ss.end()); } else if (directive == "#types") { @@ -651,6 +665,8 @@ public: } else { values.lvv_values.emplace_back(fd.fd_meta); } + values.lvv_values.back().lv_meta.lvm_user_hidden + = fd.fd_root_meta->lvm_user_hidden; } } @@ -675,20 +691,27 @@ public: bool hide_field(const intern_string_t field_name, bool val) override { - auto fd_iter - = std::find_if(this->blf_field_defs.begin(), - this->blf_field_defs.end(), - [field_name](const field_def& elem) { - return elem.fd_meta.lvm_name == field_name; - }); - if (fd_iter == this->blf_field_defs.end()) { + auto fd_iter = FIELD_META.find(field_name); + if (fd_iter == FIELD_META.end()) { return false; } - fd_iter->fd_meta.lvm_user_hidden = val; + fd_iter->second.lvm_user_hidden = val; + return true; } + std::map get_field_states() override + { + std::map retval; + + for (const auto& fd : FIELD_META) { + retval.emplace(fd.first, fd.second); + } + + return retval; + } + std::shared_ptr specialized(int fmt_lock = -1) override { auto retval = std::make_shared(*this); @@ -707,9 +730,8 @@ public: void get_columns(std::vector& cols) const override { for (const auto& fd : this->blt_format.blf_field_defs) { - std::pair type_pair - = log_vtab_impl::logline_value_to_sqlite_type( - fd.fd_meta.lvm_kind); + auto type_pair = log_vtab_impl::logline_value_to_sqlite_type( + fd.fd_meta.lvm_kind); cols.emplace_back(fd.fd_meta.lvm_name.to_string(), type_pair.first, @@ -775,6 +797,9 @@ public: std::vector blf_field_defs; }; +std::unordered_map + bro_log_format::FIELD_META; + struct ws_separated_string { const char* ss_str; size_t ss_len; @@ -877,6 +902,7 @@ public: struct field_def { const intern_string_t fd_name; logline_value_meta fd_meta; + logline_value_meta* fd_root_meta{nullptr}; std::string fd_collator; nonstd::optional fd_numeric_index; @@ -924,6 +950,9 @@ public: } }; + static std::unordered_map + FIELD_META; + struct field_to_struct_t { field_to_struct_t(const char* prefix, const char* struct_name) : fs_prefix(prefix), @@ -990,7 +1019,7 @@ public: break; } - const field_def& fd = this->wlf_field_defs[iter.index()]; + const auto& fd = this->wlf_field_defs[iter.index()]; string_fragment sf = *iter; if (sf.startswith("#")) { @@ -1051,13 +1080,12 @@ public: switch (fd.fd_meta.lvm_kind) { case value_kind_t::VALUE_INTEGER: case value_kind_t::VALUE_FLOAT: { - char field_copy[sf.length() + 1]; - double val; + auto scan_float_res + = scn::scan_value(sf.to_string_view()); - if (sscanf(sf.to_string(field_copy), "%lf", &val) == 1) - { + if (scan_float_res) { this->lf_value_stats[fd.fd_numeric_index.value()] - .add_value(val); + .add_value(scan_float_res.value()); } break; } @@ -1131,8 +1159,7 @@ public: auto line = next_read_result.unwrap(); ws_separated_string ss(line.get_data(), line.length()); auto iter = ss.begin(); - - string_fragment directive = *iter; + const auto directive = *iter; if (directive.empty() || directive[0] != '#') { continue; @@ -1170,9 +1197,25 @@ public: [&sf](auto elem) { return sf == elem.fd_name; }); if (field_iter != end(KNOWN_FIELDS)) { this->wlf_field_defs.emplace_back(*field_iter); + auto& fd = this->wlf_field_defs.back(); + auto common_iter = FIELD_META.find(fd.fd_meta.lvm_name); + if (common_iter == FIELD_META.end()) { + auto emp_res = FIELD_META.emplace( + fd.fd_meta.lvm_name, fd.fd_meta); + common_iter = emp_res.first; + } + fd.fd_root_meta = &common_iter->second; } else if (sf == "date" || sf == "time") { this->wlf_field_defs.emplace_back( intern_string::lookup(sf)); + auto& fd = this->wlf_field_defs.back(); + auto common_iter = FIELD_META.find(fd.fd_meta.lvm_name); + if (common_iter == FIELD_META.end()) { + auto emp_res = FIELD_META.emplace( + fd.fd_meta.lvm_name, fd.fd_meta); + common_iter = emp_res.first; + } + fd.fd_root_meta = &common_iter->second; } else { const auto fs_iter = std::find_if( begin(KNOWN_STRUCT_FIELDS), @@ -1181,7 +1224,7 @@ public: return sf.startswith(elem.fs_prefix); }); if (fs_iter != end(KNOWN_STRUCT_FIELDS)) { - auto field_name + const intern_string_t field_name = intern_string::lookup(sf.substr(3)); this->wlf_field_defs.emplace_back( field_name, @@ -1195,7 +1238,8 @@ public: this) .with_struct_name(fs_iter->fs_struct_name)); } else { - auto field_name = intern_string::lookup(sf); + const intern_string_t field_name + = intern_string::lookup(sf); this->wlf_field_defs.emplace_back( field_name, logline_value_meta( @@ -1253,7 +1297,7 @@ public: return; } - const field_def& fd = this->wlf_field_defs[iter.index()]; + const auto& fd = this->wlf_field_defs[iter.index()]; if (sf == "-") { sf.invalidate(); @@ -1275,6 +1319,10 @@ public: } else { values.lvv_values.emplace_back(fd.fd_meta); } + if (fd.fd_root_meta != nullptr) { + values.lvv_values.back().lv_meta.lvm_user_hidden + = fd.fd_root_meta->lvm_user_hidden; + } } } @@ -1299,20 +1347,27 @@ public: bool hide_field(const intern_string_t field_name, bool val) override { - auto fd_iter - = std::find_if(this->wlf_field_defs.begin(), - this->wlf_field_defs.end(), - [field_name](const field_def& elem) { - return elem.fd_meta.lvm_name == field_name; - }); - if (fd_iter == this->wlf_field_defs.end()) { + auto fd_iter = FIELD_META.find(field_name); + if (fd_iter == FIELD_META.end()) { return false; } - fd_iter->fd_meta.lvm_user_hidden = val; + fd_iter->second.lvm_user_hidden = val; + return true; } + std::map get_field_states() override + { + std::map retval; + + for (const auto& fd : FIELD_META) { + retval.emplace(fd.first, fd.second); + } + + return retval; + } + std::shared_ptr specialized(int fmt_lock = -1) override { auto retval = std::make_shared(*this); @@ -1402,6 +1457,9 @@ public: std::vector wlf_field_defs; }; +std::unordered_map + w3c_log_format::FIELD_META; + static int KNOWN_FIELD_INDEX = 0; const std::vector w3c_log_format::KNOWN_FIELDS = { { @@ -1551,7 +1609,7 @@ class logfmt_format : public log_format { public: const intern_string_t get_name() const override { - const static auto NAME = intern_string::lookup("logfmt_log"); + const static intern_string_t NAME = intern_string::lookup("logfmt_log"); return NAME; } diff --git a/src/log_format_loader.cc b/src/log_format_loader.cc index 300f80c7..0e4e7abf 100644 --- a/src/log_format_loader.cc +++ b/src/log_format_loader.cc @@ -918,7 +918,7 @@ const struct json_path_container format_handlers = { .with_description("A URL with more information about this log format"), json_path_handler("title", read_format_field) .with_description("The human-readable name for this log format"), - json_path_handler("description", read_format_field) + json_path_handler("description") .with_description("A longer description of this log format") .for_field(&external_log_format::lf_description), json_path_handler("timestamp-format#", read_format_field) @@ -926,7 +926,7 @@ const struct json_path_container format_handlers = { json_path_handler("module-field", read_format_field) .with_description( "The name of the module field in the log message pattern"), - json_path_handler("opid-field", read_format_field) + json_path_handler("opid-field") .with_description( "The name of the operation-id field in the log message pattern") .for_field(&external_log_format::elf_opid_field), diff --git a/src/log_vtab_impl.cc b/src/log_vtab_impl.cc index 08f37ba4..56558a89 100644 --- a/src/log_vtab_impl.cc +++ b/src/log_vtab_impl.cc @@ -1918,7 +1918,8 @@ vt_update(sqlite3_vtab* tab, const auto* part_name = sqlite3_value_text(argv[2 + VT_COL_PARTITION]); const auto* log_comment = sqlite3_value_text(argv[2 + VT_COL_LOG_COMMENT]); - const auto* log_tags = sqlite3_value_text(argv[2 + VT_COL_LOG_TAGS]); + const auto log_tags = from_sqlite>()( + argc, argv, 2 + VT_COL_LOG_TAGS); bookmark_metadata tmp_bm; if (log_tags) { @@ -1937,7 +1938,7 @@ vt_update(sqlite3_vtab* tab, errors.emplace_back(msg); }) .with_obj(tmp_bm); - ypc.parse_doc(string_fragment{log_tags}); + ypc.parse_doc(log_tags.value()); if (!errors.empty()) { auto top_error = lnav::console::user_message::error( attr_line_t("invalid value for ") @@ -1946,16 +1947,14 @@ vt_update(sqlite3_vtab* tab, .append_quoted(lnav::roles::symbol( vt->vi->get_name().to_string()))) .with_reason(errors[0].to_attr_line({})); - auto json_error = lnav::to_json(top_error); - tab->zErrMsg - = sqlite3_mprintf("lnav-error:%s", json_error.c_str()); + set_vtable_errmsg(tab, top_error); return SQLITE_ERROR; } } auto& bv = vt->tc->get_bookmarks()[&textview_curses::BM_META]; bool has_meta = part_name != nullptr || log_comment != nullptr - || log_tags != nullptr; + || log_tags.has_value(); if (binary_search(bv.begin(), bv.end(), vrowid) && !has_meta) { vt->tc->set_user_mark(&textview_curses::BM_META, vrowid, false); diff --git a/src/pcrepp/pcre2pp.hh b/src/pcrepp/pcre2pp.hh index 59a2cf1d..caef54a3 100644 --- a/src/pcrepp/pcre2pp.hh +++ b/src/pcrepp/pcre2pp.hh @@ -259,6 +259,8 @@ public: const std::string& get_pattern() const { return this->p_pattern; } + std::string to_string() const { return this->p_pattern; } + named_captures get_named_captures() const; const char* get_name_for_capture(size_t index) const; diff --git a/src/readline_possibilities.cc b/src/readline_possibilities.cc index 0525db9d..a2e8191b 100644 --- a/src/readline_possibilities.cc +++ b/src/readline_possibilities.cc @@ -504,7 +504,7 @@ add_recent_netlocs_possibilities() isc::to().send_and_wait( [&netlocs](auto& tlooper) { netlocs = tlooper.active_netlocs(); }); - netlocs.insert(session_data.sd_recent_netlocs.begin(), - session_data.sd_recent_netlocs.end()); + netlocs.insert(recent_refs.rr_netlocs.begin(), + recent_refs.rr_netlocs.end()); rc->add_possibility(ln_mode_t::COMMAND, "recent-netlocs", netlocs); } diff --git a/src/regexp_vtab.cc b/src/regexp_vtab.cc index 53241949..c5bb7a6f 100644 --- a/src/regexp_vtab.cc +++ b/src/regexp_vtab.cc @@ -31,6 +31,7 @@ # include #endif +#include "base/lnav.console.into.hh" #include "base/lnav_log.hh" #include "column_namer.hh" #include "config.h" @@ -238,9 +239,12 @@ rcFilter(sqlite3_vtab_cursor* pVtabCursor, auto pattern = from_sqlite()(argc, argv, 1); auto compile_res = lnav::pcre2pp::code::from(pattern); if (compile_res.isErr()) { - pVtabCursor->pVtab->zErrMsg - = sqlite3_mprintf("Invalid regular expression: %s", - compile_res.unwrapErr().get_message().c_str()); + static const intern_string_t PATTERN_SRC + = intern_string::lookup("pattern"); + + set_vtable_errmsg(pVtabCursor->pVtab, + lnav::console::to_user_message( + PATTERN_SRC, compile_res.unwrapErr())); return SQLITE_ERROR; } @@ -486,9 +490,12 @@ rcjFilter(sqlite3_vtab_cursor* pVtabCursor, auto pattern = from_sqlite()(argc, argv, 1); auto compile_res = lnav::pcre2pp::code::from(pattern); if (compile_res.isErr()) { - pVtabCursor->pVtab->zErrMsg - = sqlite3_mprintf("Invalid regular expression: %s", - compile_res.unwrapErr().get_message().c_str()); + static const intern_string_t PATTERN_SRC + = intern_string::lookup("pattern"); + + set_vtable_errmsg(pVtabCursor->pVtab, + lnav::console::to_user_message( + PATTERN_SRC, compile_res.unwrapErr())); return SQLITE_ERROR; } @@ -508,8 +515,7 @@ rcjFilter(sqlite3_vtab_cursor* pVtabCursor, "unable to parse flags") .with_reason(parse_res.unwrapErr()[0]); - pVtabCursor->pVtab->zErrMsg = sqlite3_mprintf( - "%s%s", sqlitepp::ERROR_PREFIX, lnav::to_json(um).c_str()); + set_vtable_errmsg(pVtabCursor->pVtab, um); return SQLITE_ERROR; } diff --git a/src/session_data.cc b/src/session_data.cc index 547264b5..5835fbe7 100644 --- a/src/session_data.cc +++ b/src/session_data.cc @@ -49,7 +49,6 @@ #include "hasher.hh" #include "lnav.events.hh" #include "lnav.hh" -#include "lnav_util.hh" #include "log_format_ext.hh" #include "logfile.hh" #include "service_tags.hh" @@ -60,7 +59,8 @@ #include "yajlpp/yajlpp.hh" #include "yajlpp/yajlpp_def.hh" -struct session_data_t session_data; +session_data_t session_data; +recent_refs_t recent_refs; static const char* LOG_METADATA_NAME = "log_metadata.db"; @@ -413,7 +413,7 @@ load_time_bookmarks() while (!done) { done = netloc_stmt.fetch_row().match( [](const std::string& netloc) { - session_data.sd_recent_netlocs.insert(netloc); + recent_refs.rr_netlocs.insert(netloc); return false; }, [](const prepared_stmt::fetch_error& fe) { @@ -472,7 +472,6 @@ load_time_bookmarks() date_time_scanner dts; bool done = false; - std::string line; int64_t last_mark_time = -1; while (!done) { @@ -510,8 +509,11 @@ load_time_bookmarks() continue; } - if (!dts.scan( - log_time, strlen(log_time), NULL, &log_tm, log_tv)) + if (!dts.scan(log_time, + strlen(log_time), + nullptr, + &log_tm, + log_tv)) { continue; } @@ -762,136 +764,32 @@ read_files(yajlpp_parse_context* ypc, const unsigned char* str, size_t len) return 1; } -static int -read_current_search(yajlpp_parse_context* ypc, - const unsigned char* str, - size_t len) -{ - const auto regex = std::string((const char*) str, len); - const char** view_name; - int view_index; - - view_name = find(lnav_view_strings, - lnav_view_strings + LNV__MAX, - ypc->get_path_fragment(-2)); - view_index = view_name - lnav_view_strings; - - if (view_index < LNV__MAX && !regex.empty()) { - lnav_data.ld_views[view_index].execute_search(regex); - lnav_data.ld_views[view_index].set_follow_search_for(-1, {}); - } - - return 1; -} - -static int -read_top_line(yajlpp_parse_context* ypc, long long value) -{ - const char** view_name; - int view_index; - - view_name = find(lnav_view_strings, - lnav_view_strings + LNV__MAX, - ypc->get_path_fragment(-2)); - view_index = view_name - lnav_view_strings; - if (view_index < LNV__MAX) { - session_data.sd_view_states[view_index].vs_top = value; - } - - return 1; -} - -static int -read_focused_line(yajlpp_parse_context* ypc, long long value) -{ - const char** view_name; - int view_index; - - view_name = find(lnav_view_strings, - lnav_view_strings + LNV__MAX, - ypc->get_path_fragment(-2)); - view_index = view_name - lnav_view_strings; - if (view_index < LNV__MAX) { - session_data.sd_view_states[view_index].vs_selection = value; - } - - return 1; -} - -static int -read_word_wrap(yajlpp_parse_context* ypc, int value) -{ - const char** view_name; - int view_index; - - view_name = find(lnav_view_strings, - lnav_view_strings + LNV__MAX, - ypc->get_path_fragment(-2)); - view_index = view_name - lnav_view_strings; - if (view_index == LNV_HELP) { - } else if (view_index < LNV__MAX) { - textview_curses& tc = lnav_data.ld_views[view_index]; - - tc.set_word_wrap(value); - } - - return 1; -} - -static int -read_filtering(yajlpp_parse_context* ypc, int value) -{ - const char** view_name; - int view_index; - - view_name = find(lnav_view_strings, - lnav_view_strings + LNV__MAX, - ypc->get_path_fragment(-2)); - view_index = view_name - lnav_view_strings; - if (view_index == LNV_HELP) { - } else if (view_index < LNV__MAX) { - textview_curses& tc = lnav_data.ld_views[view_index]; - - if (tc.get_sub_source() != nullptr) { - tc.get_sub_source()->tss_apply_filters = value; - } - } - - return 1; -} - -static int -read_commands(yajlpp_parse_context* ypc, const unsigned char* str, size_t len) -{ - std::string cmdline = std::string((const char*) str, len); - const char** view_name; - int view_index; - - view_name = find(lnav_view_strings, - lnav_view_strings + LNV__MAX, - ypc->get_path_fragment(-3)); - view_index = view_name - lnav_view_strings; - bool active = ensure_view(&lnav_data.ld_views[view_index]); - execute_command(lnav_data.ld_exec_context, cmdline); - if (!active) { - lnav_data.ld_view_stack.pop_back(); - } - - return 1; -} - static const struct json_path_container view_def_handlers = { - json_path_handler("top_line", read_top_line), - json_path_handler("focused_line", read_focused_line), - json_path_handler("search", read_current_search), - json_path_handler("word_wrap", read_word_wrap), - json_path_handler("filtering", read_filtering), - json_path_handler("commands#", read_commands), + json_path_handler("top_line").for_field(&view_state::vs_top), + json_path_handler("focused_line").for_field(&view_state::vs_selection), + json_path_handler("search").for_field(&view_state::vs_search), + json_path_handler("word_wrap").for_field(&view_state::vs_word_wrap), + json_path_handler("filtering").for_field(&view_state::vs_filtering), + json_path_handler("commands#").for_field(&view_state::vs_commands), }; static const struct json_path_container view_handlers = { - yajlpp::pattern_property_handler("([^/]+)").with_children( - view_def_handlers), + yajlpp::pattern_property_handler("(?[\\w\\-]+)") + .with_obj_provider( + +[](const yajlpp_provider_context& ypc, session_data_t* root) { + const char** view_name; + int view_index; + + view_name = find(lnav_view_strings, + lnav_view_strings + LNV__MAX, + ypc.get_substr("view_name")); + view_index = view_name - lnav_view_strings; + if (view_index < LNV__MAX) { + return &root->sd_view_states[view_index]; + } + return (view_state*) nullptr; + }) + .with_children(view_def_handlers), }; static const struct json_path_container file_state_handlers = { @@ -903,14 +801,15 @@ static const struct json_path_container file_state_handlers = { static const struct json_path_container file_states_handlers = { yajlpp::pattern_property_handler(R"((?[^/]+))") .with_description("Map of file names to file state objects") - .with_obj_provider([](const auto& ypc, auto* root) { - auto fn = ypc.get_substr("filename"); - return &session_data.sd_file_states[fn]; - }) + .with_obj_provider( + [](const auto& ypc, session_data_t* root) { + auto fn = ypc.get_substr("filename"); + return &root->sd_file_states[fn]; + }) .with_children(file_state_handlers), }; -static const struct json_path_container view_info_handlers = { +static const typed_json_path_container view_info_handlers = { yajlpp::property_handler("save-time") .for_field(&session_data_t::sd_save_time), yajlpp::property_handler("time-offset") @@ -925,33 +824,51 @@ load_session() { load_time_bookmarks(); scan_sessions() | [](const auto pair) { - yajl_handle handle; - auto_fd fd; - lnav_data.ld_session_load_time = pair.first.second; - session_data.sd_save_time = pair.first.second; const auto& view_info_path = pair.second; - - yajlpp_parse_context ypc(intern_string::lookup(view_info_path.string()), - &view_info_handlers); - ypc.with_obj(session_data); - handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc); + auto view_info_src = intern_string::lookup(view_info_path.string()); load_time_bookmarks(); - if ((fd = lnav::filesystem::openp(view_info_path, O_RDONLY)) < 0) { - perror("cannot open session file"); - } else { - unsigned char buffer[1024]; - ssize_t rc; + auto open_res = lnav::filesystem::open_file(view_info_path, O_RDONLY); + if (open_res.isErr()) { + log_error("cannot open session file: %s -- %s", + view_info_path.c_str(), + open_res.unwrapErr().c_str()); + return; + } - log_info("loading session file: %s", view_info_path.c_str()); - while ((rc = read(fd, buffer, sizeof(buffer))) > 0) { - yajl_parse(handle, buffer, rc); + auto fd = open_res.unwrap(); + unsigned char buffer[1024]; + ssize_t rc; + + log_info("loading session file: %s", view_info_path.c_str()); + auto parser = view_info_handlers.parser_for(view_info_src); + while ((rc = read(fd, buffer, sizeof(buffer))) > 0) { + auto buf_frag = string_fragment::from_bytes(buffer, rc); + auto parse_res = parser.consume(buf_frag); + if (parse_res.isErr()) { + log_error("failed to load session: %s -- %s", + view_info_path.c_str(), + parse_res.unwrapErr()[0] + .to_attr_line() + .get_string() + .c_str()); + return; } - yajl_complete_parse(handle); } - yajl_free(handle); + + auto complete_res = parser.complete(); + if (complete_res.isErr()) { + log_error("failed to load session: %s -- %s", + view_info_path.c_str(), + complete_res.unwrapErr()[0] + .to_attr_line() + .get_string() + .c_str()); + return; + } + session_data = complete_res.unwrap(); bool log_changes = false, text_changes = false; @@ -1143,7 +1060,7 @@ save_time_bookmarks() sqlite3_reset(stmt.in()); } - session_data.sd_recent_netlocs.insert(netlocs.begin(), netlocs.end()); + recent_refs.rr_netlocs.insert(netlocs.begin(), netlocs.end()); } logfile_sub_source& lss = lnav_data.ld_log_source; @@ -1470,7 +1387,7 @@ save_session_with_id(const std::string& session_id) yajlpp_map top_view_map(handle); for (int lpc = 0; lpc < LNV__MAX; lpc++) { - textview_curses& tc = lnav_data.ld_views[lpc]; + auto& tc = lnav_data.ld_views[lpc]; unsigned long width; vis_line_t height; @@ -1541,32 +1458,28 @@ save_session_with_id(const std::string& session_id) for (const auto& format : log_format::get_root_formats()) { - auto* elf = dynamic_cast( - format.get()); - - if (elf == nullptr) { - continue; - } + auto field_states = format->get_field_states(); - for (const auto& vd : elf->elf_value_defs) { - if (!vd.second->vd_meta.lvm_user_hidden) { + for (const auto& fs_pair : field_states) { + if (!fs_pair.second.lvm_user_hidden) { continue; } - if (vd.second->vd_meta.lvm_user_hidden.value()) - { - cmd_array.gen("hide-fields " - + elf->get_name().to_string() - + "." + vd.first.to_string()); - } else if (vd.second->vd_meta.lvm_hidden) { - cmd_array.gen("show-fields " - + elf->get_name().to_string() - + "." + vd.first.to_string()); + if (fs_pair.second.lvm_user_hidden.value()) { + cmd_array.gen( + "hide-fields " + + format->get_name().to_string() + "." + + fs_pair.first.to_string()); + } else if (fs_pair.second.lvm_hidden) { + cmd_array.gen( + "show-fields " + + format->get_name().to_string() + "." + + fs_pair.first.to_string()); } } } - logfile_sub_source& lss = lnav_data.ld_log_source; + auto& lss = lnav_data.ld_log_source; struct timeval min_time, max_time; bool have_min_time = lss.get_min_log_time(min_time); @@ -1701,6 +1614,49 @@ reset_session() } } +void +lnav::session::restore_view_states() +{ + log_debug("restoring view states"); + for (size_t view_index = 0; view_index < LNV__MAX; view_index++) { + const auto& vs = session_data.sd_view_states[view_index]; + auto& tview = lnav_data.ld_views[view_index]; + + if (vs.vs_top >= 0 + && (view_index == LNV_LOG || tview.get_top() == 0_vl + || tview.get_top() == tview.get_top_for_last_row())) + { + log_info("restoring %s view top: %d", + lnav_view_strings[view_index], + vs.vs_top); + lnav_data.ld_views[view_index].set_top(vis_line_t(vs.vs_top)); + } + if (vs.vs_selection) { + log_info("restoring %s view selection: %d", + lnav_view_strings[view_index], + vs.vs_selection.value()); + lnav_data.ld_views[view_index].set_selection( + vis_line_t(vs.vs_selection.value())); + } + + if (!vs.vs_search.empty()) { + tview.execute_search(vs.vs_search); + tview.set_follow_search_for(-1, {}); + } + tview.set_word_wrap(vs.vs_word_wrap); + if (tview.get_sub_source() != nullptr) { + tview.get_sub_source()->tss_apply_filters = vs.vs_filtering; + } + for (const auto& cmdline : vs.vs_commands) { + auto active = ensure_view(&tview); + execute_command(lnav_data.ld_exec_context, cmdline); + if (!active) { + lnav_data.ld_view_stack.pop_back(); + } + } + } +} + void lnav::session::regex101::insert_entry(const lnav::session::regex101::entry& ei) { diff --git a/src/session_data.hh b/src/session_data.hh index b380d3ea..6eda213e 100644 --- a/src/session_data.hh +++ b/src/session_data.hh @@ -48,17 +48,25 @@ struct file_state { struct view_state { int64_t vs_top{0}; nonstd::optional vs_selection; + std::string vs_search; + bool vs_word_wrap{false}; + bool vs_filtering{true}; + std::vector vs_commands; }; struct session_data_t { uint64_t sd_save_time{0}; bool sd_time_offset{false}; std::map sd_file_states; - std::set sd_recent_netlocs; view_state sd_view_states[LNV__MAX]; }; +struct recent_refs_t { + std::set rr_netlocs; +}; + extern struct session_data_t session_data; +extern struct recent_refs_t recent_refs; void init_session(); void load_session(); @@ -68,6 +76,9 @@ void reset_session(); namespace lnav { namespace session { + +void restore_view_states(); + namespace regex101 { struct entry { diff --git a/src/static_file_vtab.cc b/src/static_file_vtab.cc index f884cb31..70816cae 100644 --- a/src/static_file_vtab.cc +++ b/src/static_file_vtab.cc @@ -163,7 +163,7 @@ sfvt_open(sqlite3_vtab* p_svt, sqlite3_vtab_cursor** pp_cursor) { static_file_vtab* p_vt = (static_file_vtab*) p_svt; - p_vt->base.zErrMsg = NULL; + p_vt->base.zErrMsg = nullptr; sf_vtab_cursor* p_cur = (sf_vtab_cursor*) new sf_vtab_cursor(); diff --git a/src/styling.cc b/src/styling.cc index 73e3db47..0e94cfc7 100644 --- a/src/styling.cc +++ b/src/styling.cc @@ -53,17 +53,18 @@ static const struct json_path_container term_color_handler = { .with_children(term_color_rgb_handler), }; -static const struct json_path_container root_color_handler = { - yajlpp::property_handler("#") - .with_obj_provider>( - [](const yajlpp_provider_context& ypc, - std::vector* palette) { - if (ypc.ypc_index >= palette->size()) { - palette->resize(ypc.ypc_index + 1); - } - return &((*palette)[ypc.ypc_index]); - }) - .with_children(term_color_handler), +static const typed_json_path_container> + root_color_handler = { + yajlpp::property_handler("#") + .with_obj_provider>( + [](const yajlpp_provider_context& ypc, + std::vector* palette) { + if (ypc.ypc_index >= palette->size()) { + palette->resize(ypc.ypc_index + 1); + } + return &((*palette)[ypc.ypc_index]); + }) + .with_children(term_color_handler), }; term_color_palette* @@ -186,20 +187,19 @@ rgb_color::operator!=(const rgb_color& rhs) const term_color_palette::term_color_palette(const char* name, const string_fragment& json) { - yajlpp_parse_context ypc_xterm(intern_string::lookup(name), - &root_color_handler); - yajl_handle handle; - - handle = yajl_alloc(&ypc_xterm.ypc_callbacks, nullptr, &ypc_xterm); - ypc_xterm.with_ignore_unused(true) - .with_obj(this->tc_palette) - .with_handle(handle); - yajl_status st = ypc_xterm.parse(json); - ensure(st == yajl_status_ok); - st = ypc_xterm.complete_parse(); - ensure(st == yajl_status_ok); - yajl_free(handle); + intern_string_t iname = intern_string::lookup(name); + auto parse_res + = root_color_handler.parser_for(iname).with_ignore_unused(true).of( + json); + + if (parse_res.isErr()) { + log_error("failed to parse palette: %s -- %s", + name, + parse_res.unwrapErr()[0].to_attr_line().get_string().c_str()); + } + require(parse_res.isOk()); + this->tc_palette = parse_res.unwrap(); for (auto& xc : this->tc_palette) { xc.xc_lab_color = lab_color(xc.xc_color); } diff --git a/src/styling.hh b/src/styling.hh index 001383a5..ae95cee9 100644 --- a/src/styling.hh +++ b/src/styling.hh @@ -40,6 +40,7 @@ #include "log_level.hh" #include "mapbox/variant.hpp" #include "yajlpp/yajlpp.hh" +#include "yajlpp/yajlpp_def.hh" struct rgb_color { static Result from_str(const string_fragment& sf); @@ -155,7 +156,7 @@ struct style_config { }; struct highlighter_config { - std::string hc_regex; + factory_container hc_regex; style_config hc_style; }; diff --git a/src/text_format.cc b/src/text_format.cc index 0b727867..3cbdfe43 100644 --- a/src/text_format.cc +++ b/src/text_format.cc @@ -29,6 +29,8 @@ * @file text_format.cc */ +#include + #include "text_format.hh" #include "config.h" @@ -39,8 +41,13 @@ text_format_t detect_text_format(string_fragment sf, nonstd::optional path) { - static const auto GZ_EXT = ghc::filesystem::path(".gz"); - static const auto BZ2_EXT = ghc::filesystem::path(".bz2"); + static const std::set FILTER_EXTS = { + ".bz2", + ".gz", + ".lzma", + ".xz", + ".zst", + }; static const auto MD_EXT = ghc::filesystem::path(".md"); static const auto MARKDOWN_EXT = ghc::filesystem::path(".markdown"); @@ -99,10 +106,7 @@ detect_text_format(string_fragment sf, text_format_t retval = text_format_t::TF_UNKNOWN; if (path) { - if (path->extension() == GZ_EXT) { - path = path->stem(); - } - if (path->extension() == BZ2_EXT) { + while (FILTER_EXTS.count(path->extension()) > 0) { path = path->stem(); } diff --git a/src/textfile_sub_source.cc b/src/textfile_sub_source.cc index e7e28b56..c2ec04c1 100644 --- a/src/textfile_sub_source.cc +++ b/src/textfile_sub_source.cc @@ -638,9 +638,9 @@ textfile_sub_source::rescan_files( } else if (content_sf.startswith("{")) { yajlpp_parse_context ypc( intern_string::lookup(lf->get_filename())); - auto_mem handle(yajl_free); + auto handle + = yajlpp::alloc_handle(&ypc.ypc_callbacks, &ypc); - handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc); yajl_config( handle.in(), yajl_allow_trailing_garbage, 1); ypc.with_ignore_unused(true) diff --git a/src/textview_curses.cc b/src/textview_curses.cc index 87660881..147ffe16 100644 --- a/src/textview_curses.cc +++ b/src/textview_curses.cc @@ -226,19 +226,7 @@ textview_curses::reload_config(error_reporter& reporter) } for (const auto& hl_pair : theme_iter->second.lt_highlights) { - if (hl_pair.second.hc_regex.empty()) { - continue; - } - - auto regex = lnav::pcre2pp::code::from(hl_pair.second.hc_regex); - - if (regex.isErr()) { - const static intern_string_t PATTERN_SRC - = intern_string::lookup("pattern"); - - auto ce = regex.unwrapErr(); - reporter(&hl_pair.second.hc_regex, - lnav::console::to_user_message(PATTERN_SRC, ce)); + if (hl_pair.second.hc_regex.pp_value == nullptr) { continue; } @@ -283,7 +271,7 @@ textview_curses::reload_config(error_reporter& reporter) attrs.ta_attrs |= A_UNDERLINE; } this->tc_highlights[{highlight_source_t::THEME, hl_pair.first}] - = highlighter(regex.unwrap().to_shared()) + = highlighter(hl_pair.second.hc_regex.pp_value) .with_attrs(attrs) .with_color(fg, bg) .with_nestable(false); diff --git a/src/views_vtab.cc b/src/views_vtab.cc index 6dee241f..252de2ba 100644 --- a/src/views_vtab.cc +++ b/src/views_vtab.cc @@ -45,6 +45,8 @@ #include "vtab_module_json.hh" #include "yajlpp/yajlpp_def.hh" +using namespace lnav::roles::literals; + template<> struct from_sqlite { inline lnav_view_t operator()(int argc, sqlite3_value** val, int argi) @@ -406,7 +408,14 @@ CREATE TABLE lnav_views ( } } } else { - tab->zErrMsg = sqlite3_mprintf("Invalid time: %s", top_time); + auto um = lnav::console::user_message::error( + attr_line_t("Invalid ") + .append_quoted("top_time"_symbol) + .append(" value")) + .with_reason( + attr_line_t("Unrecognized time value: ") + .append(lnav::roles::string(top_time))); + set_vtable_errmsg(tab, um); return SQLITE_ERROR; } } @@ -421,9 +430,8 @@ CREATE TABLE lnav_views ( string_fragment::from_c_str(top_meta)); if (parse_res.isErr()) { auto errmsg = parse_res.unwrapErr(); - tab->zErrMsg = sqlite3_mprintf( - "Invalid top_meta: %s", - errmsg[0].to_attr_line().get_string().c_str()); + + set_vtable_errmsg(tab, errmsg[0]); return SQLITE_ERROR; } @@ -431,9 +439,15 @@ CREATE TABLE lnav_views ( if (index == LNV_TEXT && tlm.tlm_file) { if (!lnav_data.ld_text_source.to_front(tlm.tlm_file.value())) { - auto errmsg = parse_res.unwrapErr(); - tab->zErrMsg = sqlite3_mprintf("unknown top_meta.file: %s", - tlm.tlm_file->c_str()); + auto um + = lnav::console::user_message::error( + attr_line_t("Invalid ") + .append_quoted("top_meta.file"_symbol) + .append(" value")) + .with_reason(attr_line_t("Unknown text file: ") + .append(lnav::roles::file( + tlm.tlm_file.value()))); + set_vtable_errmsg(tab, um); return SQLITE_ERROR; } } @@ -451,8 +465,15 @@ CREATE TABLE lnav_views ( tc.set_selection(req_anchor_top.value()); } } else { - tab->zErrMsg = sqlite3_mprintf( - "unknown top_meta.anchor: %s", req_anchor.c_str()); + auto um + = lnav::console::user_message::error( + attr_line_t("Invalid ") + .append_quoted("top_meta.anchor"_symbol) + .append(" value")) + .with_reason( + attr_line_t("Unknown anchor: ") + .append(lnav::roles::symbol(req_anchor))); + set_vtable_errmsg(tab, um); return SQLITE_ERROR; } } @@ -570,15 +591,15 @@ struct lnav_view_filter_base { iterator& operator++() { while (this->i_view_index < LNV__MAX) { - textview_curses& tc = lnav_data.ld_views[this->i_view_index]; - text_sub_source* tss = tc.get_sub_source(); + const auto& tc = lnav_data.ld_views[this->i_view_index]; + auto* tss = tc.get_sub_source(); if (tss == nullptr) { this->i_view_index = lnav_view_t(this->i_view_index + 1); continue; } - filter_stack& fs = tss->get_filters(); + const auto& fs = tss->get_filters(); this->i_filter_index += 1; if (this->i_filter_index >= (ssize_t) fs.size()) { @@ -802,10 +823,7 @@ CREATE TABLE lnav_view_filters ( auto set_res = lnav_data.ld_log_source.set_sql_filter( clause, stmt.release()); if (set_res.isErr()) { - tab->zErrMsg = sqlite3_mprintf( - "%s%s", - sqlitepp::ERROR_PREFIX, - lnav::to_json(set_res.unwrapErr()).c_str()); + set_vtable_errmsg(tab, set_res.unwrapErr()); return SQLITE_ERROR; } tf = lnav_data.ld_log_source.get_sql_filter().value(); @@ -903,10 +921,7 @@ CREATE TABLE lnav_view_filters ( auto set_res = lnav_data.ld_log_source.set_sql_filter( clause, stmt.release()); if (set_res.isErr()) { - tab->zErrMsg = sqlite3_mprintf( - "%s%s", - sqlitepp::ERROR_PREFIX, - lnav::to_json(set_res.unwrapErr()).c_str()); + set_vtable_errmsg(tab, set_res.unwrapErr()); return SQLITE_ERROR; } *iter = lnav_data.ld_log_source.get_sql_filter().value(); diff --git a/src/vtab_module.hh b/src/vtab_module.hh index 2710856c..17f29093 100644 --- a/src/vtab_module.hh +++ b/src/vtab_module.hh @@ -153,9 +153,12 @@ template<> struct from_sqlite { inline string_fragment operator()(int argc, sqlite3_value** val, int argi) { - return string_fragment::from_bytes( - (const char*) sqlite3_value_blob(val[argi]), - sqlite3_value_bytes(val[argi])); + auto ptr = (const char*) sqlite3_value_blob(val[argi]); + + if (ptr == nullptr) { + return string_fragment::invalid(); + } + return string_fragment::from_bytes(ptr, sqlite3_value_bytes(val[argi])); } }; diff --git a/src/xpath_vtab.cc b/src/xpath_vtab.cc index 88c824b3..0fe88bdd 100644 --- a/src/xpath_vtab.cc +++ b/src/xpath_vtab.cc @@ -141,7 +141,7 @@ CREATE TABLE xpath ( { switch (col) { case XP_COL_RESULT: { - auto& xpath_node = vc.c_results[vc.c_rowid]; + const auto& xpath_node = vc.c_results[vc.c_rowid]; if (xpath_node.node()) { std::ostringstream oss; diff --git a/src/yajlpp/yajlpp.cc b/src/yajlpp/yajlpp.cc index b2e9121d..2d5bdf0a 100644 --- a/src/yajlpp/yajlpp.cc +++ b/src/yajlpp/yajlpp.cc @@ -1584,3 +1584,17 @@ yajlpp_gen::to_string_fragment() return string_fragment::from_bytes(buf, len); } + +namespace yajlpp { + +auto_mem +alloc_handle(const yajl_callbacks* cb, void* cu) +{ + auto_mem 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 497afe17..7dc966d5 100644 --- a/src/yajlpp/yajlpp.hh +++ b/src/yajlpp/yajlpp.hh @@ -112,6 +112,14 @@ struct factory_container : public positioned_property> { 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 @@ -131,6 +139,14 @@ struct factory_container : public positioned_property> { 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; @@ -283,8 +299,7 @@ struct json_path_handler_base { std::function jph_bool_cb; std::function jph_integer_cb; std::function jph_double_cb; - std::function + std::function jph_str_cb; void validate_string(yajlpp_parse_context& ypc, string_fragment sf) const; @@ -689,4 +704,10 @@ struct json_string { void dump_schema_to(const json_path_container& jpc, const char* internals_dir); +namespace yajlpp { + +auto_mem 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 d4331277..ca76bb75 100644 --- a/src/yajlpp/yajlpp_def.hh +++ b/src/yajlpp/yajlpp_def.hh @@ -256,7 +256,8 @@ struct json_path_handler : public json_path_handler_base { size_t len) { ypc->fill_in_source(); - return ypc->ypc_current_handler->jph_str_cb(ypc, str, len); + 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) @@ -439,15 +440,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; }; @@ -520,13 +519,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(); + 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; }; @@ -591,13 +589,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; }; @@ -669,13 +666,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; }; @@ -718,14 +714,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; }; @@ -765,23 +759,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; } @@ -831,14 +824,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; }; @@ -893,11 +884,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...); @@ -905,7 +894,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; }; @@ -946,11 +935,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...) @@ -993,11 +980,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...); @@ -1036,7 +1021,7 @@ struct json_path_handler : public json_path_handler_base { template struct int_ { - typedef int type; + using type = int; }; template< typename C, @@ -1048,11 +1033,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()}; @@ -1067,6 +1051,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; } @@ -1077,7 +1085,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) { @@ -1130,7 +1138,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) { @@ -1185,18 +1193,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; } @@ -1243,18 +1249,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::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; @@ -1364,6 +1368,27 @@ public: return *this; } + Result> 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> 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> of( const string_fragment& json) { diff --git a/test/bad-config2/configs/invalid-theme/config.json b/test/bad-config2/configs/invalid-theme/config.json index 6db0b4a3..cfbeda5c 100644 --- a/test/bad-config2/configs/invalid-theme/config.json +++ b/test/bad-config2/configs/invalid-theme/config.json @@ -8,6 +8,11 @@ "color": "InvalidColor", "bad-property": "abc" } + }, + "highlights": { + "foobar": { + "pattern": "abc(" + } } } } diff --git a/test/expected/expected.am b/test/expected/expected.am index e1bf64ba..e9e987b4 100644 --- a/test/expected/expected.am +++ b/test/expected/expected.am @@ -402,6 +402,8 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sessions.sh_0300a1391c33b1c45ddfa90198a6bd0a5404a77f.out \ $(srcdir)/%reldir%/test_sessions.sh_17b85654b929b2a8fc1705a170ced544783292fa.err \ $(srcdir)/%reldir%/test_sessions.sh_17b85654b929b2a8fc1705a170ced544783292fa.out \ + $(srcdir)/%reldir%/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.err \ + $(srcdir)/%reldir%/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.out \ $(srcdir)/%reldir%/test_sessions.sh_345b0e66dab7b881397c4b38380da81092ab70dd.err \ $(srcdir)/%reldir%/test_sessions.sh_345b0e66dab7b881397c4b38380da81092ab70dd.out \ $(srcdir)/%reldir%/test_sessions.sh_430b9522ba1a37983138f3c4935cba91b781e415.err \ @@ -428,6 +430,8 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sessions.sh_b932b33dd087b94d4306dd179c5d4f9ddd394960.out \ $(srcdir)/%reldir%/test_sessions.sh_ddf45811e9906de9f3930fe802ac7b2cc6e48106.err \ $(srcdir)/%reldir%/test_sessions.sh_ddf45811e9906de9f3930fe802ac7b2cc6e48106.out \ + $(srcdir)/%reldir%/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.err \ + $(srcdir)/%reldir%/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.out \ $(srcdir)/%reldir%/test_shlexer.sh_14dd967cb2af90899c9e5e45d00b676b5a3163aa.err \ $(srcdir)/%reldir%/test_shlexer.sh_14dd967cb2af90899c9e5e45d00b676b5a3163aa.out \ $(srcdir)/%reldir%/test_shlexer.sh_2781f5dd570580cbe746ad91b58a28b8371283b3.err \ @@ -766,8 +770,12 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.out \ $(srcdir)/%reldir%/test_sql_regexp.sh_03257c56e85558aa0cc925b68d3af962afc25125.err \ $(srcdir)/%reldir%/test_sql_regexp.sh_03257c56e85558aa0cc925b68d3af962afc25125.out \ + $(srcdir)/%reldir%/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.err \ + $(srcdir)/%reldir%/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.out \ $(srcdir)/%reldir%/test_sql_regexp.sh_51293df041b6969ccecc60204dce3676d0fb006d.err \ $(srcdir)/%reldir%/test_sql_regexp.sh_51293df041b6969ccecc60204dce3676d0fb006d.out \ + $(srcdir)/%reldir%/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.err \ + $(srcdir)/%reldir%/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.out \ $(srcdir)/%reldir%/test_sql_regexp.sh_b841a0c09601e2419eeb99e85f7e286c889e4801.err \ $(srcdir)/%reldir%/test_sql_regexp.sh_b841a0c09601e2419eeb99e85f7e286c889e4801.out \ $(srcdir)/%reldir%/test_sql_regexp.sh_bbd1128cf61a9af8f9dc937b46217443f42e1a7a.err \ @@ -1006,6 +1014,8 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_sql_views_vtab.sh_a1e6ee4f098d525330d5f58a9d71cbbd816d51bb.out \ $(srcdir)/%reldir%/test_sql_views_vtab.sh_a2c0f0e51b3f85ea2a05ecdcacaad962b4fe5d4f.err \ $(srcdir)/%reldir%/test_sql_views_vtab.sh_a2c0f0e51b3f85ea2a05ecdcacaad962b4fe5d4f.out \ + $(srcdir)/%reldir%/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.err \ + $(srcdir)/%reldir%/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.out \ $(srcdir)/%reldir%/test_sql_views_vtab.sh_ac1f6e9a88608ef8939f9c2f7061a25a86742d46.err \ $(srcdir)/%reldir%/test_sql_views_vtab.sh_ac1f6e9a88608ef8939f9c2f7061a25a86742d46.out \ $(srcdir)/%reldir%/test_sql_views_vtab.sh_ade121f29bedea0d1a54452cc994b2302ad9dabb.err \ diff --git a/test/expected/test_config.sh_a0907769aba112d628e7ebe39c4ec252e5e0bc69.err b/test/expected/test_config.sh_a0907769aba112d628e7ebe39c4ec252e5e0bc69.err index 1197777d..05a07b83 100644 --- a/test/expected/test_config.sh_a0907769aba112d628e7ebe39c4ec252e5e0bc69.err +++ b/test/expected/test_config.sh_a0907769aba112d628e7ebe39c4ec252e5e0bc69.err @@ -6,7 +6,18 @@ background-color #hex|color_name underline bold -✘ error: 'bad' is not a supported configuration $schema version +✘ error: “abc(” is not a valid regular expression + reason: missing closing parenthesis + --> /ui/theme-defs/invalid-theme/highlights/foobar/pattern + | abc(  + |  ^ missing closing parenthesis  + --> {test_dir}/bad-config2/configs/invalid-theme/config.json:14 + |  "pattern": "abc(" + = help: Property Synopsis + /ui/theme-defs/invalid-theme/highlights/foobar/pattern regular expression + Description + The regular expression to highlight +✘ error: “bad” is not a supported configuration $schema version  --> {test_dir}/bad-config2/formats/invalid-config/config.bad-schema.json:2  |  "$schema": "bad"   = note: expecting one of the following $schema values: diff --git a/test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.err b/test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.out b/test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.out new file mode 100644 index 00000000..0fbdae97 --- /dev/null +++ b/test/expected/test_sessions.sh_33ab03afda2c9331a289fcbd1abdbc1c37b2e87b.out @@ -0,0 +1,11 @@ +2011-11-02 17:20:39.348000 ⋮ 192.168.2.76 52099 192.150.187.43 80 2 GET www.bro-ids.org /frames/header.html http://git.bro-ids.org/ 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 3516 200 OK - - (empty) - - - - - - Fzea5XNhn9eNRMvx7 - text/html +2011-11-02 17:20:39.448000 ⋮ 192.168.2.76 52109 192.150.187.43 80 1 GET www.bro-ids.org /frames/footer.html http://git.bro-ids.org/ 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6695 200 OK - - (empty) - - - - - - FkCp6k4tqksK3tiSy7 - text/html +2011-11-02 17:20:39.463000 ⋮ 192.168.2.76 52099 192.150.187.43 80 3 GET www.bro-ids.org /images/logo-bro-small.png http://www.bro-ids.org/frames/header.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6075 200 OK - - (empty) - - - - - - Fw6FlF4WtotJFNXmHb - image/png +2011-11-02 17:20:39.786000 ⋮ 192.168.2.76 52110 199.59.148.201 80 1 GET search.twitter.com /search.json?&q=#BroIDS&rpp=2&callback=jsonp1320279639636 http://www.bro-ids.org/frames/footer.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 1543 200 OK - - (empty) - - - - - - Feut0t346XEHsQ0OC7 - text/plain +2011-11-02 17:21:12.372000 ⋮ 192.168.2.76 52111 192.150.187.43 80 1 GET www.bro-ids.org /research/index.html http://www.bro-ids.org/frames/header.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 47728 200 OK - - (empty) - - - - - - FOze0l2aT79uPyMiv7 - text/html +2011-11-02 17:21:13.121000 ⋮ 192.168.2.76 52087 209.85.145.95 80 7 GET ajax.googleapis.com /ajax/services/feed/load?v=1.0&callback=jsonp1320279672539&q=http://blog.bro-ids.org/feeds/posts/default&num=5 http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6584 200 OK - - (empty) - - - - - - FXEXQEMH8DrEuAdg8 - text/plain +2011-11-02 17:21:13.123000 ⋮ 192.168.2.76 52089 74.125.225.83 80 4 GET www.google.com /uds/css/clear.gif http://www.google.com/uds/api/search/1.0/473bb688d0c0dd605119ad983f5a4386/default+en.css 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 0 304 Not Modified - - (empty) - - - - - - - - - +2011-11-02 17:21:13.123000 ⋮ 192.168.2.76 52084 74.125.225.83 80 9 GET www.google.com /uds/css/small-logo.png http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 0 304 Not Modified - - (empty) - - - - - - - - - +2011-11-02 17:21:13.198000 ⋮ 192.168.2.76 52112 199.59.148.201 80 1 GET search.twitter.com /search.json?&q=#BroIDS&rpp=2&callback=jsonp1320279672537 http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 1543 200 OK - - (empty) - - - - - - Fzjgwn8xXem3Esvk - text/plain +#close 2017-04-16-21-36-10 +2011-11-02 17:21:13.204000 ⋮ 192.168.2.76 52113 199.59.148.20 80 1 GET api.twitter.com /1/statuses/user_timeline.json?screen_name=Bro_IDS&count=2&include_rts=1&callback=jsonp1320279672538 http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6095 200 OK - - (empty) - - - - - - FAVIuu2XZQyVznfnq8 - text/plain diff --git a/test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.err b/test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.out b/test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.out new file mode 100644 index 00000000..0fbdae97 --- /dev/null +++ b/test/expected/test_sessions.sh_e57697be4d81ac8e5b2b2fa84f919b2d494978f3.out @@ -0,0 +1,11 @@ +2011-11-02 17:20:39.348000 ⋮ 192.168.2.76 52099 192.150.187.43 80 2 GET www.bro-ids.org /frames/header.html http://git.bro-ids.org/ 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 3516 200 OK - - (empty) - - - - - - Fzea5XNhn9eNRMvx7 - text/html +2011-11-02 17:20:39.448000 ⋮ 192.168.2.76 52109 192.150.187.43 80 1 GET www.bro-ids.org /frames/footer.html http://git.bro-ids.org/ 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6695 200 OK - - (empty) - - - - - - FkCp6k4tqksK3tiSy7 - text/html +2011-11-02 17:20:39.463000 ⋮ 192.168.2.76 52099 192.150.187.43 80 3 GET www.bro-ids.org /images/logo-bro-small.png http://www.bro-ids.org/frames/header.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6075 200 OK - - (empty) - - - - - - Fw6FlF4WtotJFNXmHb - image/png +2011-11-02 17:20:39.786000 ⋮ 192.168.2.76 52110 199.59.148.201 80 1 GET search.twitter.com /search.json?&q=#BroIDS&rpp=2&callback=jsonp1320279639636 http://www.bro-ids.org/frames/footer.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 1543 200 OK - - (empty) - - - - - - Feut0t346XEHsQ0OC7 - text/plain +2011-11-02 17:21:12.372000 ⋮ 192.168.2.76 52111 192.150.187.43 80 1 GET www.bro-ids.org /research/index.html http://www.bro-ids.org/frames/header.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 47728 200 OK - - (empty) - - - - - - FOze0l2aT79uPyMiv7 - text/html +2011-11-02 17:21:13.121000 ⋮ 192.168.2.76 52087 209.85.145.95 80 7 GET ajax.googleapis.com /ajax/services/feed/load?v=1.0&callback=jsonp1320279672539&q=http://blog.bro-ids.org/feeds/posts/default&num=5 http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6584 200 OK - - (empty) - - - - - - FXEXQEMH8DrEuAdg8 - text/plain +2011-11-02 17:21:13.123000 ⋮ 192.168.2.76 52089 74.125.225.83 80 4 GET www.google.com /uds/css/clear.gif http://www.google.com/uds/api/search/1.0/473bb688d0c0dd605119ad983f5a4386/default+en.css 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 0 304 Not Modified - - (empty) - - - - - - - - - +2011-11-02 17:21:13.123000 ⋮ 192.168.2.76 52084 74.125.225.83 80 9 GET www.google.com /uds/css/small-logo.png http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 0 304 Not Modified - - (empty) - - - - - - - - - +2011-11-02 17:21:13.198000 ⋮ 192.168.2.76 52112 199.59.148.201 80 1 GET search.twitter.com /search.json?&q=#BroIDS&rpp=2&callback=jsonp1320279672537 http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 1543 200 OK - - (empty) - - - - - - Fzjgwn8xXem3Esvk - text/plain +#close 2017-04-16-21-36-10 +2011-11-02 17:21:13.204000 ⋮ 192.168.2.76 52113 199.59.148.20 80 1 GET api.twitter.com /1/statuses/user_timeline.json?screen_name=Bro_IDS&count=2&include_rts=1&callback=jsonp1320279672538 http://www.bro-ids.org/research/index.html 1.1 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1 0 6095 200 OK - - (empty) - - - - - - FAVIuu2XZQyVznfnq8 - text/plain diff --git a/test/expected/test_sql_json_func.sh_026077f4d573ee034467065b7e4f1878bdd4e2f2.err b/test/expected/test_sql_json_func.sh_026077f4d573ee034467065b7e4f1878bdd4e2f2.err index 9654daa8..973dd177 100644 --- a/test/expected/test_sql_json_func.sh_026077f4d573ee034467065b7e4f1878bdd4e2f2.err +++ b/test/expected/test_sql_json_func.sh_026077f4d573ee034467065b7e4f1878bdd4e2f2.err @@ -1,4 +1 @@ -error: sqlite3_exec failed -- parse error: premature EOF - [123, true - (right here) ------^ - +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"invalid JSON","attrs":[]},"reason":{"str":"parse error: premature EOF\n [123, true\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.err b/test/expected/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.err index e8eef686..2c593d4b 100644 --- a/test/expected/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.err +++ b/test/expected/test_sql_json_func.sh_f34f5dfa938a1ac7721f924beb16bbceec127a1b.err @@ -1,4 +1 @@ -error: sqlite3_exec failed -- parse error: premature EOF - [null, true, 20, 30, 40 - (right here) ------^ - +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"invalid JSON","attrs":[]},"reason":{"str":"parse error: premature EOF\n [null, true, 20, 30, 40\n (right here) ------^","attrs":[]},"snippets":[],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.err b/test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.err new file mode 100644 index 00000000..824c120b --- /dev/null +++ b/test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.err @@ -0,0 +1,7 @@ +✘ error: “^(” is not a valid regular expression + reason: missing closing parenthesis + --> command-option:1 + | ;SELECT * from regexp_capture_into_json('abc=def;ghi=jkl;', '^(') + --> pattern + | ^(  + |  ^ missing closing parenthesis  diff --git a/test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.out b/test/expected/test_sql_regexp.sh_219a579cf7744fa08ab79fadd08b521b2f18a661.out new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.err b/test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.err new file mode 100644 index 00000000..209f89e4 --- /dev/null +++ b/test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.err @@ -0,0 +1,7 @@ +✘ error: “^(” is not a valid regular expression + reason: missing closing parenthesis + --> command-option:1 + | ;SELECT * from regexp_capture('abc=def;ghi=jkl;', '^(') + --> pattern + | ^(  + |  ^ missing closing parenthesis  diff --git a/test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.out b/test/expected/test_sql_regexp.sh_a610798fefdacd8d0179a4b17cd757d00fb731be.out new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_str_func.sh_d4bc869850f5b7e53353fc2506fea0c8e96f29c5.err b/test/expected/test_sql_str_func.sh_d4bc869850f5b7e53353fc2506fea0c8e96f29c5.err index f4c83996..9a3b66ca 100644 --- a/test/expected/test_sql_str_func.sh_d4bc869850f5b7e53353fc2506fea0c8e96f29c5.err +++ b/test/expected/test_sql_str_func.sh_d4bc869850f5b7e53353fc2506fea0c8e96f29c5.err @@ -1 +1 @@ -error: sqlite3_exec failed -- Invalid regular expression: missing closing parenthesis +error: sqlite3_exec failed -- lnav-error:{"level":"error","message":{"str":"“(” is not a valid regular expression","attrs":[]},"reason":{"str":"missing closing parenthesis","attrs":[]},"snippets":[{"source":"pattern","line":0,"content":{"str":"(\n ^ missing closing parenthesis","attrs":[{"start":0,"end":1,"type":"role","value":3},{"start":0,"end":1,"type":"style","value":2359296},{"start":0,"end":1,"type":"role","value":5},{"start":3,"end":5,"type":"role","value":5},{"start":5,"end":32,"type":"role","value":5},{"start":0,"end":-1,"type":"role","value":40}]}}],"help":{"str":"","attrs":[]}} diff --git a/test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.err b/test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.err new file mode 100644 index 00000000..44ba5c2c --- /dev/null +++ b/test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.err @@ -0,0 +1,4 @@ +✘ error: Invalid “top_meta.file” value + reason: Unknown text file: bad + --> command-option:1 + | ;UPDATE lnav_views SET top_meta = json_object('file', 'bad') WHERE name = 'text' diff --git a/test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.out b/test/expected/test_sql_views_vtab.sh_a7a7fd577f710aa8b0ad5a94fdfb35daea75e06c.out new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_sql_views_vtab.sh_c851bdf3ba2f56fac5a216457b2d11a109e77f03.err b/test/expected/test_sql_views_vtab.sh_c851bdf3ba2f56fac5a216457b2d11a109e77f03.err index 4276af6d..d4eb1047 100644 --- a/test/expected/test_sql_views_vtab.sh_c851bdf3ba2f56fac5a216457b2d11a109e77f03.err +++ b/test/expected/test_sql_views_vtab.sh_c851bdf3ba2f56fac5a216457b2d11a109e77f03.err @@ -1,4 +1,4 @@ -✘ error: SQL statement failed - reason: Invalid time: bad-time +✘ error: Invalid “top_time” value + reason: Unrecognized time value: bad-time  --> command-option:1  | ;UPDATE lnav_views SET top_time = 'bad-time' WHERE name = 'log' diff --git a/test/test_sessions.sh b/test/test_sessions.sh index db71e5fc..c4b27d76 100644 --- a/test/test_sessions.sh +++ b/test/test_sessions.sh @@ -117,3 +117,19 @@ run_cap_test ${lnav_test} -n -d /tmp/lnav.err \ -c ":load-session" \ -c ":test-comment restore hidden lines" \ ${test_dir}/logfile_access_log.0 + +# hiding fields failed +rm -rf ./sessions +mkdir -p $HOME +run_cap_test ${lnav_test} -n \ + -c ":hide-fields bro_uid" \ + -c ":goto -10" \ + -c ":save-session" \ + ${test_dir}/logfile_bro_http.log.0 + +# restoring hidden fields failed +run_cap_test ${lnav_test} -n \ + -c ":load-session" \ + -c ":goto -10" \ + -c ":test-comment restoring hidden fields" \ + ${test_dir}/logfile_bro_http.log.0 diff --git a/test/test_sql_regexp.sh b/test/test_sql_regexp.sh index 23d0425a..89b90d9b 100644 --- a/test/test_sql_regexp.sh +++ b/test/test_sql_regexp.sh @@ -28,5 +28,11 @@ run_cap_test ${lnav_test} -n \ run_cap_test ${lnav_test} -nN \ -c ";SELECT * from regexp_capture('abc=def;ghi=jkl;', '^(\w+)=([^;]+);')" +run_cap_test ${lnav_test} -nN \ + -c ";SELECT * from regexp_capture('abc=def;ghi=jkl;', '^(')" + run_cap_test ${lnav_test} -nN \ -c ";SELECT * from regexp_capture_into_json('abc=def;ghi=jkl;', '^(\w+)=([^;]+);')" + +run_cap_test ${lnav_test} -nN \ + -c ";SELECT * from regexp_capture_into_json('abc=def;ghi=jkl;', '^(')" diff --git a/test/test_sql_views_vtab.sh b/test/test_sql_views_vtab.sh index 606a673f..c25b5a42 100644 --- a/test/test_sql_views_vtab.sh +++ b/test/test_sql_views_vtab.sh @@ -177,3 +177,7 @@ run_cap_test ${lnav_test} -n \ -c ";SELECT top_meta FROM lnav_top_view" \ -c ":write-json-to -" \ ${test_dir}/logfile_xml_msg.0 + +run_cap_test ${lnav_test} -n \ + -c ";UPDATE lnav_views SET top_meta = json_object('file', 'bad') WHERE name = 'text'" \ + ${test_dir}/textfile_ansi.0