diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ef1af81..71989f61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,10 +2,10 @@ cmake_minimum_required(VERSION 3.14) include(cmake/prelude.cmake) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) project( lnav - VERSION 0.12.2 + VERSION 0.12.3 DESCRIPTION "An advanced log file viewer for the terminal." HOMEPAGE_URL "https://lnav.org/" LANGUAGES CXX C diff --git a/NEWS.md b/NEWS.md index 3c73f015..f591f93b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,20 @@ +## lnav v0.12.3 + +Features: +* Files that contain a mixture of log messages from separate + services (e.g. docker logs) can now be automatically + de-multiplexed into separate files that lnav can digest. + +Bug Fixes: +* Log messages in formats with custom timestamp formats were + not being converted to the local timezone. +* The timezone offset is now shown in the parser details + overlay for log messages. + +Maintenance: +* Upgrade to C++17 + + ## lnav v0.12.2 Features: diff --git a/configure.ac b/configure.ac index c2e553d7..5307aafe 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([lnav],[0.12.2],[lnav@googlegroups.com],[lnav],[http://lnav.org]) +AC_INIT([lnav],[0.12.3],[lnav@googlegroups.com],[lnav],[http://lnav.org]) AC_CONFIG_SRCDIR([src/lnav.cc]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE([foreign subdir-objects]) @@ -17,7 +17,7 @@ CXX="$PTHREAD_CXX" CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" AC_LANG(C++) -AX_CXX_COMPILE_STDCXX_14([noext], [mandatory]) +AX_CXX_COMPILE_STDCXX_17([noext], [mandatory]) dnl abssrcdir is the absolute path to the source base (regardless of where dnl you are building it) diff --git a/docs/schemas/config-v1.schema.json b/docs/schemas/config-v1.schema.json index 9ca49b49..cde9d64e 100644 --- a/docs/schemas/config-v1.schema.json +++ b/docs/schemas/config-v1.schema.json @@ -899,6 +899,27 @@ } }, "additionalProperties": false + }, + "demux": { + "description": "Demultiplexer definitions", + "title": "/log/demux", + "type": "object", + "patternProperties": { + "^([\\w\\-\\.]+)$": { + "description": "The definition of a demultiplexer", + "title": "/log/demux/", + "type": "object", + "properties": { + "pattern": { + "title": "/log/demux//pattern", + "description": "A regular expression to match a line in a multiplexed file", + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } }, "additionalProperties": false diff --git a/docs/source/config.rst b/docs/source/config.rst index d4fc9d52..2d1fe6a3 100644 --- a/docs/source/config.rst +++ b/docs/source/config.rst @@ -306,11 +306,42 @@ standard input. The handler should then generate the annotation content on the standard output. The output is treated as Markdown, so the content can be styled as desired. +Demultiplexing (v0.12.3+) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Files that are a mix of content from different sources, like +the output of :code:`docker compose logs`, can be automatically +demultiplexed so that *lnav* can process them correctly. Each +line of the input file must have a unique identifier that can +be used to determine which service the line belongs to. The +lines are then distributed to separate files based on the +identifier. A demultiplexer is a regular expression that +extracts the identifier, the log message, and an optional +timestamp. + +Demultiplexers are defined in the main configuration under +the :code:`/log/demux` path. The pattern for the demuxer +has the following known capture names: + +:mux_id: (required) Captures the unique identifier. + +:body: (required) Captures the body of the log message + that should be written to the file. + +:timestamp: (optional) The timestamp for the log message. + If this is available and the log message does not have + it's own timestamp, this will be used instead. + +If there are additional captures, they will be included +in the file metadata that can be accessed by the +:code:`lnav_file_metadata` table. + Reference ^^^^^^^^^ .. jsonschema:: ../schemas/config-v1.schema.json#/properties/log/properties/watch-expressions/patternProperties/^([\w\.\-]+)$ .. jsonschema:: ../schemas/config-v1.schema.json#/properties/log/properties/annotations/patternProperties/^([\w\.\-]+)$ +.. jsonschema:: ../schemas/config-v1.schema.json#/properties/log/properties/demux/patternProperties/^([\w\-\.]+)$ .. _tuning: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4600fe84..4ef7a844 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -570,7 +570,6 @@ add_library( logfile_stats.hh md2attr_line.hh md4cpp.hh - optional.hpp file_converter_manager.hh plain_text_source.hh pretty_printer.hh diff --git a/src/Makefile.am b/src/Makefile.am index 31fd6b5f..df13df6d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -302,7 +302,6 @@ noinst_HEADERS = \ mapbox/variant_visitor.hpp \ md2attr_line.hh \ md4cpp.hh \ - optional.hpp \ piper.looper.hh \ piper.looper.cfg.hh \ plain_text_source.hh \ diff --git a/src/archive_manager.cc b/src/archive_manager.cc index 0f33cba0..ee86cea3 100644 --- a/src/archive_manager.cc +++ b/src/archive_manager.cc @@ -124,8 +124,8 @@ describe(const fs::path& filename) archive_entry_strmode(entry), archive_entry_mtime(entry), archive_entry_size_is_set(entry) - ? nonstd::make_optional(archive_entry_size(entry)) - : nonstd::nullopt, + ? std::make_optional(archive_entry_size(entry)) + : std::nullopt, }); } while (archive_read_next_header(arc, &entry) == ARCHIVE_OK); diff --git a/src/archive_manager.hh b/src/archive_manager.hh index 7fab86ff..949e5b73 100644 --- a/src/archive_manager.hh +++ b/src/archive_manager.hh @@ -41,7 +41,6 @@ #include "base/result.h" #include "ghc/filesystem.hpp" #include "mapbox/variant.hpp" -#include "optional.hpp" namespace archive_manager { @@ -64,7 +63,7 @@ struct archive_info { ghc::filesystem::path e_name; const char* e_mode; time_t e_mtime; - nonstd::optional e_size; + std::optional e_size; }; const char* ai_format_name; std::vector ai_entries; diff --git a/src/base/ansi_scrubber.cc b/src/base/ansi_scrubber.cc index ec34328b..14cc745e 100644 --- a/src/base/ansi_scrubber.cc +++ b/src/base/ansi_scrubber.cc @@ -56,7 +56,7 @@ erase_ansi_escapes(string_fragment input) static thread_local auto md = lnav::pcre2pp::match_data::unitialized(); const auto& regex = ansi_regex(); - nonstd::optional move_start; + std::optional move_start; size_t fill_index = 0; auto matcher = regex.capture_from(input).into(md); @@ -125,7 +125,7 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa) static const auto semi_pred = string_fragment::tag1{';'}; const auto& regex = ansi_regex(); - nonstd::optional href; + std::optional href; size_t href_start = 0; string_attrs_t tmp_sa; size_t cp_dst = std::string::npos; @@ -267,7 +267,7 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa) struct line_range lr; text_attrs attrs; bool has_attrs = false; - nonstd::optional role; + std::optional role; if (md[3]) { auto osc_id = scn::scan_value(md[3]->to_string_view()); @@ -289,7 +289,7 @@ scrub_ansi_string(std::string& str, string_attrs_t* sa) }, VC_HYPERLINK.value(href.value())); } - href = nonstd::nullopt; + href = std::nullopt; } if (!uri.empty()) { href = uri.to_string(); diff --git a/src/base/attr_line.builder.cc b/src/base/attr_line.builder.cc index a6071a44..593f8632 100644 --- a/src/base/attr_line.builder.cc +++ b/src/base/attr_line.builder.cc @@ -37,7 +37,7 @@ attr_line_builder::append_as_hexdump(const string_fragment& sf) if (byte_off == 8) { this->append(" "); } - nonstd::optional ro; + std::optional ro; if (ch == '\0') { ro = role_t::VCR_NULL; } else if (isspace(ch) || iscntrl(ch)) { diff --git a/src/base/attr_line.builder.hh b/src/base/attr_line.builder.hh index 9ae2caa5..84ef97e5 100644 --- a/src/base/attr_line.builder.hh +++ b/src/base/attr_line.builder.hh @@ -41,7 +41,7 @@ public: class attr_guard { public: explicit attr_guard(attr_line_t& al) - : ag_line(al), ag_start(nonstd::nullopt) + : ag_line(al), ag_start(std::nullopt) { } @@ -59,7 +59,7 @@ public: : ag_line(other.ag_line), ag_start(std::move(other.ag_start)), ag_attr(std::move(other.ag_attr)) { - other.ag_start = nonstd::nullopt; + other.ag_start = std::nullopt; } ~attr_guard() @@ -76,7 +76,7 @@ public: private: attr_line_t& ag_line; - nonstd::optional ag_start; + std::optional ag_start; string_attr_pair ag_attr; }; diff --git a/src/base/attr_line.cc b/src/base/attr_line.cc index c4065259..69c993b2 100644 --- a/src/base/attr_line.cc +++ b/src/base/attr_line.cc @@ -356,6 +356,19 @@ attr_line_t::insert(size_t index, return *this; } +attr_line_t& +attr_line_t::wrap_with(text_wrap_settings* tws) +{ + attr_line_t tmp; + + tmp.al_string = std::move(this->al_string); + tmp.al_attrs = std::move(this->al_attrs); + + this->append(tmp, tws); + + return *this; +} + attr_line_t attr_line_t::subline(size_t start, size_t len) const { @@ -457,7 +470,7 @@ attr_line_t::apply_hide() } attr_line_t& -attr_line_t::rtrim(nonstd::optional chars) +attr_line_t::rtrim(std::optional chars) { auto index = this->al_string.length(); @@ -701,7 +714,7 @@ find_string_attr(const string_attrs_t& sa, return iter; } -nonstd::optional +std::optional get_string_attr(const string_attrs_t& sa, const string_attr_type_base* type, int start) @@ -709,8 +722,8 @@ get_string_attr(const string_attrs_t& sa, auto iter = find_string_attr(sa, type, start); if (iter == sa.end()) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional(&(*iter)); + return std::make_optional(&(*iter)); } diff --git a/src/base/attr_line.hh b/src/base/attr_line.hh index c2943211..ffdb7fc7 100644 --- a/src/base/attr_line.hh +++ b/src/base/attr_line.hh @@ -97,11 +97,11 @@ using string_attrs_t = std::vector; string_attrs_t::const_iterator find_string_attr( const string_attrs_t& sa, const string_attr_type_base* type, int start = 0); -nonstd::optional get_string_attr( +std::optional get_string_attr( const string_attrs_t& sa, const string_attr_type_base* type, int start = 0); template -inline nonstd::optional> +inline std::optional> get_string_attr(const string_attrs_t& sa, const string_attr_type& type, int start = 0) @@ -109,10 +109,10 @@ get_string_attr(const string_attrs_t& sa, auto iter = find_string_attr(sa, &type, start); if (iter == sa.end()) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional(string_attr_wrapper(&(*iter))); + return std::make_optional(string_attr_wrapper(&(*iter))); } template @@ -482,7 +482,7 @@ public: attr_line_t& erase(size_t pos, size_t len = std::string::npos); - attr_line_t& rtrim(nonstd::optional chars = nonstd::nullopt); + attr_line_t& rtrim(std::optional chars = std::nullopt); attr_line_t& erase_utf8_chars(size_t start) { @@ -579,6 +579,8 @@ public: size_t nearest_text(size_t x) const; + attr_line_t& wrap_with(text_wrap_settings* tws); + void apply_hide(); std::string al_string; diff --git a/src/base/auto_mem.hh b/src/base/auto_mem.hh index b404a1bc..22155386 100644 --- a/src/base/auto_mem.hh +++ b/src/base/auto_mem.hh @@ -223,7 +223,7 @@ public: this->ab_capacity = 0; } - auto_buffer& operator=(auto_buffer&) = delete; + auto_buffer& operator=(const auto_buffer&) = delete; auto_buffer& operator=(auto_buffer&& other) noexcept { diff --git a/src/base/date_time_scanner.cc b/src/base/date_time_scanner.cc index c3a904b1..2755ca9e 100644 --- a/src/base/date_time_scanner.cc +++ b/src/base/date_time_scanner.cc @@ -195,7 +195,6 @@ date_time_scanner::scan(const char* time_dest, { const auto sec_diff = tm_out->et_tm.tm_sec - last_tm.tm_sec; - // log_debug("diff %d", sec_diff); tv_out = this->dts_last_tv; tv_out.tv_sec += sec_diff; tm_out->et_tm.tm_wday = last_tm.tm_wday; @@ -231,20 +230,43 @@ date_time_scanner::scan(const char* time_dest, if (convert_local && (this->dts_local_time || tm_out->et_flags & ETF_EPOCH_TIME - || (tm_out->et_flags & ETF_ZONE_SET + || ((tm_out->et_flags & ETF_ZONE_SET + || this->dts_default_zone != nullptr) && this->dts_zoned_to_local))) { time_t gmt = tm_out->to_timeval().tv_sec; + if (!(tm_out->et_flags & ETF_ZONE_SET) + && !(tm_out->et_flags & ETF_EPOCH_TIME) + && this->dts_default_zone != nullptr) + { + date::local_seconds stime; + stime += std::chrono::seconds{gmt}; + auto ztime + = date::make_zoned(this->dts_default_zone, stime); + gmt = std::chrono::duration_cast( + ztime.get_sys_time().time_since_epoch()) + .count(); + } this->to_localtime(gmt, *tm_out); -#ifdef HAVE_STRUCT_TM_TM_ZONE - tm_out->et_tm.tm_zone = nullptr; -#endif - tm_out->et_tm.tm_isdst = 0; } + const auto& last_tm = this->dts_last_tm.et_tm; + if (last_tm.tm_year == tm_out->et_tm.tm_year + && last_tm.tm_mon == tm_out->et_tm.tm_mon + && last_tm.tm_mday == tm_out->et_tm.tm_mday + && last_tm.tm_hour == tm_out->et_tm.tm_hour + && last_tm.tm_min == tm_out->et_tm.tm_min) + { + const auto sec_diff = tm_out->et_tm.tm_sec - last_tm.tm_sec; - tv_out = tm_out->to_timeval(); - secs2wday(tv_out, &tm_out->et_tm); + tv_out = this->dts_last_tv; + tv_out.tv_sec += sec_diff; + tm_out->et_tm.tm_wday = last_tm.tm_wday; + } else { + tv_out = tm_out->to_timeval(); + secs2wday(tv_out, &tm_out->et_tm); + } + tv_out.tv_usec = tm_out->et_nsec / 1000; this->dts_fmt_lock = curr_time_fmt; this->dts_fmt_len = retval - time_dest; diff --git a/src/base/fs_util.cc b/src/base/fs_util.cc index 7cbc228c..a56ef502 100644 --- a/src/base/fs_util.cc +++ b/src/base/fs_util.cc @@ -40,6 +40,36 @@ namespace lnav { namespace filesystem { +std::string +escape_path(const ghc::filesystem::path& p) +{ + auto p_str = p.string(); + std::string retval; + + for (const auto ch : p_str) { + switch (ch) { + case ' ': + case '$': + case '\\': + case ';': + case '&': + case '<': + case '>': + case '\'': + case '"': + case '*': + case '[': + case ']': + case '?': + retval.push_back('\\'); + break; + } + retval.push_back(ch); + } + + return retval; +} + Result realpath(const ghc::filesystem::path& path) { diff --git a/src/base/fs_util.hh b/src/base/fs_util.hh index 7553075b..db111de2 100644 --- a/src/base/fs_util.hh +++ b/src/base/fs_util.hh @@ -50,6 +50,8 @@ is_glob(const std::string& fn) || fn.find('[') != std::string::npos); } +std::string escape_path(const ghc::filesystem::path& p); + inline int statp(const ghc::filesystem::path& path, struct stat* buf) { @@ -90,7 +92,7 @@ enum class write_file_options { }; struct write_file_result { - nonstd::optional wfr_backup_path; + std::optional wfr_backup_path; }; Result write_file( @@ -144,8 +146,8 @@ public: namespace fmt { template<> struct formatter : formatter { - auto format(const ghc::filesystem::path& p, format_context& ctx) - -> decltype(ctx.out()) const; + auto format(const ghc::filesystem::path& p, + format_context& ctx) -> decltype(ctx.out()) const; }; } // namespace fmt diff --git a/src/base/humanize.cc b/src/base/humanize.cc index 5e96bf38..68b45301 100644 --- a/src/base/humanize.cc +++ b/src/base/humanize.cc @@ -77,7 +77,7 @@ file_size(file_ssize_t value, alignment align) } const std::string& -sparkline(double value, nonstd::optional upper_opt) +sparkline(double value, std::optional upper_opt) { static const std::string ZERO = " "; static const std::string BARS[] = { diff --git a/src/base/humanize.hh b/src/base/humanize.hh index 3f9f66cd..d45cdcde 100644 --- a/src/base/humanize.hh +++ b/src/base/humanize.hh @@ -51,7 +51,7 @@ enum class alignment { */ std::string file_size(file_ssize_t value, alignment align); -const std::string& sparkline(double value, nonstd::optional upper); +const std::string& sparkline(double value, std::optional upper); } // namespace humanize diff --git a/src/base/humanize.network.cc b/src/base/humanize.network.cc index 2bf390d7..1bf47b3d 100644 --- a/src/base/humanize.network.cc +++ b/src/base/humanize.network.cc @@ -30,13 +30,14 @@ #include "humanize.network.hh" #include "config.h" +#include "itertools.hh" #include "pcrepp/pcre2pp.hh" namespace humanize { namespace network { namespace path { -nonstd::optional<::network::path> +std::optional<::network::path> from_str(string_fragment sf) { static const auto REMOTE_PATTERN = lnav::pcre2pp::code::from_const( @@ -52,11 +53,11 @@ from_str(string_fragment sf) .ignore_error(); if (!match_res) { - return nonstd::nullopt; + return std::nullopt; } - const auto username = REMOTE_MATCH_DATA["username"].map( - [](auto sf) { return sf.to_string(); }); + const auto username = REMOTE_MATCH_DATA["username"] + | lnav::itertools::map([](auto sf) { return sf.to_string(); }); const auto ipv6 = REMOTE_MATCH_DATA["ipv6"]; const auto hostname = REMOTE_MATCH_DATA["hostname"]; const auto locality_hostname = ipv6 ? ipv6.value() : hostname.value(); @@ -66,7 +67,7 @@ from_str(string_fragment sf) path = string_fragment::from_const("."); } return ::network::path{ - {username, locality_hostname.to_string(), nonstd::nullopt}, + {username, locality_hostname.to_string(), std::nullopt}, path.to_string(), }; } diff --git a/src/base/humanize.network.hh b/src/base/humanize.network.hh index 609f57dd..8979e0e9 100644 --- a/src/base/humanize.network.hh +++ b/src/base/humanize.network.hh @@ -35,7 +35,6 @@ #include "fmt/format.h" #include "intern_string.hh" #include "network.tcp.hh" -#include "optional.hpp" namespace fmt { @@ -100,7 +99,7 @@ namespace humanize { namespace network { namespace path { -nonstd::optional<::network::path> from_str(string_fragment sf); +std::optional<::network::path> from_str(string_fragment sf); } // namespace path } // namespace network diff --git a/src/base/humanize.time.hh b/src/base/humanize.time.hh index e1ebf67a..df34ad73 100644 --- a/src/base/humanize.time.hh +++ b/src/base/humanize.time.hh @@ -30,12 +30,11 @@ #ifndef lnav_humanize_time_hh #define lnav_humanize_time_hh +#include #include #include -#include "optional.hpp" - namespace humanize { namespace time { @@ -66,7 +65,7 @@ private: } struct timeval p_past_point; - nonstd::optional p_recent_point; + std::optional p_recent_point; bool p_convert_to_local{false}; }; diff --git a/src/base/intern_string.cc b/src/base/intern_string.cc index 010da524..4b239665 100644 --- a/src/base/intern_string.cc +++ b/src/base/intern_string.cc @@ -179,11 +179,11 @@ string_fragment::trim() const return this->trim(" \t\r\n"); } -nonstd::optional +std::optional string_fragment::consume_n(int amount) const { if (amount > this->length()) { - return nonstd::nullopt; + return std::nullopt; } return string_fragment{ @@ -197,7 +197,7 @@ string_fragment::split_result string_fragment::split_n(int amount) const { if (amount > this->length()) { - return nonstd::nullopt; + return std::nullopt; } return std::make_pair( @@ -391,8 +391,8 @@ string_fragment string_fragment::sub_cell_range(int cell_start, int cell_end) const { int byte_index = this->sf_begin; - nonstd::optional byte_start; - nonstd::optional byte_end; + std::optional byte_start; + std::optional byte_end; int cell_index = 0; while (byte_index < this->sf_end) { diff --git a/src/base/intern_string.hh b/src/base/intern_string.hh index f77dc49a..3b0d3890 100644 --- a/src/base/intern_string.hh +++ b/src/base/intern_string.hh @@ -40,7 +40,6 @@ #include #include "fmt/format.h" -#include "optional.hpp" #include "result.h" #include "scn/util/string_view.h" #include "strnatcmp.h" @@ -302,7 +301,7 @@ struct string_fragment { return retval; } - nonstd::optional find(char ch) const + std::optional find(char ch) const { for (int lpc = this->sf_begin; lpc < this->sf_end; lpc++) { if (this->sf_string[lpc] == ch) { @@ -310,7 +309,7 @@ struct string_fragment { } } - return nonstd::nullopt; + return std::nullopt; } template @@ -374,21 +373,21 @@ struct string_fragment { start - left.sf_begin, predicate, count); } - nonstd::optional> consume_codepoint() + std::optional> consume_codepoint() const { auto cp = this->front_codepoint(); auto index_res = this->codepoint_to_byte_index(1); if (index_res.isErr()) { - return nonstd::nullopt; + return std::nullopt; } return std::make_pair(cp, this->substr(index_res.unwrap())); } template - nonstd::optional consume(P predicate) const + std::optional consume(P predicate) const { int consumed = 0; while (consumed < this->length()) { @@ -400,7 +399,7 @@ struct string_fragment { } if (consumed == 0) { - return nonstd::nullopt; + return std::nullopt; } return string_fragment{ @@ -410,7 +409,7 @@ struct string_fragment { }; } - nonstd::optional consume_n(int amount) const; + std::optional consume_n(int amount) const; template string_fragment skip(P predicate) const @@ -428,7 +427,7 @@ struct string_fragment { } using split_result - = nonstd::optional>; + = std::optional>; template split_result split_while(P&& predicate) const @@ -443,7 +442,7 @@ struct string_fragment { } if (consumed == 0) { - return nonstd::nullopt; + return std::nullopt; } return std::make_pair( @@ -500,7 +499,7 @@ struct string_fragment { } if (consumed == this->length()) { - return nonstd::nullopt; + return std::nullopt; } return std::make_pair( diff --git a/src/base/is_utf8.cc b/src/base/is_utf8.cc index b8fbab03..d976c556 100644 --- a/src/base/is_utf8.cc +++ b/src/base/is_utf8.cc @@ -60,7 +60,7 @@ error. */ utf8_scan_result -is_utf8(string_fragment str, nonstd::optional terminator) +is_utf8(string_fragment str, std::optional terminator) { const auto* ustr = str.udata(); utf8_scan_result retval; diff --git a/src/base/is_utf8.hh b/src/base/is_utf8.hh index 81d09c69..d0ba8006 100644 --- a/src/base/is_utf8.hh +++ b/src/base/is_utf8.hh @@ -32,13 +32,12 @@ #include #include "intern_string.hh" -#include "optional.hpp" struct utf8_scan_result { const char* usr_message{nullptr}; size_t usr_faulty_bytes{0}; string_fragment usr_valid_frag{string_fragment::invalid()}; - nonstd::optional usr_remaining; + std::optional usr_remaining; bool usr_has_ansi{false}; size_t usr_column_width_guess{0}; @@ -54,7 +53,7 @@ struct utf8_scan_result { }; utf8_scan_result is_utf8(string_fragment frag, - nonstd::optional terminator - = nonstd::nullopt); + std::optional terminator + = std::nullopt); #endif /* _IS_UTF8_H */ diff --git a/src/base/itertools.hh b/src/base/itertools.hh index 70286fba..9f58a800 100644 --- a/src/base/itertools.hh +++ b/src/base/itertools.hh @@ -39,7 +39,6 @@ #include #include "func_util.hh" -#include "optional.hpp" namespace lnav { namespace itertools { @@ -122,7 +121,7 @@ struct append { }; struct nth { - nonstd::optional a_index; + std::optional a_index; }; struct skip { @@ -190,7 +189,7 @@ second() } inline details::nth -nth(nonstd::optional index) +nth(std::optional index) { return details::nth{ index, @@ -340,7 +339,7 @@ sum() } // namespace lnav template -nonstd::optional>::value, typename std::remove_reference_t::const_iterator, typename std::remove_reference_t::iterator>> @@ -348,44 +347,44 @@ operator|(C&& in, const lnav::itertools::details::find_if

& finder) { for (auto iter = in.begin(); iter != in.end(); ++iter) { if (lnav::func::invoke(finder.fi_predicate, *iter)) { - return nonstd::make_optional(iter); + return std::make_optional(iter); } } - return nonstd::nullopt; + return std::nullopt; } template -nonstd::optional +std::optional operator|(const C& in, const lnav::itertools::details::find& finder) { size_t retval = 0; for (const auto& elem : in) { if (elem == finder.f_value) { - return nonstd::make_optional(retval); + return std::make_optional(retval); } retval += 1; } - return nonstd::nullopt; + return std::nullopt; } template -nonstd::optional +std::optional operator|(const C& in, const lnav::itertools::details::nth indexer) { if (!indexer.a_index.has_value()) { - return nonstd::nullopt; + return std::nullopt; } if (indexer.a_index.value() < in.size()) { auto iter = in.begin(); std::advance(iter, indexer.a_index.value()); - return nonstd::make_optional(iter); + return std::make_optional(iter); } - return nonstd::nullopt; + return std::nullopt; } template @@ -402,10 +401,10 @@ operator|(const C& in, const lnav::itertools::details::first indexer) } template -nonstd::optional +std::optional operator|(const C& in, const lnav::itertools::details::max_value maxer) { - nonstd::optional retval; + std::optional retval; for (const auto& elem : in) { if (!retval) { @@ -572,13 +571,13 @@ template::value, int> = 0> auto -operator|(nonstd::optional in, +operator|(std::optional in, const lnav::itertools::details::flat_mapper& mapper) -> typename std::remove_const_t> { if (!in) { - return nonstd::nullopt; + return std::nullopt; } return lnav::func::invoke(mapper.fm_func, in.value()); @@ -588,7 +587,7 @@ template::value, int> = 0> void -operator|(nonstd::optional in, +operator|(std::optional in, const lnav::itertools::details::for_eacher& eacher) { if (!in) { @@ -614,17 +613,17 @@ template::value, int> = 0> auto -operator|(nonstd::optional in, +operator|(std::optional in, const lnav::itertools::details::mapper& mapper) - -> nonstd::optional< + -> std::optional< typename std::remove_const_t>> { if (!in) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional(lnav::func::invoke(mapper.m_func, in.value())); + return std::make_optional(lnav::func::invoke(mapper.m_func, in.value())); } template @@ -813,38 +812,38 @@ template::value, int> = 0> auto -operator|(nonstd::optional in, +operator|(std::optional in, const lnav::itertools::details::mapper& mapper) - -> nonstd::optional std::optional>> { if (!in) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional((in.value()).*mapper.m_func); + return std::make_optional((in.value()).*mapper.m_func); } template::value, int> = 0> auto -operator|(nonstd::optional in, +operator|(std::optional in, const lnav::itertools::details::mapper& mapper) - -> nonstd::optional< + -> std::optional< typename std::remove_const_t>> { if (!in) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional((*in.value()).*mapper.m_func); + return std::make_optional((*in.value()).*mapper.m_func); } template T -operator|(nonstd::optional in, +operator|(std::optional in, const lnav::itertools::details::unwrap_or& unwrapper) { return in.value_or(unwrapper.uo_value); diff --git a/src/base/lnav.console.cc b/src/base/lnav.console.cc index b9d2d6c2..edab1bed 100644 --- a/src/base/lnav.console.cc +++ b/src/base/lnav.console.cc @@ -252,7 +252,7 @@ user_message::to_attr_line(std::set flags) const return retval; } -static nonstd::optional +static std::optional curses_color_to_terminal_color(int curses_color) { switch (curses_color) { @@ -273,7 +273,7 @@ curses_color_to_terminal_color(int curses_color) case COLOR_RED: return fmt::terminal_color::red; default: - return nonstd::nullopt; + return std::nullopt; } } @@ -326,7 +326,7 @@ println(FILE* file, const attr_line_t& al) } } - nonstd::optional last_point; + std::optional last_point; for (const auto& point : points) { if (!last_point) { last_point = point; @@ -337,7 +337,7 @@ println(FILE* file, const attr_line_t& al) auto line_style = fmt::text_style{}; auto fg_style = fmt::text_style{}; auto start = last_point.value(); - nonstd::optional href; + std::optional href; for (const auto& attr : al.get_attrs()) { if (!attr.sa_range.contains(start) diff --git a/src/base/lnav_log.cc b/src/base/lnav_log.cc index b7706988..f6655944 100644 --- a/src/base/lnav_log.cc +++ b/src/base/lnav_log.cc @@ -103,10 +103,10 @@ static const char* CRASH_MSG " %s\n" "=========================\n"; -nonstd::optional lnav_log_file; +std::optional lnav_log_file; lnav_log_level_t lnav_log_level = lnav_log_level_t::DEBUG; const char* lnav_log_crash_dir; -nonstd::optional lnav_log_orig_termios; +std::optional lnav_log_orig_termios; // NOTE: This mutex is leaked so that it is not destroyed during exit. // Otherwise, any attempts to log will fail. static std::mutex* diff --git a/src/base/lnav_log.hh b/src/base/lnav_log.hh index 551b4f8c..986a38a1 100644 --- a/src/base/lnav_log.hh +++ b/src/base/lnav_log.hh @@ -33,6 +33,7 @@ #define lnav_log_hh #include +#include #include #include @@ -43,8 +44,6 @@ # define lnav_dead2 __attribute__((noreturn)) #endif -#include "optional.hpp" - struct termios; enum class lnav_log_level_t : uint32_t { @@ -80,7 +79,7 @@ public: virtual ~log_state_dumper(); - virtual void log_state(){ + virtual void log_state() { }; @@ -97,9 +96,9 @@ public: virtual void log_crash_recover() = 0; }; -extern nonstd::optional lnav_log_file; +extern std::optional lnav_log_file; extern const char* lnav_log_crash_dir; -extern nonstd::optional lnav_log_orig_termios; +extern std::optional lnav_log_orig_termios; extern enum lnav_log_level_t lnav_log_level; #define log_msg_wrapper(level, fmt...) \ @@ -146,15 +145,17 @@ extern enum lnav_log_level_t lnav_log_level; ((void) ((lhs >= rhs) \ ? 0 \ : lnav_require_binary( \ - #lhs " >= " #rhs, lhs, rhs, __FILE__, __LINE__))) + #lhs " >= " #rhs, lhs, rhs, __FILE__, __LINE__))) #define require_gt(lhs, rhs) \ - ((void) ((lhs > rhs) ? 0 \ - : lnav_require_binary( \ - #lhs " > " #rhs, lhs, rhs, __FILE__, __LINE__))) + ((void) ((lhs > rhs) \ + ? 0 \ + : lnav_require_binary( \ + #lhs " > " #rhs, lhs, rhs, __FILE__, __LINE__))) #define require_lt(lhs, rhs) \ - ((void) ((lhs < rhs) ? 0 \ - : lnav_require_binary( \ - #lhs " < " #rhs, lhs, rhs, __FILE__, __LINE__))) + ((void) ((lhs < rhs) \ + ? 0 \ + : lnav_require_binary( \ + #lhs " < " #rhs, lhs, rhs, __FILE__, __LINE__))) #define lnav_require_binary(e, lhs, rhs, file, line) \ (log_msg(lnav_log_level_t::ERROR, \ diff --git a/src/base/lrucache.hpp b/src/base/lrucache.hpp index 8bcbad69..01b25829 100644 --- a/src/base/lrucache.hpp +++ b/src/base/lrucache.hpp @@ -1,4 +1,4 @@ -/* +/* * File: lrucache.hpp * Author: Alexander Ponomarev * @@ -6,78 +6,75 @@ */ #ifndef _LRUCACHE_HPP_INCLUDED_ -#define _LRUCACHE_HPP_INCLUDED_ +#define _LRUCACHE_HPP_INCLUDED_ -#include -#include #include +#include +#include +#include #include -#include "optional.hpp" - namespace cache { template class lru_cache { public: - typedef typename std::pair key_value_pair_t; - typedef typename std::list::iterator list_iterator_t; - - lru_cache(size_t max_size) : - _max_size(max_size) { - } - - void put(const key_t& key, const value_t& value) { - auto it = _cache_items_map.find(key); - _cache_items_list.push_front(key_value_pair_t(key, value)); - if (it != _cache_items_map.end()) { - _cache_items_list.erase(it->second); - _cache_items_map.erase(it); - } - _cache_items_map[key] = _cache_items_list.begin(); - - if (_cache_items_map.size() > _max_size) { - auto last = _cache_items_list.end(); - last--; - _cache_items_map.erase(last->first); - _cache_items_list.pop_back(); - } - } - - nonstd::optional get(const key_t& key) { - auto it = _cache_items_map.find(key); - if (it == _cache_items_map.end()) { - return nonstd::nullopt; - } - - _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second); + typedef typename std::pair key_value_pair_t; + typedef typename std::list::iterator list_iterator_t; + + lru_cache(size_t max_size) : _max_size(max_size) {} + + void put(const key_t& key, const value_t& value) + { + auto it = _cache_items_map.find(key); + _cache_items_list.push_front(key_value_pair_t(key, value)); + if (it != _cache_items_map.end()) { + _cache_items_list.erase(it->second); + _cache_items_map.erase(it); + } + _cache_items_map[key] = _cache_items_list.begin(); + + if (_cache_items_map.size() > _max_size) { + auto last = _cache_items_list.end(); + last--; + _cache_items_map.erase(last->first); + _cache_items_list.pop_back(); + } + } + + std::optional get(const key_t& key) + { + auto it = _cache_items_map.find(key); + if (it == _cache_items_map.end()) { + return std::nullopt; + } + + _cache_items_list.splice( + _cache_items_list.begin(), _cache_items_list, it->second); return it->second->second; - } - - bool exists(const key_t& key) const { - return _cache_items_map.find(key) != _cache_items_map.end(); - } - - size_t size() const { - return _cache_items_map.size(); - } - - void set_max_size(size_t max_size) { - this->_max_size = max_size; - } - - void clear() { - this->_cache_items_map.clear(); - this->_cache_items_list.clear(); - } - + } + + bool exists(const key_t& key) const + { + return _cache_items_map.find(key) != _cache_items_map.end(); + } + + size_t size() const { return _cache_items_map.size(); } + + void set_max_size(size_t max_size) { this->_max_size = max_size; } + + void clear() + { + this->_cache_items_map.clear(); + this->_cache_items_list.clear(); + } + private: - std::list _cache_items_list; - std::map _cache_items_map; - size_t _max_size; + std::list _cache_items_list; + std::map _cache_items_map; + size_t _max_size; }; -} // namespace cache - -#endif /* _LRUCACHE_HPP_INCLUDED_ */ +} // namespace cache +#endif /* _LRUCACHE_HPP_INCLUDED_ */ diff --git a/src/base/map_util.hh b/src/base/map_util.hh index a3e565eb..1ab56293 100644 --- a/src/base/map_util.hh +++ b/src/base/map_util.hh @@ -35,13 +35,12 @@ #include #include -#include "optional.hpp" namespace lnav { namespace map { template -nonstd::optional< +std::optional< std::reference_wrapper::value, const typename C::mapped_type, typename C::mapped_type>>> @@ -49,10 +48,10 @@ find(C& container, const typename C::key_type& key) { auto iter = container.find(key); if (iter != container.end()) { - return nonstd::make_optional(std::ref(iter->second)); + return std::make_optional(std::ref(iter->second)); } - return nonstd::nullopt; + return std::nullopt; } template> diff --git a/src/base/network.tcp.hh b/src/base/network.tcp.hh index c046bb6f..01738ee8 100644 --- a/src/base/network.tcp.hh +++ b/src/base/network.tcp.hh @@ -33,23 +33,22 @@ #include #include "auto_fd.hh" -#include "optional.hpp" #include "result.h" namespace network { struct locality { - locality(nonstd::optional username, + locality(std::optional username, std::string hostname, - nonstd::optional service) + std::optional service) : l_username(std::move(username)), l_hostname(std::move(hostname)), l_service(std::move(service)) { } - nonstd::optional l_username; + std::optional l_username; std::string l_hostname; - nonstd::optional l_service; + std::optional l_service; }; struct path { diff --git a/src/base/opt_util.hh b/src/base/opt_util.hh index aea038ef..b7379b12 100644 --- a/src/base/opt_util.hh +++ b/src/base/opt_util.hh @@ -30,9 +30,9 @@ #ifndef lnav_opt_util_hh #define lnav_opt_util_hh -#include +#include -#include "optional.hpp" +#include namespace detail { @@ -47,25 +47,22 @@ template typename std::enable_if::value, T>::type void_or_nullopt() { - return nonstd::nullopt; + return std::nullopt; } template -struct is_optional : std::false_type { -}; +struct is_optional : std::false_type {}; template -struct is_optional> : std::true_type { -}; +struct is_optional> : std::true_type {}; } // namespace detail template>::value, int> = 0> auto -operator|(T&& t, F f) - -> decltype(detail::void_or_nullopt(t). - operator*()))>()) +operator|(T&& t, F f) -> decltype(detail::void_or_nullopt(t).operator*()))>()) { using return_type = decltype(f(std::forward(t).operator*())); if (t) @@ -75,28 +72,27 @@ operator|(T&& t, F f) } template -optional_constexpr nonstd::optional::type> +constexpr std::optional::type> make_optional_from_nullable(T&& v) { if (v != nullptr) { - return nonstd::optional::type>( - std::forward(v)); + return std::optional::type>(std::forward(v)); } - return nonstd::nullopt; + return std::nullopt; } template class C, typename T> -nonstd::optional +std::optional cget(const C& container, size_t index) { if (index < container.size()) { return container[index]; } - return nonstd::nullopt; + return std::nullopt; } -inline nonstd::optional +inline std::optional getenv_opt(const char* name) { return make_optional_from_nullable(getenv(name)); diff --git a/src/base/piper.file.cc b/src/base/piper.file.cc index 14436049..67e1737b 100644 --- a/src/base/piper.file.cc +++ b/src/base/piper.file.cc @@ -32,8 +32,10 @@ #include #include +#include "base/injector.hh" #include "base/lnav_log.hh" #include "base/paths.hh" +#include "piper.looper.cfg.hh" namespace lnav { namespace piper { @@ -48,7 +50,7 @@ storage_path() return INSTANCE; } -nonstd::optional +std::optional read_header(int fd, const char* first8) { if (memcmp(first8, HEADER_MAGIC, sizeof(HEADER_MAGIC)) != 0) { @@ -57,7 +59,7 @@ read_header(int fd, const char* first8) first8[1], first8[2], first8[3]); - return nonstd::nullopt; + return std::nullopt; } uint32_t meta_size = ntohl(*((uint32_t*) &first8[4])); @@ -65,17 +67,54 @@ read_header(int fd, const char* first8) auto meta_buf = auto_buffer::alloc(meta_size); if (meta_buf.in() == nullptr) { log_error("failed to alloc %d bytes for header", meta_size); - return nonstd::nullopt; + return std::nullopt; } auto meta_prc = pread(fd, meta_buf.in(), meta_size, 8); if (meta_prc != meta_size) { log_error("failed to read piper header: %s", strerror(errno)); - return nonstd::nullopt; + return std::nullopt; } meta_buf.resize(meta_size); return meta_buf; } +std::optional +multiplex_id_for_line(string_fragment line) +{ + const auto& cfg = injector::get(); + auto md = lnav::pcre2pp::match_data::unitialized(); + + for (const auto& demux_pair : cfg.c_demux_definitions) { + const auto& df = demux_pair.second; + + if (!df.dd_enabled) { + continue; + } + + log_info("attempting to demux using: %s", demux_pair.first.c_str()); + md = df.dd_pattern.pp_value->create_match_data(); + if (df.dd_pattern.pp_value->capture_from(line) + .into(md) + .matches() + .ignore_error()) + { + log_info(" demuxer pattern matched"); + if (!md[df.dd_muxid_capture_index].has_value()) { + log_info(" however, mux_id was not captured"); + continue; + } + if (!md[df.dd_body_capture_index].has_value()) { + log_info(" however, body was not captured"); + continue; + } + log_info(" and required captures were found, using demuxer"); + return demux_pair.first; + } + } + + return std::nullopt; +} + } // namespace piper } // namespace lnav diff --git a/src/base/piper.file.hh b/src/base/piper.file.hh index 7a263ea2..99ab0c67 100644 --- a/src/base/piper.file.hh +++ b/src/base/piper.file.hh @@ -31,13 +31,14 @@ #define lnav_piper_file_hh #include +#include #include #include #include "auto_mem.hh" +#include "base/intern_string.hh" #include "ghc/filesystem.hpp" -#include "optional.hpp" #include "time_util.hh" namespace lnav { @@ -48,6 +49,8 @@ struct header { std::string h_name; std::string h_cwd; std::map h_env; + std::string h_timezone; + std::map h_demux_meta; bool operator<(const header& rhs) const { @@ -68,7 +71,9 @@ const ghc::filesystem::path& storage_path(); constexpr size_t HEADER_SIZE = 8; extern const char HEADER_MAGIC[4]; -nonstd::optional read_header(int fd, const char* first8); +std::optional read_header(int fd, const char* first8); + +std::optional multiplex_id_for_line(string_fragment line); } // namespace piper } // namespace lnav diff --git a/src/base/snippet_highlighters.cc b/src/base/snippet_highlighters.cc index 058fa41f..904ae707 100644 --- a/src/base/snippet_highlighters.cc +++ b/src/base/snippet_highlighters.cc @@ -99,7 +99,7 @@ find_matching_bracket( } } - nonstd::optional first_left; + std::optional first_left; depth = 0; diff --git a/src/base/string_attr_type.hh b/src/base/string_attr_type.hh index 0b8cd853..59e026a9 100644 --- a/src/base/string_attr_type.hh +++ b/src/base/string_attr_type.hh @@ -164,8 +164,8 @@ struct text_attrs { } int32_t ta_attrs{0}; - nonstd::optional ta_fg_color; - nonstd::optional ta_bg_color; + std::optional ta_fg_color; + std::optional ta_bg_color; }; struct block_elem_t { diff --git a/src/base/string_util.cc b/src/base/string_util.cc index 39e80f6c..1cfdc85d 100644 --- a/src/base/string_util.cc +++ b/src/base/string_util.cc @@ -375,7 +375,7 @@ is_meta(char ch) } } -static nonstd::optional +static std::optional char_escape_seq(char ch) { switch (ch) { @@ -385,7 +385,7 @@ char_escape_seq(char ch) return "\\n"; } - return nonstd::nullopt; + return std::nullopt; } std::string diff --git a/src/base/time_util.cc b/src/base/time_util.cc index 5aee0179..940cacc4 100644 --- a/src/base/time_util.cc +++ b/src/base/time_util.cc @@ -38,7 +38,6 @@ #include "config.h" #include "lnav_log.hh" -#include "optional.hpp" namespace lnav { @@ -80,18 +79,18 @@ strftime_rfc3339( return index; } -static nonstd::optional +static std::optional get_posix_zone(const char* name) { if (name == nullptr) { - return nonstd::nullopt; + return std::nullopt; } try { return date::zoned_traits::locate_zone(name); } catch (const std::runtime_error& e) { log_error("invalid TZ value: %s -- %s", name, e.what()); - return nonstd::nullopt; + return std::nullopt; } } @@ -121,6 +120,8 @@ to_sys_time(date::local_seconds secs) return TZ_POSIX_ZONE.value().to_sys(secs); } + auto inf = TZ_DATE_ZONE->get_info(secs); + return TZ_DATE_ZONE->to_sys(secs); } @@ -138,6 +139,34 @@ to_local_time(date::sys_seconds secs) return TZ_DATE_ZONE->to_local(secs); } +date::sys_info +sys_time_to_info(date::sys_seconds secs) +{ + static const auto* TZ = getenv("TZ"); + static const auto TZ_POSIX_ZONE = get_posix_zone(TZ); + static const auto* TZ_DATE_ZONE = get_date_zone(TZ); + + if (TZ_POSIX_ZONE) { + return TZ_POSIX_ZONE.value().get_info(secs); + } + + return TZ_DATE_ZONE->get_info(secs); +} + +date::local_info +local_time_to_info(date::local_seconds secs) +{ + static const auto* TZ = getenv("TZ"); + static const auto TZ_POSIX_ZONE = get_posix_zone(TZ); + static const auto* TZ_DATE_ZONE = get_date_zone(TZ); + + if (TZ_POSIX_ZONE) { + return TZ_POSIX_ZONE.value().get_info(secs); + } + + return TZ_DATE_ZONE->get_info(secs); +} + } // namespace lnav static time_t BAD_DATE = -1; diff --git a/src/base/time_util.hh b/src/base/time_util.hh index 5640463c..1e5b7982 100644 --- a/src/base/time_util.hh +++ b/src/base/time_util.hh @@ -40,6 +40,7 @@ #include "config.h" #include "date/date.h" +#include "date/tz.h" namespace lnav { @@ -51,6 +52,10 @@ ssize_t strftime_rfc3339(char* buffer, int millis, char sep = ' '); +date::sys_info sys_time_to_info(date::sys_seconds secs); + +date::local_info local_time_to_info(date::local_seconds secs); + date::sys_seconds to_sys_time(date::local_seconds secs); date::local_seconds to_local_time(date::sys_seconds secs); diff --git a/src/bookmarks.cc b/src/bookmarks.cc index fd166c42..043574e0 100644 --- a/src/bookmarks.cc +++ b/src/bookmarks.cc @@ -87,7 +87,7 @@ bookmark_metadata::clear() this->bm_annotations.la_pairs.clear(); } -nonstd::optional +std::optional bookmark_type_t::find_type(const std::string& name) { return get_all_types() diff --git a/src/bookmarks.hh b/src/bookmarks.hh index c8ffa569..99b0b714 100644 --- a/src/bookmarks.hh +++ b/src/bookmarks.hh @@ -153,7 +153,7 @@ public: * the next bookmark is returned. If the 'start' value is not a * bookmark, the next highest value in the vector is returned. */ - nonstd::optional next(LineType start) const; + std::optional next(LineType start) const; /** * @param start The value to start the search for the previous @@ -162,7 +162,7 @@ public: * are no more prior bookmarks. * @see next */ - nonstd::optional prev(LineType start) const; + std::optional prev(LineType start) const; }; /** @@ -177,7 +177,7 @@ public: static type_iterator type_end() { return get_all_types().end(); } - static nonstd::optional find_type( + static std::optional find_type( const std::string& name); static std::vector& get_all_types(); @@ -194,10 +194,10 @@ private: }; template -nonstd::optional +std::optional bookmark_vector::next(LineType start) const { - nonstd::optional retval; + std::optional retval; require(start >= -1); @@ -212,10 +212,10 @@ bookmark_vector::next(LineType start) const } template -nonstd::optional +std::optional bookmark_vector::prev(LineType start) const { - nonstd::optional retval; + std::optional retval; require(start >= 0); diff --git a/src/bottom_status_source.cc b/src/bottom_status_source.cc index 080be39d..5b1b2ef5 100644 --- a/src/bottom_status_source.cc +++ b/src/bottom_status_source.cc @@ -71,13 +71,13 @@ bottom_status_source::update_line_number(listview_curses* lc) this->bss_line_error.set_value( lc->map_top_row([](const attr_line_t& top_row) - -> nonstd::optional { + -> std::optional { const auto& sa = top_row.get_attrs(); auto error_wrapper = get_string_attr(sa, SA_ERROR); if (error_wrapper) { return error_wrapper.value().get(); } - return nonstd::nullopt; + return std::nullopt; }).value_or("")); } diff --git a/src/breadcrumb.hh b/src/breadcrumb.hh index 108c7822..f44d3ce7 100644 --- a/src/breadcrumb.hh +++ b/src/breadcrumb.hh @@ -136,7 +136,7 @@ struct crumb { attr_line_t c_display_value; crumb_possibilities c_possibility_provider; perform c_performer; - nonstd::optional c_possible_range; + std::optional c_possible_range; expected_input_t c_expected_input{expected_input_t::exact}; std::string c_search_placeholder; }; diff --git a/src/breadcrumb_curses.cc b/src/breadcrumb_curses.cc index 62322213..7b3453f0 100644 --- a/src/breadcrumb_curses.cc +++ b/src/breadcrumb_curses.cc @@ -126,7 +126,7 @@ breadcrumb_curses::reload_data() = this->bc_focused_crumbs[this->bc_selected_crumb.value()]; this->bc_possible_values = selected_crumb_ref.c_possibility_provider(); - nonstd::optional selected_value; + std::optional selected_value; this->bc_similar_values = this->bc_possible_values | lnav::itertools::similar_to( [](const auto& elem) { return elem.p_key; }, @@ -210,7 +210,7 @@ breadcrumb_curses::blur() { this->bc_last_selected_crumb = this->bc_selected_crumb; this->bc_focused_crumbs.clear(); - this->bc_selected_crumb = nonstd::nullopt; + this->bc_selected_crumb = std::nullopt; this->bc_current_search.clear(); this->bc_match_view.set_height(0_vl); this->bc_match_view.set_selection(-1_vl); diff --git a/src/breadcrumb_curses.hh b/src/breadcrumb_curses.hh index 93733d6f..de034bdd 100644 --- a/src/breadcrumb_curses.hh +++ b/src/breadcrumb_curses.hh @@ -92,8 +92,8 @@ private: WINDOW* bc_window{nullptr}; std::function()> bc_line_source; std::vector bc_focused_crumbs; - nonstd::optional bc_selected_crumb; - nonstd::optional bc_last_selected_crumb; + std::optional bc_selected_crumb; + std::optional bc_last_selected_crumb; std::vector bc_possible_values; std::vector bc_similar_values; std::string bc_current_search; diff --git a/src/byte_array.hh b/src/byte_array.hh index 9057f963..eb0827ae 100644 --- a/src/byte_array.hh +++ b/src/byte_array.hh @@ -38,7 +38,6 @@ #include "base/lnav_log.hh" #include "fmt/format.h" -#include "optional.hpp" template struct byte_array { @@ -82,7 +81,7 @@ struct byte_array { template void to_string(OutputIt out, - nonstd::optional separator = nonstd::nullopt) const + std::optional separator = std::nullopt) const { for (size_t lpc = 0; lpc < BYTE_COUNT; lpc++) { if (lpc > 0 && separator) { @@ -115,8 +114,8 @@ struct byte_array { this->ba_data[15 % BYTE_COUNT]); } - std::string to_string(nonstd::optional separator - = nonstd::nullopt) const + std::string to_string(std::optional separator + = std::nullopt) const { std::string retval; diff --git a/src/command_executor.cc b/src/command_executor.cc index ca62818a..9a87b122 100644 --- a/src/command_executor.cc +++ b/src/command_executor.cc @@ -804,7 +804,7 @@ execute_any(exec_context& ec, const std::string& cmdline_with_mode) (lnav_data.ld_flags & LNF_HEADLESS || ec.ec_path_stack.size() > 1)) { rescan_files(); - wait_for_pipers(nonstd::nullopt); + wait_for_pipers(std::nullopt); rebuild_indexes_repeatedly(); } }); @@ -842,7 +842,7 @@ execute_init_commands( return; } - nonstd::optional ec_out; + std::optional ec_out; auto_fd fd_copy; if (!(lnav_data.ld_flags & LNF_HEADLESS)) { @@ -1090,7 +1090,7 @@ pipe_callback(exec_context& ec, const std::string& cmdline, auto_fd& fd) static int exec_count = 0; auto desc - = fmt::format(FMT_STRING("[{}] Output of {}"), exec_count++, cmdline); + = fmt::format(FMT_STRING("exec-{}-output {}"), exec_count++, cmdline); lnav_data.ld_active_files.fc_file_names[tmp_pair.first] .with_filename(desc) .with_include_in_session(false) @@ -1145,7 +1145,7 @@ exec_context::clear_output() out.second(out.first); } }; - this->ec_output_stack.back() = std::make_pair("default", nonstd::nullopt); + this->ec_output_stack.back() = std::make_pair("default", std::nullopt); } exec_context::exec_context(logline_value_vector* line_values, @@ -1161,7 +1161,7 @@ exec_context::exec_context(logline_value_vector* line_values, this->ec_path_stack.emplace_back("."); this->ec_source.emplace_back( lnav::console::snippet::from(COMMAND_SRC, "").with_line(1)); - this->ec_output_stack.emplace_back("screen", nonstd::nullopt); + this->ec_output_stack.emplace_back("screen", std::nullopt); this->ec_error_callback_stack.emplace_back( [](const auto& um) { lnav::console::print(stderr, um); }); } @@ -1239,7 +1239,7 @@ exec_context::enter_source(intern_string_t path, exec_context::output_guard::output_guard(exec_context& context, std::string name, - const nonstd::optional& file) + const std::optional& file) : sg_context(context) { if (file) { diff --git a/src/command_executor.hh b/src/command_executor.hh index ea29451e..12d7a9a2 100644 --- a/src/command_executor.hh +++ b/src/command_executor.hh @@ -42,7 +42,6 @@ #include "fmt/format.h" #include "ghc/filesystem.hpp" #include "help_text.hh" -#include "optional.hpp" #include "shlex.resolver.hh" #include "vis_line.hh" @@ -103,7 +102,7 @@ struct exec_context { return Err(this->make_error_msg(format_str, args...)); } - nonstd::optional get_output() + std::optional get_output() { for (auto iter = this->ec_output_stack.rbegin(); iter != this->ec_output_stack.rend(); @@ -114,7 +113,7 @@ struct exec_context { } } - return nonstd::nullopt; + return std::nullopt; } void set_output(const std::string& name, FILE* file, int (*closer)(FILE*)); @@ -183,8 +182,8 @@ struct exec_context { struct output_guard { explicit output_guard(exec_context& context, std::string name = "default", - const nonstd::optional& file - = nonstd::nullopt); + const std::optional& file + = std::nullopt); ~output_guard(); @@ -282,7 +281,7 @@ struct exec_context { } template - nonstd::optional get_provenance() const + std::optional get_provenance() const { for (const auto& elem : this->ec_provenance) { if (elem.is()) { @@ -290,7 +289,7 @@ struct exec_context { } } - return nonstd::nullopt; + return std::nullopt; } vis_line_t ec_top_line{0_vl}; @@ -305,7 +304,7 @@ struct exec_context { std::vector ec_source; help_text* ec_current_help{nullptr}; - std::vector>> + std::vector>> ec_output_stack; std::unique_ptr ec_accumulator; @@ -326,7 +325,7 @@ class multiline_executor { public: exec_context& me_exec_context; std::string me_source; - nonstd::optional me_cmdline; + std::optional me_cmdline; int me_line_number{0}; int me_starting_line_number{0}; std::string me_last_result; diff --git a/src/data_scanner.cc b/src/data_scanner.cc index 3727407f..53c25651 100644 --- a/src/data_scanner.cc +++ b/src/data_scanner.cc @@ -305,7 +305,7 @@ data_scanner::cleanup_end() } } -nonstd::optional +std::optional data_scanner::tokenize2(text_format_t tf) { auto retval = this->tokenize_int(tf); @@ -340,7 +340,7 @@ data_scanner::tokenize2(text_format_t tf) return retval; } -nonstd::optional +std::optional data_scanner::find_matching_bracket(text_format_t tf, tokenize_result tr) { switch (tr.tr_token) { @@ -401,5 +401,5 @@ data_scanner::find_matching_bracket(text_format_t tf, tokenize_result tr) break; } - return nonstd::nullopt; + return std::nullopt; } diff --git a/src/data_scanner.hh b/src/data_scanner.hh index 86551de6..ad7291c2 100644 --- a/src/data_scanner.hh +++ b/src/data_scanner.hh @@ -203,10 +203,10 @@ public: } }; - nonstd::optional tokenize2(text_format_t tf + std::optional tokenize2(text_format_t tf = text_format_t::TF_UNKNOWN); - nonstd::optional find_matching_bracket(text_format_t tf, + std::optional find_matching_bracket(text_format_t tf, tokenize_result tr); void reset() { this->ds_next_offset = this->ds_init_offset; } @@ -225,7 +225,7 @@ private: bool is_credit_card(string_fragment frag) const; - nonstd::optional tokenize_int(text_format_t tf + std::optional tokenize_int(text_format_t tf = text_format_t::TF_UNKNOWN); std::string ds_line; diff --git a/src/data_scanner_re.cc b/src/data_scanner_re.cc index ae65b3d2..e3af69b2 100644 --- a/src/data_scanner_re.cc +++ b/src/data_scanner_re.cc @@ -48,7 +48,7 @@ enum YYCONDTYPE { #line 38 "../../lnav/src/data_scanner_re.re" -nonstd::optional data_scanner::tokenize_int(text_format_t tf) +std::optional data_scanner::tokenize_int(text_format_t tf) { data_token_t token_out = DT_INVALID; capture_t cap_all; @@ -832,7 +832,7 @@ yyc_bol: yy1: ++YYCURSOR; #line 172 "../../lnav/src/data_scanner_re.re" - { return nonstd::nullopt; } + { return std::nullopt; } #line 837 "../../lnav/src/data_scanner_re.cc" yy2: ++YYCURSOR; @@ -1955,7 +1955,7 @@ yy62: ++YYCURSOR; yy63: #line 173 "../../lnav/src/data_scanner_re.re" - { return nonstd::nullopt; } + { return std::nullopt; } #line 1960 "../../lnav/src/data_scanner_re.cc" yy64: yych = *++YYCURSOR; @@ -43435,7 +43435,7 @@ yyc_init: yy1612: ++YYCURSOR; #line 172 "../../lnav/src/data_scanner_re.re" - { return nonstd::nullopt; } + { return std::nullopt; } #line 43440 "../../lnav/src/data_scanner_re.cc" yy1613: ++YYCURSOR; @@ -44503,7 +44503,7 @@ yy1671: ++YYCURSOR; yy1672: #line 173 "../../lnav/src/data_scanner_re.re" - { return nonstd::nullopt; } + { return std::nullopt; } #line 44508 "../../lnav/src/data_scanner_re.cc" yy1673: yych = *++YYCURSOR; @@ -84403,7 +84403,7 @@ yy3116: ++YYCURSOR; yy3117: #line 173 "../../lnav/src/data_scanner_re.re" - { return nonstd::nullopt; } + { return std::nullopt; } #line 84408 "../../lnav/src/data_scanner_re.cc" yy3118: ++YYCURSOR; @@ -84475,5 +84475,5 @@ yy3125: #line 478 "../../lnav/src/data_scanner_re.re" - return nonstd::nullopt; + return std::nullopt; } diff --git a/src/data_scanner_re.re b/src/data_scanner_re.re index f2871581..cda50100 100644 --- a/src/data_scanner_re.re +++ b/src/data_scanner_re.re @@ -37,7 +37,7 @@ /*!conditions:re2c*/ -nonstd::optional data_scanner::tokenize_int(text_format_t tf) +std::optional data_scanner::tokenize_int(text_format_t tf) { data_token_t token_out = DT_INVALID; capture_t cap_all; @@ -168,9 +168,9 @@ nonstd::optional data_scanner::tokenize_int(text_ ); UNITS = (([mup]?("s"|"S"))|(([kKmMgG]"i"?)?[bB])|("m"|"min")); - EOF { return nonstd::nullopt; } - [\x00] { return nonstd::nullopt; } - <*> * { return nonstd::nullopt; } + EOF { return std::nullopt; } + [\x00] { return std::nullopt; } + <*> * { return std::nullopt; } SYN+ { RET(DT_ZERO_WIDTH_SPACE); } @@ -477,5 +477,5 @@ nonstd::optional data_scanner::tokenize_int(text_ */ - return nonstd::nullopt; + return std::nullopt; } diff --git a/src/db_sub_source.cc b/src/db_sub_source.cc index 94538766..1fbdf12c 100644 --- a/src/db_sub_source.cc +++ b/src/db_sub_source.cc @@ -299,13 +299,13 @@ db_label_source::clear() this->dls_allocator = std::make_unique>(64 * 1024); } -nonstd::optional +std::optional db_label_source::column_name_to_index(const std::string& name) const { return this->dls_headers | lnav::itertools::find(name); } -nonstd::optional +std::optional db_label_source::row_for_time(struct timeval time_bucket) { std::vector::iterator iter; @@ -316,20 +316,20 @@ db_label_source::row_for_time(struct timeval time_bucket) if (iter != this->dls_time_column.end()) { return vis_line_t(std::distance(this->dls_time_column.begin(), iter)); } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional db_label_source::time_for_row(vis_line_t row) { if ((row < 0_vl) || (((size_t) row) >= this->dls_time_column.size())) { - return nonstd::nullopt; + return std::nullopt; } return row_info{this->dls_time_column[row], row}; } -nonstd::optional +std::optional db_overlay_source::list_header_for_overlay(const listview_curses& lv, vis_line_t line) { diff --git a/src/db_sub_source.hh b/src/db_sub_source.hh index d233498d..4039a903 100644 --- a/src/db_sub_source.hh +++ b/src/db_sub_source.hh @@ -83,13 +83,13 @@ public: void clear(); - nonstd::optional column_name_to_index( + std::optional column_name_to_index( const std::string& name) const; - nonstd::optional row_for_time( + std::optional row_for_time( struct timeval time_bucket) override; - nonstd::optional time_for_row(vis_line_t row) override; + std::optional time_for_row(vis_line_t row) override; struct header_meta { explicit header_meta(std::string name) : hm_name(std::move(name)) {} @@ -114,7 +114,7 @@ public: std::vector dls_time_column; std::vector dls_cell_width; int dls_time_column_index{-1}; - nonstd::optional dls_time_column_invalidated_at; + std::optional dls_time_column_invalidated_at; std::unique_ptr> dls_allocator{ std::make_unique>(64 * 1024)}; string_attrs_t dls_ansi_attrs; @@ -133,7 +133,7 @@ public: vis_line_t line, std::vector& value_out) override; - nonstd::optional list_header_for_overlay( + std::optional list_header_for_overlay( const listview_curses& lv, vis_line_t line) override; void set_show_details_in_overlay(bool val) override diff --git a/src/document.sections.cc b/src/document.sections.cc index 57820fb3..bf52312f 100644 --- a/src/document.sections.cc +++ b/src/document.sections.cc @@ -42,7 +42,7 @@ namespace lnav { namespace document { -nonstd::optional +std::optional hier_node::lookup_child(section_key_t key) const { return make_optional_from_nullable(key.match( @@ -62,7 +62,7 @@ hier_node::lookup_child(section_key_t key) const })); } -nonstd::optional +std::optional hier_node::child_index(const hier_node* hn) const { size_t retval = 0; @@ -74,16 +74,16 @@ hier_node::child_index(const hier_node* hn) const retval += 1; } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional hier_node::child_neighbors(const lnav::document::hier_node* hn, file_off_t offset) const { auto index_opt = this->child_index(hn); if (!index_opt) { - return nonstd::nullopt; + return std::nullopt; } hier_node::child_neighbors_result retval; @@ -153,11 +153,11 @@ hier_node::child_neighbors(const lnav::document::hier_node* hn, return retval; } -nonstd::optional +std::optional hier_node::line_neighbors(size_t ln) const { if (this->hn_children.empty()) { - return nonstd::nullopt; + return std::nullopt; } hier_node::child_neighbors_result retval; @@ -173,7 +173,7 @@ hier_node::line_neighbors(size_t ln) const return retval; } -nonstd::optional +std::optional hier_node::lookup_path(const hier_node* root, const std::vector& path) { @@ -188,7 +188,7 @@ hier_node::lookup_path(const hier_node* root, } if (!retval) { - return nonstd::nullopt; + return std::nullopt; } return retval; @@ -484,7 +484,7 @@ public: } if (term) { this->append_child_node(term); - term = nonstd::nullopt; + term = std::nullopt; } this->sw_interval_state.pop_back(); this->sw_hier_stage @@ -605,7 +605,7 @@ public: found = true; } this->append_child_node(term); - term = nonstd::nullopt; + term = std::nullopt; this->sw_depth -= 1; this->sw_interval_state.pop_back(); this->sw_hier_stage @@ -758,15 +758,15 @@ private: }; struct interval_state { - nonstd::optional is_start; + std::optional is_start; size_t is_line_number{0}; std::string is_name; }; - nonstd::optional flush_values() + std::optional flush_values() { - nonstd::optional last_key; - nonstd::optional retval; + std::optional last_key; + std::optional retval; if (!this->sw_values.empty()) { if (!this->sw_interval_state.back().is_start) { @@ -799,7 +799,7 @@ private: this->sw_interval_state.back().is_line_number = this->sw_line_number; } - last_key = nonstd::nullopt; + last_key = std::nullopt; } break; default: @@ -812,11 +812,11 @@ private: return retval; } - void append_child_node(nonstd::optional terminator) + void append_child_node(std::optional terminator) { auto& ivstate = this->sw_interval_state.back(); if (!ivstate.is_start || !terminator || this->sw_depth == 0) { - ivstate.is_start = nonstd::nullopt; + ivstate.is_start = std::nullopt; ivstate.is_line_number = 0; ivstate.is_name.clear(); return; @@ -847,7 +847,7 @@ private: } top_node->hn_children.emplace_back(std::move(new_node)); } - ivstate.is_start = nonstd::nullopt; + ivstate.is_start = std::nullopt; ivstate.is_line_number = 0; ivstate.is_name.clear(); } diff --git a/src/document.sections.hh b/src/document.sections.hh index 9129cf51..0af7551a 100644 --- a/src/document.sections.hh +++ b/src/document.sections.hh @@ -40,7 +40,6 @@ #include "breadcrumb.hh" #include "intervaltree/IntervalTree.h" #include "mapbox/variant.hpp" -#include "optional.hpp" #include "text_format.hh" namespace lnav { @@ -67,37 +66,37 @@ struct hier_node { std::multimap hn_named_children; std::vector> hn_children; - nonstd::optional lookup_child(section_key_t key) const; + std::optional lookup_child(section_key_t key) const; - nonstd::optional child_index(const hier_node* hn) const; + std::optional child_index(const hier_node* hn) const; struct child_neighbors_result { - nonstd::optional cnr_previous; - nonstd::optional cnr_next; + std::optional cnr_previous; + std::optional cnr_next; }; - nonstd::optional child_neighbors( + std::optional child_neighbors( const hier_node* hn, file_off_t offset) const; - nonstd::optional line_neighbors(size_t ln) const; + std::optional line_neighbors(size_t ln) const; - nonstd::optional find_line_number(const std::string& str) const + std::optional find_line_number(const std::string& str) const { auto iter = this->hn_named_children.find(str); if (iter != this->hn_named_children.end()) { - return nonstd::make_optional(iter->second->hn_line_number); + return std::make_optional(iter->second->hn_line_number); } - return nonstd::nullopt; + return std::nullopt; } - nonstd::optional find_line_number(size_t index) const + std::optional find_line_number(size_t index) const { if (index < this->hn_children.size()) { - return nonstd::make_optional( + return std::make_optional( this->hn_children[index]->hn_line_number); } - return nonstd::nullopt; + return std::nullopt; } bool is_named_only() const @@ -105,7 +104,7 @@ struct hier_node { return this->hn_children.size() == this->hn_named_children.size(); } - static nonstd::optional lookup_path( + static std::optional lookup_path( const hier_node* root, const std::vector& path); template diff --git a/src/field_overlay_source.cc b/src/field_overlay_source.cc index 821a8b98..2791307a 100644 --- a/src/field_overlay_source.cc +++ b/src/field_overlay_source.cc @@ -110,12 +110,22 @@ field_overlay_source::build_field_lines(const listview_curses& lv, attr_line_t time_line; auto& time_str = time_line.get_string(); struct line_range time_lr; + off_t ts_len = sql_strftime(curr_timestamp, + sizeof(curr_timestamp), + ll->get_time(), + ll->get_millis(), + 'T'); + { + exttm tmptm; - sql_strftime(curr_timestamp, - sizeof(curr_timestamp), - ll->get_time(), - ll->get_millis(), - 'T'); + tmptm.et_flags |= ETF_ZONE_SET; + tmptm.et_gmtoff + = lnav::local_time_to_info( + date::local_seconds{std::chrono::seconds{ll->get_time()}}) + .first.offset.count(); + ftime_z(curr_timestamp, ts_len, sizeof(curr_timestamp), tmptm); + curr_timestamp[ts_len] = '\0'; + } if (ll->is_time_skewed()) { time_lr.lr_start = 1; @@ -212,11 +222,13 @@ field_overlay_source::build_field_lines(const listview_curses& lv, } time_line.append(" Format: ") .append(lnav::roles::symbol( - ts_formats[format->lf_date_time.dts_fmt_lock])); + ts_formats[format->lf_date_time.dts_fmt_lock])) + .append(" Default Zone: "); if (format->lf_date_time.dts_default_zone != nullptr) { - time_line.append(" Default Zone: ") - .append(lnav::roles::symbol( - format->lf_date_time.dts_default_zone->name())); + time_line.append(lnav::roles::symbol( + format->lf_date_time.dts_default_zone->name())); + } else { + time_line.append("none"_comment); } } @@ -672,7 +684,7 @@ field_overlay_source::list_value_for_overlay( this->build_meta_line(lv, value_out, row); } -nonstd::optional +std::optional field_overlay_source::list_header_for_overlay(const listview_curses& lv, vis_line_t vl) { diff --git a/src/field_overlay_source.hh b/src/field_overlay_source.hh index 34410fcd..0bc43518 100644 --- a/src/field_overlay_source.hh +++ b/src/field_overlay_source.hh @@ -55,7 +55,7 @@ public: this->fos_meta_lines.clear(); } - nonstd::optional list_header_for_overlay( + std::optional list_header_for_overlay( const listview_curses& lv, vis_line_t vl) override; void list_value_for_overlay(const listview_curses& lv, diff --git a/src/file_collection.cc b/src/file_collection.cc index 96ec69d4..7dccdd0c 100644 --- a/src/file_collection.cc +++ b/src/file_collection.cc @@ -66,7 +66,7 @@ child_poller::poll(file_collection& fc) } auto poll_res = std::move(this->cp_child.value()).poll(); - this->cp_child = nonstd::nullopt; + this->cp_child = std::nullopt; return poll_res.match( [this](auto_pid& alive) { this->cp_child = std::move(alive); @@ -178,6 +178,7 @@ file_collection::regenerate_unique_file_names() switch (pair.second.ofd_format) { case file_format_t::UNKNOWN: case file_format_t::ARCHIVE: + case file_format_t::MULTIPLEXED: case file_format_t::SQLITE_DB: { auto bn = ghc::filesystem::path(pair.first).filename().string(); if (bn.length() > this->fc_largest_path_length) { @@ -218,8 +219,9 @@ file_collection::merge(file_collection& other) errs->insert(new_errors.begin(), new_errors.end()); } - this->fc_file_names.insert(other.fc_file_names.begin(), - other.fc_file_names.end()); + for (const auto& fn_pair : other.fc_file_names) { + this->fc_file_names[fn_pair.first] = fn_pair.second; + } if (!other.fc_files.empty()) { for (const auto& lf : other.fc_files) { this->fc_name_to_errors->writeAccess()->erase(lf->get_filename()); @@ -291,7 +293,7 @@ struct same_file { * @param fd An already-opened descriptor for 'filename'. * @param required Specifies whether or not the file must exist and be valid. */ -nonstd::optional> +std::optional> file_collection::watch_logfile(const std::string& filename, logfile_open_options& loo, bool required) @@ -301,7 +303,7 @@ file_collection::watch_logfile(const std::string& filename, auto filename_key = loo.loo_filename.empty() ? filename : loo.loo_filename; if (this->fc_closed_files.count(filename)) { - return nonstd::nullopt; + return std::nullopt; } rc = stat(filename.c_str(), &st); @@ -321,14 +323,14 @@ file_collection::watch_logfile(const std::string& filename, .with_visible_size_limit(256 * 1024)); return lnav::futures::make_ready_future(std::move(retval)); } - return nonstd::nullopt; + return std::nullopt; } if (!S_ISREG(st.st_mode)) { if (required) { rc = -1; errno = EINVAL; } else { - return nonstd::nullopt; + return std::nullopt; } } { @@ -357,7 +359,7 @@ file_collection::watch_logfile(const std::string& filename, }); return lnav::futures::make_ready_future(std::move(retval)); } - return nonstd::nullopt; + return std::nullopt; } if (this->fc_new_stats | lnav::itertools::find_if([&st](const auto& elem) { @@ -366,7 +368,7 @@ file_collection::watch_logfile(const std::string& filename, { // this file is probably a link that we have already scanned in this // pass. - return nonstd::nullopt; + return std::nullopt; } this->fc_new_stats.emplace_back(st); @@ -376,7 +378,7 @@ file_collection::watch_logfile(const std::string& filename, if (file_iter == this->fc_files.end()) { if (this->fc_other_files.find(filename) != this->fc_other_files.end()) { - return nonstd::nullopt; + return std::nullopt; } require(this->fc_progress.get() != nullptr); @@ -405,8 +407,33 @@ file_collection::watch_logfile(const std::string& filename, retval.fc_other_files[filename].ofd_format = ff; break; + case file_format_t::MULTIPLEXED: { + log_info("%s: file is multiplexed, creating piper", + filename.c_str()); + + auto open_res + = lnav::filesystem::open_file(filename, O_RDONLY); + if (open_res.isOk()) { + auto looper_options = lnav::piper::options{}; + looper_options.with_tail(loo.loo_tail); + auto create_res + = lnav::piper::create_looper(filename, + open_res.unwrap(), + auto_fd{-1}, + looper_options); + + if (create_res.isOk()) { + retval.fc_other_files[filename] = ff; + retval.fc_file_names[filename] = loo; + retval.fc_file_names[filename].with_piper( + create_res.unwrap()); + } + } + break; + } + case file_format_t::ARCHIVE: { - nonstd::optional< + std::optional< std::list::iterator> prog_iter_opt; @@ -530,6 +557,12 @@ file_collection::watch_logfile(const std::string& filename, log_info("loading new file: filename=%s", filename.c_str()); + if (loo.loo_piper && !loo.loo_piper->get_demux_id().empty()) + { + log_info(" treating demuxed file as a log"); + loo.loo_text_format = text_format_t::TF_LOG; + } + auto open_res = logfile::open(filename_to_open, loo); if (open_res.isOk()) { retval.fc_files.push_back(open_res.unwrap()); @@ -563,7 +596,7 @@ file_collection::watch_logfile(const std::string& filename, return lnav::futures::make_ready_future(std::move(retval)); } - return nonstd::nullopt; + return std::nullopt; } /** diff --git a/src/file_collection.hh b/src/file_collection.hh index 9ff260df..cdb78de9 100644 --- a/src/file_collection.hh +++ b/src/file_collection.hh @@ -92,7 +92,7 @@ enum class child_poll_result_t { class child_poller { public: explicit child_poller( - nonstd::optional filename, + std::optional filename, auto_pid child, std::function&)> finalizer) @@ -126,7 +126,7 @@ public: child_poller& operator=(const child_poller&) = delete; - const nonstd::optional& get_filename() const + const std::optional& get_filename() const { return this->cp_filename; } @@ -136,8 +136,8 @@ public: child_poll_result_t poll(file_collection& fc); private: - nonstd::optional cp_filename; - nonstd::optional> cp_child; + std::optional cp_filename; + std::optional> cp_child; std::function&)> cp_finalizer; }; @@ -212,7 +212,7 @@ struct file_collection { logfile_open_options& loo, bool required); - nonstd::optional> watch_logfile( + std::optional> watch_logfile( const std::string& filename, logfile_open_options& loo, bool required); void merge(file_collection& other); diff --git a/src/file_format.cc b/src/file_format.cc index 9858c267..b109a4fe 100644 --- a/src/file_format.cc +++ b/src/file_format.cc @@ -37,6 +37,7 @@ #include "base/intern_string.hh" #include "base/lnav_log.hh" #include "config.h" +#include "line_buffer.hh" file_format_t detect_file_format(const ghc::filesystem::path& filename) @@ -68,7 +69,30 @@ detect_file_format(const ghc::filesystem::path& filename) auto header_frag = string_fragment::from_bytes(buffer, rc); if (header_frag.startswith(SQLITE3_HEADER)) { + log_info("%s: appears to be a SQLite DB", filename.c_str()); retval = file_format_t::SQLITE_DB; + } else { + file_range next_range; + line_buffer lb; + lb.set_fd(fd); + + auto load_res = lb.load_next_line(next_range); + if (load_res.isOk() && lb.is_header_utf8()) { + auto li = load_res.unwrap(); + auto read_res = lb.read_range(li.li_file_range); + if (read_res.isOk()) { + auto sbr = read_res.unwrap(); + auto demux_id_opt = lnav::piper::multiplex_id_for_line( + sbr.to_string_fragment()); + + if (demux_id_opt) { + log_info("%s: is multiplexed using %s", + filename.c_str(), + demux_id_opt.value().c_str()); + return file_format_t::MULTIPLEXED; + } + } + } } } } diff --git a/src/file_format.hh b/src/file_format.hh index d74347be..954f4568 100644 --- a/src/file_format.hh +++ b/src/file_format.hh @@ -34,12 +34,12 @@ #include "fmt/format.h" #include "ghc/filesystem.hpp" -#include "optional.hpp" enum class file_format_t : int { UNKNOWN, SQLITE_DB, ARCHIVE, + MULTIPLEXED, REMOTE, }; @@ -51,7 +51,7 @@ struct external_file_format { file_format_t detect_file_format(const ghc::filesystem::path& filename); -nonstd::optional detect_mime_type( +std::optional detect_mime_type( const ghc::filesystem::path& filename); namespace fmt { @@ -68,6 +68,9 @@ struct formatter : formatter { case file_format_t::ARCHIVE: name = "\U0001F5C4 Archive"; break; + case file_format_t::MULTIPLEXED: + name = "\u22fa Multiplexed"; + break; case file_format_t::REMOTE: name = "\U0001F5A5 Remote"; break; diff --git a/src/file_options.cc b/src/file_options.cc index 8d83f872..88aa7cc4 100644 --- a/src/file_options.cc +++ b/src/file_options.cc @@ -89,7 +89,7 @@ file_options_collection::to_json() const .to_string(); } -nonstd::optional> +std::optional> file_options_collection::match(const std::string& path) const { auto iter = this->foc_pattern_to_options.find(path); @@ -111,10 +111,10 @@ file_options_collection::match(const std::string& path) const } } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional> +std::optional> file_options_hier::match(const ghc::filesystem::path& path) const { static const auto ROOT_PATH = ghc::filesystem::path("/"); @@ -138,7 +138,7 @@ file_options_hier::match(const ghc::filesystem::path& path) const } lookup_path = next_lookup_path; } - return nonstd::nullopt; + return std::nullopt; } } // namespace lnav diff --git a/src/file_options.hh b/src/file_options.hh index 7102593d..48971db7 100644 --- a/src/file_options.hh +++ b/src/file_options.hh @@ -59,7 +59,7 @@ struct file_options_collection { std::map foc_pattern_to_options; - nonstd::optional> match( + std::optional> match( const std::string& path) const; std::string to_json() const; @@ -70,7 +70,7 @@ struct file_options_hier { foh_path_to_collection; size_t foh_generation{0}; - nonstd::optional> match( + std::optional> match( const ghc::filesystem::path& path) const; }; diff --git a/src/filter_sub_source.cc b/src/filter_sub_source.cc index a3c566aa..e454dbf3 100644 --- a/src/filter_sub_source.cc +++ b/src/filter_sub_source.cc @@ -290,14 +290,14 @@ size_t filter_sub_source::text_line_count() { return (lnav_data.ld_view_stack.top() | - [](auto tc) -> nonstd::optional { + [](auto tc) -> std::optional { text_sub_source* tss = tc->get_sub_source(); if (tss == nullptr) { - return nonstd::nullopt; + return std::nullopt; } auto& fs = tss->get_filters(); - return nonstd::make_optional(fs.size()); + return std::make_optional(fs.size()); }) .value_or(0); } diff --git a/src/formats/cloudvm_ram_log.json b/src/formats/cloudvm_ram_log.json index e1293442..1972bbf5 100644 --- a/src/formats/cloudvm_ram_log.json +++ b/src/formats/cloudvm_ram_log.json @@ -5,7 +5,7 @@ "description": "Periodic dumps of ram sizes", "regex": { "std": { - "pattern": "========== Start of cloudvm ram size dump at (?[^=]+) ==========(?.*)" + "pattern": "^========== Start of cloudvm ram size dump at (?[^=]+) ==========(?.*)" } }, "sample": [ diff --git a/src/formats/formats.am b/src/formats/formats.am index 78963644..fdc1316f 100644 --- a/src/formats/formats.am +++ b/src/formats/formats.am @@ -48,4 +48,5 @@ FORMAT_FILES = \ $(srcdir)/%reldir%/vmw_py_log.json \ $(srcdir)/%reldir%/vpostgres_log.json \ $(srcdir)/%reldir%/xmlrpc_log.json \ + $(srcdir)/%reldir%/zookeeper_log.json \ $() diff --git a/src/formats/haproxy_log.json b/src/formats/haproxy_log.json index 9795a19a..8c2b079b 100644 --- a/src/formats/haproxy_log.json +++ b/src/formats/haproxy_log.json @@ -6,22 +6,22 @@ "url": "http://www.haproxy.org/download/1.4/doc/configuration.txt", "regex": { "event_started": { - "pattern": "(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: Proxy (?[^ ]+) started." + "pattern": "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: Proxy (?[^ ]+) started." }, "event_stopping": { - "pattern": "(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: Stopping frontend (?[^ ]+) in (?\\d+) ms." + "pattern": "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: Stopping frontend (?[^ ]+) in (?\\d+) ms." }, "event_stopped": { - "pattern": "(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: Proxy (?[^ ]+) stopped \\(FE: (?\\d+) conns, BE: (?\\d+) conns\\)." + "pattern": "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: Proxy (?[^ ]+) stopped \\(FE: (?\\d+) conns, BE: (?\\d+) conns\\)." }, "tcp": { - "pattern": "(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: (?[^:]+):(?\\d+) \\[(?\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2}.\\d{3})\\] (?[^ ]+) (?[^ ]+)\\/(?[^ ]+) (?\\d+)\\/(?\\d+)\\/(?\\d+) (?\\d+) (?..) (?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+) (?\\d+)\\/(?\\d+)" + "pattern": "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: (?[^:]+):(?\\d+) \\[(?\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2}.\\d{3})\\] (?[^ ]+) (?[^ ]+)\\/(?[^ ]+) (?\\d+)\\/(?\\d+)\\/(?\\d+) (?\\d+) (?..) (?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+) (?\\d+)\\/(?\\d+)" }, "http": { - "pattern": "(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: (?[^:]+):(?\\d+) \\[(?\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2}.\\d{3})\\] (?[^ ]+)(?~)? (?[^ ]+)\\/(?[^ ]+) (?-?\\d+)\\/(?-?\\d+)\\/(?-?\\d+)\\/(?-?\\d+)\\/(?\\d+) (?\\d{3}|-1) (?\\d+) (?.*) (?.*) (?....) (?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+) (?\\d+)\\/(?\\d+) (?:\\{(?.*)\\} \\{(?.*)\\} )?\"(?[A-Z<>]+)(?: (?.*?))?(?: (?HTTP\\/\\d+.\\d+))?\"?$" + "pattern": "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: (?[^:]+):(?\\d+) \\[(?\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2}.\\d{3})\\] (?[^ ]+)(?~)? (?[^ ]+)\\/(?[^ ]+) (?-?\\d+)\\/(?-?\\d+)\\/(?-?\\d+)\\/(?-?\\d+)\\/(?\\d+) (?\\d{3}|-1) (?\\d+) (?.*) (?.*) (?....) (?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+)\\/(?\\d+) (?\\d+)\\/(?\\d+) (?:\\{(?.*)\\} \\{(?.*)\\} )?\"(?[A-Z<>]+)(?: (?.*?))?(?: (?HTTP\\/\\d+.\\d+))?\"?$" }, "ssl": { - "pattern": "(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: (?[^:]+):(?\\d+) \\[(?\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2}.\\d{3})\\] (?[^ ]+)\\/(?[^ ]+): (?.+)$" + "pattern": "^(?\\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}) (?[^ ]+) (?\\w+)\\[(?\\d+)\\]: (?[^:]+):(?\\d+) \\[(?\\d{2}\\/\\w{3}\\/\\d{4}:\\d{2}:\\d{2}:\\d{2}.\\d{3})\\] (?[^ ]+)\\/(?[^ ]+): (?.+)$" } }, "json": false, diff --git a/src/formats/nextflow_log.json b/src/formats/nextflow_log.json index c4dc39c4..5e1d64dd 100644 --- a/src/formats/nextflow_log.json +++ b/src/formats/nextflow_log.json @@ -8,7 +8,7 @@ ], "regex": { "std": { - "pattern": "(?\\w{3}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}) \\[(?[^\\]]+)\\] (?[^ ]+)\\s+(?[^ ]+) - (?.*)" + "pattern": "^(?\\w{3}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3}) \\[(?[^\\]]+)\\] (?[^ ]+)\\s+(?[^ ]+) - (?.*)" } }, "timestamp-format": [ diff --git a/src/formats/procstate_log.json b/src/formats/procstate_log.json index c6fe7277..da142dc0 100644 --- a/src/formats/procstate_log.json +++ b/src/formats/procstate_log.json @@ -5,7 +5,7 @@ "description": "Periodic dumps of process state", "regex": { "std": { - "pattern": "========== Start of system state dump at (?[^=]+) ==========(?.*)" + "pattern": "^========== Start of system state dump at (?[^=]+) ==========(?.*)" } }, "sample": [ diff --git a/src/formats/redis_log.json b/src/formats/redis_log.json index faf9a5b0..bda38789 100644 --- a/src/formats/redis_log.json +++ b/src/formats/redis_log.json @@ -9,13 +9,13 @@ "description": "The Redis database", "regex": { "v2.x": { - "pattern": "\\[(?\\d+)\\]\\s+(?\\d{1,2} [a-zA-Z]{3} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(?[\\.\\-\\*\\#])\\s+(?.*)" + "pattern": "^\\[(?\\d+)\\]\\s+(?\\d{1,2} [a-zA-Z]{3} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(?[\\.\\-\\*\\#])\\s+(?.*)" }, "v3.x": { - "pattern": "(?\\d+):(?[XCSM])\\s+(?\\d{1,2} [a-zA-Z]{3} \\d{4} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(?[\\.\\*\\#\\-])\\s+(?.*)" + "pattern": "^(?\\d+):(?[XCSM])\\s+(?\\d{1,2} [a-zA-Z]{3} \\d{4} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(?[\\.\\*\\#\\-])\\s+(?.*)" }, "sig": { - "pattern": "(?\\d+):(?signal-handler) \\((?\\d+)\\) (?.*)" + "pattern": "^(?\\d+):(?signal-handler) \\((?\\d+)\\) (?.*)" } }, "timestamp-format": [ diff --git a/src/formats/zookeeper_log.json b/src/formats/zookeeper_log.json new file mode 100644 index 00000000..a3b74a52 --- /dev/null +++ b/src/formats/zookeeper_log.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://lnav.org/schemas/format-v1.schema.json", + "zookeeper_log": { + "title": "ZooKeeper log format", + "description": "Log format for the ZooKeeper coordination service", + "regex": { + "std": { + "pattern": "^(?\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3}) \\[myid:(?\\d+)?\\] - (?\\w+)\\s+\\[(?.*):(?[\\w\\.\\$]+)@(?\\d+)\\] - (?.*)" + } + }, + "value": { + "thread": { + "kind": "string", + "identifier": true + }, + "level": { + "kind": "string" + }, + "myid": { + "kind": "integer", + "identifier": true + }, + "logger": { + "kind": "string", + "identifier": true + }, + "line_number": { + "kind": "integer", + "foreign-key": true + } + }, + "search-table": { + "zk_notifications": { + "level": "info", + "pattern": "Notification: my state:(?\\w+); (?.*)" + } + }, + "sample": [ + { + "line": "2024-04-23 09:24:31,484 [myid:] - INFO [WorkerReceiver[myid=3]:o.a.z.s.q.FastLeaderElection$Messenger$WorkerReceiver@391] - Notification: my state:FOLLOWING; n.sid:1, n.state:LOOKING, n.leader:2, n.round:0x1, n.peerEpoch:0x1, n.zxid:0x100000057, message format version:0x2, n.config version:0x0" + } + ] + } +} diff --git a/src/fs-extension-functions.cc b/src/fs-extension-functions.cc index cbc23667..741f4d8d 100644 --- a/src/fs-extension-functions.cc +++ b/src/fs-extension-functions.cc @@ -101,18 +101,18 @@ sql_dirname(const char* path_in) return path_in[0] == '/' ? "/" : "."; } -static nonstd::optional +static std::optional sql_joinpath(const std::vector& paths) { std::string full_path; if (paths.empty()) { - return nonstd::nullopt; + return std::nullopt; } for (auto& path_in : paths) { if (path_in == nullptr) { - return nonstd::nullopt; + return std::nullopt; } if (path_in[0] == '/' || path_in[0] == '\\') { @@ -168,7 +168,7 @@ sql_realpath(const char* path) } struct shell_exec_options { - std::map> po_env; + std::map> po_env; }; static const json_path_container shell_exec_env_handlers = { @@ -183,8 +183,8 @@ static const typed_json_path_container static blob_auto_buffer sql_shell_exec(const char* cmd, - nonstd::optional input, - nonstd::optional opts_json) + std::optional input, + std::optional opts_json) { static const intern_string_t SRC = intern_string::lookup("options"); diff --git a/src/gantt_source.cc b/src/gantt_source.cc index 7d9f81df..42c735a0 100644 --- a/src/gantt_source.cc +++ b/src/gantt_source.cc @@ -324,7 +324,7 @@ gantt_header_overlay::list_value_for_overlay( VC_STYLE.value(ta_under)); } } -nonstd::optional +std::optional gantt_header_overlay::list_header_for_overlay(const listview_curses& lv, vis_line_t line) { @@ -659,7 +659,7 @@ gantt_source::rebuild_indexes() continue; } for (const auto sbr : {&sbr_opid, &sbr_desc}) { - if (filt->matches(nonstd::nullopt, *sbr)) { + if (filt->matches(std::nullopt, *sbr)) { this->gs_filter_hits[filt->get_index()] += 1; switch (filt->get_type()) { case text_filter::INCLUDE: @@ -731,13 +731,13 @@ gantt_source::rebuild_indexes() this->tss_view->set_needs_update(); } -nonstd::optional +std::optional gantt_source::row_for_time(struct timeval time_bucket) { auto iter = this->gs_time_order.begin(); while (true) { if (iter == this->gs_time_order.end()) { - return nonstd::nullopt; + return std::nullopt; } if (iter->get().or_value.otr_range.contains_inclusive(time_bucket)) { @@ -778,11 +778,11 @@ gantt_source::row_for_time(struct timeval time_bucket) return vis_line_t(std::distance(this->gs_time_order.begin(), closest_iter)); } -nonstd::optional +std::optional gantt_source::time_for_row(vis_line_t row) { if (row >= this->gs_time_order.size()) { - return nonstd::nullopt; + return std::nullopt; } const auto& otr = this->gs_time_order[row].get().or_value; @@ -838,7 +838,7 @@ gantt_source::text_selection_changed(textview_curses& tc) high_tv.tv_sec += 1; auto low_vl = this->gs_lss.row_for_time(low_tv); auto high_vl = this->gs_lss.row_for_time(high_tv).value_or( - this->gs_lss.text_line_count()); + vis_line_t(this->gs_lss.text_line_count())); if (!low_vl) { return; diff --git a/src/gantt_source.hh b/src/gantt_source.hh index cc764476..b9a6e020 100644 --- a/src/gantt_source.hh +++ b/src/gantt_source.hh @@ -72,9 +72,9 @@ public: void text_crumbs_for_line(int line, std::vector& crumbs) override; - nonstd::optional row_for_time( + std::optional row_for_time( struct timeval time_bucket) override; - nonstd::optional time_for_row(vis_line_t row) override; + std::optional time_for_row(vis_line_t row) override; void rebuild_indexes(); @@ -174,7 +174,7 @@ public: int bottom, attr_line_t& value_out) override; - nonstd::optional list_header_for_overlay( + std::optional list_header_for_overlay( const listview_curses& lv, vis_line_t line) override; void list_value_for_overlay(const listview_curses& lv, diff --git a/src/hist_source.cc b/src/hist_source.cc index 98819162..e0d441a8 100644 --- a/src/hist_source.cc +++ b/src/hist_source.cc @@ -33,7 +33,7 @@ #include "config.h" #include "fmt/chrono.h" -nonstd::optional +std::optional hist_source2::row_for_time(struct timeval tv_bucket) { std::map::iterator iter; @@ -176,11 +176,11 @@ hist_source2::end_of_row() } } -nonstd::optional +std::optional hist_source2::time_for_row(vis_line_t row) { if (row < 0 || row > this->hs_line_count) { - return nonstd::nullopt; + return std::nullopt; } bucket_t& bucket = this->find_bucket(row); diff --git a/src/hist_source.hh b/src/hist_source.hh index 81245af2..2e39b989 100644 --- a/src/hist_source.hh +++ b/src/hist_source.hh @@ -411,9 +411,9 @@ public: return 0; } - nonstd::optional time_for_row(vis_line_t row) override; + std::optional time_for_row(vis_line_t row) override; - nonstd::optional row_for_time( + std::optional row_for_time( struct timeval tv_bucket) override; private: diff --git a/src/input_dispatcher.cc b/src/input_dispatcher.cc index 7df19aa9..564fa16d 100644 --- a/src/input_dispatcher.cc +++ b/src/input_dispatcher.cc @@ -74,7 +74,7 @@ to_key_seq(A& dst, const char* src) void input_dispatcher::new_input(const struct timeval& current_time, int ch) { - nonstd::optional handled = nonstd::nullopt; + std::optional handled = std::nullopt; std::array keyseq{0}; switch (ch) { diff --git a/src/itertools.similar.hh b/src/itertools.similar.hh index 3f9a7045..9a9fff3a 100644 --- a/src/itertools.similar.hh +++ b/src/itertools.similar.hh @@ -43,7 +43,7 @@ namespace details { template struct similar_to { - nonstd::optional st_mapper; + std::optional st_mapper; std::string st_pattern; size_t st_count{5}; }; diff --git a/src/json-extension-functions.cc b/src/json-extension-functions.cc index 034b713d..70d267e4 100644 --- a/src/json-extension-functions.cc +++ b/src/json-extension-functions.cc @@ -490,7 +490,7 @@ concat_gen_elements(yajl_gen gen, const unsigned char* text, size_t len) } static json_string -json_concat(nonstd::optional json_in, +json_concat(std::optional json_in, const std::vector& values) { yajlpp_gen gen; diff --git a/src/line_buffer.cc b/src/line_buffer.cc index a5101692..39edae7e 100644 --- a/src/line_buffer.cc +++ b/src/line_buffer.cc @@ -768,13 +768,13 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) start, this->lb_loader_file_offset.value()); #endif - nonstd::optional wait_start; + std::optional wait_start; if (this->lb_loader_future.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { wait_start - = nonstd::make_optional(std::chrono::system_clock::now()); + = std::make_optional(std::chrono::system_clock::now()); } retval = this->lb_loader_future.get(); if (false && wait_start) { @@ -785,7 +785,7 @@ line_buffer::fill_range(file_off_t start, ssize_t max_length) this->lb_loader_future = {}; this->lb_share_manager.invalidate_refs(); this->lb_file_offset = this->lb_loader_file_offset.value(); - this->lb_loader_file_offset = nonstd::nullopt; + this->lb_loader_file_offset = std::nullopt; this->lb_buffer.swap(this->lb_alt_buffer.value()); this->lb_alt_buffer.value().clear(); this->lb_line_starts = std::move(this->lb_alt_line_starts); diff --git a/src/line_buffer.hh b/src/line_buffer.hh index 15691980..32775c41 100644 --- a/src/line_buffer.hh +++ b/src/line_buffer.hh @@ -345,12 +345,12 @@ private: file_ssize_t lb_piper_header_size{0}; auto_buffer lb_buffer{auto_buffer::alloc(DEFAULT_LINE_BUFFER_SIZE)}; - nonstd::optional lb_alt_buffer; + std::optional lb_alt_buffer; std::vector lb_alt_line_starts; std::vector lb_alt_line_is_utf; std::vector lb_alt_line_has_ansi; std::future lb_loader_future; - nonstd::optional lb_loader_file_offset; + std::optional lb_loader_file_offset; file_off_t lb_compressed_offset{ 0}; /*< The offset into the compressed file. */ @@ -375,7 +375,7 @@ private: std::vector lb_line_has_ansi; stats lb_stats; - nonstd::optional lb_cached_fd; + std::optional lb_cached_fd; file_header_t lb_header{mapbox::util::no_init{}}; }; diff --git a/src/listview_curses.cc b/src/listview_curses.cc index d7e028b0..108ec17e 100644 --- a/src/listview_curses.cc +++ b/src/listview_curses.cc @@ -1180,7 +1180,7 @@ listview_curses::get_overlay_height(size_t total, vis_line_t view_height) } void -listview_curses::set_overlay_selection(nonstd::optional sel) +listview_curses::set_overlay_selection(std::optional sel) { if (sel) { if (sel.value() == this->lv_focused_overlay_selection) { diff --git a/src/listview_curses.hh b/src/listview_curses.hh index 6e003e40..b9713b0e 100644 --- a/src/listview_curses.hh +++ b/src/listview_curses.hh @@ -120,10 +120,10 @@ public: return {}; } - virtual nonstd::optional list_header_for_overlay( + virtual std::optional list_header_for_overlay( const listview_curses& lv, vis_line_t line) { - return nonstd::nullopt; + return std::nullopt; } virtual void list_value_for_overlay(const listview_curses& lv, @@ -250,16 +250,16 @@ public: return this->lv_top; } - nonstd::optional get_overlay_selection() const + std::optional get_overlay_selection() const { if (this->lv_overlay_focused) { return this->lv_focused_overlay_selection; } - return nonstd::nullopt; + return std::nullopt; } - void set_overlay_selection(nonstd::optional sel); + void set_overlay_selection(std::optional sel); void set_sync_selection_and_top(bool value) { @@ -299,7 +299,7 @@ public: typename std::result_of::type { if (this->lv_top >= this->get_inner_height()) { - return nonstd::nullopt; + return std::nullopt; } std::vector top_line{1}; @@ -328,10 +328,10 @@ public: /** @return The line number that is displayed at the top. */ vis_line_t get_top() const { return this->lv_top; } - nonstd::optional get_top_opt() const + std::optional get_top_opt() const { if (this->get_inner_height() == 0_vl) { - return nonstd::nullopt; + return std::nullopt; } return this->lv_top; diff --git a/src/lnav.cc b/src/lnav.cc index 136f61f8..33742b66 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -702,7 +702,7 @@ handle_config_ui_key(int ch, const char* keyseq) return retval; } - nonstd::optional new_mode; + std::optional new_mode; lnav_data.ld_filter_help_status_source.fss_error.clear(); if (ch == 'F') { @@ -868,7 +868,7 @@ gather_pipers() } void -wait_for_pipers(nonstd::optional deadline) +wait_for_pipers(std::optional deadline) { static const auto MAX_SLEEP_TIME = std::chrono::milliseconds(300); auto sleep_time = std::chrono::milliseconds(10); @@ -3108,7 +3108,8 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%' } else { lnav_data.ld_active_files.fc_file_names.emplace( abspath.in(), - logfile_open_options().with_init_location(file_loc)); + logfile_open_options().with_init_location(file_loc).with_tail( + !(lnav_data.ld_flags & LNF_HEADLESS))); if (file_loc.valid()) { lnav_data.ld_files_to_front.emplace_back(abspath.in(), file_loc); @@ -3196,7 +3197,7 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%' retval = EXIT_FAILURE; } - nonstd::optional stdin_url; + std::optional stdin_url; ghc::filesystem::path stdin_dir; if (load_stdin && !isatty(STDIN_FILENO) && !is_dev_null(STDIN_FILENO) && !exec_stdin) diff --git a/src/lnav.hh b/src/lnav.hh index b260333d..fe4e9f1d 100644 --- a/src/lnav.hh +++ b/src/lnav.hh @@ -293,6 +293,6 @@ extern const ssize_t ZOOM_COUNT; bool setup_logline_table(exec_context& ec); void wait_for_children(); -void wait_for_pipers(nonstd::optional deadline = nonstd::nullopt); +void wait_for_pipers(std::optional deadline = std::nullopt); #endif diff --git a/src/lnav.indexing.cc b/src/lnav.indexing.cc index 345d5df9..b66705ca 100644 --- a/src/lnav.indexing.cc +++ b/src/lnav.indexing.cc @@ -200,7 +200,7 @@ public: }; rebuild_indexes_result_t -rebuild_indexes(nonstd::optional deadline) +rebuild_indexes(std::optional deadline) { logfile_sub_source& lss = lnav_data.ld_log_source; textview_curses& log_view = lnav_data.ld_views[LNV_LOG]; @@ -247,7 +247,7 @@ rebuild_indexes(nonstd::optional deadline) tss->to_front(cb.front_file); } - nonstd::optional new_top_opt; + std::optional new_top_opt; cb.front_top.match( [&new_top_opt](vis_line_t vl) { log_info("file open request to jump to line: %d", (int) vl); diff --git a/src/lnav.indexing.hh b/src/lnav.indexing.hh index d694e381..2a40eb3e 100644 --- a/src/lnav.indexing.hh +++ b/src/lnav.indexing.hh @@ -32,7 +32,6 @@ #include "file_collection.hh" #include "logfile_fwd.hh" -#include "optional.hpp" void rebuild_hist(); @@ -42,7 +41,7 @@ struct rebuild_indexes_result_t { }; rebuild_indexes_result_t rebuild_indexes( - nonstd::optional deadline = nonstd::nullopt); + std::optional deadline = std::nullopt); void rebuild_indexes_repeatedly(); bool rescan_files(bool required = false); bool update_active_files(file_collection& new_files); diff --git a/src/lnav.management_cli.cc b/src/lnav.management_cli.cc index 48828d4a..d2662752 100644 --- a/src/lnav.management_cli.cc +++ b/src/lnav.management_cli.cc @@ -59,10 +59,16 @@ struct no_subcmd_t { CLI::App* ns_root_app{nullptr}; }; +static auto DEFAULT_WRAPPING + = text_wrap_settings{}.with_padding_indent(4).with_width(60); + inline attr_line_t& symbol_reducer(const std::string& elem, attr_line_t& accum) { - return accum.append("\n ").append(lnav::roles::symbol(elem)); + if (!accum.empty()) { + accum.append(", "); + } + return accum.append(lnav::roles::symbol(elem)); } inline attr_line_t& @@ -209,7 +215,8 @@ struct subcmd_format_t { | lnav::itertools::sort_with(intern_string_t::case_lt) | lnav::itertools::map(&intern_string_t::to_string) | lnav::itertools::fold(symbol_reducer, attr_line_t{})) - .add_header("the available formats are:")); + .add_header("the available formats are: ") + .wrap_with(&DEFAULT_WRAPPING)); return Err(um); } @@ -225,7 +232,8 @@ struct subcmd_format_t { | lnav::itertools::similar_to(this->sf_name) | lnav::itertools::map(&intern_string_t::to_string) | lnav::itertools::fold(symbol_reducer, attr_line_t{})) - .add_header("did you mean one of the following?")); + .add_header("did you mean one of the following?\n") + .wrap_with(&DEFAULT_WRAPPING)); return Err(um); } @@ -265,7 +273,8 @@ struct subcmd_format_t { | lnav::itertools::map(&external_log_format::pattern::p_name) | lnav::itertools::map(&intern_string_t::to_string) | lnav::itertools::fold( - symbol_reducer, attr_line_t{"the available regexes are:"})); + symbol_reducer, + attr_line_t{"the available regexes are: "})); return Err(um); } @@ -285,7 +294,7 @@ struct subcmd_format_t { | lnav::itertools::map(&intern_string_t::to_string) | lnav::itertools::similar_to(this->sf_regex_name) | lnav::itertools::fold(symbol_reducer, attr_line_t{})) - .add_header("did you mean one of the following?")); + .add_header("did you mean one of the following?\n")); return Err(um); } @@ -784,7 +793,7 @@ struct subcmd_piper_t { continue; } - nonstd::optional hdr_opt; + std::optional hdr_opt; auto url = fmt::format(FMT_STRING("piper://{}"), instance_dir.path().filename().string()); file_size_t total_size{0}; diff --git a/src/lnav_commands.cc b/src/lnav_commands.cc index 18f440b3..36233231 100644 --- a/src/lnav_commands.cc +++ b/src/lnav_commands.cc @@ -156,7 +156,7 @@ remaining_args_frag(const std::string& cmdline, cmdline, index_in_cmdline, cmdline.size()); } -static nonstd::optional +static std::optional find_arg(std::vector& args, const std::string& flag) { auto iter = find_if(args.begin(), args.end(), [&flag](const auto elem) { @@ -164,7 +164,7 @@ find_arg(std::vector& args, const std::string& flag) }); if (iter == args.end()) { - return nonstd::nullopt; + return std::nullopt; } auto index = iter->find('='); @@ -472,7 +472,7 @@ com_set_file_timezone_prompt(exec_context& ec, const std::string& cmdline) auto match_res = options_hier->match(pattern_arg); if (match_res) { file_zone = match_res->second.fo_default_zone.pp_value->name(); - pattern_arg = match_res->first; + pattern_arg = lnav::filesystem::escape_path(match_res->first); auto new_prompt = fmt::format(FMT_STRING("{} {} {}"), trim(cmdline), @@ -488,7 +488,10 @@ com_set_file_timezone_prompt(exec_context& ec, const std::string& cmdline) } } auto arg_path = ghc::filesystem::path(pattern_arg); - auto arg_parent = arg_path.parent_path().string() + "/"; + auto arg_parent = lnav::filesystem::escape_path(arg_path.parent_path()); + if (!endswith(arg_parent, "/")) { + arg_parent += "/"; + } if (elems.size() == 2 && endswith(cmdline, " ")) { return {"", arg_parent}; } @@ -698,7 +701,7 @@ com_goto(exec_context& ec, std::string cmdline, std::vector& args) } else if (args.size() > 1) { std::string all_args = remaining_args(cmdline, args); auto* tc = *lnav_data.ld_view_stack.top(); - nonstd::optional dst_vl; + std::optional dst_vl; auto is_location = false; if (startswith(all_args, "#")) { @@ -1136,7 +1139,7 @@ com_goto_mark(exec_context& ec, } if (!ec.ec_dry_run) { - nonstd::optional new_top; + std::optional new_top; if (args[0] == "next-mark") { auto search_from_top = search_forward_from(tc); @@ -1806,7 +1809,7 @@ com_save_to(exec_context& ec, line_count += 1; } } else if (tc == &lnav_data.ld_views[LNV_LOG]) { - nonstd::optional> last_line; + std::optional> last_line; bookmark_vector visited; auto& lss = lnav_data.ld_log_source; std::vector rows(1); @@ -2191,8 +2194,6 @@ com_redirect_to(exec_context& ec, return Ok("info: output will be redirected to -- " + split_args[0]); } - nonstd::optional file; - if (split_args[0] == "-") { ec.clear_output(); } else if (split_args[0] == "/dev/clipboard") { @@ -3455,7 +3456,7 @@ com_close(exec_context& ec, std::string cmdline, std::vector& args) } auto* tc = *lnav_data.ld_view_stack.top(); - std::vector> actual_path_v; + std::vector> actual_path_v; std::vector fn_v; if (args.size() > 1) { @@ -4075,7 +4076,7 @@ com_clear_partition(exec_context& ec, textview_curses& tc = lnav_data.ld_views[LNV_LOG]; logfile_sub_source& lss = lnav_data.ld_log_source; auto& bv = tc.get_bookmarks()[&textview_curses::BM_PARTITION]; - nonstd::optional part_start; + std::optional part_start; if (binary_search(bv.begin(), bv.end(), tc.get_selection())) { part_start = tc.get_selection(); @@ -4757,7 +4758,7 @@ com_hide_line(exec_context& ec, auto& lss = lnav_data.ld_log_source; date_time_scanner dts; struct timeval tv_abs; - nonstd::optional tv_opt; + std::optional tv_opt; auto parse_res = relative_time::from_str(all_args); if (parse_res.isOk()) { @@ -4956,7 +4957,7 @@ com_sh(exec_context& ec, std::string cmdline, std::vector& args) static size_t EXEC_COUNT = 0; if (!ec.ec_dry_run) { - nonstd::optional name_flag; + std::optional name_flag; shlex lexer(cmdline); auto cmd_start = args[0].size(); @@ -5047,7 +5048,7 @@ com_sh(exec_context& ec, std::string cmdline, std::vector& args) display_name = name_flag.value(); } else { display_name - = fmt::format(FMT_STRING("[{}] {}"), EXEC_COUNT++, carg); + = fmt::format(FMT_STRING("sh-{} {}"), EXEC_COUNT++, carg); } auto name_base = display_name; diff --git a/src/lnav_config.cc b/src/lnav_config.cc index e8f91d31..50712b01 100644 --- a/src/lnav_config.cc +++ b/src/lnav_config.cc @@ -1195,6 +1195,23 @@ static const struct json_path_container archive_handlers = { &archive_manager::config::amc_cache_ttl), }; +static const struct typed_json_path_container + demux_def_handlers = { + yajlpp::property_handler("pattern") + .with_synopsis("") + .with_description( + "A regular expression to match a line in a multiplexed file") + .for_field(&lnav::piper::demux_def::dd_pattern), +}; + +static const struct json_path_container demux_defs_handlers = { + yajlpp::pattern_property_handler("(?[\\w\\-\\.]+)") + .with_description("The definition of a demultiplexer") + .with_children(demux_def_handlers) + .for_field(&_lnav_config::lc_piper, + &lnav::piper::config::c_demux_definitions), +}; + static const struct json_path_container piper_handlers = { yajlpp::property_handler("max-size") .with_synopsis("") @@ -1450,6 +1467,9 @@ static const struct json_path_container log_source_handlers = { .with_description("Log message watch expressions") .with_children(log_source_watch_handlers), yajlpp::property_handler("annotations").with_children(annotations_handlers), + yajlpp::property_handler("demux") + .with_description("Demultiplexer definitions") + .with_children(demux_defs_handlers), }; static const struct json_path_container url_scheme_handlers = { diff --git a/src/lnav_util.hh b/src/lnav_util.hh index 13b5ac6c..16fac8b1 100644 --- a/src/lnav_util.hh +++ b/src/lnav_util.hh @@ -54,7 +54,6 @@ #include "base/result.h" #include "config.h" #include "fmt/format.h" -#include "optional.hpp" #if SIZEOF_OFF_T == 8 # define FORMAT_OFF_T "%lld" diff --git a/src/log_format.cc b/src/log_format.cc index 0569d395..8a80d91d 100644 --- a/src/log_format.cc +++ b/src/log_format.cc @@ -198,7 +198,7 @@ log_opid_state::sub_op_in_use(ArenaAlloc::Alloc& alloc, } } -nonstd::optional +std::optional log_format::opid_descriptor::matches(const string_fragment& sf) const { if (this->od_extractor.pp_value) { @@ -213,7 +213,7 @@ log_format::opid_descriptor::matches(const string_fragment& sf) const return desc_md.to_string(); } - return nonstd::nullopt; + return std::nullopt; } return sf.to_string(); } @@ -461,7 +461,7 @@ external_log_format::update_op_description( const pattern* fpat, const lnav::pcre2pp::match_data& md) { - nonstd::optional desc_elem_str; + std::optional desc_elem_str; if (!lod.lod_id) { for (const auto& desc_def_pair : desc_defs) { if (lod.lod_id) { @@ -529,7 +529,7 @@ external_log_format::update_op_description( found_desc->second.append(desc_elem_str.value()); } } - desc_elem_str = nonstd::nullopt; + desc_elem_str = std::nullopt; } } } @@ -539,7 +539,7 @@ external_log_format::update_op_description( const std::map& desc_defs, log_op_description& lod) { - nonstd::optional desc_elem_str; + std::optional desc_elem_str; if (!lod.lod_id) { for (const auto& desc_def_pair : desc_defs) { if (lod.lod_id) { @@ -594,7 +594,7 @@ external_log_format::update_op_description( found_desc->second.append(desc_elem_str.value()); } } - desc_elem_str = nonstd::nullopt; + desc_elem_str = std::nullopt; } } } @@ -650,7 +650,7 @@ log_format::log_scanf(uint32_t line_number, struct timeval* tv_out, string_fragment* ts_out, - nonstd::optional* level_out) + std::optional* level_out) { int curr_fmt = -1; const char* retval = nullptr; @@ -794,7 +794,7 @@ struct json_log_userdata { void add_sub_lines_for(const intern_string_t ist, bool top_level, - nonstd::optional val = nonstd::nullopt, + std::optional val = std::nullopt, const unsigned char* str = nullptr, ssize_t len = -1) { @@ -821,8 +821,8 @@ struct json_log_userdata { uint32_t jlu_quality{0}; shared_buffer_ref& jlu_shared_buffer; scan_batch_context* jlu_batch_context; - nonstd::optional jlu_opid_frag; - nonstd::optional jlu_subid; + std::optional jlu_opid_frag; + std::optional jlu_subid; struct exttm jlu_exttm; }; @@ -1293,7 +1293,7 @@ external_log_format::scan(logfile& lf, this->update_op_description(*this->lf_opid_description_def, otr.otr_description); } else { - this->jlf_line_values.lvv_opid_value = nonstd::nullopt; + this->jlf_line_values.lvv_opid_value = std::nullopt; } jlu.jlu_sub_line_count += this->jlf_line_format_init_count; @@ -1579,7 +1579,7 @@ external_log_format::scan(logfile& lf, } } - nonstd::optional dvalue_opt; + std::optional dvalue_opt; switch (vd.vd_meta.lvm_kind) { case value_kind_t::VALUE_INTEGER: { auto scan_res = scn::scan_value( @@ -1630,7 +1630,7 @@ external_log_format::scan(logfile& lf, } this->lf_pattern_locks.emplace_back(lock_line, curr_fmt); } - return log_format::scan_match{0}; + return log_format::scan_match{1000}; } if (this->lf_specialized && !this->lf_multiline) { @@ -1764,7 +1764,7 @@ external_log_format::annotate(uint64_t line_number, return; } - nonstd::optional module_cap; + std::optional module_cap; if (!pat.p_module_format) { auto ts_cap = md[pat.p_timestamp_field_index]; if (ts_cap) { @@ -2027,7 +2027,7 @@ read_json_field(yajlpp_parse_context* ypc, const unsigned char* str, size_t len) } jlu->add_sub_lines_for( - field_name, ypc->is_level(1), nonstd::nullopt, str, len); + field_name, ypc->is_level(1), std::nullopt, str, len); return 1; } @@ -2592,7 +2592,7 @@ using safe_format_header_expressions = safe::Safe; static safe_format_header_expressions format_header_exprs; -nonstd::optional +std::optional detect_mime_type(const ghc::filesystem::path& filename) { uint8_t buffer[1024]; @@ -2602,13 +2602,13 @@ detect_mime_type(const ghc::filesystem::path& filename) auto_fd fd; if ((fd = lnav::filesystem::openp(filename, O_RDONLY)) == -1) { - return nonstd::nullopt; + return std::nullopt; } ssize_t rc; if ((rc = read(fd, buffer, sizeof(buffer))) == -1) { - return nonstd::nullopt; + return std::nullopt; } buffer_size = rc; } @@ -2713,7 +2713,7 @@ detect_mime_type(const ghc::filesystem::path& filename) } } - return nonstd::nullopt; + return std::nullopt; } void @@ -3604,7 +3604,7 @@ external_log_format::build(std::vector& errors) size_t value_def_index = 0; for (auto& elf_value_def : this->elf_value_def_order) { elf_value_def->vd_meta.lvm_values_index - = nonstd::make_optional(value_def_index++); + = std::make_optional(value_def_index++); if (elf_value_def->vd_meta.lvm_foreign_key || elf_value_def->vd_meta.lvm_identifier) @@ -4004,7 +4004,7 @@ external_log_format::match_name(const std::string& filename) auto external_log_format::value_line_count(const intern_string_t ist, bool top_level, - nonstd::optional val, + std::optional val, const unsigned char* str, ssize_t len) -> value_line_count_result { diff --git a/src/log_format.hh b/src/log_format.hh index 8766558a..227369f7 100644 --- a/src/log_format.hh +++ b/src/log_format.hh @@ -56,7 +56,6 @@ #include "line_buffer.hh" #include "log_format_fwd.hh" #include "log_level.hh" -#include "optional.hpp" #include "pcrepp/pcre2pp.hh" #include "shared_buffer.hh" @@ -136,8 +135,8 @@ struct logline_value_meta { logline_value_meta(intern_string_t name, value_kind_t kind, column_t col = external_column{}, - const nonstd::optional& format - = nonstd::nullopt) + const std::optional& format + = std::nullopt) : lvm_name(name), lvm_kind(kind), lvm_column(col), lvm_format(format) { } @@ -161,14 +160,14 @@ struct logline_value_meta { intern_string_t lvm_name; value_kind_t lvm_kind; column_t lvm_column{external_column{}}; - nonstd::optional lvm_values_index; + std::optional lvm_values_index; bool lvm_identifier{false}; bool lvm_foreign_key{false}; bool lvm_hidden{false}; - nonstd::optional lvm_user_hidden; + std::optional lvm_user_hidden; bool lvm_from_module{false}; intern_string_t lvm_struct_name; - nonstd::optional lvm_format; + std::optional lvm_format; }; class logline_value { @@ -269,7 +268,7 @@ public: value_u(int64_t i) : i(i) {} value_u(double d) : d(d) {} } lv_value; - nonstd::optional lv_str; + std::optional lv_str; string_fragment lv_frag; int lv_sub_offset{0}; intern_string_t lv_intern_string; @@ -281,7 +280,7 @@ struct logline_value_vector { { this->lvv_values.clear(); this->lvv_sbr.disown(); - this->lvv_opid_value = nonstd::nullopt; + this->lvv_opid_value = std::nullopt; } logline_value_vector() {} @@ -303,7 +302,7 @@ struct logline_value_vector { shared_buffer_ref lvv_sbr; std::vector lvv_values; - nonstd::optional lvv_opid_value; + std::optional lvv_opid_value; }; struct logline_value_stats { @@ -332,7 +331,7 @@ struct logline_value_stats { struct logline_value_cmp { explicit logline_value_cmp( const intern_string_t* name = nullptr, - nonstd::optional col = nonstd::nullopt) + std::optional col = std::nullopt) : lvc_name(name), lvc_column(col) { } @@ -353,7 +352,7 @@ struct logline_value_cmp { } const intern_string_t* lvc_name; - nonstd::optional lvc_column; + std::optional lvc_column; }; class log_vtab_impl; @@ -577,7 +576,7 @@ public: std::vector lf_pattern_locks; intern_string_t lf_timestamp_field{intern_string::lookup("timestamp", -1)}; intern_string_t lf_subsecond_field; - nonstd::optional lf_subsecond_unit; + std::optional lf_subsecond_unit; intern_string_t lf_time_field; std::vector lf_timestamp_format; unsigned int lf_timestamp_flags{0}; @@ -587,7 +586,7 @@ public: bool lf_is_self_describing{false}; bool lf_time_ordered{true}; bool lf_specialized{false}; - nonstd::optional lf_max_unrecognized_lines; + std::optional lf_max_unrecognized_lines; std::map> lf_tag_defs; @@ -601,7 +600,7 @@ public: std::string od_suffix; std::string od_joiner{", "}; - nonstd::optional matches(const string_fragment& sf) const; + std::optional matches(const string_fragment& sf) const; }; struct opid_descriptors { @@ -666,7 +665,7 @@ protected: struct timeval* tv_out, string_fragment* ts_out, - nonstd::optional* level_out); + std::optional* level_out); }; #endif diff --git a/src/log_format_ext.hh b/src/log_format_ext.hh index 35361b3c..b885bb69 100644 --- a/src/log_format_ext.hh +++ b/src/log_format_ext.hh @@ -287,8 +287,8 @@ public: value_line_count_result value_line_count(const intern_string_t ist, bool top_level, - nonstd::optional val - = nonstd::nullopt, + std::optional val + = std::nullopt, const unsigned char* str = nullptr, ssize_t len = -1); diff --git a/src/log_format_fwd.hh b/src/log_format_fwd.hh index dbcc3568..e5725fef 100644 --- a/src/log_format_fwd.hh +++ b/src/log_format_fwd.hh @@ -58,7 +58,7 @@ struct log_level_stats { }; struct log_op_description { - nonstd::optional lod_id; + std::optional lod_id; lnav::map::small lod_elements; log_op_description& operator|=(const log_op_description& rhs); diff --git a/src/log_format_impls.cc b/src/log_format_impls.cc index 3bd45ad0..8784c11d 100644 --- a/src/log_format_impls.cc +++ b/src/log_format_impls.cc @@ -41,6 +41,7 @@ #include "config.h" #include "formats/logfmt/logfmt.parser.hh" #include "log_vtab_impl.hh" +#include "ptimec.hh" #include "scn/scn.h" #include "sql_util.hh" #include "yajlpp/yajlpp.hh" @@ -90,6 +91,21 @@ public: this->plf_cached_line.size(), ll.get_timeval(), 'T'); + { + char zone_str[16]; + exttm tmptm; + + tmptm.et_flags |= ETF_ZONE_SET; + tmptm.et_gmtoff + = lnav::local_time_to_info( + date::local_seconds{std::chrono::seconds{ll.get_time()}}) + .first.offset.count(); + off_t zone_len = 0; + ftime_z(zone_str, zone_len, sizeof(zone_str), tmptm); + for (off_t lpc = 0; lpc < zone_len; lpc++) { + this->plf_cached_line.push_back(zone_str[lpc]); + } + } this->plf_cached_line.push_back(' '); const auto prefix_len = this->plf_cached_line.size(); this->plf_cached_line.resize(this->plf_cached_line.size() @@ -107,6 +123,7 @@ public: auto retval = std::make_shared(*this); retval->lf_specialized = true; + retval->lf_timestamp_flags |= ETF_ZONE_SET; return retval; } @@ -175,7 +192,7 @@ public: struct exttm log_time; struct timeval log_tv; string_fragment ts; - nonstd::optional level; + std::optional level; const char* last_pos; if (dst.empty()) { @@ -356,7 +373,7 @@ from_escaped_string(const char* str, size_t len) return retval; } -nonstd::optional +std::optional lnav_strnstr(const char* s, const char* find, size_t slen) { char c, sc; @@ -367,13 +384,13 @@ lnav_strnstr(const char* s, const char* find, size_t slen) do { do { if (slen < 1 || (sc = *s) == '\0') { - return nonstd::nullopt; + return std::nullopt; } --slen; ++s; } while (sc != c); if (len > slen) { - return nonstd::nullopt; + return std::nullopt; } } while (strncmp(s, find, len) != 0); s--; @@ -474,7 +491,7 @@ public: logline_value_meta fd_meta; logline_value_meta* fd_root_meta; std::string fd_collator; - nonstd::optional fd_numeric_index; + std::optional fd_numeric_index; explicit field_def(const intern_string_t name, size_t col, @@ -567,7 +584,7 @@ public: for (auto iter = ss.begin(); iter != ss.end(); ++iter) { if (iter.index() == 0 && *iter == "#close") { - return scan_match{0}; + return scan_match{2000}; } if (iter.index() >= this->blf_field_defs.size()) { @@ -649,7 +666,7 @@ public: } } dst.emplace_back(li.li_file_range.fr_offset, tv, level, 0, opid); - return scan_match{0}; + return scan_match{2000}; } return scan_no_match{}; } @@ -1115,7 +1132,7 @@ public: logline_value_meta fd_meta; logline_value_meta* fd_root_meta{nullptr}; std::string fd_collator; - nonstd::optional fd_numeric_index; + std::optional fd_numeric_index; explicit field_def(const intern_string_t name) : fd_name(name), fd_meta(intern_string::lookup(sql_safe_ident( @@ -1262,7 +1279,7 @@ public: } dst.emplace_back( li.li_file_range.fr_offset, 0, 0, LEVEL_IGNORE, 0); - return scan_match{0}; + return scan_match{2000}; } sf = sf.trim("\" \t"); @@ -1328,7 +1345,7 @@ public: } } dst.emplace_back(li.li_file_range.fr_offset, tv, level, 0); - return scan_match{0}; + return scan_match{2000}; } return scan_no_match{}; @@ -1476,7 +1493,7 @@ public: } } auto& fd = this->wlf_field_defs.back(); - fd.fd_meta.lvm_format = nonstd::make_optional(this); + fd.fd_meta.lvm_format = std::make_optional(this); switch (fd.fd_meta.lvm_kind) { case value_kind_t::VALUE_FLOAT: case value_kind_t::VALUE_INTEGER: @@ -1953,7 +1970,7 @@ public: if (lph.lph_found_time) { dst.emplace_back( li.li_file_range.fr_offset, lph.lph_tv, lph.lph_level); - retval = scan_match{0}; + retval = scan_match{2000}; } return retval; diff --git a/src/log_search_table.hh b/src/log_search_table.hh index 1ae98d6c..96296a93 100644 --- a/src/log_search_table.hh +++ b/src/log_search_table.hh @@ -71,7 +71,7 @@ public: log_format* lst_format{nullptr}; mutable size_t lst_format_column_count{0}; std::string lst_log_path_glob; - nonstd::optional lst_log_level; + std::optional lst_log_level; mutable std::vector lst_column_metas; int64_t lst_match_index{-1}; mutable std::vector lst_cols; diff --git a/src/log_vtab_impl.cc b/src/log_vtab_impl.cc index 0f905fc0..8a925fcf 100644 --- a/src/log_vtab_impl.cc +++ b/src/log_vtab_impl.cc @@ -409,7 +409,7 @@ vt_open(sqlite3_vtab* p_svt, sqlite3_vtab_cursor** pp_cursor) *pp_cursor = (sqlite3_vtab_cursor*) p_cur; p_cur->base.pVtab = p_svt; - p_cur->log_cursor.lc_opid = nonstd::nullopt; + p_cur->log_cursor.lc_opid = std::nullopt; p_cur->log_cursor.lc_curr_line = 0_vl; p_cur->log_cursor.lc_end_line = vis_line_t(p_vt->lss->text_line_count()); p_cur->log_cursor.lc_sub_index = 0; @@ -1295,8 +1295,8 @@ log_cursor::string_constraint::matches(const std::string& sf) const } struct vtab_time_range { - nonstd::optional vtr_begin; - nonstd::optional vtr_end; + std::optional vtr_begin; + std::optional vtr_end; bool empty() const { return !this->vtr_begin && !this->vtr_end; } @@ -1342,8 +1342,8 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, #endif p_cur->log_cursor.lc_format_name.clear(); p_cur->log_cursor.lc_pattern_name.clear(); - p_cur->log_cursor.lc_opid = nonstd::nullopt; - p_cur->log_cursor.lc_level_constraint = nonstd::nullopt; + p_cur->log_cursor.lc_opid = std::nullopt; + p_cur->log_cursor.lc_level_constraint = std::nullopt; p_cur->log_cursor.lc_log_path.clear(); p_cur->log_cursor.lc_indexed_columns.clear(); p_cur->log_cursor.lc_last_log_path_match = nullptr; @@ -1354,8 +1354,8 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, p_cur->log_cursor.lc_curr_line = 0_vl; p_cur->log_cursor.lc_end_line = vis_line_t(vt->lss->text_line_count()); - nonstd::optional log_time_range; - nonstd::optional opid_val; + std::optional log_time_range; + std::optional opid_val; std::vector log_path_constraints; std::vector log_unique_path_constraints; @@ -1634,7 +1634,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, } if (!p_cur->log_cursor.lc_indexed_columns.empty()) { - nonstd::optional max_indexed_line; + std::optional max_indexed_line; for (const auto& icol : p_cur->log_cursor.lc_indexed_columns) { auto& coli = vt->vi->vi_column_indexes[icol.cc_column]; @@ -1688,10 +1688,10 @@ vt_filter(sqlite3_vtab_cursor* p_vtc, && max_indexed_line.value() < vt->lss->text_line_count()) { log_debug("max indexed out of sync, clearing other indexes"); - p_cur->log_cursor.lc_level_constraint = nonstd::nullopt; + p_cur->log_cursor.lc_level_constraint = std::nullopt; p_cur->log_cursor.lc_curr_line = 0_vl; - opid_val = nonstd::nullopt; - log_time_range = nonstd::nullopt; + opid_val = std::nullopt; + log_time_range = std::nullopt; p_cur->log_cursor.lc_indexed_lines.clear(); log_path_constraints.clear(); log_unique_path_constraints.clear(); @@ -1982,9 +1982,9 @@ vt_update(sqlite3_vtab* tab, argv[2 + vt->footer_index(log_footer_columns::partition)]); const auto* log_comment = sqlite3_value_text( argv[2 + vt->footer_index(log_footer_columns::comment)]); - const auto log_tags = from_sqlite>()( + const auto log_tags = from_sqlite>()( argc, argv, 2 + vt->footer_index(log_footer_columns::tags)); - const auto log_annos = from_sqlite>()( + const auto log_annos = from_sqlite>()( argc, argv, 2 + vt->footer_index(log_footer_columns::annotations)); bookmark_metadata tmp_bm; diff --git a/src/log_vtab_impl.hh b/src/log_vtab_impl.hh index bbd5b4cc..eacd071a 100644 --- a/src/log_vtab_impl.hh +++ b/src/log_vtab_impl.hh @@ -132,10 +132,10 @@ struct log_cursor { using level_constraint = integral_constraint; - nonstd::optional lc_level_constraint; + std::optional lc_level_constraint; intern_string_t lc_format_name; intern_string_t lc_pattern_name; - nonstd::optional lc_opid; + std::optional lc_opid; std::vector lc_log_path; logfile* lc_last_log_path_match{nullptr}; logfile* lc_last_log_path_mismatch{nullptr}; diff --git a/src/logfile.cc b/src/logfile.cc index 03845359..3bc1a166 100644 --- a/src/logfile.cc +++ b/src/logfile.cc @@ -155,13 +155,33 @@ logfile::open(ghc::filesystem::path filename, } }, [&lf](const lnav::piper::header& phdr) { + static auto& safe_options_hier + = injector::get(); + lf->lf_embedded_metadata["org.lnav.piper.header"] = { text_format_t::TF_JSON, lnav::piper::header_handlers.to_string(phdr), }; - log_debug("setting file name: %s", phdr.h_name.c_str()); + log_info("setting file name from piper header: %s", + phdr.h_name.c_str()); lf->set_filename(phdr.h_name); lf->lf_valid_filename = false; + + lnav::file_options fo; + if (!phdr.h_timezone.empty()) { + log_info("setting default time zone from piper header: %s", + phdr.h_timezone.c_str()); + fo.fo_default_zone.pp_value + = date::locate_zone(phdr.h_timezone); + } + if (!fo.empty()) { + safe::WriteAccess + options_hier(safe_options_hier); + + options_hier->foh_generation += 1; + auto& coll = options_hier->foh_path_to_collection["/"]; + coll.foc_pattern_to_options[lf->get_filename()] = fo; + } }); } @@ -217,6 +237,7 @@ logfile::file_options_have_changed() && this->lf_format != nullptr && !(this->lf_format->lf_timestamp_flags & ETF_ZONE_SET)) { + log_info(" tz change affects this file"); tz_changed = true; } } else if (this->lf_format != nullptr @@ -306,7 +327,7 @@ logfile::process_prefix(shared_buffer_ref& sbr, found = this->lf_format->scan(*this, this->lf_index, li, sbr, sbc); } else if (this->lf_options.loo_detect_format) { const auto& root_formats = log_format::get_root_formats(); - nonstd::optional> + std::optional> best_match; size_t scan_count = 0; @@ -565,7 +586,7 @@ logfile::process_prefix(shared_buffer_ref& sbr, } logfile::rebuild_result_t -logfile::rebuild_index(nonstd::optional deadline) +logfile::rebuild_index(std::optional deadline) { static const auto& dts_cfg = injector::get(); @@ -1239,8 +1260,8 @@ logfile::message_byte_length(logfile::const_iterator ll, bool include_continues) } else { retval = next_line->get_offset() - ll->get_offset() - 1; if (!include_continues) { - this->lf_next_line_cache = nonstd::make_optional( - std::make_pair(ll->get_offset(), retval)); + this->lf_next_line_cache + = std::make_optional(std::make_pair(ll->get_offset(), retval)); } } @@ -1265,13 +1286,13 @@ logfile::get_format_name() const return {}; } -nonstd::optional +std::optional logfile::find_from_time(const timeval& tv) const { auto retval = std::lower_bound(this->lf_index.begin(), this->lf_index.end(), tv); if (retval == this->lf_index.end()) { - return nonstd::nullopt; + return std::nullopt; } return retval; @@ -1340,7 +1361,7 @@ logfile::original_line_time(logfile::iterator ll) return ll->get_timeval(); } -nonstd::optional +std::optional logfile::line_for_offset(file_off_t off) const { struct cmper { @@ -1356,7 +1377,7 @@ logfile::line_for_offset(file_off_t off) const }; if (this->lf_index.empty()) { - return nonstd::nullopt; + return std::nullopt; } auto iter = std::lower_bound( @@ -1365,16 +1386,16 @@ logfile::line_for_offset(file_off_t off) const if (this->lf_index.back().get_offset() <= off && off < this->lf_index_size) { - return nonstd::make_optional(iter); + return std::make_optional(iter); } - return nonstd::nullopt; + return std::nullopt; } if (off < iter->get_offset() && iter != this->lf_index.begin()) { --iter; } - return nonstd::make_optional(iter); + return std::make_optional(iter); } void diff --git a/src/logfile.hh b/src/logfile.hh index e936e79f..8bc1e018 100644 --- a/src/logfile.hh +++ b/src/logfile.hh @@ -122,7 +122,7 @@ public: const logfile_activity& get_activity() const { return this->lf_activity; } - nonstd::optional get_actual_path() const + std::optional get_actual_path() const { return this->lf_actual_path; } @@ -160,7 +160,7 @@ public: file_off_t get_index_size() const { return this->lf_index_size; } - nonstd::optional line_for_offset(file_off_t off) const; + std::optional line_for_offset(file_off_t off) const; /** * @return The detected format, rebuild_index() must be called before this @@ -235,7 +235,7 @@ public: /** @return The number of lines in the index. */ size_t size() const { return this->lf_index.size(); } - nonstd::optional find_from_time( + std::optional find_from_time( const struct timeval& tv) const; logline& operator[](int index) { return this->lf_index[index]; } @@ -328,7 +328,7 @@ public: * @return True if any new lines were indexed. */ rebuild_result_t rebuild_index( - nonstd::optional deadline = nonstd::nullopt); + std::optional deadline = std::nullopt); void reobserve_from(iterator iter); @@ -410,7 +410,7 @@ public: return this->lf_embedded_metadata; } - nonstd::optional> + std::optional> get_file_options() const { return this->lf_file_options; @@ -440,7 +440,7 @@ private: logfile_activity lf_activity; bool lf_named_file{true}; bool lf_valid_filename{true}; - nonstd::optional lf_actual_path; + std::optional lf_actual_path; std::string lf_basename; std::string lf_content_id; struct stat lf_stat {}; @@ -467,10 +467,10 @@ private: safe_opid_state lf_opids; size_t lf_watch_count{0}; ArenaAlloc::Alloc lf_allocator{64 * 1024}; - nonstd::optional lf_cached_base_time; - nonstd::optional lf_cached_base_tm; + std::optional lf_cached_base_time; + std::optional lf_cached_base_tm; - nonstd::optional> lf_next_line_cache; + std::optional> lf_next_line_cache; std::set lf_mismatched_formats; robin_hood::unordered_map lf_bookmark_metadata; @@ -479,7 +479,7 @@ private: lf_applicable_partitioners; std::map lf_embedded_metadata; size_t lf_file_options_generation{0}; - nonstd::optional> + std::optional> lf_file_options; }; diff --git a/src/logfile_fwd.hh b/src/logfile_fwd.hh index 4d169f30..3c1792fa 100644 --- a/src/logfile_fwd.hh +++ b/src/logfile_fwd.hh @@ -69,9 +69,9 @@ struct logfile_open_options_base { ssize_t loo_visible_size_limit{-1}; bool loo_tail{true}; file_format_t loo_file_format{file_format_t::UNKNOWN}; - nonstd::optional loo_format_name; - nonstd::optional loo_text_format; - nonstd::optional loo_piper; + std::optional loo_format_name; + std::optional loo_text_format; + std::optional loo_piper; file_location_t loo_init_location{mapbox::util::no_init{}}; }; diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index b78b00cb..b722fcc9 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -214,7 +214,7 @@ struct filtered_logline_cmp { const logfile_sub_source& llss_controller; }; -nonstd::optional +std::optional logfile_sub_source::find_from_time(const struct timeval& start) const { auto lb = std::lower_bound(this->lss_filtered_index.begin(), @@ -225,7 +225,7 @@ logfile_sub_source::find_from_time(const struct timeval& start) const return vis_line_t(lb - this->lss_filtered_index.begin()); } - return nonstd::nullopt; + return std::nullopt; } void @@ -747,7 +747,7 @@ struct logline_cmp { logfile_sub_source::rebuild_result logfile_sub_source::rebuild_index( - nonstd::optional deadline) + std::optional deadline) { if (this->tss_view == nullptr) { return rebuild_result::rr_no_change; @@ -762,7 +762,7 @@ logfile_sub_source::rebuild_index( int file_count = 0; bool force = this->lss_force_rebuild; auto retval = rebuild_result::rr_no_change; - nonstd::optional lowest_tv = nonstd::nullopt; + std::optional lowest_tv = std::nullopt; vis_line_t search_start = 0_vl; this->lss_force_rebuild = false; @@ -1469,7 +1469,7 @@ logfile_sub_source::list_input_handle_key(listview_curses& lv, int ch) return false; } -nonstd::optional< +std::optional< std::pair*, grep_proc_sink*>> logfile_sub_source::get_grepper() { @@ -2008,7 +2008,7 @@ logfile_sub_source::remove_file(std::shared_ptr lf) } } -nonstd::optional +std::optional logfile_sub_source::find_from_content(content_line_t cl) { content_line_t line = cl; @@ -2020,7 +2020,7 @@ logfile_sub_source::find_from_content(content_line_t cl) auto vis_start_opt = this->find_from_time(ll.get_timeval()); if (!vis_start_opt) { - return nonstd::nullopt; + return std::nullopt; } auto vis_start = *vis_start_opt; @@ -2035,14 +2035,14 @@ logfile_sub_source::find_from_content(content_line_t cl) auto guess_line = this->find_line(guess_cl); if (!guess_line || ll < *guess_line) { - return nonstd::nullopt; + return std::nullopt; } ++vis_start; } } - return nonstd::nullopt; + return std::nullopt; } void @@ -2065,7 +2065,7 @@ logfile_sub_source::reload_index_delegate() this->lss_index_delegate->index_complete(*this); } -nonstd::optional> +std::optional> logfile_sub_source::get_sql_filter() { return this->tss_filters | lnav::itertools::find_if([](const auto& filt) { @@ -2090,7 +2090,7 @@ log_location_history::loc_history_append(vis_line_t top) this->llh_history.push_back(cl); } -nonstd::optional +std::optional log_location_history::loc_history_back(vis_line_t current_top) { while (this->lh_history_position < this->llh_history.size()) { @@ -2117,10 +2117,10 @@ log_location_history::loc_history_back(vis_line_t current_top) } } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional log_location_history::loc_history_forward(vis_line_t current_top) { while (this->lh_history_position > 0) { @@ -2137,11 +2137,11 @@ log_location_history::loc_history_forward(vis_line_t current_top) } } - return nonstd::nullopt; + return std::nullopt; } bool -sql_filter::matches(nonstd::optional ls_opt, +sql_filter::matches(std::optional ls_opt, const shared_buffer_ref& line) { if (!ls_opt) { @@ -2759,7 +2759,7 @@ logfile_sub_source::get_bookmark_metadata_context( const auto& bv = bv_iter->second; auto vl_iter = std::lower_bound(bv.begin(), bv.end(), vl + 1_vl); - nonstd::optional next_line; + std::optional next_line; for (auto next_vl_iter = vl_iter; next_vl_iter != bv.end(); ++next_vl_iter) { auto bm_opt = this->find_bookmark_metadata(*next_vl_iter); @@ -2774,7 +2774,7 @@ logfile_sub_source::get_bookmark_metadata_context( } if (vl_iter == bv.begin()) { return bookmark_metadata_context{ - nonstd::nullopt, nonstd::nullopt, next_line}; + std::nullopt, std::nullopt, next_line}; } --vl_iter; @@ -2789,15 +2789,15 @@ logfile_sub_source::get_bookmark_metadata_context( if (vl_iter == bv.begin()) { return bookmark_metadata_context{ - nonstd::nullopt, nonstd::nullopt, next_line}; + std::nullopt, std::nullopt, next_line}; } --vl_iter; } return bookmark_metadata_context{ - nonstd::nullopt, nonstd::nullopt, next_line}; + std::nullopt, std::nullopt, next_line}; } -nonstd::optional +std::optional logfile_sub_source::find_bookmark_metadata(content_line_t cl) const { auto line_pair = this->find_line_with_file(cl).value(); @@ -2807,7 +2807,7 @@ logfile_sub_source::find_bookmark_metadata(content_line_t cl) const auto& bm = line_pair.first->get_bookmark_metadata(); auto bm_iter = bm.find(line_number); if (bm_iter == bm.end()) { - return nonstd::nullopt; + return std::nullopt; } return &bm_iter->second; @@ -2951,7 +2951,7 @@ logfile_sub_source::get_filtered_count_for(size_t filter_index) const return retval; } -nonstd::optional +std::optional logfile_sub_source::row_for(const row_info& ri) { auto lb = std::lower_bound(this->lss_filtered_index.begin(), @@ -2976,10 +2976,10 @@ logfile_sub_source::row_for(const row_info& ri) return vis_line_t(first_lb - this->lss_filtered_index.begin()); } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional logfile_sub_source::row_for_anchor(const std::string& id) { auto& vb = this->tss_view->get_bookmarks(); @@ -2997,10 +2997,10 @@ logfile_sub_source::row_for_anchor(const std::string& id) } } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional logfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) { auto bmc = this->get_bookmark_metadata_context( @@ -3024,16 +3024,16 @@ logfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) case text_anchors::direction::next: return bmc.bmc_next_line; } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional logfile_sub_source::anchor_for_row(vis_line_t vl) { auto line_meta = this->get_bookmark_metadata_context( vl, bookmark_metadata::categories::partition); if (!line_meta.bmc_current_metadata) { - return nonstd::nullopt; + return std::nullopt; } return text_anchors::to_anchor_string( diff --git a/src/logfile_sub_source.hh b/src/logfile_sub_source.hh index a82db601..83e05e3e 100644 --- a/src/logfile_sub_source.hh +++ b/src/logfile_sub_source.hh @@ -84,7 +84,7 @@ public: this->sf_filter_stmt = stmt; } - bool matches(nonstd::optional ls, + bool matches(std::optional ls, const shared_buffer_ref& line) override; std::string to_command() const override; @@ -106,10 +106,10 @@ public: void loc_history_append(vis_line_t top) override; - nonstd::optional loc_history_back( + std::optional loc_history_back( vis_line_t current_top) override; - nonstd::optional loc_history_forward( + std::optional loc_history_forward( vis_line_t current_top) override; private: @@ -242,12 +242,12 @@ public: } } - nonstd::optional get_min_log_time() const + std::optional get_min_log_time() const { if (this->lss_min_log_time.tv_sec == 0 && this->lss_min_log_time.tv_usec == 0) { - return nonstd::nullopt; + return std::nullopt; } return this->lss_min_log_time; @@ -261,12 +261,12 @@ public: } } - nonstd::optional get_max_log_time() const + std::optional get_max_log_time() const { if (this->lss_max_log_time.tv_sec == std::numeric_limits::max() && this->lss_max_log_time.tv_usec == 0) { - return nonstd::nullopt; + return std::nullopt; } return this->lss_max_log_time; @@ -331,8 +331,8 @@ public: rr_full_rebuild, }; - rebuild_result rebuild_index(nonstd::optional deadline - = nonstd::nullopt); + rebuild_result rebuild_index(std::optional deadline + = std::nullopt); void text_update_marks(vis_bookmarks& bm); @@ -354,9 +354,9 @@ public: } struct bookmark_metadata_context { - nonstd::optional bmc_current; - nonstd::optional bmc_current_metadata; - nonstd::optional bmc_next_line; + std::optional bmc_current; + std::optional bmc_current_metadata; + std::optional bmc_next_line; }; bookmark_metadata_context get_bookmark_metadata_context( @@ -364,10 +364,10 @@ public: bookmark_metadata::categories desired = bookmark_metadata::categories::any) const; - nonstd::optional find_bookmark_metadata( + std::optional find_bookmark_metadata( content_line_t cl) const; - nonstd::optional find_bookmark_metadata( + std::optional find_bookmark_metadata( vis_line_t vl) const { return this->find_bookmark_metadata(this->at(vl)); @@ -408,7 +408,7 @@ public: return ""; } - nonstd::optional> get_sql_filter(); + std::optional> get_sql_filter(); std::string get_sql_marker_text() const { @@ -450,7 +450,7 @@ public: return retval; } - nonstd::optional, logfile::iterator>> + std::optional, logfile::iterator>> find_line_with_file(content_line_t line) const { std::shared_ptr lf = this->find(line); @@ -461,37 +461,37 @@ public: return std::make_pair(lf, ll_iter); } - return nonstd::nullopt; + return std::nullopt; } - nonstd::optional, logfile::iterator>> + std::optional, logfile::iterator>> find_line_with_file(vis_line_t vl) const { if (vl >= 0_vl && vl <= vis_line_t(this->lss_filtered_index.size())) { return this->find_line_with_file(this->at(vl)); } - return nonstd::nullopt; + return std::nullopt; } - nonstd::optional find_from_time( + std::optional find_from_time( const struct timeval& start) const; - nonstd::optional find_from_time(time_t start) const + std::optional find_from_time(time_t start) const { struct timeval tv = {start, 0}; return this->find_from_time(tv); } - nonstd::optional find_from_time(const exttm& etm) const + std::optional find_from_time(const exttm& etm) const { return this->find_from_time(etm.to_timeval()); } - nonstd::optional find_from_content(content_line_t cl); + std::optional find_from_content(content_line_t cl); - nonstd::optional time_for_row(vis_line_t row) + std::optional time_for_row(vis_line_t row) { if (row >= 0_vl && row < (ssize_t) this->text_line_count()) { auto cl = this->at(row); @@ -500,12 +500,12 @@ public: (int64_t) cl, }; } - return nonstd::nullopt; + return std::nullopt; } - nonstd::optional row_for(const row_info& ri); + std::optional row_for(const row_info& ri); - nonstd::optional row_for_time(struct timeval time_bucket) + std::optional row_for_time(struct timeval time_bucket) { return this->find_from_time(time_bucket); } @@ -605,7 +605,7 @@ public: return retval; } - nonstd::optional find_data( + std::optional find_data( const std::shared_ptr& lf) { for (auto& ld : *this) { @@ -613,7 +613,7 @@ public: return ld.get(); } } - return nonstd::nullopt; + return std::nullopt; } iterator find_data_i(const std::shared_ptr& lf) @@ -678,11 +678,11 @@ public: bool lmg_done{false}; }; - nonstd::optional< + std::optional< std::pair*, grep_proc_sink*>> get_grepper(); - nonstd::optional get_location_history() + std::optional get_location_history() { return &this->lss_location_history; } @@ -732,11 +732,11 @@ public: big_array lss_index; - nonstd::optional row_for_anchor(const std::string& id); + std::optional row_for_anchor(const std::string& id); - nonstd::optional adjacent_anchor(vis_line_t vl, direction dir); + std::optional adjacent_anchor(vis_line_t vl, direction dir); - nonstd::optional anchor_for_row(vis_line_t vl); + std::optional anchor_for_row(vis_line_t vl); std::unordered_set get_anchors(); diff --git a/src/md2attr_line.cc b/src/md2attr_line.cc index 7c58ae1d..f2b4b114 100644 --- a/src/md2attr_line.cc +++ b/src/md2attr_line.cc @@ -655,7 +655,7 @@ md2attr_line::to_attr_line(const pugi::xml_node& doc) } for (const auto& child : doc.children()) { if (child.name() == NAME_IMG) { - nonstd::optional src_href; + std::optional src_href; std::string link_label; auto img_src = child.attribute("src"); auto img_alt = child.attribute("alt"); @@ -710,8 +710,8 @@ md2attr_line::to_attr_line(const pugi::xml_node& doc) retval.append(link_label); } } else if (child.name() == NAME_SPAN) { - nonstd::optional left_border; - nonstd::optional right_border; + std::optional left_border; + std::optional right_border; auto styled_span = attr_line_t(child.text().get()); auto span_class = child.attribute("class"); diff --git a/src/md2attr_line.hh b/src/md2attr_line.hh index 212b3ac2..eb29e271 100644 --- a/src/md2attr_line.hh +++ b/src/md2attr_line.hh @@ -42,7 +42,7 @@ class md2attr_line : public md4cpp::typed_event_handler { public: md2attr_line() { this->ml_blocks.resize(1); } - md2attr_line& with_source_path(nonstd::optional path) + md2attr_line& with_source_path(std::optional path) { this->ml_source_path = path; return *this; @@ -83,7 +83,7 @@ private: void flush_footnotes(); attr_line_t to_attr_line(const pugi::xml_node& doc); - nonstd::optional ml_source_path; + std::optional ml_source_path; std::vector ml_blocks; std::vector ml_list_stack; std::vector ml_tables; diff --git a/src/optional.hpp b/src/optional.hpp deleted file mode 100644 index a5f49610..00000000 --- a/src/optional.hpp +++ /dev/null @@ -1,1808 +0,0 @@ -// -// Copyright (c) 2014-2018 Martin Moene -// -// https://github.com/martinmoene/optional-lite -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#pragma once - -#ifndef NONSTD_OPTIONAL_LITE_HPP -# define NONSTD_OPTIONAL_LITE_HPP - -# define optional_lite_MAJOR 3 -# define optional_lite_MINOR 4 -# define optional_lite_PATCH 0 - -# define optional_lite_VERSION \ - optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY( \ - optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) - -#define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) -#define optional_STRINGIFY_( x ) #x - -// optional-lite configuration: - -#define optional_OPTIONAL_DEFAULT 0 -#define optional_OPTIONAL_NONSTD 1 -#define optional_OPTIONAL_STD 2 - -// tweak header support: - -#ifdef __has_include -# if __has_include() -# include -# endif -#define optional_HAVE_TWEAK_HEADER 1 -#else -#define optional_HAVE_TWEAK_HEADER 0 -//# pragma message("optional.hpp: Note: Tweak header not supported.") -#endif - -// optional selection and configuration: - -#if !defined( optional_CONFIG_SELECT_OPTIONAL ) -# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) -#endif - -// Control presence of exception handling (try and auto discover): - -#ifndef optional_CONFIG_NO_EXCEPTIONS -# if _MSC_VER -# include // for _HAS_EXCEPTIONS -# endif -# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) -# define optional_CONFIG_NO_EXCEPTIONS 0 -# else -# define optional_CONFIG_NO_EXCEPTIONS 1 -# endif -#endif - -// C++ language version detection (C++20 is speculative): -// Note: VC14.0/1900 (VS2015) lacks too much from C++14. - -#ifndef optional_CPLUSPLUS -# if defined(_MSVC_LANG ) && !defined(__clang__) -# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) -# else -# define optional_CPLUSPLUS __cplusplus -# endif -#endif - -#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) -#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) -#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) -#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) -#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) -#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) - -// C++ language version (represent 98 as 3): - -#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) - -// Use C++17 std::optional if available and requested: - -#if optional_CPP17_OR_GREATER && defined(__has_include ) -# if __has_include( ) -# define optional_HAVE_STD_OPTIONAL 1 -# else -# define optional_HAVE_STD_OPTIONAL 0 -# endif -#else -# define optional_HAVE_STD_OPTIONAL 0 -#endif - -#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) - -// -// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: -// - -#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES -#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 - -// C++17 std::in_place in : - -#if optional_CPP17_OR_GREATER - -#include - -namespace nonstd { - -using std::in_place; -using std::in_place_type; -using std::in_place_index; -using std::in_place_t; -using std::in_place_type_t; -using std::in_place_index_t; - -#define nonstd_lite_in_place_t( T) std::in_place_t -#define nonstd_lite_in_place_type_t( T) std::in_place_type_t -#define nonstd_lite_in_place_index_t(K) std::in_place_index_t - -#define nonstd_lite_in_place( T) std::in_place_t{} -#define nonstd_lite_in_place_type( T) std::in_place_type_t{} -#define nonstd_lite_in_place_index(K) std::in_place_index_t{} - -} // namespace nonstd - -#else // optional_CPP17_OR_GREATER - -#include - -namespace nonstd { -namespace detail { - -template< class T > -struct in_place_type_tag {}; - -template< std::size_t K > -struct in_place_index_tag {}; - -} // namespace detail - -struct in_place_t {}; - -template< class T > -inline in_place_t in_place( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) -{ - return in_place_t(); -} - -template< std::size_t K > -inline in_place_t in_place( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) -{ - return in_place_t(); -} - -template< class T > -inline in_place_t in_place_type( detail::in_place_type_tag /*unused*/ = detail::in_place_type_tag() ) -{ - return in_place_t(); -} - -template< std::size_t K > -inline in_place_t in_place_index( detail::in_place_index_tag /*unused*/ = detail::in_place_index_tag() ) -{ - return in_place_t(); -} - -// mimic templated typedef: - -#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) -#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag ) -#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag ) - -#define nonstd_lite_in_place( T) nonstd::in_place_type -#define nonstd_lite_in_place_type( T) nonstd::in_place_type -#define nonstd_lite_in_place_index(K) nonstd::in_place_index - -} // namespace nonstd - -#endif // optional_CPP17_OR_GREATER -#endif // nonstd_lite_HAVE_IN_PLACE_TYPES - -// -// Using std::optional: -// - -#if optional_USES_STD_OPTIONAL - -#include - -namespace nonstd { - - using std::optional; - using std::bad_optional_access; - using std::hash; - - using std::nullopt; - using std::nullopt_t; - - using std::operator==; - using std::operator!=; - using std::operator<; - using std::operator<=; - using std::operator>; - using std::operator>=; - using std::make_optional; - using std::swap; -} - -#else // optional_USES_STD_OPTIONAL - -#include -#include - -// optional-lite alignment configuration: - -#ifndef optional_CONFIG_MAX_ALIGN_HACK -# define optional_CONFIG_MAX_ALIGN_HACK 0 -#endif - -#ifndef optional_CONFIG_ALIGN_AS -// no default, used in #if defined() -#endif - -#ifndef optional_CONFIG_ALIGN_AS_FALLBACK -# define optional_CONFIG_ALIGN_AS_FALLBACK double -#endif - -// Compiler warning suppression: - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wundef" -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wundef" -#elif defined(_MSC_VER ) -# pragma warning( push ) -#endif - -// half-open range [lo..hi): -#define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) - -// Compiler versions: -// -// MSVC++ 6.0 _MSC_VER == 1200 optional_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) -// MSVC++ 7.0 _MSC_VER == 1300 optional_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) -// MSVC++ 7.1 _MSC_VER == 1310 optional_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) -// MSVC++ 8.0 _MSC_VER == 1400 optional_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) -// MSVC++ 9.0 _MSC_VER == 1500 optional_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) -// MSVC++ 10.0 _MSC_VER == 1600 optional_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) -// MSVC++ 11.0 _MSC_VER == 1700 optional_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) -// MSVC++ 12.0 _MSC_VER == 1800 optional_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) -// MSVC++ 14.0 _MSC_VER == 1900 optional_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) -// MSVC++ 14.1 _MSC_VER >= 1910 optional_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) -// MSVC++ 14.2 _MSC_VER >= 1920 optional_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) - -#if defined(_MSC_VER ) && !defined(__clang__) -# define optional_COMPILER_MSVC_VER (_MSC_VER ) -# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) -#else -# define optional_COMPILER_MSVC_VER 0 -# define optional_COMPILER_MSVC_VERSION 0 -#endif - -#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) ) - -#if defined(__GNUC__) && !defined(__clang__) -# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) -#else -# define optional_COMPILER_GNUC_VERSION 0 -#endif - -#if defined(__clang__) -# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) -#else -# define optional_COMPILER_CLANG_VERSION 0 -#endif - -#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) -# pragma warning( disable: 4345 ) // initialization behavior changed -#endif - -#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) -# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' -#endif - -// Presence of language and library features: - -#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) - -#ifdef _HAS_CPP0X -# define optional_HAS_CPP0X _HAS_CPP0X -#else -# define optional_HAS_CPP0X 0 -#endif - -// Unless defined otherwise below, consider VC14 as C++11 for optional-lite: - -#if optional_COMPILER_MSVC_VER >= 1900 -# undef optional_CPP11_OR_GREATER -# define optional_CPP11_OR_GREATER 1 -#endif - -#define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) -#define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) -#define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) -#define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) -#define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) -#define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) - -#define optional_CPP14_000 (optional_CPP14_OR_GREATER) -#define optional_CPP17_000 (optional_CPP17_OR_GREATER) - -// clang >= 2.9, gcc >= 4.9, msvc >= vc14.0/1900 (vs15): -#define optional_CPP11_140_C290_G490 ((optional_CPP11_OR_GREATER_ && (optional_COMPILER_CLANG_VERSION >= 290 || optional_COMPILER_GNUC_VERSION >= 490)) || (optional_COMPILER_MSVC_VER >= 1900)) - -// clang >= 3.5, msvc >= vc11 (vs12): -#define optional_CPP11_110_C350 ( optional_CPP11_110 && !optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) ) - -// clang >= 3.5, gcc >= 5.0, msvc >= vc11 (vs12): -#define optional_CPP11_110_C350_G500 \ - ( optional_CPP11_110 && \ - !( optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) \ - || optional_BETWEEN( optional_COMPILER_GNUC_VERSION , 1, 500 ) ) ) - -// Presence of C++11 language features: - -#define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 -#define optional_HAVE_IS_DEFAULT optional_CPP11_140 -#define optional_HAVE_NOEXCEPT optional_CPP11_140 -#define optional_HAVE_NULLPTR optional_CPP11_100 -#define optional_HAVE_REF_QUALIFIER optional_CPP11_140_C290_G490 -#define optional_HAVE_INITIALIZER_LIST optional_CPP11_140 - -// Presence of C++14 language features: - -#define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 - -// Presence of C++17 language features: - -#define optional_HAVE_NODISCARD optional_CPP17_000 - -// Presence of C++ library features: - -#define optional_HAVE_CONDITIONAL optional_CPP11_120 -#define optional_HAVE_REMOVE_CV optional_CPP11_120 -#define optional_HAVE_TYPE_TRAITS optional_CPP11_90 - -#define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) -#define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) - -#define optional_HAVE_IS_ASSIGNABLE optional_CPP11_110_C350 -#define optional_HAVE_IS_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350 -#define optional_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE optional_CPP11_110_C350 -#define optional_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350 -#define optional_HAVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE optional_CPP11_110_C350_G500 -#define optional_HAVE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350_G500 - -// C++ feature usage: - -#if optional_HAVE( CONSTEXPR_11 ) -# define optional_constexpr constexpr -#else -# define optional_constexpr /*constexpr*/ -#endif - -#if optional_HAVE( IS_DEFAULT ) -# define optional_is_default = default; -#else -# define optional_is_default {} -#endif - -#if optional_HAVE( CONSTEXPR_14 ) -# define optional_constexpr14 constexpr -#else -# define optional_constexpr14 /*constexpr*/ -#endif - -#if optional_HAVE( NODISCARD ) -# define optional_nodiscard [[nodiscard]] -#else -# define optional_nodiscard /*[[nodiscard]]*/ -#endif - -#if optional_HAVE( NOEXCEPT ) -# define optional_noexcept noexcept -#else -# define optional_noexcept /*noexcept*/ -#endif - -#if optional_HAVE( NULLPTR ) -# define optional_nullptr nullptr -#else -# define optional_nullptr NULL -#endif - -#if optional_HAVE( REF_QUALIFIER ) -// NOLINTNEXTLINE( bugprone-macro-parentheses ) -# define optional_ref_qual & -# define optional_refref_qual && -#else -# define optional_ref_qual /*&*/ -# define optional_refref_qual /*&&*/ -#endif - -// additional includes: - -#if optional_CONFIG_NO_EXCEPTIONS -// already included: -#else -# include -#endif - -#if optional_CPP11_OR_GREATER -# include -#endif - -#if optional_HAVE( INITIALIZER_LIST ) -# include -#endif - -#if optional_HAVE( TYPE_TRAITS ) -# include -#elif optional_HAVE( TR1_TYPE_TRAITS ) -# include -#endif - -// Method enabling - -#if optional_CPP11_OR_GREATER - -#define optional_REQUIRES_0(...) \ - template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > - -#define optional_REQUIRES_T(...) \ - , typename std::enable_if< (__VA_ARGS__), int >::type = 0 - -#define optional_REQUIRES_R(R, ...) \ - typename std::enable_if< (__VA_ARGS__), R>::type - -#define optional_REQUIRES_A(...) \ - , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr - -#endif - -// -// optional: -// - -namespace nonstd { namespace optional_lite { - -namespace std11 { - -template< class T, T v > struct integral_constant { enum { value = v }; }; -template< bool B > struct bool_constant : integral_constant{}; - -typedef bool_constant< true > true_type; -typedef bool_constant< false > false_type; - -#if optional_CPP11_OR_GREATER - using std::move; -#else - template< typename T > T & move( T & t ) { return t; } -#endif - -#if optional_HAVE( CONDITIONAL ) - using std::conditional; -#else - template< bool B, typename T, typename F > struct conditional { typedef T type; }; - template< typename T, typename F > struct conditional { typedef F type; }; -#endif // optional_HAVE_CONDITIONAL - -#if optional_HAVE( IS_ASSIGNABLE ) - using std::is_assignable; -#else - template< class T, class U > struct is_assignable : std11::true_type{}; -#endif - -#if optional_HAVE( IS_MOVE_CONSTRUCTIBLE ) - using std::is_move_constructible; -#else - template< class T > struct is_move_constructible : std11::true_type{}; -#endif - -#if optional_HAVE( IS_NOTHROW_MOVE_ASSIGNABLE ) - using std::is_nothrow_move_assignable; -#else - template< class T > struct is_nothrow_move_assignable : std11::true_type{}; -#endif - -#if optional_HAVE( IS_NOTHROW_MOVE_CONSTRUCTIBLE ) - using std::is_nothrow_move_constructible; -#else - template< class T > struct is_nothrow_move_constructible : std11::true_type{}; -#endif - -#if optional_HAVE( IS_TRIVIALLY_COPY_CONSTRUCTIBLE ) - using std::is_trivially_copy_constructible; -#else - template< class T > struct is_trivially_copy_constructible : std11::true_type{}; -#endif - -#if optional_HAVE( IS_TRIVIALLY_MOVE_CONSTRUCTIBLE ) - using std::is_trivially_move_constructible; -#else - template< class T > struct is_trivially_move_constructible : std11::true_type{}; -#endif - -} // namespace std11 - -#if optional_CPP11_OR_GREATER - -/// type traits C++17: - -namespace std17 { - -#if optional_CPP17_OR_GREATER - -using std::is_swappable; -using std::is_nothrow_swappable; - -#elif optional_CPP11_OR_GREATER - -namespace detail { - -using std::swap; - -struct is_swappable -{ - template< typename T, typename = decltype( swap( std::declval(), std::declval() ) ) > - static std11::true_type test( int /*unused*/ ); - - template< typename > - static std11::false_type test(...); -}; - -struct is_nothrow_swappable -{ - // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): - - template< typename T > - static constexpr bool satisfies() - { - return noexcept( swap( std::declval(), std::declval() ) ); - } - - template< typename T > - static auto test( int /*unused*/ ) -> std11::integral_constant()>{} - - template< typename > - static auto test(...) -> std11::false_type; -}; - -} // namespace detail - -// is [nothow] swappable: - -template< typename T > -struct is_swappable : decltype( detail::is_swappable::test(0) ){}; - -template< typename T > -struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test(0) ){}; - -#endif // optional_CPP17_OR_GREATER - -} // namespace std17 - -/// type traits C++20: - -namespace std20 { - -template< typename T > -struct remove_cvref -{ - typedef typename std::remove_cv< typename std::remove_reference::type >::type type; -}; - -} // namespace std20 - -#endif // optional_CPP11_OR_GREATER - -/// class optional - -template< typename T > -class optional; - -namespace detail { - -// C++11 emulation: - -struct nulltype{}; - -template< typename Head, typename Tail > -struct typelist -{ - typedef Head head; - typedef Tail tail; -}; - -#if optional_CONFIG_MAX_ALIGN_HACK - -// Max align, use most restricted type for alignment: - -#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) -#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) -#define optional_UNIQUE3( name, line ) name ## line - -#define optional_ALIGN_TYPE( type ) \ - type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) - -template< typename T > -struct struct_t { T _; }; - -union max_align_t -{ - optional_ALIGN_TYPE( char ); - optional_ALIGN_TYPE( short int ); - optional_ALIGN_TYPE( int ); - optional_ALIGN_TYPE( long int ); - optional_ALIGN_TYPE( float ); - optional_ALIGN_TYPE( double ); - optional_ALIGN_TYPE( long double ); - optional_ALIGN_TYPE( char * ); - optional_ALIGN_TYPE( short int * ); - optional_ALIGN_TYPE( int * ); - optional_ALIGN_TYPE( long int * ); - optional_ALIGN_TYPE( float * ); - optional_ALIGN_TYPE( double * ); - optional_ALIGN_TYPE( long double * ); - optional_ALIGN_TYPE( void * ); - -#ifdef HAVE_LONG_LONG - optional_ALIGN_TYPE( long long ); -#endif - - struct Unknown; - - Unknown ( * optional_UNIQUE(_) )( Unknown ); - Unknown * Unknown::* optional_UNIQUE(_); - Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); - - struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); - struct_t< Unknown * Unknown::* > optional_UNIQUE(_); - struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); -}; - -#undef optional_UNIQUE -#undef optional_UNIQUE2 -#undef optional_UNIQUE3 - -#undef optional_ALIGN_TYPE - -#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK - -// Use user-specified type for alignment: - -#define optional_ALIGN_AS( unused ) \ - optional_CONFIG_ALIGN_AS - -#else // optional_CONFIG_MAX_ALIGN_HACK - -// Determine POD type to use for alignment: - -#define optional_ALIGN_AS( to_align ) \ - typename type_of_size< alignment_types, alignment_of< to_align >::value >::type - -template< typename T > -struct alignment_of; - -template< typename T > -struct alignment_of_hack -{ - char c; - T t; - alignment_of_hack(); -}; - -template< size_t A, size_t S > -struct alignment_logic -{ - enum { value = A < S ? A : S }; -}; - -template< typename T > -struct alignment_of -{ - enum { value = alignment_logic< - sizeof( alignment_of_hack ) - sizeof(T), sizeof(T) >::value }; -}; - -template< typename List, size_t N > -struct type_of_size -{ - typedef typename std11::conditional< - N == sizeof( typename List::head ), - typename List::head, - typename type_of_size::type >::type type; -}; - -template< size_t N > -struct type_of_size< nulltype, N > -{ - typedef optional_CONFIG_ALIGN_AS_FALLBACK type; -}; - -template< typename T> -struct struct_t { T _; }; - -#define optional_ALIGN_TYPE( type ) \ - typelist< type , typelist< struct_t< type > - -struct Unknown; - -typedef - optional_ALIGN_TYPE( char ), - optional_ALIGN_TYPE( short ), - optional_ALIGN_TYPE( int ), - optional_ALIGN_TYPE( long ), - optional_ALIGN_TYPE( float ), - optional_ALIGN_TYPE( double ), - optional_ALIGN_TYPE( long double ), - - optional_ALIGN_TYPE( char *), - optional_ALIGN_TYPE( short * ), - optional_ALIGN_TYPE( int * ), - optional_ALIGN_TYPE( long * ), - optional_ALIGN_TYPE( float * ), - optional_ALIGN_TYPE( double * ), - optional_ALIGN_TYPE( long double * ), - - optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ), - optional_ALIGN_TYPE( Unknown * Unknown::* ), - optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), - - nulltype - > > > > > > > > > > > > > > - > > > > > > > > > > > > > > - > > > > > > - alignment_types; - -#undef optional_ALIGN_TYPE - -#endif // optional_CONFIG_MAX_ALIGN_HACK - -/// C++03 constructed union to hold value. - -template< typename T > -union storage_t -{ -//private: -// template< typename > friend class optional; - - typedef T value_type; - - storage_t() optional_is_default - - explicit storage_t( value_type const & v ) - { - construct_value( v ); - } - - void construct_value( value_type const & v ) - { - ::new( value_ptr() ) value_type( v ); - } - -#if optional_CPP11_OR_GREATER - - explicit storage_t( value_type && v ) - { - construct_value( std::move( v ) ); - } - - void construct_value( value_type && v ) - { - ::new( value_ptr() ) value_type( std::move( v ) ); - } - - template< class... Args > - storage_t( nonstd_lite_in_place_t(T), Args&&... args ) - { - emplace( std::forward(args)... ); - } - - template< class... Args > - void emplace( Args&&... args ) - { - ::new( value_ptr() ) value_type( std::forward(args)... ); - } - - template< class U, class... Args > - void emplace( std::initializer_list il, Args&&... args ) - { - ::new( value_ptr() ) value_type( il, std::forward(args)... ); - } - -#endif - - void destruct_value() - { - value_ptr()->~T(); - } - - optional_nodiscard value_type const * value_ptr() const - { - return as(); - } - - value_type * value_ptr() - { - return as(); - } - - optional_nodiscard value_type const & value() const optional_ref_qual - { - return * value_ptr(); - } - - value_type & value() optional_ref_qual - { - return * value_ptr(); - } - -#if optional_HAVE( REF_QUALIFIER ) - - optional_nodiscard value_type const && value() const optional_refref_qual - { - return std::move( value() ); - } - - value_type && value() optional_refref_qual - { - return std::move( value() ); - } - -#endif - -#if optional_CPP11_OR_GREATER - - using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type; - aligned_storage_t data; - -#elif optional_CONFIG_MAX_ALIGN_HACK - - typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t; - - max_align_t hack; - aligned_storage_t data; - -#else - typedef optional_ALIGN_AS(value_type) align_as_type; - - typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; - aligned_storage_t data; - -# undef optional_ALIGN_AS - -#endif // optional_CONFIG_MAX_ALIGN_HACK - - optional_nodiscard void * ptr() optional_noexcept - { - return &data; - } - - optional_nodiscard void const * ptr() const optional_noexcept - { - return &data; - } - - template - optional_nodiscard U * as() - { - return reinterpret_cast( ptr() ); - } - - template - optional_nodiscard U const * as() const - { - return reinterpret_cast( ptr() ); - } -}; - -} // namespace detail - -/// disengaged state tag - -struct nullopt_t -{ - struct init{}; - explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {} -}; - -#if optional_HAVE( CONSTEXPR_11 ) -constexpr nullopt_t nullopt{ nullopt_t::init{} }; -#else -// extra parenthesis to prevent the most vexing parse: -const nullopt_t nullopt(( nullopt_t::init() )); -#endif - -/// optional access error - -#if ! optional_CONFIG_NO_EXCEPTIONS - -class bad_optional_access : public std::logic_error -{ -public: - explicit bad_optional_access() - : logic_error( "bad optional access" ) {} -}; - -#endif //optional_CONFIG_NO_EXCEPTIONS - -/// optional - -template< typename T> -class optional -{ -private: - template< typename > friend class optional; - - typedef void (optional::*safe_bool)() const; - -public: - typedef T value_type; - - // x.x.3.1, constructors - - // 1a - default construct - optional_constexpr optional() optional_noexcept - : has_value_( false ) - , contained() - {} - - // 1b - construct explicitly empty - // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) - optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept - : has_value_( false ) - , contained() - {} - - // 2 - copy-construct -#if optional_CPP11_OR_GREATER - // template< typename U = T - // optional_REQUIRES_T( - // std::is_copy_constructible::value - // || std11::is_trivially_copy_constructible::value - // ) - // > -#endif - optional_constexpr14 optional( optional const & other ) - : has_value_( other.has_value() ) - { - if ( other.has_value() ) - { - contained.construct_value( other.contained.value() ); - } - } - -#if optional_CPP11_OR_GREATER - - // 3 (C++11) - move-construct from optional - template< typename U = T - optional_REQUIRES_T( - std11::is_move_constructible::value - || std11::is_trivially_move_constructible::value - ) - > - optional_constexpr14 optional( optional && other ) - // NOLINTNEXTLINE( performance-noexcept-move-constructor ) - noexcept( std11::is_nothrow_move_constructible::value ) - : has_value_( other.has_value() ) - { - if ( other.has_value() ) - { - contained.construct_value( std::move( other.contained.value() ) ); - } - } - - // 4a (C++11) - explicit converting copy-construct from optional - template< typename U - optional_REQUIRES_T( - std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< optional & , T>::value - && !std::is_convertible< optional && , T>::value - && !std::is_convertible< optional const & , T>::value - && !std::is_convertible< optional const &&, T>::value - && !std::is_convertible< U const & , T>::value /*=> explicit */ - ) - > - explicit optional( optional const & other ) - : has_value_( other.has_value() ) - { - if ( other.has_value() ) - { - contained.construct_value( T{ other.contained.value() } ); - } - } -#endif // optional_CPP11_OR_GREATER - - // 4b (C++98 and later) - non-explicit converting copy-construct from optional - template< typename U -#if optional_CPP11_OR_GREATER - optional_REQUIRES_T( - std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< optional & , T>::value - && !std::is_convertible< optional && , T>::value - && !std::is_convertible< optional const & , T>::value - && !std::is_convertible< optional const &&, T>::value - && std::is_convertible< U const & , T>::value /*=> non-explicit */ - ) -#endif // optional_CPP11_OR_GREATER - > - // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) - /*non-explicit*/ optional( optional const & other ) - : has_value_( other.has_value() ) - { - if ( other.has_value() ) - { - contained.construct_value( other.contained.value() ); - } - } - -#if optional_CPP11_OR_GREATER - - // 5a (C++11) - explicit converting move-construct from optional - template< typename U - optional_REQUIRES_T( - std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< optional & , T>::value - && !std::is_convertible< optional && , T>::value - && !std::is_convertible< optional const & , T>::value - && !std::is_convertible< optional const &&, T>::value - && !std::is_convertible< U &&, T>::value /*=> explicit */ - ) - > - explicit optional( optional && other - ) - : has_value_( other.has_value() ) - { - if ( other.has_value() ) - { - contained.construct_value( T{ std::move( other.contained.value() ) } ); - } - } - - // 5a (C++11) - non-explicit converting move-construct from optional - template< typename U - optional_REQUIRES_T( - std::is_constructible::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< optional & , T>::value - && !std::is_convertible< optional && , T>::value - && !std::is_convertible< optional const & , T>::value - && !std::is_convertible< optional const &&, T>::value - && std::is_convertible< U &&, T>::value /*=> non-explicit */ - ) - > - // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) - /*non-explicit*/ optional( optional && other ) - : has_value_( other.has_value() ) - { - if ( other.has_value() ) - { - contained.construct_value( std::move( other.contained.value() ) ); - } - } - - // 6 (C++11) - in-place construct - template< typename... Args - optional_REQUIRES_T( - std::is_constructible::value - ) - > - optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args ) - : has_value_( true ) - , contained( T( std::forward(args)...) ) - {} - - // 7 (C++11) - in-place construct, initializer-list - template< typename U, typename... Args - optional_REQUIRES_T( - std::is_constructible&, Args&&...>::value - ) - > - optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list il, Args&&... args ) - : has_value_( true ) - , contained( T( il, std::forward(args)...) ) - {} - - // 8a (C++11) - explicit move construct from value - template< typename U = T - optional_REQUIRES_T( - std::is_constructible::value - && !std::is_same::type, nonstd_lite_in_place_t(U)>::value - && !std::is_same::type, optional>::value - && !std::is_convertible::value /*=> explicit */ - ) - > - optional_constexpr explicit optional( U && value ) - : has_value_( true ) - , contained( nonstd_lite_in_place(T), std::forward( value ) ) - {} - - // 8b (C++11) - non-explicit move construct from value - template< typename U = T - optional_REQUIRES_T( - std::is_constructible::value - && !std::is_same::type, nonstd_lite_in_place_t(U)>::value - && !std::is_same::type, optional>::value - && std::is_convertible::value /*=> non-explicit */ - ) - > - // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) - optional_constexpr /*non-explicit*/ optional( U && value ) - : has_value_( true ) - , contained( nonstd_lite_in_place(T), std::forward( value ) ) - {} - -#else // optional_CPP11_OR_GREATER - - // 8 (C++98) - optional( value_type const & value ) - : has_value_( true ) - , contained( value ) - {} - -#endif // optional_CPP11_OR_GREATER - - // x.x.3.2, destructor - - ~optional() - { - if ( has_value() ) - { - contained.destruct_value(); - } - } - - // x.x.3.3, assignment - - // 1 (C++98and later) - assign explicitly empty - optional & operator=( nullopt_t /*unused*/) optional_noexcept - { - reset(); - return *this; - } - - // 2 (C++98and later) - copy-assign from optional -#if optional_CPP11_OR_GREATER - // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) - optional_REQUIRES_R( - optional &, - true -// std::is_copy_constructible::value -// && std::is_copy_assignable::value - ) - operator=( optional const & other ) - noexcept( - std11::is_nothrow_move_assignable::value - && std11::is_nothrow_move_constructible::value - ) -#else - optional & operator=( optional const & other ) -#endif - { - if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } - else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); } - else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; } - return *this; - } - -#if optional_CPP11_OR_GREATER - - // 3 (C++11) - move-assign from optional - // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) - optional_REQUIRES_R( - optional &, - true -// std11::is_move_constructible::value -// && std::is_move_assignable::value - ) - operator=( optional && other ) noexcept - { - if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } - else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); } - else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); } - return *this; - } - - // 4 (C++11) - move-assign from value - template< typename U = T > - // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) - optional_REQUIRES_R( - optional &, - std::is_constructible::value - && std11::is_assignable::value - && !std::is_same::type, nonstd_lite_in_place_t(U)>::value - && !std::is_same::type, optional>::value - && !(std::is_scalar::value && std::is_same::type>::value) - ) - operator=( U && value ) - { - if ( has_value() ) - { - contained.value() = std::forward( value ); - } - else - { - initialize( T( std::forward( value ) ) ); - } - return *this; - } - -#else // optional_CPP11_OR_GREATER - - // 4 (C++98) - copy-assign from value - template< typename U /*= T*/ > - optional & operator=( U const & value ) - { - if ( has_value() ) contained.value() = value; - else initialize( T( value ) ); - return *this; - } - -#endif // optional_CPP11_OR_GREATER - - // 5 (C++98 and later) - converting copy-assign from optional - template< typename U > -#if optional_CPP11_OR_GREATER - // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) - optional_REQUIRES_R( - optional&, - std::is_constructible< T , U const &>::value - && std11::is_assignable< T&, U const &>::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< optional & , T>::value - && !std::is_convertible< optional && , T>::value - && !std::is_convertible< optional const & , T>::value - && !std::is_convertible< optional const &&, T>::value - && !std11::is_assignable< T&, optional & >::value - && !std11::is_assignable< T&, optional && >::value - && !std11::is_assignable< T&, optional const & >::value - && !std11::is_assignable< T&, optional const && >::value - ) -#else - optional& -#endif // optional_CPP11_OR_GREATER - operator=( optional const & other ) - { - return *this = optional( other ); - } - -#if optional_CPP11_OR_GREATER - - // 6 (C++11) - converting move-assign from optional - template< typename U > - // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) - optional_REQUIRES_R( - optional&, - std::is_constructible< T , U>::value - && std11::is_assignable< T&, U>::value - && !std::is_constructible & >::value - && !std::is_constructible && >::value - && !std::is_constructible const & >::value - && !std::is_constructible const && >::value - && !std::is_convertible< optional & , T>::value - && !std::is_convertible< optional && , T>::value - && !std::is_convertible< optional const & , T>::value - && !std::is_convertible< optional const &&, T>::value - && !std11::is_assignable< T&, optional & >::value - && !std11::is_assignable< T&, optional && >::value - && !std11::is_assignable< T&, optional const & >::value - && !std11::is_assignable< T&, optional const && >::value - ) - operator=( optional && other ) - { - return *this = optional( std::move( other ) ); - } - - // 7 (C++11) - emplace - template< typename... Args - optional_REQUIRES_T( - std::is_constructible::value - ) - > - T& emplace( Args&&... args ) - { - *this = nullopt; - contained.emplace( std::forward(args)... ); - has_value_ = true; - return contained.value(); - } - - // 8 (C++11) - emplace, initializer-list - template< typename U, typename... Args - optional_REQUIRES_T( - std::is_constructible&, Args&&...>::value - ) - > - T& emplace( std::initializer_list il, Args&&... args ) - { - *this = nullopt; - contained.emplace( il, std::forward(args)... ); - has_value_ = true; - return contained.value(); - } - -#endif // optional_CPP11_OR_GREATER - - // x.x.3.4, swap - - void swap( optional & other ) -#if optional_CPP11_OR_GREATER - noexcept( - std11::is_nothrow_move_constructible::value - && std17::is_nothrow_swappable::value - ) -#endif - { - using std::swap; - if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); } - else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); } - else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); } - } - - // x.x.3.5, observers - - optional_constexpr value_type const * operator ->() const - { - return assert( has_value() ), - contained.value_ptr(); - } - - optional_constexpr14 value_type * operator ->() - { - return assert( has_value() ), - contained.value_ptr(); - } - - optional_constexpr value_type const & operator *() const optional_ref_qual - { - return assert( has_value() ), - contained.value(); - } - - optional_constexpr14 value_type & operator *() optional_ref_qual - { - return assert( has_value() ), - contained.value(); - } - -#if optional_HAVE( REF_QUALIFIER ) - - optional_constexpr value_type const && operator *() const optional_refref_qual - { - return std::move( **this ); - } - - optional_constexpr14 value_type && operator *() optional_refref_qual - { - return std::move( **this ); - } - -#endif - -#if optional_CPP11_OR_GREATER - optional_constexpr explicit operator bool() const optional_noexcept - { - return has_value(); - } -#else - optional_constexpr operator safe_bool() const optional_noexcept - { - return has_value() ? &optional::this_type_does_not_support_comparisons : 0; - } -#endif - - // NOLINTNEXTLINE( modernize-use-nodiscard ) - /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept - { - return has_value_; - } - - // NOLINTNEXTLINE( modernize-use-nodiscard ) - /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual - { -#if optional_CONFIG_NO_EXCEPTIONS - assert( has_value() ); -#else - if ( ! has_value() ) - { - throw bad_optional_access(); - } -#endif - return contained.value(); - } - - optional_constexpr14 value_type & value() optional_ref_qual - { -#if optional_CONFIG_NO_EXCEPTIONS - assert( has_value() ); -#else - if ( ! has_value() ) - { - throw bad_optional_access(); - } -#endif - return contained.value(); - } - -#if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) - - // NOLINTNEXTLINE( modernize-use-nodiscard ) - /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual - { - return std::move( value() ); - } - - optional_constexpr14 value_type && value() optional_refref_qual - { - return std::move( value() ); - } - -#endif - -#if optional_HAVE( REF_QUALIFIER ) - - template< typename U > - optional_constexpr value_type value_or( U && v ) const optional_ref_qual - { - return has_value() ? contained.value() : static_cast(std::forward( v ) ); - } - - template< typename U > - optional_constexpr14 value_type value_or( U && v ) optional_refref_qual - { -#if optional_COMPILER_CLANG_VERSION - return has_value() ? /*std::move*/( contained.value() ) : static_cast(std::forward( v ) ); -#else - return has_value() ? std::move( contained.value() ) : static_cast(std::forward( v ) ); -#endif - } - -#else - - template< typename U > - optional_constexpr value_type value_or( U const & v ) const - { - return has_value() ? contained.value() : static_cast( v ); - } - -#endif // optional_CPP11_OR_GREATER - - // x.x.3.6, modifiers - - void reset() optional_noexcept - { - if ( has_value() ) - { - contained.destruct_value(); - } - - has_value_ = false; - } - - template - auto map(F func) -> optionalvalue()))>; - -private: - void this_type_does_not_support_comparisons() const {} - - template< typename V > - void initialize( V const & value ) - { - assert( ! has_value() ); - contained.construct_value( value ); - has_value_ = true; - } - -#if optional_CPP11_OR_GREATER - template< typename V > - void initialize( V && value ) - { - assert( ! has_value() ); - contained.construct_value( std::move( value ) ); - has_value_ = true; - } - -#endif - -private: - bool has_value_; - detail::storage_t< value_type > contained; - -}; - -// Relational operators - -template< typename T, typename U > -inline optional_constexpr bool operator==( optional const & x, optional const & y ) -{ - return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; -} - -template< typename T, typename U > -inline optional_constexpr bool operator!=( optional const & x, optional const & y ) -{ - return !(x == y); -} - -template< typename T, typename U > -inline optional_constexpr bool operator<( optional const & x, optional const & y ) -{ - return (!y) ? false : (!x) ? true : *x < *y; -} - -template< typename T, typename U > -inline optional_constexpr bool operator>( optional const & x, optional const & y ) -{ - return (y < x); -} - -template< typename T, typename U > -inline optional_constexpr bool operator<=( optional const & x, optional const & y ) -{ - return !(y < x); -} - -template< typename T, typename U > -inline optional_constexpr bool operator>=( optional const & x, optional const & y ) -{ - return !(x < y); -} - -// Comparison with nullopt - -template< typename T > -inline optional_constexpr bool operator==( optional const & x, nullopt_t /*unused*/ ) optional_noexcept -{ - return (!x); -} - -template< typename T > -inline optional_constexpr bool operator==( nullopt_t /*unused*/, optional const & x ) optional_noexcept -{ - return (!x); -} - -template< typename T > -inline optional_constexpr bool operator!=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept -{ - return bool(x); -} - -template< typename T > -inline optional_constexpr bool operator!=( nullopt_t /*unused*/, optional const & x ) optional_noexcept -{ - return bool(x); -} - -template< typename T > -inline optional_constexpr bool operator<( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept -{ - return false; -} - -template< typename T > -inline optional_constexpr bool operator<( nullopt_t /*unused*/, optional const & x ) optional_noexcept -{ - return bool(x); -} - -template< typename T > -inline optional_constexpr bool operator<=( optional const & x, nullopt_t /*unused*/ ) optional_noexcept -{ - return (!x); -} - -template< typename T > -inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept -{ - return true; -} - -template< typename T > -inline optional_constexpr bool operator>( optional const & x, nullopt_t /*unused*/ ) optional_noexcept -{ - return bool(x); -} - -template< typename T > -inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional const & /*unused*/ ) optional_noexcept -{ - return false; -} - -template< typename T > -inline optional_constexpr bool operator>=( optional const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept -{ - return true; -} - -template< typename T > -inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional const & x ) optional_noexcept -{ - return (!x); -} - -// Comparison with T - -template< typename T, typename U > -inline optional_constexpr bool operator==( optional const & x, U const & v ) -{ - return bool(x) ? *x == v : false; -} - -template< typename T, typename U > -inline optional_constexpr bool operator==( U const & v, optional const & x ) -{ - return bool(x) ? v == *x : false; -} - -template< typename T, typename U > -inline optional_constexpr bool operator!=( optional const & x, U const & v ) -{ - return bool(x) ? *x != v : true; -} - -template< typename T, typename U > -inline optional_constexpr bool operator!=( U const & v, optional const & x ) -{ - return bool(x) ? v != *x : true; -} - -template< typename T, typename U > -inline optional_constexpr bool operator<( optional const & x, U const & v ) -{ - return bool(x) ? *x < v : true; -} - -template< typename T, typename U > -inline optional_constexpr bool operator<( U const & v, optional const & x ) -{ - return bool(x) ? v < *x : false; -} - -template< typename T, typename U > -inline optional_constexpr bool operator<=( optional const & x, U const & v ) -{ - return bool(x) ? *x <= v : true; -} - -template< typename T, typename U > -inline optional_constexpr bool operator<=( U const & v, optional const & x ) -{ - return bool(x) ? v <= *x : false; -} - -template< typename T, typename U > -inline optional_constexpr bool operator>( optional const & x, U const & v ) -{ - return bool(x) ? *x > v : false; -} - -template< typename T, typename U > -inline optional_constexpr bool operator>( U const & v, optional const & x ) -{ - return bool(x) ? v > *x : true; -} - -template< typename T, typename U > -inline optional_constexpr bool operator>=( optional const & x, U const & v ) -{ - return bool(x) ? *x >= v : false; -} - -template< typename T, typename U > -inline optional_constexpr bool operator>=( U const & v, optional const & x ) -{ - return bool(x) ? v >= *x : true; -} - -// Specialized algorithms - -template< typename T -#if optional_CPP11_OR_GREATER - optional_REQUIRES_T( - std11::is_move_constructible::value - && std17::is_swappable::value ) -#endif -> -void swap( optional & x, optional & y ) -#if optional_CPP11_OR_GREATER - noexcept( noexcept( x.swap(y) ) ) -#endif -{ - x.swap( y ); -} - -#if optional_CPP11_OR_GREATER - -template< typename T > -optional_constexpr optional< typename std::decay::type > make_optional( T && value ) -{ - return optional< typename std::decay::type >( std::forward( value ) ); -} - -template< typename T, typename...Args > -optional_constexpr optional make_optional( Args&&... args ) -{ - return optional( nonstd_lite_in_place(T), std::forward(args)...); -} - -template< typename T, typename U, typename... Args > -optional_constexpr optional make_optional( std::initializer_list il, Args&&... args ) -{ - return optional( nonstd_lite_in_place(T), il, std::forward(args)...); -} - -#else - -template< typename T > -optional make_optional( T const & value ) -{ - return optional( value ); -} - -#endif // optional_CPP11_OR_GREATER - -template -template -auto optional::map(F func) -> optionalvalue()))> -{ - if (this->has_value()) { - return make_optional(func(this->value())); - } - - return nullopt; -} - -} // namespace optional_lite - -using optional_lite::optional; -using optional_lite::nullopt_t; -using optional_lite::nullopt; - -#if ! optional_CONFIG_NO_EXCEPTIONS -using optional_lite::bad_optional_access; -#endif - -using optional_lite::make_optional; - -} // namespace nonstd - -#if optional_CPP11_OR_GREATER - -// specialize the std::hash algorithm: - -namespace std { - -template< class T > -struct hash< nonstd::optional > -{ -public: - std::size_t operator()( nonstd::optional const & v ) const optional_noexcept - { - return bool( v ) ? std::hash{}( *v ) : 0; - } -}; - -} //namespace std - -#endif // optional_CPP11_OR_GREATER - -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#elif defined(_MSC_VER ) -# pragma warning( pop ) -#endif - -#endif // optional_USES_STD_OPTIONAL - -#endif // NONSTD_OPTIONAL_LITE_HPP diff --git a/src/pcrepp/pcre2pp.hh b/src/pcrepp/pcre2pp.hh index ae39871b..8c224ae9 100644 --- a/src/pcrepp/pcre2pp.hh +++ b/src/pcrepp/pcre2pp.hh @@ -78,23 +78,23 @@ public: this->md_input.i_string.sf_end); } - nonstd::optional operator[](size_t index) const + std::optional operator[](size_t index) const { if (index >= this->md_capture_end) { - return nonstd::nullopt; + return std::nullopt; } auto start = this->md_ovector[(index * 2)]; auto stop = this->md_ovector[(index * 2) + 1]; if (start == PCRE2_UNSET || stop == PCRE2_UNSET) { - return nonstd::nullopt; + return std::nullopt; } return this->md_input.i_string.sub_range(start, stop); } template - nonstd::optional operator[](const T (&name)[N]) const; + std::optional operator[](const T (&name)[N]) const; size_t get_count() const { return this->md_capture_end; } @@ -141,14 +141,14 @@ public: public: using variant::variant; - nonstd::optional ignore_error() + std::optional ignore_error() { return this->match( - [](found fo) { return nonstd::make_optional(fo); }, - [](not_found) { return nonstd::nullopt; }, + [](found fo) { return std::make_optional(fo); }, + [](not_found) { return std::nullopt; }, [](error err) { handle_error(err); - return nonstd::nullopt; + return std::nullopt; }); } @@ -325,7 +325,7 @@ private: }; template -nonstd::optional +std::optional match_data::operator[](const T (&name)[N]) const { auto index = pcre2_substring_number_from_name( diff --git a/src/piper.looper.cc b/src/piper.looper.cc index 91cc19fa..ffc667fd 100644 --- a/src/piper.looper.cc +++ b/src/piper.looper.cc @@ -28,30 +28,32 @@ */ #include +#include #include "piper.looper.hh" #include #include +#include "ArenaAlloc/arenaalloc.h" +#include "base/date_time_scanner.hh" #include "base/fs_util.hh" #include "base/injector.hh" #include "base/time_util.hh" #include "config.h" #include "hasher.hh" #include "line_buffer.hh" +#include "lnav_config_fwd.hh" #include "pcrepp/pcre2pp.hh" #include "piper.looper.cfg.hh" +#include "robin_hood/robin_hood.h" using namespace std::chrono_literals; static ssize_t -write_timestamp(int fd, log_level_t level, off_t woff) +write_line_meta(int fd, struct timeval& tv, log_level_t level, off_t woff) { char time_str[64]; - struct timeval tv; - - gettimeofday(&tv, nullptr); auto fmt_res = fmt::format_to_n(time_str, sizeof(time_str), FMT_STRING("{: 12}.{:06}:{};"), @@ -67,17 +69,84 @@ extern char** environ; namespace lnav { namespace piper { +class piper_config_listener : public lnav_config_listener { +public: + piper_config_listener() : lnav_config_listener(__FILE__) {} + + void reload_config(lnav_config_listener::error_reporter& reporter) override + { + static const auto KNOWN_CAPTURES + = std::unordered_set>{ + string_fragment::from_const("mux_id"), + string_fragment::from_const("timestamp"), + string_fragment::from_const("body"), + }; + + auto* cfg = injector::get(); + + for (auto& demux_pair : cfg->c_demux_definitions) { + auto pat = demux_pair.second.dd_pattern.pp_value; + auto& dd = demux_pair.second; + + log_info("checking demux definition: %s", demux_pair.first.c_str()); + dd.dd_muxid_capture_index = pat->name_index("mux_id"); + + if (dd.dd_muxid_capture_index < 0) { + auto um = lnav::console::user_message::error( + "mux_id not found in pattern"); + + reporter(&dd.dd_pattern, um); + continue; + } + + dd.dd_body_capture_index = pat->name_index("body"); + if (dd.dd_body_capture_index < 0) { + auto um = lnav::console::user_message::error( + "body not found in pattern"); + + reporter(&dd.dd_pattern, um); + continue; + } + dd.dd_timestamp_capture_index = pat->name_index("timestamp"); + + for (const auto& ncap : pat->get_named_captures()) { + if (KNOWN_CAPTURES.count(ncap.get_name())) { + continue; + } + + dd.dd_meta_capture_indexes[ncap.get_name().to_string()] + = ncap.get_index(); + } + + dd.dd_enabled = true; + } + } +}; + +piper_config_listener _PIPER_LISTENER; + const json_path_container header_env_handlers = { yajlpp::pattern_property_handler("(?.*)") .with_synopsis("") .for_field(&lnav::piper::header::h_env), }; +const json_path_container header_demux_handlers = { + yajlpp::pattern_property_handler("(?.*)") + .with_synopsis("") + .for_field(&lnav::piper::header::h_demux_meta), +}; + const typed_json_path_container header_handlers = { yajlpp::property_handler("name").for_field(&lnav::piper::header::h_name), + yajlpp::property_handler("timezone") + .for_field(&lnav::piper::header::h_timezone), yajlpp::property_handler("ctime").for_field(&lnav::piper::header::h_ctime), yajlpp::property_handler("cwd").for_field(&lnav::piper::header::h_cwd), yajlpp::property_handler("env").with_children(header_env_handlers), + yajlpp::property_handler("demux_meta").with_children(header_demux_handlers), }; static std::map @@ -105,10 +174,13 @@ environ_to_map() return retval; } -looper::looper(std::string name, auto_fd stdout_fd, auto_fd stderr_fd) +looper::looper(std::string name, + auto_fd stdout_fd, + auto_fd stderr_fd, + options opts) : l_name(std::move(name)), l_cwd(ghc::filesystem::current_path().string()), l_env(environ_to_map()), l_stdout(std::move(stdout_fd)), - l_stderr(std::move(stderr_fd)) + l_stderr(std::move(stderr_fd)), l_options(opts) { size_t count = 0; do { @@ -140,6 +212,9 @@ void looper::loop() { static const auto FORCE_MTIME_UPDATE_DURATION = 8h; + static const auto DEFAULT_ID = string_fragment{}; + static const auto OUT_OF_FRAME_ID + = string_fragment::from_const("_out_of_frame_"); const auto& cfg = injector::get(); struct pollfd pfd[2]; @@ -157,9 +232,25 @@ looper::loop() this->pfd->revents = 0; } } captured_fds[2]; - off_t woff = 0, last_woff = 0; - auto_fd outfd; + struct out_state { + auto_fd os_fd; + off_t os_woff{0}; + off_t os_last_woff{0}; + std::string os_hash_id; + }; + robin_hood::unordered_map> + outfds; size_t rotate_count = 0; + std::optional curr_demux_def; + auto md = lnav::pcre2pp::match_data::unitialized(); + ArenaAlloc::Alloc sf_allocator{64 * 1024}; + bool demux_attempted = false; + date_time_scanner dts; + struct timeval line_tv; + struct exttm line_tm; log_info("starting loop to capture: %s (%d %d)", this->l_name.c_str(), @@ -176,47 +267,60 @@ looper::loop() do { static const auto TIMEOUT = std::chrono::duration_cast(1s).count(); + static const auto FILE_TIMEOUT = (30ms).count(); + auto poll_timeout = TIMEOUT; size_t used_pfds = 0; + size_t file_count = 0; for (auto& cap : captured_fds) { - if (cap.lb.get_fd() != -1 && cap.lb.is_pipe() - && !cap.lb.is_pipe_closed()) - { + cap.pfd = nullptr; + if (cap.lb.get_fd() == -1) { + continue; + } + + if (!cap.lb.is_pipe()) { + file_count += 1; + poll_timeout = FILE_TIMEOUT; + } else if (!cap.lb.is_pipe_closed()) { cap.pfd = &pfd[used_pfds]; used_pfds += 1; cap.reset_pfd(); - } else { - cap.pfd = nullptr; } } - if (used_pfds == 0) { + if (used_pfds == 0 && file_count == 0) { log_info("inputs consumed, breaking loop: %s", this->l_name.c_str()); this->l_looping = false; break; } - auto poll_rc = poll(pfd, used_pfds, TIMEOUT); + auto poll_rc = poll(pfd, used_pfds, poll_timeout); if (poll_rc == 0) { // update the timestamp to keep the file alive from any // cleanup processes - if (outfd.has_value()) { + for (const auto& outfd_pair : outfds) { auto now = std::chrono::system_clock::now(); if ((now - last_write) >= FORCE_MTIME_UPDATE_DURATION) { last_write = now; - log_perror(futimes(outfd.get(), nullptr)); + log_perror(futimes(outfd_pair.second.os_fd.get(), nullptr)); } } - continue; + if (file_count == 0) { + continue; + } } else { last_write = std::chrono::system_clock::now(); } for (auto& cap : captured_fds) { + if (cap.lb.get_fd() == -1) { + continue; + } while (this->l_looping) { - if (cap.pfd == nullptr - || !(cap.pfd->revents & (POLLIN | POLLHUP))) + if (file_count == 0 + && (cap.pfd == nullptr + || !(cap.pfd->revents & (POLLIN | POLLHUP)))) { break; } @@ -237,7 +341,8 @@ looper::loop() } else if (read_rc == 0) { this->l_looping = false; } else { - auto rc = write(outfd.get(), buffer, read_rc); + auto rc = write( + outfds[DEFAULT_ID].os_fd.get(), buffer, read_rc); if (rc != read_rc) { log_error( "failed to write to capture file: %s -- %s", @@ -294,12 +399,14 @@ looper::loop() break; } - outfd = create_res.unwrap(); + outfds[DEFAULT_ID].os_fd = create_res.unwrap(); auto header_avail = cap.lb.get_available(); auto read_res = cap.lb.read_range(header_avail); if (read_res.isOk()) { auto sbr = read_res.unwrap(); - write(outfd.get(), sbr.get_data(), sbr.length()); + write(outfds[DEFAULT_ID].os_fd.get(), + sbr.get_data(), + sbr.length()); } else { log_error("failed to get header data: %s -- %s", this->l_name.c_str(), @@ -308,16 +415,20 @@ looper::loop() continue; } - if (li.li_partial && !cap.lb.is_pipe_closed()) { + if (li.li_file_range.empty()) { + if (!this->l_options.o_tail) { + log_info("%s: reached EOF, exiting", + this->l_name.c_str()); + this->l_looping = false; + } break; } - if (li.li_file_range.empty()) { + if (li.li_partial && !cap.lb.is_pipe_closed()) { break; } auto read_result = cap.lb.read_range(li.li_file_range); - if (read_result.isErr()) { log_error("failed to read next line: %s -- %s", this->l_name.c_str(), @@ -327,22 +438,85 @@ looper::loop() } auto sbr = read_result.unwrap(); + auto line_muxid_sf = DEFAULT_ID; + auto body_sf = sbr.to_string_fragment(); + auto ts_sf = string_fragment{}; + if (!curr_demux_def && !demux_attempted) { + log_trace("first input line: %s", + fmt::format(FMT_STRING("{:?}"), body_sf).c_str()); + + auto demux_id_opt = multiplex_id_for_line(body_sf); + if (demux_id_opt) { + curr_demux_def = cfg.c_demux_definitions + .find(demux_id_opt.value()) + ->second; + { + safe::WriteAccess di( + this->l_demux_id); + + di->assign(demux_id_opt.value()); + } + } + demux_attempted = true; + } + if (curr_demux_def + && curr_demux_def->dd_pattern.pp_value + ->capture_from(body_sf) + .into(md) + .matches() + .ignore_error()) + { + auto muxid_cap_opt + = md[curr_demux_def->dd_muxid_capture_index]; + auto body_cap_opt + = md[curr_demux_def->dd_body_capture_index]; + if (muxid_cap_opt && body_cap_opt) { + line_muxid_sf = muxid_cap_opt.value(); + body_sf = body_cap_opt.value(); + } else { + line_muxid_sf = OUT_OF_FRAME_ID; + } + if (curr_demux_def->dd_timestamp_capture_index >= 0) { + auto ts_cap_opt + = md[curr_demux_def->dd_timestamp_capture_index]; + if (ts_cap_opt) { + ts_sf = ts_cap_opt.value(); + } + } + } else if (curr_demux_def) { + line_muxid_sf = OUT_OF_FRAME_ID; + } - if (woff > last_woff && woff >= cfg.c_max_size) { + auto outfds_iter = outfds.find(line_muxid_sf); + if (outfds_iter == outfds.end()) { + line_muxid_sf = line_muxid_sf.to_owned(sf_allocator); + auto emp_res + = outfds.emplace(line_muxid_sf, out_state{auto_fd{-1}}); + outfds_iter = emp_res.first; + outfds_iter->second.os_hash_id + = hasher().update(line_muxid_sf).to_string(); + } + auto& os = outfds_iter->second; + if (os.os_woff > os.os_last_woff + && os.os_woff >= cfg.c_max_size) + { log_info( "capture file has reached max size, rotating: %s -- " "%lld", this->l_name.c_str(), - woff); - outfd.reset(); + os.os_woff); + os.os_fd.reset(); } - if (!outfd.has_value()) { + if (!os.os_fd.has_value()) { auto out_path = this->l_out_dir - / fmt::format(FMT_STRING("out.{}"), + / fmt::format(FMT_STRING("out.{}.{}"), + os.os_hash_id, rotate_count % cfg.c_rotations); - log_info("creating capturing file: %s -- %s", + log_info("creating capturing file: %s (mux_id: %.*s) -- %s", this->l_name.c_str(), + line_muxid_sf.length(), + line_muxid_sf.data(), out_path.c_str()); auto create_res = lnav::filesystem::create_file( out_path, O_WRONLY | O_CLOEXEC | O_TRUNC, 0600); @@ -353,7 +527,7 @@ looper::loop() break; } - outfd = create_res.unwrap(); + os.os_fd = create_res.unwrap(); rotate_count += 1; auto hdr = header{ @@ -362,41 +536,71 @@ looper::loop() this->l_cwd, this->l_env, }; + if (!line_muxid_sf.empty()) { + hdr.h_name = fmt::format( + FMT_STRING("{}/{}"), hdr.h_name, line_muxid_sf); + hdr.h_timezone = "UTC"; + + for (const auto& meta_cap : + curr_demux_def->dd_meta_capture_indexes) + { + auto mc_opt = md[meta_cap.second]; + if (!mc_opt) { + continue; + } + + hdr.h_demux_meta[meta_cap.first] + = mc_opt.value().to_string(); + } + } - woff = 0; + os.os_woff = 0; auto hdr_str = header_handlers.to_string(hdr); uint32_t meta_size = htonl(hdr_str.length()); auto prc = write( - outfd.get(), HEADER_MAGIC, sizeof(HEADER_MAGIC)); + os.os_fd.get(), HEADER_MAGIC, sizeof(HEADER_MAGIC)); if (prc < sizeof(HEADER_MAGIC)) { log_error("unable to write file header: %s -- %s", this->l_name.c_str(), strerror(errno)); break; } - woff += prc; - prc = write(outfd.get(), &meta_size, sizeof(meta_size)); + os.os_woff += prc; + prc = write(os.os_fd.get(), &meta_size, sizeof(meta_size)); if (prc < sizeof(meta_size)) { log_error("unable to write file header: %s -- %s", this->l_name.c_str(), strerror(errno)); break; } - woff += prc; - prc = write(outfd.get(), hdr_str.c_str(), hdr_str.size()); + os.os_woff += prc; + prc = write( + os.os_fd.get(), hdr_str.c_str(), hdr_str.size()); if (prc < hdr_str.size()) { log_error("unable to write file header: %s -- %s", this->l_name.c_str(), strerror(errno)); break; } - woff += prc; + os.os_woff += prc; } ssize_t wrc; - last_woff = woff; - wrc = write_timestamp(outfd.get(), cap.cf_level, woff); + os.os_last_woff = os.os_woff; + if (!ts_sf.empty() + && dts.scan(ts_sf.data(), + ts_sf.length(), + nullptr, + &line_tm, + line_tv, + false)) + { + } else { + gettimeofday(&line_tv, nullptr); + } + wrc = write_line_meta( + os.os_fd.get(), line_tv, cap.cf_level, os.os_woff); if (wrc == -1) { log_error("unable to write timestamp: %s -- %s", this->l_name.c_str(), @@ -404,12 +608,15 @@ looper::loop() this->l_looping = false; break; } - woff += wrc; + os.os_woff += wrc; /* Need to do pwrite here since the fd is used by the main * lnav process as well. */ - wrc = pwrite(outfd.get(), sbr.get_data(), sbr.length(), woff); + wrc = pwrite(os.os_fd.get(), + body_sf.data(), + body_sf.length(), + os.os_woff); if (wrc == -1) { log_error("unable to write captured data: %s -- %s", this->l_name.c_str(), @@ -417,13 +624,24 @@ looper::loop() this->l_looping = false; break; } - woff += wrc; + os.os_woff += wrc; + if (!body_sf.endswith("\n")) { + wrc = pwrite(os.os_fd.get(), "\n", 1, os.os_woff); + if (wrc == -1) { + log_error("unable to write captured data: %s -- %s", + this->l_name.c_str(), + strerror(errno)); + this->l_looping = false; + break; + } + os.os_woff += wrc; + } cap.last_range = li.li_file_range; if (li.li_partial && sbr.get_data()[sbr.length() - 1] != '\n' && (cap.last_range.next_offset() != cap.lb.get_file_size())) { - woff = last_woff; + os.os_woff = os.os_last_woff; } } } @@ -433,10 +651,13 @@ looper::loop() } Result, std::string> -create_looper(std::string name, auto_fd stdout_fd, auto_fd stderr_fd) +create_looper(std::string name, + auto_fd stdout_fd, + auto_fd stderr_fd, + options opts) { return Ok(handle(std::make_shared( - name, std::move(stdout_fd), std::move(stderr_fd)))); + name, std::move(stdout_fd), std::move(stderr_fd), opts))); } void diff --git a/src/piper.looper.cfg.hh b/src/piper.looper.cfg.hh index b9740281..b4703a3d 100644 --- a/src/piper.looper.cfg.hh +++ b/src/piper.looper.cfg.hh @@ -30,15 +30,32 @@ #ifndef piper_looper_cfg_hh #define piper_looper_cfg_hh +#include +#include + #include +#include "pcrepp/pcre2pp.hh" +#include "yajlpp/yajlpp_def.hh" + namespace lnav { namespace piper { +struct demux_def { + bool dd_enabled{false}; + factory_container dd_pattern; + int dd_timestamp_capture_index{-1}; + int dd_muxid_capture_index{-1}; + int dd_body_capture_index{-1}; + std::map dd_meta_capture_indexes; +}; + struct config { uint64_t c_max_size{10ULL * 1024ULL * 1024ULL}; uint32_t c_rotations{4}; std::chrono::seconds c_ttl{std::chrono::hours(48)}; + + std::map c_demux_definitions; }; } // namespace piper diff --git a/src/piper.looper.hh b/src/piper.looper.hh index fae45e03..e0f86836 100644 --- a/src/piper.looper.hh +++ b/src/piper.looper.hh @@ -38,6 +38,7 @@ #include "base/piper.file.hh" #include "base/result.h" #include "ghc/filesystem.hpp" +#include "safe/safe.h" #include "yajlpp/yajlpp_def.hh" namespace lnav { @@ -48,9 +49,24 @@ enum class state { finished, }; +using safe_demux_id = safe::Safe; + +struct options { + bool o_tail{true}; + + options& with_tail(bool v) + { + this->o_tail = v; + return *this; + } +}; + class looper { public: - looper(std::string name, auto_fd stdout_fd, auto_fd stderr_fd); + looper(std::string name, + auto_fd stdout_fd, + auto_fd stderr_fd, + options opts); ~looper(); @@ -63,6 +79,8 @@ public: return this->l_out_dir / "out.*"; } + std::string get_demux_id() const { return *this->l_demux_id.readAccess(); } + std::string get_url() const { return fmt::format(FMT_STRING("piper://{}"), @@ -97,8 +115,10 @@ private: ghc::filesystem::path l_out_dir; auto_fd l_stdout; auto_fd l_stderr; + options l_options; std::future l_future; std::atomic l_finished{0}; + safe_demux_id l_demux_id; }; template @@ -121,6 +141,8 @@ public: return this->h_looper->get_out_pattern(); } + std::string get_demux_id() const { return this->h_looper->get_demux_id(); } + std::string get_url() const { return this->h_looper->get_url(); } bool is_finished() const { return this->h_looper->is_finished(); } @@ -142,7 +164,8 @@ using running_handle = handle; Result, std::string> create_looper(std::string name, auto_fd stdout_fd, - auto_fd stderr_fd); + auto_fd stderr_fd, + options opts = {}); void cleanup(); diff --git a/src/plain_text_source.cc b/src/plain_text_source.cc index 608c6231..f7e4a909 100644 --- a/src/plain_text_source.cc +++ b/src/plain_text_source.cc @@ -251,7 +251,7 @@ plain_text_source::compute_longest_line() return retval; } -nonstd::optional +std::optional plain_text_source::line_for_offset(file_off_t off) const { struct cmper { @@ -267,24 +267,24 @@ plain_text_source::line_for_offset(file_off_t off) const }; if (this->tds_lines.empty()) { - return nonstd::nullopt; + return std::nullopt; } auto iter = std::lower_bound( this->tds_lines.begin(), this->tds_lines.end(), off, cmper{}); if (iter == this->tds_lines.end()) { if (this->tds_lines.back().contains_offset(off)) { - return nonstd::make_optional( + return std::make_optional( vis_line_t(std::distance(this->tds_lines.end() - 1, iter))); } - return nonstd::nullopt; + return std::nullopt; } if (!iter->contains_offset(off) && iter != this->tds_lines.begin()) { --iter; } - return nonstd::make_optional( + return std::make_optional( vis_line_t(std::distance(this->tds_lines.begin(), iter))); } @@ -391,10 +391,10 @@ plain_text_source::text_crumbs_for_line(int line, } } -nonstd::optional +std::optional plain_text_source::row_for_anchor(const std::string& id) { - nonstd::optional retval; + std::optional retval; if (this->tds_doc_sections.m_sections_root == nullptr) { return retval; @@ -464,10 +464,10 @@ plain_text_source::get_anchors() return retval; } -nonstd::optional +std::optional plain_text_source::anchor_for_row(vis_line_t vl) { - nonstd::optional retval; + std::optional retval; if (vl > this->tds_lines.size() || this->tds_doc_sections.m_sections_root == nullptr) @@ -481,7 +481,7 @@ plain_text_source::anchor_for_row(vis_line_t vl) tl.tl_offset, tl.tl_offset + tl.tl_value.al_string.length()); if (path_for_line.empty()) { - return nonstd::nullopt; + return std::nullopt; } if ((path_for_line.size() == 1 @@ -504,13 +504,13 @@ plain_text_source::anchor_for_row(vis_line_t vl) fmt::join(comps.begin(), comps.end(), "/")); } -nonstd::optional +std::optional plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) { if (vl > this->tds_lines.size() || this->tds_doc_sections.m_sections_root == nullptr) { - return nonstd::nullopt; + return std::nullopt; } const auto& tl = this->tds_lines[vl]; @@ -521,7 +521,7 @@ plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) if (path_for_line.empty()) { auto neighbors_res = md.m_sections_root->line_neighbors(vl); if (!neighbors_res) { - return nonstd::nullopt; + return std::nullopt; } switch (dir) { @@ -543,7 +543,7 @@ plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) break; } } - return nonstd::nullopt; + return std::nullopt; } auto last_key = path_for_line.back(); @@ -552,20 +552,20 @@ plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) auto parent_opt = lnav::document::hier_node::lookup_path( md.m_sections_root.get(), path_for_line); if (!parent_opt) { - return nonstd::nullopt; + return std::nullopt; } auto parent = parent_opt.value(); auto child_hn = parent->lookup_child(last_key); if (!child_hn) { // XXX "should not happen" - return nonstd::nullopt; + return std::nullopt; } auto neighbors_res = parent->child_neighbors( child_hn.value(), tl.tl_offset + tl.tl_value.al_string.length() + 1); if (!neighbors_res) { - return nonstd::nullopt; + return std::nullopt; } if (neighbors_res->cnr_previous && last_key.is()) { @@ -601,5 +601,5 @@ plain_text_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) } } - return nonstd::nullopt; + return std::nullopt; } diff --git a/src/plain_text_source.hh b/src/plain_text_source.hh index 5f395252..5a014e87 100644 --- a/src/plain_text_source.hh +++ b/src/plain_text_source.hh @@ -115,7 +115,7 @@ public: return *this; } - nonstd::optional get_location_history() override + std::optional get_location_history() override { return this; } @@ -123,16 +123,16 @@ public: void text_crumbs_for_line(int line, std::vector& crumbs) override; - nonstd::optional row_for_anchor(const std::string& id) override; - nonstd::optional anchor_for_row(vis_line_t vl) override; + std::optional row_for_anchor(const std::string& id) override; + std::optional anchor_for_row(vis_line_t vl) override; std::unordered_set get_anchors() override; - nonstd::optional adjacent_anchor(vis_line_t vl, + std::optional adjacent_anchor(vis_line_t vl, direction dir) override; protected: size_t compute_longest_line(); - nonstd::optional line_for_offset(file_off_t off) const; + std::optional line_for_offset(file_off_t off) const; std::vector tds_lines; text_format_t tds_text_format{text_format_t::TF_UNKNOWN}; diff --git a/src/pretty_printer.cc b/src/pretty_printer.cc index 0e9ec0e6..7c6e1967 100644 --- a/src/pretty_printer.cc +++ b/src/pretty_printer.cc @@ -267,7 +267,7 @@ pretty_printer::append_indent() bool pretty_printer::flush_values(bool start_on_depth) { - nonstd::optional last_key; + std::optional last_key; bool retval = false; while (!this->pp_values.empty()) { @@ -292,7 +292,7 @@ pretty_printer::flush_values(bool start_on_depth) this->pp_interval_state.back().is_start = static_cast(this->pp_stream.tellp()); } - last_key = nonstd::nullopt; + last_key = std::nullopt; } break; default: @@ -416,6 +416,6 @@ pretty_printer::append_child_node() }); } top_node->hn_children.emplace_back(std::move(new_node)); - ivstate.is_start = nonstd::nullopt; + ivstate.is_start = std::nullopt; ivstate.is_name.clear(); } diff --git a/src/pretty_printer.hh b/src/pretty_printer.hh index 495eb4eb..610f6c5c 100644 --- a/src/pretty_printer.hh +++ b/src/pretty_printer.hh @@ -40,7 +40,6 @@ #include "base/file_range.hh" #include "data_scanner.hh" #include "document.sections.hh" -#include "optional.hpp" class pretty_printer { public: @@ -112,7 +111,7 @@ private: void append_child_node(); struct interval_state { - nonstd::optional is_start; + std::optional is_start; std::string is_name; }; diff --git a/src/readline_callbacks.cc b/src/readline_callbacks.cc index 6a751c7d..e9b3c517 100644 --- a/src/readline_callbacks.cc +++ b/src/readline_callbacks.cc @@ -935,7 +935,7 @@ rl_callback_int(readline_curses* rc, bool is_alt) return false; } - nonstd::optional first_hit; + std::optional first_hit; if (is_alt) { first_hit = bm[&textview_curses::BM_SEARCH].prev( diff --git a/src/readline_curses.cc b/src/readline_curses.cc index 326b4534..d1dee6a4 100644 --- a/src/readline_curses.cc +++ b/src/readline_curses.cc @@ -101,7 +101,7 @@ std::set* readline_context::arg_possibilities; static std::string last_match_str; static bool last_match_str_valid; static bool arg_needs_shlex; -static nonstd::optional rewrite_line_start; +static std::optional rewrite_line_start; static std::string rc_local_suggestion; static void @@ -1006,7 +1006,7 @@ readline_curses::start() } rl_redisplay(); } - rewrite_line_start = nonstd::nullopt; + rewrite_line_start = std::nullopt; SpookyHash::Hash128(rl_line_buffer, rl_end, &h1, &h2); diff --git a/src/readline_highlighters.cc b/src/readline_highlighters.cc index 9fe84187..e4d38b49 100644 --- a/src/readline_highlighters.cc +++ b/src/readline_highlighters.cc @@ -100,7 +100,7 @@ find_matching_bracket( } } - nonstd::optional first_left; + std::optional first_left; depth = 0; @@ -315,7 +315,7 @@ readline_shlex_highlighter_int(attr_line_t& al, int x, line_range sub) { attr_line_builder alb(al); const auto& str = al.get_string(); - nonstd::optional quote_start; + std::optional quote_start; shlex lexer(string_fragment{al.al_string.data(), sub.lr_start, sub.lr_end}); bool done = false; @@ -355,7 +355,7 @@ readline_shlex_highlighter_int(attr_line_t& al, int x, line_range sub) line_range(quote_start.value(), sub.lr_start + token.tr_frag.sf_end), VC_ROLE.value(role_t::VCR_STRING)); - quote_start = nonstd::nullopt; + quote_start = std::nullopt; break; case shlex_token_t::variable_ref: case shlex_token_t::quoted_variable_ref: { @@ -438,7 +438,7 @@ readline_lnav_highlighter(attr_line_t& al, int x) attr_line_builder alb(al); size_t start = 0, lf_pos; - nonstd::optional section_start; + std::optional section_start; while ((lf_pos = al.get_string().find('\n', start)) != std::string::npos) { line_range line{(int) start, (int) lf_pos}; @@ -460,7 +460,7 @@ readline_lnav_highlighter(attr_line_t& al, int x) (int) section_start.value(), line.lr_start, }); - section_start = nonstd::nullopt; + section_start = std::nullopt; } alb.overlay_attr(line_range{find_res->f_all.sf_begin, line.lr_end}, VC_ROLE.value(role_t::VCR_COMMENT)); diff --git a/src/regex101.client.hh b/src/regex101.client.hh index 87476ed7..77a5c945 100644 --- a/src/regex101.client.hh +++ b/src/regex101.client.hh @@ -63,7 +63,7 @@ struct entry { std::string e_delimiter{"/"}; std::string e_flavor{"pcre"}; std::vector e_unit_tests; - nonstd::optional e_permalink_fragment; + std::optional e_permalink_fragment; bool operator==(const entry& rhs) const; bool operator!=(const entry& rhs) const; diff --git a/src/regexp_vtab.cc b/src/regexp_vtab.cc index d992ea95..30fcde5a 100644 --- a/src/regexp_vtab.cc +++ b/src/regexp_vtab.cc @@ -317,7 +317,7 @@ CREATE TABLE regexp_capture_into_json ( size_t c_match_index{0}; sqlite3_int64 c_rowid{0}; std::string c_flags_string; - nonstd::optional c_flags; + std::optional c_flags; cursor(sqlite3_vtab* vt) : base({vt}) {} @@ -480,7 +480,7 @@ rcjFilter(sqlite3_vtab_cursor* pVtabCursor, pCur->c_content.clear(); pCur->c_pattern.reset(); pCur->c_flags_string.clear(); - pCur->c_flags = nonstd::nullopt; + pCur->c_flags = std::nullopt; return SQLITE_OK; } @@ -503,7 +503,7 @@ rcjFilter(sqlite3_vtab_cursor* pVtabCursor, } pCur->c_flags_string.clear(); - pCur->c_flags = nonstd::nullopt; + pCur->c_flags = std::nullopt; if (argc == 3) { static const intern_string_t FLAGS_SRC = intern_string::lookup("flags"); const auto flags_json = from_sqlite()(argc, argv, 2); diff --git a/src/relative_time.cc b/src/relative_time.cc index 6024dc59..ee892276 100644 --- a/src/relative_time.cc +++ b/src/relative_time.cc @@ -983,7 +983,7 @@ relative_time::adjust(const exttm& tm) const return retval; } -nonstd::optional +std::optional relative_time::window_start(const struct exttm& tm) const { auto retval = tm; @@ -1009,7 +1009,7 @@ relative_time::window_start(const struct exttm& tm) const if (this->rt_field[RTF_YEARS].is_set) { if (this->rt_field[RTF_YEARS].value > tm.et_tm.tm_year) { - return nonstd::nullopt; + return std::nullopt; } retval.et_tm.tm_year = this->rt_field[RTF_YEARS].value; clear = true; @@ -1017,7 +1017,7 @@ relative_time::window_start(const struct exttm& tm) const if (this->rt_field[RTF_MONTHS].is_set) { if (this->rt_field[RTF_MONTHS].value > tm.et_tm.tm_mon) { - return nonstd::nullopt; + return std::nullopt; } retval.et_tm.tm_mon = this->rt_field[RTF_MONTHS].value; clear = true; @@ -1027,7 +1027,7 @@ relative_time::window_start(const struct exttm& tm) const if (this->rt_field[RTF_DAYS].is_set) { if (this->rt_field[RTF_DAYS].value > tm.et_tm.tm_mday) { - return nonstd::nullopt; + return std::nullopt; } retval.et_tm.tm_mday = this->rt_field[RTF_DAYS].value; clear = true; @@ -1040,14 +1040,14 @@ relative_time::window_start(const struct exttm& tm) const (token_t) (RTT_SUNDAY + tm.et_tm.tm_wday)); if (iter == this->rt_included_days.end()) { - return nonstd::nullopt; + return std::nullopt; } clear = true; } if (this->rt_field[RTF_HOURS].is_set) { if (this->rt_field[RTF_HOURS].value > tm.et_tm.tm_hour) { - return nonstd::nullopt; + return std::nullopt; } retval.et_tm.tm_hour = this->rt_field[RTF_HOURS].value; clear = true; @@ -1057,7 +1057,7 @@ relative_time::window_start(const struct exttm& tm) const if (this->rt_field[RTF_MINUTES].is_set) { if (this->rt_field[RTF_MINUTES].value > tm.et_tm.tm_min) { - return nonstd::nullopt; + return std::nullopt; } retval.et_tm.tm_min = this->rt_field[RTF_MINUTES].value; clear = true; @@ -1067,7 +1067,7 @@ relative_time::window_start(const struct exttm& tm) const if (this->rt_field[RTF_SECONDS].is_set) { if (this->rt_field[RTF_SECONDS].value > tm.et_tm.tm_sec) { - return nonstd::nullopt; + return std::nullopt; } retval.et_tm.tm_sec = this->rt_field[RTF_SECONDS].value; clear = true; @@ -1077,7 +1077,7 @@ relative_time::window_start(const struct exttm& tm) const if (this->rt_field[RTF_MICROSECONDS].is_set) { if (this->rt_field[RTF_MICROSECONDS].value > tm.et_nsec / 1000) { - return nonstd::nullopt; + return std::nullopt; } retval.et_nsec = this->rt_field[RTF_MICROSECONDS].value * 1000ULL; clear = true; @@ -1092,7 +1092,7 @@ relative_time::window_start(const struct exttm& tm) const .to_timeval(); if (tv < start_time || end_time < tv) { - return nonstd::nullopt; + return std::nullopt; } return retval; diff --git a/src/relative_time.hh b/src/relative_time.hh index 1310dd9a..310cad77 100644 --- a/src/relative_time.hh +++ b/src/relative_time.hh @@ -208,7 +208,7 @@ public: struct exttm adjust(const struct exttm& tm) const; - nonstd::optional window_start(const struct exttm& tm) const; + std::optional window_start(const struct exttm& tm) const; int64_t to_microseconds() const; diff --git a/src/root-config.json b/src/root-config.json index cc7e8c51..c7918fe2 100644 --- a/src/root-config.json +++ b/src/root-config.json @@ -23,6 +23,14 @@ "condition": ":log_body LIKE '%[context]%[/context]%'", "handler": "com.vmware.btresolver.py" } + }, + "demux": { + "container": { + "pattern": "^(?:\\x1b\\[\\d*K)?(?[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]*)\\s+\\| (?\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d{9}Z )?(?.*)" + }, + "recv-with-pod": { + "pattern": "^(?\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}(?:Z|[+\\-]\\d{2}:\\d{2})) source=[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]* (?.*) kubernetes_host=(?[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]*) kubernetes_pod_name=(?[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]*)" + } } }, "tuning": { diff --git a/src/safe/safe.h b/src/safe/safe.h index 2beab55b..999bad57 100644 --- a/src/safe/safe.h +++ b/src/safe/safe.h @@ -11,348 +11,357 @@ #pragma once +#include +#include + #include "accessmode.h" #include "defaulttypes.h" #include "mutableref.h" -#include -#include - #if __cplusplus >= 201703L -#define EXPLICIT_IF_CPP17 explicit -#define EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17 ReturnType +# define EXPLICIT_IF_CPP17 explicit +# define EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17 ReturnType #else -#define EXPLICIT_IF_CPP17 -#define EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17 +# define EXPLICIT_IF_CPP17 +# define EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17 #endif -namespace safe -{ - /** - * @brief Use this tag to default construct the mutex when constructing a - * Safe object. - */ - struct DefaultConstructMutex {}; - static constexpr DefaultConstructMutex default_construct_mutex; - - /** - * @brief Wraps a value together with a mutex. - * - * @tparam ValueType The type of the value to protect. - * @tparam MutexType The type of the mutex. - */ - template - class Safe - { - private: - /// Type ValueType with reference removed, if present - using RemoveRefValueType = typename std::remove_reference::type; - /// Type MutexType with reference removed, if present - using RemoveRefMutexType = typename std::remove_reference::type; - - /** - * @brief Manages a mutex and gives pointer-like access to a value - * object. - * - * @tparam LockType The type of the lock object that manages the - * mutex, example: std::lock_guard. - * @tparam Mode Determines the access mode of the Access - * object. Can be either AccessMode::ReadOnly or - * AccessMode::ReadWrite. - */ - template class LockType, AccessMode Mode> - class Access - { - // Make sure AccessMode is ReadOnly if a read-only lock is used - static_assert(!(AccessTraits>::IsReadOnly && Mode==AccessMode::ReadWrite), "Cannot have ReadWrite access mode with ReadOnly lock. Check the value of AccessTraits::IsReadOnly if it exists."); - - /// ValueType with const qualifier if AccessMode is ReadOnly. - using ConstIfReadOnlyValueType = typename std::conditional::type; - - public: - /// Pointer-to-const ValueType - using ConstPointerType = const ConstIfReadOnlyValueType*; - /// Pointer-to-const ValueType if Mode is ReadOnly, pointer to ValueType otherwise. - using PointerType = ConstIfReadOnlyValueType*; - /// Reference-to-const ValueType - using ConstReferenceType = const ConstIfReadOnlyValueType&; - /// Reference-to-const ValueType if Mode is ReadOnly, reference to ValueType otherwise. - using ReferenceType = ConstIfReadOnlyValueType&; - - /** - * @brief Construct an Access object from a possibly const - * reference to the value object and any additionnal argument - * needed to construct the Lock object. - * - * @tparam LockArgs Deduced from lockArgs. - * @param value Reference to the value. - * @param lockArgs Arguments needed to construct the lock object. - */ - template - EXPLICIT_IF_CPP17 - Access(ReferenceType value, MutexType& mutex, OtherLockArgs&&... otherLockArgs): - lock(mutex, std::forward(otherLockArgs)...), - m_value(value) - {} - - /** - * @brief Construct a read-only Access object from a const - * safe::Safe object and any additionnal argument needed to - * construct the Lock object. - * - * If needed, you can provide additionnal arguments to construct - * the lock object (such as std::adopt_lock). The mutex from the - * safe::Locakble object is already passed to the lock object's - * constructor though, you must not provide it. - * - * @tparam OtherLockArgs Deduced from otherLockArgs. - * @param safe The const Safe object to give protected access to. - * @param otherLockArgs Other arguments needed to construct the lock - * object. - */ - template - EXPLICIT_IF_CPP17 - Access(const Safe& safe, OtherLockArgs&&... otherLockArgs): - Access(safe.m_value, safe.m_mutex.get, std::forward(otherLockArgs)...) - {} - - /** - * @brief Construct a read-write Access object from a - * safe::Safe object and any additionnal argument needed to - * construct the Lock object. - * - * If needed, you can provide additionnal arguments to construct - * the lock object (such as std::adopt_lock). The mutex from the - * safe object is already passed to the lock object's constructor - * though, you must not provide it. - * - * @tparam OtherLockArgs Deduced from otherLockArgs. - * @param safe The Safe object to give protected access to. - * @param otherLockArgs Other arguments needed to construct the lock - * object. - */ - template - EXPLICIT_IF_CPP17 - Access(Safe& safe, OtherLockArgs&&... otherLockArgs): - Access(safe.m_value, safe.m_mutex.get, std::forward(otherLockArgs)...) - {} - - /** - * @brief Construct an Access object from another one. - * OtherLockType must implement release() like std::unique_lock - * does. - * - * @tparam OtherLockType Deduced from otherAccess. - * @tparam OtherMode Deduced from otherAccess. - * @tparam OtherLockArgs Deduced from otherLockArgs. - * @param otherAccess The Access object to construct from. - * @param otherLockArgs Other arguments needed to construct the lock - * object. - */ - template class OtherLockType, AccessMode OtherMode, typename... OtherLockArgs> - EXPLICIT_IF_CPP17 - Access(Access& otherAccess, OtherLockArgs&&... otherLockArgs): - Access(*otherAccess, *otherAccess.lock.release(), std::adopt_lock, std::forward(otherLockArgs)...) - { - static_assert(OtherMode == AccessMode::ReadWrite || OtherMode == Mode, "Cannot construct a ReadWrite Access object from a ReadOnly one!"); - } - - /** - * @brief Const accessor to the value. - * @return ConstPointerType Const pointer to the protected value. - */ - ConstPointerType operator->() const noexcept - { - return &m_value; - } - - /** - * @brief Accessor to the value. - * @return ValuePointerType Pointer to the protected value. - */ - PointerType operator->() noexcept - { - return &m_value; - } - - /** - * @brief Const accessor to the value. - * @return ConstValueReferenceType Const reference to the protected - * value. - */ - ConstReferenceType operator*() const noexcept - { - return m_value; - } - - /** - * @brief Accessor to the value. - * @return ValueReferenceType Reference to the protected. - */ - ReferenceType operator*() noexcept - { - return m_value; - } - - /// The lock that manages the mutex. - mutable LockType lock; - - private: - /// The protected value. - ReferenceType m_value; - }; - - /// Reference-to-const ValueType. - using ConstValueReferenceType = const RemoveRefValueType&; - /// Reference to ValueType. - using ValueReferenceType = RemoveRefValueType&; - /// Reference to MutexType. - using MutexReferenceType = RemoveRefMutexType&; - - public: - /// Aliases to ReadAccess and WriteAccess classes for this Safe class. - template class LockType=DefaultReadOnlyLock> - using ReadAccess = Access; - template class LockType=DefaultReadWriteLock> - using WriteAccess = Access; - - /** - * @brief Construct a Safe object - */ - Safe() = default; - - /** - * @brief Construct a Safe object with default construction of - * the mutex and perfect forwarding of the other arguments to - * construct the value object. - * - * @tparam ValueArgs Deduced from valueArgs. - * @param valueArgs Perfect forwarding arguments to construct the value object. - * @param tag Indicates that the mutex should be default constructed. - */ - template - explicit Safe(DefaultConstructMutex, ValueArgs&&... valueArgs): - m_mutex(), - m_value(std::forward(valueArgs)...) - {} - /** - * @brief Construct a Safe object, forwarding the first - * argument to construct the mutex and the other arguments to - * construct the value object. - * - * @tparam MutexArg Deduced from mutexArg. - * @tparam ValueArgs Deduced from valueArgs. - * @param valueArgs Perfect forwarding arguments to construct the - * value object. - * @param mutexArg Perfect forwarding argument to construct the - * mutex object. - */ - template - explicit Safe(MutexArg&& mutexArg, ValueArgs&&... valueArgs): - m_mutex{std::forward(mutexArg)}, - m_value(std::forward(valueArgs)...) - {} - - /// Delete all copy/move construction/assignment, as these operations - /// require locking the mutex under the covers. - /// Use copy(), assign() and other defined constructors to get the behavior - /// you need with an explicit syntax. - Safe(const Safe&) = delete; - Safe(Safe&&) = delete; - Safe& operator =(const Safe&) = delete; - Safe& operator =(Safe&&) = delete; - - template class LockType=DefaultReadOnlyLock, typename... LockArgs> - ReadAccess readAccess(LockArgs&&... lockArgs) const - { - // using ReturnType = ReadAccess; - return EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17{*this, std::forward(lockArgs)...}; - } - - template class LockType=DefaultReadWriteLock, typename... LockArgs> - WriteAccess writeAccess(LockArgs&&... lockArgs) - { - // using ReturnType = WriteAccess; - return EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17{*this, std::forward(lockArgs)...}; - } - - template class LockType=DefaultReadOnlyLock, typename... LockArgs> - RemoveRefValueType copy(LockArgs&&... lockArgs) const - { - return *readAccess(std::forward(lockArgs)...); - } - - template class LockType=DefaultReadWriteLock, typename... LockArgs> - void assign(ConstValueReferenceType value, LockArgs&&... lockArgs) - { - *writeAccess(std::forward(lockArgs)...) = value; - } - template class LockType=DefaultReadWriteLock, typename... LockArgs> - void assign(RemoveRefValueType&& value, LockArgs&&... lockArgs) - { - *writeAccess(std::forward(lockArgs)...) = std::move(value); - } - - /** - * @brief Unsafe const accessor to the value. If you use this - * function, you exit the realm of safe! - * - * @return ConstValueReferenceType Const reference to the value - * object. - */ - ConstValueReferenceType unsafe() const noexcept - { - return m_value; - } - /** - * @brief Unsafe accessor to the value. If you use this function, - * you exit the realm of safe! - * - * @return ValueReferenceType Reference to the value object. - */ - ValueReferenceType unsafe() noexcept - { - return m_value; - } - - /** - * @brief Accessor to the mutex. - * - * @return MutexReferenceType Reference to the mutex. - */ - MutexReferenceType mutex() const noexcept - { - return m_mutex.get; - } - - private: - /// The helper object that holds the mutable mutex, or a reference to a mutex. - impl::MutableIfNotReference m_mutex; - /// The value to protect. - ValueType m_value; - }; - - /** - * @brief Type alias for read-only Access. - * - * @tparam SafeType The type of Safe object to give read-only access to. - * @tparam LockType=DefaultReadOnlyLock The type of lock. - */ - template< - typename SafeType, - template class LockType=DefaultReadOnlyLock> - using ReadAccess = typename SafeType::template ReadAccess; - - /** - * @brief Type alias for read-write Access. - * - * @tparam SafeType The type of Safe object to give read-write access to. - * @tparam LockType=DefaultReadWriteLock The type of lock. - */ - template< - typename SafeType, - template class LockType=DefaultReadWriteLock> - using WriteAccess = typename SafeType::template WriteAccess; +namespace safe { +/** + * @brief Use this tag to default construct the mutex when constructing a + * Safe object. + */ +struct DefaultConstructMutex {}; +static constexpr DefaultConstructMutex default_construct_mutex; + +/** + * @brief Wraps a value together with a mutex. + * + * @tparam ValueType The type of the value to protect. + * @tparam MutexType The type of the mutex. + */ +template +class Safe { +private: + /// Type ValueType with reference removed, if present + using RemoveRefValueType = typename std::remove_reference::type; + /// Type MutexType with reference removed, if present + using RemoveRefMutexType = typename std::remove_reference::type; + + /** + * @brief Manages a mutex and gives pointer-like access to a value + * object. + * + * @tparam LockType The type of the lock object that manages the + * mutex, example: std::lock_guard. + * @tparam Mode Determines the access mode of the Access + * object. Can be either AccessMode::ReadOnly or + * AccessMode::ReadWrite. + */ + template class LockType, AccessMode Mode> + class Access { + // Make sure AccessMode is ReadOnly if a read-only lock is used + static_assert( + !(AccessTraits>::IsReadOnly + && Mode == AccessMode::ReadWrite), + "Cannot have ReadWrite access mode with ReadOnly lock. Check the " + "value of AccessTraits::IsReadOnly if it exists."); + + /// ValueType with const qualifier if AccessMode is ReadOnly. + using ConstIfReadOnlyValueType = + typename std::conditional::type; + + public: + /// Pointer-to-const ValueType + using ConstPointerType = const ConstIfReadOnlyValueType*; + /// Pointer-to-const ValueType if Mode is ReadOnly, pointer to ValueType + /// otherwise. + using PointerType = ConstIfReadOnlyValueType*; + /// Reference-to-const ValueType + using ConstReferenceType = const ConstIfReadOnlyValueType&; + /// Reference-to-const ValueType if Mode is ReadOnly, reference to + /// ValueType otherwise. + using ReferenceType = ConstIfReadOnlyValueType&; + + /** + * @brief Construct an Access object from a possibly const + * reference to the value object and any additionnal argument + * needed to construct the Lock object. + * + * @tparam LockArgs Deduced from lockArgs. + * @param value Reference to the value. + * @param lockArgs Arguments needed to construct the lock object. + */ + template + EXPLICIT_IF_CPP17 Access(ReferenceType value, + MutexType& mutex, + OtherLockArgs&&... otherLockArgs) + : lock(mutex, std::forward(otherLockArgs)...), + m_value(value) + { + } + + /** + * @brief Construct a read-only Access object from a const + * safe::Safe object and any additionnal argument needed to + * construct the Lock object. + * + * If needed, you can provide additionnal arguments to construct + * the lock object (such as std::adopt_lock). The mutex from the + * safe::Locakble object is already passed to the lock object's + * constructor though, you must not provide it. + * + * @tparam OtherLockArgs Deduced from otherLockArgs. + * @param safe The const Safe object to give protected access to. + * @param otherLockArgs Other arguments needed to construct the lock + * object. + */ + template + EXPLICIT_IF_CPP17 Access(const Safe& safe, + OtherLockArgs&&... otherLockArgs) + : Access(safe.m_value, + safe.m_mutex.get, + std::forward(otherLockArgs)...) + { + } + + /** + * @brief Construct a read-write Access object from a + * safe::Safe object and any additionnal argument needed to + * construct the Lock object. + * + * If needed, you can provide additionnal arguments to construct + * the lock object (such as std::adopt_lock). The mutex from the + * safe object is already passed to the lock object's constructor + * though, you must not provide it. + * + * @tparam OtherLockArgs Deduced from otherLockArgs. + * @param safe The Safe object to give protected access to. + * @param otherLockArgs Other arguments needed to construct the lock + * object. + */ + template + EXPLICIT_IF_CPP17 Access(Safe& safe, OtherLockArgs&&... otherLockArgs) + : Access(safe.m_value, + safe.m_mutex.get, + std::forward(otherLockArgs)...) + { + } + + /** + * @brief Construct an Access object from another one. + * OtherLockType must implement release() like std::unique_lock + * does. + * + * @tparam OtherLockType Deduced from otherAccess. + * @tparam OtherMode Deduced from otherAccess. + * @tparam OtherLockArgs Deduced from otherLockArgs. + * @param otherAccess The Access object to construct from. + * @param otherLockArgs Other arguments needed to construct the lock + * object. + */ + template class OtherLockType, + AccessMode OtherMode, + typename... OtherLockArgs> + EXPLICIT_IF_CPP17 Access(Access& otherAccess, + OtherLockArgs&&... otherLockArgs) + : Access(*otherAccess, + *otherAccess.lock.release(), + std::adopt_lock, + std::forward(otherLockArgs)...) + { + static_assert( + OtherMode == AccessMode::ReadWrite || OtherMode == Mode, + "Cannot construct a ReadWrite Access object from a ReadOnly " + "one!"); + } + + /** + * @brief Const accessor to the value. + * @return ConstPointerType Const pointer to the protected value. + */ + ConstPointerType operator->() const noexcept { return &m_value; } + + /** + * @brief Accessor to the value. + * @return ValuePointerType Pointer to the protected value. + */ + PointerType operator->() noexcept { return &m_value; } + + /** + * @brief Const accessor to the value. + * @return ConstValueReferenceType Const reference to the protected + * value. + */ + ConstReferenceType operator*() const noexcept { return m_value; } + + /** + * @brief Accessor to the value. + * @return ValueReferenceType Reference to the protected. + */ + ReferenceType operator*() noexcept { return m_value; } + + /// The lock that manages the mutex. + mutable LockType lock; + + private: + /// The protected value. + ReferenceType m_value; + }; + + /// Reference-to-const ValueType. + using ConstValueReferenceType = const RemoveRefValueType&; + /// Reference to ValueType. + using ValueReferenceType = RemoveRefValueType&; + /// Reference to MutexType. + using MutexReferenceType = RemoveRefMutexType&; + +public: + /// Aliases to ReadAccess and WriteAccess classes for this Safe class. + template class LockType = DefaultReadOnlyLock> + using ReadAccess = Access; + template class LockType = DefaultReadWriteLock> + using WriteAccess = Access; + + /** + * @brief Construct a Safe object + */ + Safe() = default; + + /** + * @brief Construct a Safe object with default construction of + * the mutex and perfect forwarding of the other arguments to + * construct the value object. + * + * @tparam ValueArgs Deduced from valueArgs. + * @param valueArgs Perfect forwarding arguments to construct the value + * object. + * @param tag Indicates that the mutex should be default constructed. + */ + template + explicit Safe(DefaultConstructMutex, ValueArgs&&... valueArgs) + : m_mutex(), m_value(std::forward(valueArgs)...) + { + } + /** + * @brief Construct a Safe object, forwarding the first + * argument to construct the mutex and the other arguments to + * construct the value object. + * + * @tparam MutexArg Deduced from mutexArg. + * @tparam ValueArgs Deduced from valueArgs. + * @param valueArgs Perfect forwarding arguments to construct the + * value object. + * @param mutexArg Perfect forwarding argument to construct the + * mutex object. + */ + template + explicit Safe(MutexArg&& mutexArg, ValueArgs&&... valueArgs) + : m_mutex{std::forward(mutexArg)}, + m_value(std::forward(valueArgs)...) + { + } + + /// Delete all copy/move construction/assignment, as these operations + /// require locking the mutex under the covers. + /// Use copy(), assign() and other defined constructors to get the behavior + /// you need with an explicit syntax. + Safe(const Safe&) = delete; + Safe(Safe&&) = delete; + Safe& operator=(const Safe&) = delete; + Safe& operator=(Safe&&) = delete; + + template class LockType = DefaultReadOnlyLock, + typename... LockArgs> + ReadAccess readAccess(LockArgs&&... lockArgs) const + { + using ReturnType = ReadAccess; + return EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17{ + *this, std::forward(lockArgs)...}; + } + + template class LockType = DefaultReadWriteLock, + typename... LockArgs> + WriteAccess writeAccess(LockArgs&&... lockArgs) + { + using ReturnType = WriteAccess; + return EXPLICITLY_CONSTRUCT_RETURN_TYPE_IF_CPP17{ + *this, std::forward(lockArgs)...}; + } + + template class LockType = DefaultReadOnlyLock, + typename... LockArgs> + RemoveRefValueType copy(LockArgs&&... lockArgs) const + { + return *readAccess(std::forward(lockArgs)...); + } + + template class LockType = DefaultReadWriteLock, + typename... LockArgs> + void assign(ConstValueReferenceType value, LockArgs&&... lockArgs) + { + *writeAccess(std::forward(lockArgs)...) = value; + } + template class LockType = DefaultReadWriteLock, + typename... LockArgs> + void assign(RemoveRefValueType&& value, LockArgs&&... lockArgs) + { + *writeAccess(std::forward(lockArgs)...) + = std::move(value); + } + + /** + * @brief Unsafe const accessor to the value. If you use this + * function, you exit the realm of safe! + * + * @return ConstValueReferenceType Const reference to the value + * object. + */ + ConstValueReferenceType unsafe() const noexcept { return m_value; } + /** + * @brief Unsafe accessor to the value. If you use this function, + * you exit the realm of safe! + * + * @return ValueReferenceType Reference to the value object. + */ + ValueReferenceType unsafe() noexcept { return m_value; } + + /** + * @brief Accessor to the mutex. + * + * @return MutexReferenceType Reference to the mutex. + */ + MutexReferenceType mutex() const noexcept { return m_mutex.get; } + +private: + /// The helper object that holds the mutable mutex, or a reference to a + /// mutex. + impl::MutableIfNotReference m_mutex; + /// The value to protect. + ValueType m_value; +}; + +/** + * @brief Type alias for read-only Access. + * + * @tparam SafeType The type of Safe object to give read-only access to. + * @tparam LockType=DefaultReadOnlyLock The type of lock. + */ +template class LockType = DefaultReadOnlyLock> +using ReadAccess = typename SafeType::template ReadAccess; + +/** + * @brief Type alias for read-write Access. + * + * @tparam SafeType The type of Safe object to give read-write access to. + * @tparam LockType=DefaultReadWriteLock The type of lock. + */ +template class LockType = DefaultReadWriteLock> +using WriteAccess = typename SafeType::template WriteAccess; } // namespace safe #undef EXPLICIT_IF_CPP17 diff --git a/src/session.export.cc b/src/session.export.cc index 75550d1f..95ac0a0f 100644 --- a/src/session.export.cc +++ b/src/session.export.cc @@ -40,9 +40,9 @@ struct log_message_session_state { int64_t lmss_time_msecs; std::string lmss_format; bool lmss_mark; - nonstd::optional lmss_comment; - nonstd::optional lmss_tags; - nonstd::optional lmss_annotations; + std::optional lmss_comment; + std::optional lmss_tags; + std::optional lmss_annotations; std::string lmss_hash; }; @@ -56,9 +56,9 @@ struct from_sqlite { from_sqlite()(argc, argv, argi + 0), from_sqlite()(argc, argv, argi + 1), from_sqlite()(argc, argv, argi + 2), - from_sqlite>()(argc, argv, argi + 3), - from_sqlite>()(argc, argv, argi + 4), - from_sqlite>()(argc, argv, argi + 5), + from_sqlite>()(argc, argv, argi + 3), + from_sqlite>()(argc, argv, argi + 4), + from_sqlite>()(argc, argv, argi + 5), from_sqlite()(argc, argv, argi + 6), }; } @@ -111,14 +111,14 @@ struct from_sqlite { namespace lnav { namespace session { -static nonstd::optional +static std::optional find_container_dir(ghc::filesystem::path file_path) { if (!ghc::filesystem::exists(file_path)) { - return nonstd::nullopt; + return std::nullopt; } - nonstd::optional dir_with_last_readme; + std::optional dir_with_last_readme; while (file_path.has_parent_path() && file_path != file_path.root_directory()) @@ -147,7 +147,7 @@ find_container_dir(ghc::filesystem::path file_path) file_path = parent; } - return nonstd::nullopt; + return std::nullopt; } static std::string diff --git a/src/session_data.cc b/src/session_data.cc index 1b57da45..a7b5ef1d 100644 --- a/src/session_data.cc +++ b/src/session_data.cc @@ -302,7 +302,7 @@ init_session() session_data.sd_view_states[LNV_LOG].vs_top = -1; } -static nonstd::optional +static std::optional compute_session_id() { bool has_files = false; @@ -327,13 +327,13 @@ compute_session_id() h.update(lf->get_filename()); } if (!has_files) { - return nonstd::nullopt; + return std::nullopt; } return h.to_string(); } -nonstd::optional +std::optional scan_sessions() { static_root_mem view_info_list; @@ -342,7 +342,7 @@ scan_sessions() const auto session_id = compute_session_id(); if (!session_id) { - return nonstd::nullopt; + return std::nullopt; } std::list& session_file_names = lnav_data.ld_session_id[session_id.value()]; @@ -394,10 +394,10 @@ scan_sessions() } if (session_file_names.empty()) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional(session_file_names.back()); + return std::make_optional(session_file_names.back()); } void @@ -1744,7 +1744,7 @@ reset_session() bool changed = false; for (const auto& vd : elf->elf_value_defs) { if (vd.second->vd_meta.lvm_user_hidden) { - vd.second->vd_meta.lvm_user_hidden = nonstd::nullopt; + vd.second->vd_meta.lvm_user_hidden = std::nullopt; changed = true; } } diff --git a/src/session_data.hh b/src/session_data.hh index 6eda213e..c7009da7 100644 --- a/src/session_data.hh +++ b/src/session_data.hh @@ -38,7 +38,6 @@ #include #include "mapbox/variant.hpp" -#include "optional.hpp" #include "view_helpers.hh" struct file_state { @@ -47,7 +46,7 @@ struct file_state { struct view_state { int64_t vs_top{0}; - nonstd::optional vs_selection; + std::optional vs_selection; std::string vs_search; bool vs_word_wrap{false}; bool vs_filtering{true}; diff --git a/src/spectro_impls.cc b/src/spectro_impls.cc index 7ad78e41..ddc2d36e 100644 --- a/src/spectro_impls.cc +++ b/src/spectro_impls.cc @@ -76,13 +76,12 @@ public: }); } - nonstd::optional row_for_time( - struct timeval time_bucket) override + std::optional row_for_time(struct timeval time_bucket) override { return this->fss_time_delegate->row_for_time(time_bucket); } - nonstd::optional time_for_row(vis_line_t row) override + std::optional time_for_row(vis_line_t row) override { return this->fss_lines | lnav::itertools::nth(row) | lnav::itertools::flat_map([this](const auto row) { @@ -190,8 +189,8 @@ log_spectro_value_source::spectro_row(spectrogram_request& sr, { auto& lss = lnav_data.ld_log_source; auto begin_line = lss.find_from_time(sr.sr_begin_time).value_or(0_vl); - auto end_line - = lss.find_from_time(sr.sr_end_time).value_or(lss.text_line_count()); + auto end_line = lss.find_from_time(sr.sr_end_time) + .value_or(vis_line_t(lss.text_line_count())); for (const auto& msg_info : lss.window_at(begin_line, end_line)) { const auto& ll = msg_info.get_logline(); @@ -226,7 +225,7 @@ log_spectro_value_source::spectro_row(spectrogram_request& sr, auto retval = std::make_unique(); auto begin_line = lss.find_from_time(sr.sr_begin_time).value_or(0_vl); auto end_line = lss.find_from_time(sr.sr_end_time) - .value_or(lss.text_line_count()); + .value_or(vis_line_t(lss.text_line_count())); retval->fss_delegate = &lss; retval->fss_time_delegate = &lss; @@ -281,8 +280,8 @@ log_spectro_value_source::spectro_mark(textview_curses& tc, auto& log_tc = lnav_data.ld_views[LNV_LOG]; auto& lss = lnav_data.ld_log_source; vis_line_t begin_line = lss.find_from_time(begin_time).value_or(0_vl); - vis_line_t end_line - = lss.find_from_time(end_time).value_or(lss.text_line_count()); + vis_line_t end_line = lss.find_from_time(end_time).value_or( + vis_line_t(lss.text_line_count())); logline_value_vector values; string_attrs_t sa; @@ -478,8 +477,8 @@ db_spectro_value_source::spectro_row(spectrogram_request& sr, { auto& dls = lnav_data.ld_db_row_source; auto begin_row = dls.row_for_time({sr.sr_begin_time, 0}).value_or(0_vl); - auto end_row - = dls.row_for_time({sr.sr_end_time, 0}).value_or(dls.dls_rows.size()); + auto end_row = dls.row_for_time({sr.sr_end_time, 0}) + .value_or(vis_line_t(dls.dls_rows.size())); for (auto lpc = begin_row; lpc < end_row; ++lpc) { auto scan_res = scn::scan_value(scn::string_view{ @@ -501,7 +500,7 @@ db_spectro_value_source::spectro_row(spectrogram_request& sr, retval->fss_overlay_delegate = &lnav_data.ld_db_overlay; auto begin_row = dls.row_for_time({sr.sr_begin_time, 0}).value_or(0_vl); auto end_row = dls.row_for_time({sr.sr_end_time, 0}) - .value_or(dls.dls_rows.size()); + .value_or(vis_line_t(dls.dls_rows.size())); for (auto lpc = begin_row; lpc < end_row; ++lpc) { auto scan_res = scn::scan_value(scn::string_view{ diff --git a/src/spectro_impls.hh b/src/spectro_impls.hh index 9d4ddeba..644c4b42 100644 --- a/src/spectro_impls.hh +++ b/src/spectro_impls.hh @@ -80,8 +80,8 @@ public: logline_value_stats dsvs_stats; time_t dsvs_begin_time{0}; time_t dsvs_end_time{0}; - nonstd::optional dsvs_column_index; - nonstd::optional dsvs_error_msg; + std::optional dsvs_column_index; + std::optional dsvs_error_msg; }; #endif diff --git a/src/spectro_source.cc b/src/spectro_source.cc index 5a694dc3..c3783ab9 100644 --- a/src/spectro_source.cc +++ b/src/spectro_source.cc @@ -35,11 +35,11 @@ #include "base/math_util.hh" #include "config.h" -nonstd::optional +std::optional spectrogram_row::nearest_column(size_t current) const { - nonstd::optional retval; - nonstd::optional nearest_distance; + std::optional retval; + std::optional nearest_distance; for (size_t lpc = 0; lpc < this->sr_width; lpc++) { if (this->sr_values[lpc].rb_counter == 0) { @@ -133,7 +133,7 @@ spectrogram_source::list_input_handle_key(listview_curses& lv, int ch) if (sa.empty()) { this->ss_details_source.reset(); - this->ss_cursor_column = nonstd::nullopt; + this->ss_cursor_column = std::nullopt; return true; } @@ -320,7 +320,7 @@ spectrogram_source::text_line_width(textview_curses& tc) return width; } -nonstd::optional +std::optional spectrogram_source::time_for_row(vis_line_t row) { if (this->ss_details_source != nullptr) { @@ -335,7 +335,7 @@ spectrogram_source::time_for_row(vis_line_t row) return this->time_for_row_int(row); } -nonstd::optional +std::optional spectrogram_source::time_for_row_int(vis_line_t row) { struct timeval retval { @@ -350,11 +350,11 @@ spectrogram_source::time_for_row_int(vis_line_t row) return row_info{retval, row}; } -nonstd::optional +std::optional spectrogram_source::row_for_time(struct timeval time_bucket) { if (this->ss_value_source == nullptr) { - return nonstd::nullopt; + return std::nullopt; } time_t diff; @@ -457,7 +457,7 @@ spectrogram_source::cache_bounds() if (this->ss_value_source == nullptr) { this->ss_cached_bounds.sb_count = 0; this->ss_cached_bounds.sb_begin_time = 0; - this->ss_cursor_column = nonstd::nullopt; + this->ss_cursor_column = std::nullopt; this->reset_details_source(); return; } @@ -474,7 +474,7 @@ spectrogram_source::cache_bounds() if (sb.sb_count == 0) { this->ss_cached_line_count = 0; - this->ss_cursor_column = nonstd::nullopt; + this->ss_cursor_column = std::nullopt; this->reset_details_source(); return; } @@ -556,7 +556,7 @@ void spectrogram_source::text_selection_changed(textview_curses& tc) { if (this->ss_value_source == nullptr || this->text_line_count() == 0) { - this->ss_cursor_column = nonstd::nullopt; + this->ss_cursor_column = std::nullopt; this->ss_details_source.reset(); return; } diff --git a/src/spectro_source.hh b/src/spectro_source.hh index d861b5bd..79a1332d 100644 --- a/src/spectro_source.hh +++ b/src/spectro_source.hh @@ -93,7 +93,7 @@ struct spectrogram_row { } } - nonstd::optional nearest_column(size_t current) const; + std::optional nearest_column(size_t current) const; }; class spectrogram_value_source { @@ -126,7 +126,7 @@ public: { this->ss_cached_bounds.sb_count = 0; this->ss_row_cache.clear(); - this->ss_cursor_column = nonstd::nullopt; + this->ss_cursor_column = std::nullopt; } bool list_input_handle_key(listview_curses& lv, int ch) override; @@ -159,9 +159,9 @@ public: void text_selection_changed(textview_curses& tc) override; - nonstd::optional time_for_row(vis_line_t row) override; + std::optional time_for_row(vis_line_t row) override; - nonstd::optional row_for_time( + std::optional row_for_time( struct timeval time_bucket) override; void text_value_for_line(textview_curses& tc, @@ -175,7 +175,7 @@ public: void cache_bounds(); - nonstd::optional time_for_row_int(vis_line_t row); + std::optional time_for_row_int(vis_line_t row); const spectrogram_row& load_row(const listview_curses& lv, int row); @@ -191,7 +191,7 @@ public: spectrogram_thresholds ss_cached_thresholds; size_t ss_cached_line_count{0}; std::unordered_map ss_row_cache; - nonstd::optional ss_cursor_column; + std::optional ss_cursor_column; }; class spectro_status_source : public status_data_source { diff --git a/src/sql_util.cc b/src/sql_util.cc index ce17d9b2..3e214168 100644 --- a/src/sql_util.cc +++ b/src/sql_util.cc @@ -1462,7 +1462,7 @@ annotate_prql_statement(attr_line_t& al) auto stages = std::vector{}; std::vector> groups; std::vector fqids; - nonstd::optional id_start; + std::optional id_start; bool saw_id_dot = false; for (const auto& attr : sa) { if (groups.empty() && attr.sa_type == &PRQL_PIPE_ATTR) { @@ -1478,7 +1478,7 @@ annotate_prql_statement(attr_line_t& al) saw_id_dot = true; } else { fqids.emplace_back(id_start.value()); - id_start = nonstd::nullopt; + id_start = std::nullopt; saw_id_dot = false; } } else { @@ -1488,7 +1488,7 @@ annotate_prql_statement(attr_line_t& al) attr.sa_range.lr_end, }; } else { - id_start = nonstd::nullopt; + id_start = std::nullopt; } saw_id_dot = false; } diff --git a/src/sqlitepp.client.hh b/src/sqlitepp.client.hh index 46c4a646..4eaa1626 100644 --- a/src/sqlitepp.client.hh +++ b/src/sqlitepp.client.hh @@ -163,7 +163,7 @@ struct prepared_stmt { template Result for_each_row(F func) { - nonstd::optional err; + std::optional err; auto done = false; while (!done) { diff --git a/src/sqlitepp.hh b/src/sqlitepp.hh index 0db20208..7e48454c 100644 --- a/src/sqlitepp.hh +++ b/src/sqlitepp.hh @@ -39,7 +39,6 @@ #include "base/auto_mem.hh" #include "base/intern_string.hh" #include "base/types.hh" -#include "optional.hpp" /* XXX figure out how to do this with the template */ void sqlite_close_wrapper(void* mem); @@ -49,7 +48,7 @@ using auto_sqlite3 = auto_mem; namespace sqlitepp { inline auto_mem -quote(const nonstd::optional& str) +quote(const std::optional& str) { auto_mem retval(sqlite3_free); diff --git a/src/state-extension-functions.cc b/src/state-extension-functions.cc index e7aca121..b54c2993 100644 --- a/src/state-extension-functions.cc +++ b/src/state-extension-functions.cc @@ -40,30 +40,30 @@ #include "sqlite3.h" #include "vtab_module.hh" -static nonstd::optional +static std::optional sql_log_top_line() { const auto& tc = lnav_data.ld_views[LNV_LOG]; if (tc.get_inner_height() == 0_vl) { - return nonstd::nullopt; + return std::nullopt; } return (int64_t) tc.get_selection(); } -static nonstd::optional +static std::optional sql_log_msg_line() { const auto& tc = lnav_data.ld_views[LNV_LOG]; if (tc.get_inner_height() == 0_vl) { - return nonstd::nullopt; + return std::nullopt; } auto top_line = tc.get_selection(); auto line_pair_opt = lnav_data.ld_log_source.find_line_with_file(top_line); if (!line_pair_opt) { - return nonstd::nullopt; + return std::nullopt; } auto ll = line_pair_opt.value().second; @@ -75,19 +75,19 @@ sql_log_msg_line() return (int64_t) top_line; } -static nonstd::optional +static std::optional sql_log_top_datetime() { const auto& tc = lnav_data.ld_views[LNV_LOG]; if (tc.get_inner_height() == 0_vl) { - return nonstd::nullopt; + return std::nullopt; } auto top_ri = lnav_data.ld_log_source.time_for_row( lnav_data.ld_views[LNV_LOG].get_selection()); if (!top_ri) { - return nonstd::nullopt; + return std::nullopt; } char buffer[64]; @@ -96,13 +96,13 @@ sql_log_top_datetime() return buffer; } -static nonstd::optional +static std::optional sql_lnav_top_file() { auto top_view_opt = lnav_data.ld_view_stack.top(); if (!top_view_opt) { - return nonstd::nullopt; + return std::nullopt; } auto* top_view = top_view_opt.value(); @@ -111,7 +111,7 @@ sql_lnav_top_file() [](const auto wrapper) { auto lf = wrapper.get(); - return nonstd::make_optional(lf->get_filename()); + return std::make_optional(lf->get_filename()); }; }); } @@ -123,7 +123,7 @@ sql_lnav_version() } static int64_t -sql_error(const char* str, nonstd::optional reason) +sql_error(const char* str, std::optional reason) { auto um = lnav::console::user_message::error(str); @@ -133,8 +133,8 @@ sql_error(const char* str, nonstd::optional reason) throw um; } -static nonstd::optional -sql_echoln(nonstd::optional arg) +static std::optional +sql_echoln(std::optional arg) { if (arg) { auto& ec = lnav_data.ld_exec_context; diff --git a/src/statusview_curses.cc b/src/statusview_curses.cc index c069f6dd..33ee3a69 100644 --- a/src/statusview_curses.cc +++ b/src/statusview_curses.cc @@ -132,8 +132,8 @@ statusview_curses::do_update() if (sa.sa_type == &VC_STYLE) { auto sa_attrs = sa.sa_value.get(); sa_attrs.ta_attrs &= ~(A_REVERSE | A_COLOR); - sa_attrs.ta_fg_color = nonstd::nullopt; - sa_attrs.ta_bg_color = nonstd::nullopt; + sa_attrs.ta_fg_color = std::nullopt; + sa_attrs.ta_bg_color = std::nullopt; sa.sa_value = sa_attrs; } else if (sa.sa_type == &VC_ROLE) { if (sa.sa_value.get() diff --git a/src/string-extension-functions.cc b/src/string-extension-functions.cc index 59c5e835..f5a66d98 100644 --- a/src/string-extension-functions.cc +++ b/src/string-extension-functions.cc @@ -28,7 +28,6 @@ #include "formats/logfmt/logfmt.parser.hh" #include "libbase64.h" #include "mapbox/variant.hpp" -#include "optional.hpp" #include "pcrepp/pcre2pp.hh" #include "safe/safe.h" #include "scn/scn.h" @@ -394,7 +393,7 @@ sparkline_final(sqlite3_context* context) sc->~sparkline_context(); } -nonstd::optional> +std::optional> sql_gunzip(sqlite3_value* val) { switch (sqlite3_value_type(val)) { @@ -423,10 +422,10 @@ sql_gunzip(sqlite3_value* val) return sqlite3_value_double(val); } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional sql_gzip(sqlite3_value* val) { switch (sqlite3_value_type(val)) { @@ -458,7 +457,7 @@ sql_gzip(sqlite3_value* val) } } - return nonstd::nullopt; + return std::nullopt; } #if defined(HAVE_LIBCURL) @@ -764,15 +763,15 @@ sql_parse_url(std::string url) } struct url_parts { - nonstd::optional up_scheme; - nonstd::optional up_username; - nonstd::optional up_password; - nonstd::optional up_host; - nonstd::optional up_port; - nonstd::optional up_path; - nonstd::optional up_query; - std::map> up_parameters; - nonstd::optional up_fragment; + std::optional up_scheme; + std::optional up_username; + std::optional up_password; + std::optional up_host; + std::optional up_port; + std::optional up_path; + std::optional up_query; + std::map> up_parameters; + std::optional up_fragment; }; static const json_path_container url_params_handlers = { diff --git a/src/sysclip.cc b/src/sysclip.cc index 725e4047..6e9aaea8 100644 --- a/src/sysclip.cc +++ b/src/sysclip.cc @@ -45,7 +45,7 @@ namespace sysclip { -static nonstd::optional +static std::optional get_commands() { const auto& cfg = injector::get(); @@ -63,7 +63,7 @@ get_commands() } } - return nonstd::nullopt; + return std::nullopt; } static int diff --git a/src/text_anonymizer.cc b/src/text_anonymizer.cc index a9b11931..2770dc13 100644 --- a/src/text_anonymizer.cc +++ b/src/text_anonymizer.cc @@ -343,14 +343,14 @@ text_anonymizer::next(string_fragment line) }); return anon_mac.to_string( - nonstd::make_optional(inp[2])); + std::make_optional(inp[2])); }); break; } case DT_HEX_DUMP: { auto hex_str = tok_res->to_string(); auto hash_str = hasher().update(hex_str).to_array().to_string( - nonstd::make_optional(hex_str[2])); + std::make_optional(hex_str[2])); std::string anon_hex; while (anon_hex.size() < hex_str.size()) { diff --git a/src/text_format.cc b/src/text_format.cc index dc63cf66..fe00cbc9 100644 --- a/src/text_format.cc +++ b/src/text_format.cc @@ -40,7 +40,7 @@ text_format_t detect_text_format(string_fragment sf, - nonstd::optional path) + std::optional path) { static const std::set FILTER_EXTS = { ".bz2", @@ -230,7 +230,7 @@ detect_text_format(string_fragment sf, return text_format_t::TF_UNKNOWN; } -nonstd::optional +std::optional extract_text_meta(string_fragment sf, text_format_t tf) { static const auto MAN_NAME = lnav::pcre2pp::code::from_const( @@ -255,5 +255,5 @@ extract_text_meta(string_fragment sf, text_format_t tf) break; } - return nonstd::nullopt; + return std::nullopt; } diff --git a/src/text_format.hh b/src/text_format.hh index b3966292..8c8645a6 100644 --- a/src/text_format.hh +++ b/src/text_format.hh @@ -131,14 +131,14 @@ struct formatter : formatter { * @return The detected format. */ text_format_t detect_text_format(string_fragment sf, - nonstd::optional path - = nonstd::nullopt); + std::optional path + = std::nullopt); struct text_format_meta_t { std::string tfm_filename; }; -nonstd::optional extract_text_meta(string_fragment sf, +std::optional extract_text_meta(string_fragment sf, text_format_t tf); #endif diff --git a/src/textfile_sub_source.cc b/src/textfile_sub_source.cc index 79643ffb..b99a1137 100644 --- a/src/textfile_sub_source.cc +++ b/src/textfile_sub_source.cc @@ -688,7 +688,7 @@ textfile_sub_source::text_crumbs_for_line( textfile_sub_source::rescan_result_t textfile_sub_source::rescan_files( textfile_sub_source::scan_callback& callback, - nonstd::optional deadline) + std::optional deadline) { static auto& lnav_db = injector::get(); @@ -1009,12 +1009,12 @@ textfile_sub_source::quiesce() } } -nonstd::optional +std::optional textfile_sub_source::row_for_anchor(const std::string& id) { auto lf = this->current_file(); if (!lf || id.empty()) { - return nonstd::nullopt; + return std::nullopt; } auto rend_iter = this->tss_rendered_files.find(lf->get_filename()); @@ -1024,11 +1024,11 @@ textfile_sub_source::row_for_anchor(const std::string& id) auto iter = this->tss_doc_metadata.find(lf->get_filename()); if (iter == this->tss_doc_metadata.end()) { - return nonstd::nullopt; + return std::nullopt; } const auto& meta = iter->second.ms_metadata; - nonstd::optional retval; + std::optional retval; auto is_ptr = startswith(id, "#/"); if (is_ptr) { @@ -1155,7 +1155,7 @@ textfile_sub_source::get_anchors() return retval; } -static nonstd::optional +static std::optional to_vis_line(const std::shared_ptr& lf, file_off_t off) { auto ll_opt = lf->line_for_offset(off); @@ -1163,15 +1163,15 @@ to_vis_line(const std::shared_ptr& lf, file_off_t off) return vis_line_t(std::distance(lf->cbegin(), ll_opt.value())); } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) { auto lf = this->current_file(); if (!lf) { - return nonstd::nullopt; + return std::nullopt; } log_debug("adjacent_anchor: %s:L%d:%s", @@ -1186,7 +1186,7 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) auto iter = this->tss_doc_metadata.find(lf->get_filename()); if (iter == this->tss_doc_metadata.end()) { log_debug(" no metadata available"); - return nonstd::nullopt; + return std::nullopt; } auto& md = iter->second.ms_metadata; @@ -1194,7 +1194,7 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) if (vl >= lfo->lfo_filter_state.tfs_index.size() || md.m_sections_root == nullptr) { - return nonstd::nullopt; + return std::nullopt; } auto ll_iter = lf->begin() + lfo->lfo_filter_state.tfs_index[vl]; auto line_offsets = lf->get_file_range(ll_iter, false); @@ -1207,7 +1207,7 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) log_debug(" no path found"); auto neighbors_res = md.m_sections_root->line_neighbors(vl); if (!neighbors_res) { - return nonstd::nullopt; + return std::nullopt; } switch (dir) { @@ -1229,7 +1229,7 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) break; } } - return nonstd::nullopt; + return std::nullopt; } log_debug(" path for line: %s", fmt::to_string(path_for_line).c_str()); @@ -1241,7 +1241,7 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) if (!parent_opt) { log_debug(" no parent for path: %s", fmt::to_string(path_for_line).c_str()); - return nonstd::nullopt; + return std::nullopt; } auto parent = parent_opt.value(); @@ -1249,14 +1249,14 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) if (!child_hn) { // XXX "should not happen" log_debug(" child not found"); - return nonstd::nullopt; + return std::nullopt; } auto neighbors_res = parent->child_neighbors( child_hn.value(), line_offsets.next_offset() + 1); if (!neighbors_res) { log_debug(" no neighbors found"); - return nonstd::nullopt; + return std::nullopt; } log_debug(" neighbors p:%d n:%d", @@ -1295,15 +1295,15 @@ textfile_sub_source::adjacent_anchor(vis_line_t vl, text_anchors::direction dir) } } - return nonstd::nullopt; + return std::nullopt; } -nonstd::optional +std::optional textfile_sub_source::anchor_for_row(vis_line_t vl) { auto lf = this->current_file(); if (!lf) { - return nonstd::nullopt; + return std::nullopt; } auto rend_iter = this->tss_rendered_files.find(lf->get_filename()); @@ -1313,12 +1313,12 @@ textfile_sub_source::anchor_for_row(vis_line_t vl) auto iter = this->tss_doc_metadata.find(lf->get_filename()); if (iter == this->tss_doc_metadata.end()) { - return nonstd::nullopt; + return std::nullopt; } auto* lfo = dynamic_cast(lf->get_logline_observer()); if (vl >= lfo->lfo_filter_state.tfs_index.size()) { - return nonstd::nullopt; + return std::nullopt; } auto& md = iter->second.ms_metadata; auto ll_iter = lf->begin() + lfo->lfo_filter_state.tfs_index[vl]; @@ -1327,7 +1327,7 @@ textfile_sub_source::anchor_for_row(vis_line_t vl) = md.path_for_range(line_offsets.fr_offset, line_offsets.next_offset()); if (path_for_line.empty()) { - return nonstd::nullopt; + return std::nullopt; } if ((path_for_line.size() == 1 diff --git a/src/textfile_sub_source.hh b/src/textfile_sub_source.hh index e9b759ee..7f66555b 100644 --- a/src/textfile_sub_source.hh +++ b/src/textfile_sub_source.hh @@ -125,8 +125,8 @@ public: }; rescan_result_t rescan_files(scan_callback& callback, - nonstd::optional deadline - = nonstd::nullopt); + std::optional deadline + = std::nullopt); void text_filters_changed() override; @@ -136,7 +136,7 @@ public: text_format_t get_text_format() const override; - nonstd::optional get_location_history() override + std::optional get_location_history() override { return this; } @@ -144,11 +144,11 @@ public: void text_crumbs_for_line(int line, std::vector& crumbs) override; - nonstd::optional row_for_anchor(const std::string& id) override; + std::optional row_for_anchor(const std::string& id) override; - nonstd::optional anchor_for_row(vis_line_t vl) override; + std::optional anchor_for_row(vis_line_t vl) override; - nonstd::optional adjacent_anchor(vis_line_t vl, + std::optional adjacent_anchor(vis_line_t vl, direction dir) override; std::unordered_set get_anchors() override; diff --git a/src/textview_curses.cc b/src/textview_curses.cc index c0783664..7ca33d94 100644 --- a/src/textview_curses.cc +++ b/src/textview_curses.cc @@ -164,12 +164,12 @@ text_accel_source::get_time_offset_for_line(textview_curses& tc, vis_line_t vl) = tc.get_bookmarks()[&textview_curses::BM_USER_EXPR].next(vl); if (!prev_umark && !prev_emark && (next_umark || next_emark)) { auto next_line = this->text_accel_get_line( - std::max(next_umark.value_or(0), next_emark.value_or(0))); + std::max(next_umark.value_or(0_vl), next_emark.value_or(0_vl))); diff_tv = curr_tv - next_line->get_timeval(); } else { auto prev_row - = std::max(prev_umark.value_or(0), prev_emark.value_or(0)); + = std::max(prev_umark.value_or(0_vl), prev_emark.value_or(0_vl)); auto first_line = this->text_accel_get_line(prev_row); auto start_tv = first_line->get_timeval(); diff_tv = curr_tv - start_tv; @@ -289,7 +289,7 @@ textview_curses::reload_config(error_reporter& reporter) void textview_curses::invoke_scroll() { - this->tc_selected_text = nonstd::nullopt; + this->tc_selected_text = std::nullopt; if (this->tc_sub_source != nullptr) { this->tc_sub_source->scroll_invoked(this); } @@ -300,7 +300,7 @@ textview_curses::invoke_scroll() void textview_curses::reload_data() { - this->tc_selected_text = nonstd::nullopt; + this->tc_selected_text = std::nullopt; if (this->tc_sub_source != nullptr) { this->tc_sub_source->text_update_marks(this->tc_bookmarks); } @@ -427,12 +427,12 @@ textview_curses::handle_mouse(mouse_event& me) && (me.me_button != mouse_button_t::BUTTON_LEFT || me.me_state != mouse_button_state_t::BUTTON_STATE_RELEASED)) { - this->tc_selected_text = nonstd::nullopt; + this->tc_selected_text = std::nullopt; this->set_needs_update(); } - nonstd::optional overlay_content_min_y; - nonstd::optional overlay_content_max_y; + std::optional overlay_content_min_y; + std::optional overlay_content_max_y; if (this->tc_press_line.is()) { auto main_line = this->tc_press_line.get().oc_main_line; @@ -687,7 +687,7 @@ textview_curses::handle_mouse(mouse_event& me) this->get_selection()); this->reload_data(); } - this->tc_selection_start = nonstd::nullopt; + this->tc_selection_start = std::nullopt; } if (this->tc_delegate != nullptr) { this->tc_delegate->text_handle_mouse(*this, mouse_line, me); @@ -696,7 +696,7 @@ textview_curses::handle_mouse(mouse_event& me) sub_delegate->text_handle_mouse(*this, mouse_line, me); } if (mouse_line.is()) { - this->tc_selected_text = nonstd::nullopt; + this->tc_selected_text = std::nullopt; this->set_needs_update(); } break; @@ -908,7 +908,7 @@ textview_curses::execute_search(const std::string& regex_orig) } } -nonstd::optional> +std::optional> textview_curses::horiz_shift(vis_line_t start, vis_line_t end, int off_start) { auto hl_iter @@ -916,7 +916,7 @@ textview_curses::horiz_shift(vis_line_t start, vis_line_t end, int off_start) if (hl_iter == this->tc_highlights.end() || hl_iter->second.h_regex == nullptr) { - return nonstd::nullopt; + return std::nullopt; } int prev_hit = -1, next_hit = INT_MAX; @@ -937,7 +937,7 @@ textview_curses::horiz_shift(vis_line_t start, vis_line_t end, int off_start) } if (prev_hit == -1 && next_hit == INT_MAX) { - return nonstd::nullopt; + return std::nullopt; } return std::make_pair(prev_hit, next_hit); } @@ -1099,7 +1099,7 @@ void text_time_translator::data_reloaded(textview_curses* tc) { if (tc->get_inner_height() == 0) { - this->ttt_top_row_info = nonstd::nullopt; + this->ttt_top_row_info = std::nullopt; return; } if (this->ttt_top_row_info) { @@ -1111,7 +1111,7 @@ text_time_translator::data_reloaded(textview_curses* tc) template class bookmark_vector; bool -empty_filter::matches(nonstd::optional ls, +empty_filter::matches(std::optional ls, const shared_buffer_ref& line) { return false; @@ -1123,7 +1123,7 @@ empty_filter::to_command() const return ""; } -nonstd::optional +std::optional filter_stack::next_index() { bool used[32]; @@ -1148,7 +1148,7 @@ filter_stack::next_index() return lpc; } } - return nonstd::nullopt; + return std::nullopt; } std::shared_ptr @@ -1252,7 +1252,7 @@ vis_location_history::loc_history_append(vis_line_t top) this->vlh_history.push_back(top); } -nonstd::optional +std::optional vis_location_history::loc_history_back(vis_line_t current_top) { if (this->lh_history_position == 0) { @@ -1263,7 +1263,7 @@ vis_location_history::loc_history_back(vis_line_t current_top) } if (this->lh_history_position + 1 >= this->vlh_history.size()) { - return nonstd::nullopt; + return std::nullopt; } this->lh_history_position += 1; @@ -1271,11 +1271,11 @@ vis_location_history::loc_history_back(vis_line_t current_top) return this->current_position(); } -nonstd::optional +std::optional vis_location_history::loc_history_forward(vis_line_t current_top) { if (this->lh_history_position == 0) { - return nonstd::nullopt; + return std::nullopt; } this->lh_history_position -= 1; @@ -1367,21 +1367,21 @@ logfile_filter_state::resize(size_t newsize) } } -nonstd::optional +std::optional logfile_filter_state::content_line_to_vis_line(uint32_t line) { if (this->tfs_index.empty()) { - return nonstd::nullopt; + return std::nullopt; } auto iter = std::lower_bound( this->tfs_index.begin(), this->tfs_index.end(), line); if (iter == this->tfs_index.end() || *iter != line) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::make_optional(std::distance(this->tfs_index.begin(), iter)); + return std::make_optional(std::distance(this->tfs_index.begin(), iter)); } std::string diff --git a/src/textview_curses.hh b/src/textview_curses.hh index 4f80a01e..3e6ab142 100644 --- a/src/textview_curses.hh +++ b/src/textview_curses.hh @@ -65,7 +65,7 @@ public: void resize(size_t newsize); - nonstd::optional content_line_to_vis_line(uint32_t line); + std::optional content_line_to_vis_line(uint32_t line); const static int MAX_FILTERS = 32; @@ -124,7 +124,7 @@ public: logfile_const_iterator ls_line; }; - virtual bool matches(nonstd::optional ls, + virtual bool matches(std::optional ls, const shared_buffer_ref& line) = 0; @@ -149,7 +149,7 @@ public: { } - bool matches(nonstd::optional ls, + bool matches(std::optional ls, const shared_buffer_ref& line) override; std::string to_command() const override; @@ -168,7 +168,7 @@ public: ~pcre_filter() override = default; - bool matches(nonstd::optional ls, + bool matches(std::optional ls, const shared_buffer_ref& line) override { return this->pf_pcre->find_in(line.to_string_fragment()) @@ -214,7 +214,7 @@ public: == logfile_filter_state::MAX_FILTERS; } - nonstd::optional next_index(); + std::optional next_index(); void add_filter(const std::shared_ptr& filter); @@ -259,23 +259,23 @@ public: virtual ~text_time_translator() = default; - virtual nonstd::optional row_for_time( + virtual std::optional row_for_time( struct timeval time_bucket) = 0; - virtual nonstd::optional row_for(const row_info& ri) + virtual std::optional row_for(const row_info& ri) { return this->row_for_time(ri.ri_time); } - virtual nonstd::optional time_for_row(vis_line_t row) = 0; + virtual std::optional time_for_row(vis_line_t row) = 0; void data_reloaded(textview_curses* tc); void ttt_scroll_invoked(textview_curses* tc); protected: - nonstd::optional ttt_top_row_info; + std::optional ttt_top_row_info; }; class text_accel_source { @@ -321,7 +321,7 @@ public: static std::string to_anchor_string(const std::string& raw); - virtual nonstd::optional row_for_anchor(const std::string& id) + virtual std::optional row_for_anchor(const std::string& id) = 0; enum class direction { @@ -329,13 +329,13 @@ public: next, }; - virtual nonstd::optional adjacent_anchor(vis_line_t vl, + virtual std::optional adjacent_anchor(vis_line_t vl, direction dir) { - return nonstd::nullopt; + return std::nullopt; } - virtual nonstd::optional anchor_for_row(vis_line_t vl) = 0; + virtual std::optional anchor_for_row(vis_line_t vl) = 0; virtual std::unordered_set get_anchors() = 0; }; @@ -346,11 +346,11 @@ public: virtual void loc_history_append(vis_line_t top) = 0; - virtual nonstd::optional loc_history_back( + virtual std::optional loc_history_back( vis_line_t current_top) = 0; - virtual nonstd::optional loc_history_forward( + virtual std::optional loc_history_forward( vis_line_t current_top) = 0; @@ -487,16 +487,16 @@ public: return text_format_t::TF_UNKNOWN; } - virtual nonstd::optional< + virtual std::optional< std::pair*, grep_proc_sink*>> get_grepper() { - return nonstd::nullopt; + return std::nullopt; } - virtual nonstd::optional get_location_history() + virtual std::optional get_location_history() { - return nonstd::nullopt; + return std::nullopt; } void toggle_apply_filters(); @@ -526,10 +526,10 @@ public: void loc_history_append(vis_line_t top) override; - nonstd::optional loc_history_back( + std::optional loc_history_back( vis_line_t current_top) override; - nonstd::optional loc_history_forward( + std::optional loc_history_forward( vis_line_t current_top) override; nonstd::ring_span vlh_history; @@ -627,7 +627,7 @@ public: return this->tc_delegate; } - nonstd::optional> horiz_shift(vis_line_t start, + std::optional> horiz_shift(vis_line_t start, vis_line_t end, int off_start); @@ -800,8 +800,8 @@ public: std::function tc_state_event_handler; - nonstd::optional tc_cursor_role; - nonstd::optional tc_disabled_cursor_role; + std::optional tc_cursor_role; + std::optional tc_disabled_cursor_role; struct selected_text_info { int sti_x; @@ -810,7 +810,7 @@ public: std::string sti_value; }; - nonstd::optional tc_selected_text; + std::optional tc_selected_text; bool tc_text_selection_active{false}; display_line_content_t tc_press_line; int tc_press_left{0}; @@ -861,7 +861,7 @@ protected: highlight_map_t tc_highlights; std::set tc_disabled_highlights; - nonstd::optional tc_selection_start; + std::optional tc_selection_start; mouse_event tc_press_event; bool tc_hide_fields{true}; bool tc_paused{false}; diff --git a/src/time-extension-functions.cc b/src/time-extension-functions.cc index b6567fd1..d833aff9 100644 --- a/src/time-extension-functions.cc +++ b/src/time-extension-functions.cc @@ -44,8 +44,8 @@ #include "sql_util.hh" #include "vtab_module.hh" -static nonstd::optional -timeslice(sqlite3_value* time_in, nonstd::optional slice_in_opt) +static std::optional +timeslice(sqlite3_value* time_in, std::optional slice_in_opt) { thread_local date_time_scanner dts; thread_local struct { @@ -128,14 +128,14 @@ timeslice(sqlite3_value* time_in, nonstd::optional slice_in_opt) break; } case SQLITE_NULL: { - return nonstd::nullopt; + return std::nullopt; } } auto win_start_opt = cache.c_rel_time.window_start(tm); if (!win_start_opt) { - return nonstd::nullopt; + return std::nullopt; } auto win_start = *win_start_opt; @@ -147,7 +147,7 @@ timeslice(sqlite3_value* time_in, nonstd::optional slice_in_opt) return text_auto_buffer{std::move(ts)}; } -static nonstd::optional +static std::optional sql_timediff(string_fragment time1, string_fragment time2) { struct timeval tv1, tv2, retval; @@ -159,7 +159,7 @@ sql_timediff(string_fragment time1, string_fragment time2) } else if (!dts1.convert_to_timeval( time1.data(), time1.length(), nullptr, tv1)) { - return nonstd::nullopt; + return std::nullopt; } auto parse_res2 = relative_time::from_str(time2); @@ -168,7 +168,7 @@ sql_timediff(string_fragment time1, string_fragment time2) } else if (!dts2.convert_to_timeval( time2.data(), time2.length(), nullptr, tv2)) { - return nonstd::nullopt; + return std::nullopt; } timersub(&tv1, &tv2, &retval); @@ -188,7 +188,7 @@ sql_humanize_duration(double value) return humanize::time::duration::from_tv(tv).to_string(); } -static nonstd::optional +static std::optional sql_timezone(std::string tz_str, string_fragment ts_str) { thread_local date_time_scanner dts; diff --git a/src/view_curses.cc b/src/view_curses.cc index 352ee42f..c2914ccb 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -353,7 +353,6 @@ view_curses::mvwattrline(WINDOW* window, full_line = expanded_line; auto& vc = view_colors::singleton(); - auto text_role_attrs = vc.attrs_for_role(role_t::VCR_TEXT); auto base_attrs = vc.attrs_for_role(base_role); wmove(window, y, x); wattr_set( @@ -453,8 +452,8 @@ view_curses::mvwattrline(WINDOW* window, if (attr_range.lr_start < attr_range.lr_end) { auto attrs = text_attrs{}; - nonstd::optional graphic; - nonstd::optional block_elem; + std::optional graphic; + std::optional block_elem; if (iter->sa_type == &VC_GRAPHIC) { graphic = iter->sa_value.get(); @@ -734,7 +733,7 @@ view_colors::init(bool headless) } inline text_attrs -attr_for_colors(nonstd::optional fg, nonstd::optional bg) +attr_for_colors(std::optional fg, std::optional bg) { if (fg && fg.value() == -1) { fg = COLOR_WHITE; @@ -1264,8 +1263,7 @@ view_colors::ensure_color_pair(short fg, short bg) } int -view_colors::ensure_color_pair(nonstd::optional fg, - nonstd::optional bg) +view_colors::ensure_color_pair(std::optional fg, std::optional bg) { return this->ensure_color_pair(fg.value_or(-1), bg.value_or(-1)); } @@ -1280,23 +1278,23 @@ view_colors::ensure_color_pair(const styling::color_unit& rgb_fg, return this->ensure_color_pair(fg, bg); } -nonstd::optional +std::optional view_colors::match_color(const styling::color_unit& color) const { return color.cu_value.match( - [](styling::semantic) -> nonstd::optional { + [](styling::semantic) -> std::optional { return MATCH_COLOR_SEMANTIC; }, - [](const rgb_color& color) -> nonstd::optional { + [](const rgb_color& color) -> std::optional { if (color.empty()) { - return nonstd::nullopt; + return std::nullopt; } return vc_active_palette->match_color(lab_color(color)); }); } -nonstd::optional +std::optional view_colors::color_for_ident(const char* str, size_t len) const { auto index = crc32(1, (const Bytef*) str, len); diff --git a/src/view_curses.hh b/src/view_curses.hh index eb2fb15d..5fc9b2de 100644 --- a/src/view_curses.hh +++ b/src/view_curses.hh @@ -67,7 +67,6 @@ #include "base/opt_util.hh" #include "lnav_config_fwd.hh" #include "log_level.hh" -#include "optional.hpp" #include "styling.hh" class view_curses; @@ -226,9 +225,9 @@ public: : this->vc_role_attrs[lnav::enums::to_underlying(role)].ra_normal; } - nonstd::optional color_for_ident(const char* str, size_t len) const; + std::optional color_for_ident(const char* str, size_t len) const; - nonstd::optional color_for_ident(const string_fragment& sf) const + std::optional color_for_ident(const string_fragment& sf) const { return this->color_for_ident(sf.data(), sf.length()); } @@ -252,8 +251,8 @@ public: int ensure_color_pair(short fg, short bg); - int ensure_color_pair(nonstd::optional fg, - nonstd::optional bg); + int ensure_color_pair(std::optional fg, + std::optional bg); int ensure_color_pair(const styling::color_unit& fg, const styling::color_unit& bg); @@ -261,7 +260,7 @@ public: static constexpr short MATCH_COLOR_DEFAULT = -1; static constexpr short MATCH_COLOR_SEMANTIC = -10; - nonstd::optional match_color(const styling::color_unit& color) const; + std::optional match_color(const styling::color_unit& color) const; short ansi_to_theme_color(short ansi_fg) const { @@ -480,10 +479,10 @@ class view_stack : public view_curses { public: using iterator = typename std::vector::iterator; - nonstd::optional top() + std::optional top() { if (this->vs_views.empty()) { - return nonstd::nullopt; + return std::nullopt; } return this->vs_views.back(); } diff --git a/src/view_helpers.cc b/src/view_helpers.cc index d79f7745..45a9cd00 100644 --- a/src/view_helpers.cc +++ b/src/view_helpers.cc @@ -81,11 +81,11 @@ const char* lnav_view_titles[LNV__MAX] = { "GANTT", }; -nonstd::optional +std::optional view_from_string(const char* name) { if (name == nullptr) { - return nonstd::nullopt; + return std::nullopt; } auto* view_name_iter @@ -96,7 +96,7 @@ view_from_string(const char* name) }); if (view_name_iter == std::end(lnav_view_strings)) { - return nonstd::nullopt; + return std::nullopt; } return lnav_view_t(view_name_iter - lnav_view_strings); @@ -900,7 +900,7 @@ update_hits(textview_curses* tc) } } - nonstd::optional next_vl; + std::optional next_vl; while ((next_vl = bv.next(vl)) && preview_count < MAX_MATCH_COUNT) { if (next_vl.value() < 0_vl || next_vl.value() >= tc->get_inner_height()) @@ -1155,8 +1155,8 @@ ensure_view(lnav_view_t expected) return ensure_view(&lnav_data.ld_views[expected]); } -nonstd::optional -next_cluster(nonstd::optional (bookmark_vector::*f)( +std::optional +next_cluster(std::optional (bookmark_vector::*f)( vis_line_t) const, const bookmark_type_t* bt, const vis_line_t top) @@ -1166,7 +1166,7 @@ next_cluster(nonstd::optional (bookmark_vector::*f)( auto& bv = bm[bt]; bool top_is_marked = binary_search(bv.begin(), bv.end(), top); vis_line_t last_top(top), tc_height; - nonstd::optional new_top = top; + std::optional new_top = top; unsigned long tc_width; int hit_count = 0; @@ -1202,11 +1202,11 @@ next_cluster(nonstd::optional (bookmark_vector::*f)( return last_top; } - return nonstd::nullopt; + return std::nullopt; } bool -moveto_cluster(nonstd::optional (bookmark_vector::*f)( +moveto_cluster(std::optional (bookmark_vector::*f)( vis_line_t) const, const bookmark_type_t* bt, vis_line_t top) @@ -1328,7 +1328,7 @@ view_title_poss() for (int view_index = 0; view_index < LNV__MAX; view_index++) { attr_line_t display_value{lnav_view_titles[view_index]}; - nonstd::optional quantity; + std::optional quantity; std::string units; switch (view_index) { diff --git a/src/view_helpers.hh b/src/view_helpers.hh index de3d43ab..76d26f8e 100644 --- a/src/view_helpers.hh +++ b/src/view_helpers.hh @@ -80,7 +80,7 @@ enum class ln_mode_t : int { extern const char* lnav_view_strings[LNV__MAX + 1]; extern const char* lnav_view_titles[LNV__MAX]; -nonstd::optional view_from_string(const char* name); +std::optional view_from_string(const char* name); bool ensure_view(textview_curses* expected_tc); bool ensure_view(lnav_view_t expected); @@ -91,12 +91,12 @@ void update_hits(textview_curses* tc); void clear_preview(); void set_view_mode(ln_mode_t mode); -nonstd::optional next_cluster( - nonstd::optional (bookmark_vector::*f)(vis_line_t) +std::optional next_cluster( + std::optional (bookmark_vector::*f)(vis_line_t) const, const bookmark_type_t* bt, vis_line_t top); -bool moveto_cluster(nonstd::optional ( +bool moveto_cluster(std::optional ( bookmark_vector::*f)(vis_line_t) const, const bookmark_type_t* bt, vis_line_t top); diff --git a/src/views_vtab.cc b/src/views_vtab.cc index 7c399afb..0412f1f3 100644 --- a/src/views_vtab.cc +++ b/src/views_vtab.cc @@ -160,9 +160,9 @@ static const typed_json_path_container breadcrumb_crumb_handlers }; struct top_line_meta { - nonstd::optional tlm_time; - nonstd::optional tlm_file; - nonstd::optional tlm_anchor; + std::optional tlm_time; + std::optional tlm_file; + std::optional tlm_anchor; std::vector tlm_crumbs; }; @@ -202,11 +202,11 @@ enum class word_wrap_t { }; struct view_options { - nonstd::optional vo_row_details; - nonstd::optional vo_row_time_offset; - nonstd::optional vo_overlay_focus; - nonstd::optional vo_word_wrap; - nonstd::optional vo_hidden_fields; + std::optional vo_row_details; + std::optional vo_row_time_offset; + std::optional vo_overlay_focus; + std::optional vo_word_wrap; + std::optional vo_hidden_fields; bool empty() const { @@ -343,7 +343,7 @@ CREATE TABLE lnav_views ( [](const auto wrapper) { auto lf = wrapper.get(); - return nonstd::make_optional(lf->get_filename()); + return std::make_optional(lf->get_filename()); }; })); break; @@ -411,7 +411,7 @@ CREATE TABLE lnav_views ( | [](const auto wrapper) { auto lf = wrapper.get(); - return nonstd::make_optional( + return std::make_optional( lf->get_filename()); }; }); @@ -517,8 +517,8 @@ CREATE TABLE lnav_views ( string_fragment movement, const char* top_meta, int64_t selection, - nonstd::optional options, - nonstd::optional selected_text) + std::optional options, + std::optional selected_text) { auto& tc = lnav_data.ld_views[index]; auto* time_source @@ -922,10 +922,10 @@ CREATE TABLE lnav_view_filters ( int insert_row(sqlite3_vtab* tab, sqlite3_int64& rowid_out, lnav_view_t view_index, - nonstd::optional _filter_id, - nonstd::optional enabled, - nonstd::optional type, - nonstd::optional lang, + std::optional _filter_id, + std::optional enabled, + std::optional type, + std::optional lang, sqlite3_value* pattern_str) { auto* mod_vt = (vtab_module::vtab*) tab; @@ -935,7 +935,7 @@ CREATE TABLE lnav_view_filters ( auto filter_index = lang.value_or(filter_lang_t::REGEX) == filter_lang_t::REGEX ? fs.next_index() - : nonstd::make_optional(size_t{0}); + : std::make_optional(size_t{0}); if (!filter_index) { throw sqlite_func_error("Too many filters"); } diff --git a/src/vtab_module.hh b/src/vtab_module.hh index ff08bfd2..64e7e38a 100644 --- a/src/vtab_module.hh +++ b/src/vtab_module.hh @@ -44,7 +44,6 @@ #include "fmt/format.h" #include "help_text_formatter.hh" #include "mapbox/variant.hpp" -#include "optional.hpp" #include "sqlite-extension-func.hh" lnav::console::user_message sqlite3_error_to_user_message(sqlite3*); @@ -181,16 +180,16 @@ struct from_sqlite { }; template -struct from_sqlite> { - inline nonstd::optional operator()(int argc, +struct from_sqlite> { + inline std::optional operator()(int argc, sqlite3_value** val, int argi) { if (argi >= argc || sqlite3_value_type(val[argi]) == SQLITE_NULL) { - return nonstd::nullopt; + return std::nullopt; } - return nonstd::optional(from_sqlite()(argc, val, argi)); + return std::optional(from_sqlite()(argc, val, argi)); } }; @@ -305,7 +304,7 @@ to_sqlite(sqlite3_context* ctx, auto_mem str) template inline void -to_sqlite(sqlite3_context* ctx, nonstd::optional& val) +to_sqlite(sqlite3_context* ctx, std::optional& val) { if (val.has_value()) { to_sqlite(ctx, val.value()); @@ -316,7 +315,7 @@ to_sqlite(sqlite3_context* ctx, nonstd::optional& val) template inline void -to_sqlite(sqlite3_context* ctx, nonstd::optional val) +to_sqlite(sqlite3_context* ctx, std::optional val) { if (val.has_value()) { to_sqlite(ctx, std::move(val.value())); @@ -352,17 +351,17 @@ struct optional_counter { }; template -struct optional_counter> { +struct optional_counter> { constexpr static int value = 1; }; template -struct optional_counter, const std::vector&> { +struct optional_counter, const std::vector&> { constexpr static int value = 1; }; template -struct optional_counter, Rest...> { +struct optional_counter, Rest...> { constexpr static int value = 1 + sizeof...(Rest); }; diff --git a/src/yajlpp/yajlpp.cc b/src/yajlpp/yajlpp.cc index 0fc00014..a00d8f90 100644 --- a/src/yajlpp/yajlpp.cc +++ b/src/yajlpp/yajlpp.cc @@ -461,19 +461,23 @@ json_path_handler_base::walk( this->jph_path_provider(root, local_paths); for (const auto& lpath : local_paths) { + const void* field = nullptr; + if (this->jph_field_getter) { + field = this->jph_field_getter(root, lpath); + } cb(*this, fmt::format(FMT_STRING("{}{}{}"), base, json_ptr::encode_str(lpath), this->jph_children ? "/" : ""), - nullptr); + field); } if (this->jph_obj_deleter) { 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); + const auto* field = this->jph_field_getter(root, std::nullopt); if (field != nullptr) { cb(*this, base, field); } @@ -484,9 +488,13 @@ json_path_handler_base::walk( std::string full_path = base + this->jph_property; if (this->jph_children) { full_path += "/"; - } - cb(*this, full_path, nullptr); + const void* field = nullptr; + if (this->jph_field_getter) { + field = this->jph_field_getter(root, this->jph_property); + } + cb(*this, full_path, field); + } } if (this->jph_children) { @@ -544,7 +552,7 @@ json_path_handler_base::walk( } } -nonstd::optional +std::optional json_path_handler_base::to_enum_value(const string_fragment& sf) const { for (int lpc = 0; this->jph_enum_values[lpc].first; lpc++) { @@ -555,7 +563,7 @@ json_path_handler_base::to_enum_value(const string_fragment& sf) const } } - return nonstd::nullopt; + return std::nullopt; } const char* diff --git a/src/yajlpp/yajlpp.hh b/src/yajlpp/yajlpp.hh index ecf97341..1a6aef2c 100644 --- a/src/yajlpp/yajlpp.hh +++ b/src/yajlpp/yajlpp.hh @@ -52,7 +52,6 @@ #include "base/lnav_log.hh" #include "base/opt_util.hh" #include "json_ptr.hh" -#include "optional.hpp" #include "pcrepp/pcre2pp.hh" #include "relative_time.hh" #include "yajl/api/yajl_gen.h" @@ -224,7 +223,7 @@ struct json_path_handler_base { bool is_array() const { return this->jph_is_array; } - nonstd::optional to_enum_value(const string_fragment& sf) const; + std::optional to_enum_value(const string_fragment& sf) const; const char* to_enum_string(int value) const; template @@ -271,7 +270,7 @@ struct json_path_handler_base { std::function jph_validator; - std::function name)> + std::function name)> jph_field_getter; std::function jph_obj_provider; @@ -572,7 +571,7 @@ public: } template - yajl_gen_status operator()(nonstd::optional value) + yajl_gen_status operator()(std::optional value) { if (!value.has_value()) { return yajl_gen_status_ok; diff --git a/src/yajlpp/yajlpp_def.hh b/src/yajlpp/yajlpp_def.hh index 7bcb687c..256f17cf 100644 --- a/src/yajlpp/yajlpp_def.hh +++ b/src/yajlpp/yajlpp_def.hh @@ -333,7 +333,7 @@ struct json_path_handler : public json_path_handler_base { }; template - struct LastIsEnum T::*> { + struct LastIsEnum T::*> { using value_type = U; static constexpr bool value = std::is_enum::value; @@ -351,7 +351,7 @@ struct json_path_handler : public json_path_handler_base { }; template - struct LastIsInteger T::*> { + struct LastIsInteger T::*> { static constexpr bool value = std::is_integral::value && !std::is_same::value; }; @@ -367,7 +367,7 @@ struct json_path_handler : public json_path_handler_base { }; template - struct LastIsFloat T::*> { + struct LastIsFloat T::*> { static constexpr bool value = std::is_same::value; }; @@ -416,6 +416,7 @@ struct json_path_handler : public json_path_handler_base { template struct LastIsMap { + static constexpr bool is_ptr = LastIsMap::is_ptr; using key_type = typename LastIsMap::key_type; using value_type = typename LastIsMap::value_type; static constexpr bool value = LastIsMap::value; @@ -423,6 +424,7 @@ struct json_path_handler : public json_path_handler_base { template struct LastIsMap> T::*> { + static constexpr bool is_ptr = true; using key_type = K; using value_type = U; static constexpr bool value = true; @@ -430,6 +432,7 @@ struct json_path_handler : public json_path_handler_base { template struct LastIsMap T::*> { + static constexpr bool is_ptr = false; using key_type = K; using value_type = U; static constexpr bool value = true; @@ -437,13 +440,14 @@ struct json_path_handler : public json_path_handler_base { template struct LastIsMap { + static constexpr bool is_ptr = false; using key_type = void; using value_type = void; static constexpr bool value = false; }; template - static bool is_field_set(const nonstd::optional& field) + static bool is_field_set(const std::optional& field) { return field.has_value(); } @@ -490,7 +494,7 @@ struct json_path_handler : public json_path_handler_base { return gen(field); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; @@ -581,6 +585,10 @@ struct json_path_handler : public json_path_handler_base { } return &child.pp_value; }; + this->jph_field_getter + = [field](void* root, std::optional name) { + return (void*) &json_path_handler::get_field(root, field); + }; return *this; } @@ -626,7 +634,7 @@ struct json_path_handler : public json_path_handler_base { }; this->jph_field_getter = [args...](void* root, - nonstd::optional name) -> const void* { + std::optional name) -> const void* { const auto& field = json_path_handler::get_field(root, args...); if (!name) { return &field; @@ -684,6 +692,30 @@ struct json_path_handler : public json_path_handler_base { paths_out.emplace_back(std::to_string(pair.first)); } }; + this->jph_field_getter + = [args...](void* root, + std::optional name) -> const void* { + const auto& field = json_path_handler::get_field(root, args...); + if (!name) { + return &field; + } + + if constexpr (std::is_same_v::key_type, + intern_string_t>) + { + auto iter = field.find(intern_string::lookup(name.value())); + if (iter == field.end()) { + return nullptr; + } + return (void*) &iter->second; + } else { + auto iter = field.find(name.value()); + if (iter == field.end()) { + return nullptr; + } + return (void*) &iter->second; + } + }; this->jph_obj_provider = [args...](const yajlpp_provider_context& ypc, void* root) { auto& field = json_path_handler::get_field(root, args...); @@ -707,7 +739,7 @@ struct json_path_handler : public json_path_handler_base { && !std::is_same::value_type>::value && !std::is_same< - nonstd::optional, + std::optional, typename LastIsMap::value_type>::value, bool> = true> @@ -733,7 +765,7 @@ struct json_path_handler : public json_path_handler_base { template>, + LastIs>, Args...>::value, bool> = true> @@ -755,7 +787,7 @@ struct json_path_handler : public json_path_handler_base { auto* obj = ypc->ypc_obj_stack.top(); auto key = ypc->get_path_fragment(-1); - json_path_handler::get_field(obj, args...)[key] = nonstd::nullopt; + json_path_handler::get_field(obj, args...)[key] = std::nullopt; return 1; }; @@ -899,7 +931,7 @@ struct json_path_handler : public json_path_handler_base { return gen(field); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; return *this; @@ -961,7 +993,7 @@ struct json_path_handler : public json_path_handler_base { return gen(string_fragment::from_bytes(buf, buf_len)); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; return *this; @@ -969,7 +1001,7 @@ struct json_path_handler : public json_path_handler_base { template< typename... Args, - std::enable_if_t, Args...>::value, + std::enable_if_t, Args...>::value, bool> = true> json_path_handler& for_field(Args... args) @@ -989,7 +1021,7 @@ struct json_path_handler : public json_path_handler_base { 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; + json_path_handler::get_field(obj, args...) = std::nullopt; return 1; }; @@ -1021,7 +1053,7 @@ struct json_path_handler : public json_path_handler_base { return gen(field.value()); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; return *this; @@ -1074,7 +1106,7 @@ struct json_path_handler : public json_path_handler_base { return gen(field.pp_value); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; return *this; @@ -1281,6 +1313,10 @@ struct json_path_handler : public json_path_handler_base { return gen(field.to_string()); }; + this->jph_field_getter + = [args..., ptr_arg](void* root, std::optional name) { + return &json_path_handler::get_field(root, args..., ptr_arg); + }; return *this; } @@ -1331,7 +1367,7 @@ struct json_path_handler : public json_path_handler_base { return gen(field); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; @@ -1384,7 +1420,7 @@ struct json_path_handler : public json_path_handler_base { return gen(field); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; @@ -1443,7 +1479,7 @@ struct json_path_handler : public json_path_handler_base { .to_string()); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; return *this; @@ -1497,7 +1533,7 @@ struct json_path_handler : public json_path_handler_base { return gen(jph.to_enum_string(field)); }; this->jph_field_getter - = [args...](void* root, nonstd::optional name) { + = [args...](void* root, std::optional name) { return (void*) &json_path_handler::get_field(root, args...); }; diff --git a/test/Makefile.am b/test/Makefile.am index f7d83f78..d53b66d8 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -203,6 +203,7 @@ dist_noinst_SCRIPTS = \ test_config.sh \ test_curl.sh \ test_data_parser.sh \ + test_demux.sh \ test_events.sh \ test_format_installer.sh \ test_format_loader.sh \ @@ -330,6 +331,8 @@ dist_noinst_DATA = \ logfile_crlf.0 \ logfile_cloudflare.json \ logfile_cxx.0 \ + logfile_docker_compose.0 \ + logfile_docker_compose_with_ts.0 \ logfile_empty.0 \ logfile_epoch.0 \ logfile_epoch.1 \ @@ -479,6 +482,8 @@ TESTS = \ test_cli.sh \ test_cmds.sh \ test_config.sh \ + test_data_parser.sh \ + test_demux.sh \ test_events.sh \ test_listview.sh \ test_meta.sh \ @@ -509,7 +514,6 @@ TESTS = \ test_text_anonymizer \ test_text_file.sh \ test_tui.sh \ - test_data_parser.sh \ test_pretty_print.sh \ test_view_colors.sh \ test_vt52_curses.sh diff --git a/test/expected/expected.am b/test/expected/expected.am index bedc4dcf..8e935eaf 100644 --- a/test/expected/expected.am +++ b/test/expected/expected.am @@ -12,12 +12,16 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_cli.sh_3114508cf42fb2608ef77f4bc294a84885c97a79.out \ $(srcdir)/%reldir%/test_cli.sh_4327033cfae0d4c170a38a3c4a570520bfabb493.err \ $(srcdir)/%reldir%/test_cli.sh_4327033cfae0d4c170a38a3c4a570520bfabb493.out \ + $(srcdir)/%reldir%/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.err \ + $(srcdir)/%reldir%/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.out \ $(srcdir)/%reldir%/test_cli.sh_5524542b1a6954ff9741155101497270a2f0c557.err \ $(srcdir)/%reldir%/test_cli.sh_5524542b1a6954ff9741155101497270a2f0c557.out \ $(srcdir)/%reldir%/test_cli.sh_76aa57821598962e59063a40c20171040c95a731.err \ $(srcdir)/%reldir%/test_cli.sh_76aa57821598962e59063a40c20171040c95a731.out \ $(srcdir)/%reldir%/test_cli.sh_97e19b9ff3775d84074455a2e8993a0611b1c269.err \ $(srcdir)/%reldir%/test_cli.sh_97e19b9ff3775d84074455a2e8993a0611b1c269.out \ + $(srcdir)/%reldir%/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.err \ + $(srcdir)/%reldir%/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.out \ $(srcdir)/%reldir%/test_cli.sh_af3ace7762b4cc150fcdcac86083b379bded7b32.err \ $(srcdir)/%reldir%/test_cli.sh_af3ace7762b4cc150fcdcac86083b379bded7b32.out \ $(srcdir)/%reldir%/test_cli.sh_c69c835a3c43210225cf62564b3e9584c899af20.err \ @@ -268,6 +272,12 @@ EXPECTED_FILES = \ $(srcdir)/%reldir%/test_config.sh_d708b6fd32d83ce0ee00ca5383388308ba5a06e1.out \ $(srcdir)/%reldir%/test_config.sh_eec3768ebc201ca63bca1411270965f78db1abfc.err \ $(srcdir)/%reldir%/test_config.sh_eec3768ebc201ca63bca1411270965f78db1abfc.out \ + $(srcdir)/%reldir%/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.err \ + $(srcdir)/%reldir%/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.out \ + $(srcdir)/%reldir%/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.err \ + $(srcdir)/%reldir%/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.out \ + $(srcdir)/%reldir%/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.err \ + $(srcdir)/%reldir%/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.out \ $(srcdir)/%reldir%/test_events.sh_09ba47d70bfca88e89faf29598c1095292cad435.err \ $(srcdir)/%reldir%/test_events.sh_09ba47d70bfca88e89faf29598c1095292cad435.out \ $(srcdir)/%reldir%/test_events.sh_153e221f3cb50f4d3e4581be0bf311e62489c42d.err \ diff --git a/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out b/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out index 1a62b0e3..95c25953 100644 --- a/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out +++ b/test/expected/test_cli.sh_0b3639753916f71254e8c9cce4ebb8bfd9978d3e.out @@ -5241,6 +5241,14 @@ "condition": ":c_ip IS NOT NULL AND $TEST_ANNO = '1'", "handler": "anno-test.sh" } + }, + "demux": { + "container": { + "pattern": "^(?:\\x1b\\[\\d*K)?(?[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]*)\\s+\\| (?\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d{9}Z )?(?.*)" + }, + "recv-with-pod": { + "pattern": "^(?\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}(?:Z|[+\\-]\\d{2}:\\d{2})) source=[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]* (?.*) kubernetes_host=(?[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]*) kubernetes_pod_name=(?[a-zA-Z0-9][a-zA-Z0-9_\\.\\-]*)" + } } }, "global": { diff --git a/test/expected/test_cli.sh_10c33e465ef7681c6b5519d05d557426b26cd43d.out b/test/expected/test_cli.sh_10c33e465ef7681c6b5519d05d557426b26cd43d.out index 26c71119..568fe05e 100644 --- a/test/expected/test_cli.sh_10c33e465ef7681c6b5519d05d557426b26cd43d.out +++ b/test/expected/test_cli.sh_10c33e465ef7681c6b5519d05d557426b26cd43d.out @@ -1 +1 @@ - just now piper://p-e25e2eb68547f31e42da0818b4d0084f-000  33.0 B “[0] echo hi” + just now piper://p-c2c985d5a09bfe95a9997cc8952c5269-000  33.0 B “sh-0 echo hi” diff --git a/test/expected/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.err b/test/expected/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.out b/test/expected/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.out new file mode 100644 index 00000000..236d6ccc --- /dev/null +++ b/test/expected/test_cli.sh_4761827b538a623c60d2e7d243bae9b653bb1975.out @@ -0,0 +1,9 @@ +[ + { + "filepath": "sh-0 echo hi", + "descriptor": "org.lnav.piper.header", + "mimetype": "application/json", + "ctime": "2013-06-06T19:13:20.000", + "cwd": "{test_dir}" + } +] diff --git a/test/expected/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.err b/test/expected/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.out b/test/expected/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.out new file mode 100644 index 00000000..45b983be --- /dev/null +++ b/test/expected/test_cli.sh_a2f9a3e798e5f4f09c92eaa25ae236a2fb09dbd9.out @@ -0,0 +1 @@ +hi diff --git a/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out b/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out index 22a87a39..d0fcb1ff 100644 --- a/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out +++ b/test/expected/test_cli.sh_cc06341dd560f927512e92c7c0985ed8b25827ae.out @@ -19,41 +19,43 @@ /log/annotations/org.lnav.test/description -> {test_dir}/configs/installed/anno-test.json:6 /log/annotations/org.lnav.test/handler -> {test_dir}/configs/installed/anno-test.json:8 /log/date-time/convert-zoned-to-local -> root-config.json:18 -/tuning/archive-manager/cache-ttl -> root-config.json:31 -/tuning/archive-manager/min-free-space -> root-config.json:30 -/tuning/clipboard/impls/MacOS/find/read -> root-config.json:59 -/tuning/clipboard/impls/MacOS/find/write -> root-config.json:58 -/tuning/clipboard/impls/MacOS/general/read -> root-config.json:55 -/tuning/clipboard/impls/MacOS/general/write -> root-config.json:54 -/tuning/clipboard/impls/MacOS/test -> root-config.json:52 -/tuning/clipboard/impls/NeoVim/general/read -> root-config.json:87 -/tuning/clipboard/impls/NeoVim/general/write -> root-config.json:86 -/tuning/clipboard/impls/NeoVim/test -> root-config.json:84 -/tuning/clipboard/impls/Wayland/general/read -> root-config.json:66 -/tuning/clipboard/impls/Wayland/general/write -> root-config.json:65 -/tuning/clipboard/impls/Wayland/test -> root-config.json:63 -/tuning/clipboard/impls/Windows/general/write -> root-config.json:93 -/tuning/clipboard/impls/Windows/test -> root-config.json:91 -/tuning/clipboard/impls/X11-xclip/general/read -> root-config.json:73 -/tuning/clipboard/impls/X11-xclip/general/write -> root-config.json:72 -/tuning/clipboard/impls/X11-xclip/test -> root-config.json:70 -/tuning/clipboard/impls/tmux/general/read -> root-config.json:80 -/tuning/clipboard/impls/tmux/general/write -> root-config.json:79 -/tuning/clipboard/impls/tmux/test -> root-config.json:77 -/tuning/piper/max-size -> root-config.json:45 -/tuning/piper/rotations -> root-config.json:46 -/tuning/piper/ttl -> root-config.json:47 -/tuning/remote/ssh/command -> root-config.json:35 -/tuning/remote/ssh/config/BatchMode -> root-config.json:37 -/tuning/remote/ssh/config/ConnectTimeout -> root-config.json:38 -/tuning/remote/ssh/start-command -> root-config.json:40 -/tuning/remote/ssh/transfer-command -> root-config.json:41 -/tuning/url-scheme/docker-compose/handler -> root-config.json:103 -/tuning/url-scheme/docker/handler -> root-config.json:100 +/log/demux/container/pattern -> root-config.json:29 +/log/demux/recv-with-pod/pattern -> root-config.json:32 +/tuning/archive-manager/cache-ttl -> root-config.json:39 +/tuning/archive-manager/min-free-space -> root-config.json:38 +/tuning/clipboard/impls/MacOS/find/read -> root-config.json:67 +/tuning/clipboard/impls/MacOS/find/write -> root-config.json:66 +/tuning/clipboard/impls/MacOS/general/read -> root-config.json:63 +/tuning/clipboard/impls/MacOS/general/write -> root-config.json:62 +/tuning/clipboard/impls/MacOS/test -> root-config.json:60 +/tuning/clipboard/impls/NeoVim/general/read -> root-config.json:95 +/tuning/clipboard/impls/NeoVim/general/write -> root-config.json:94 +/tuning/clipboard/impls/NeoVim/test -> root-config.json:92 +/tuning/clipboard/impls/Wayland/general/read -> root-config.json:74 +/tuning/clipboard/impls/Wayland/general/write -> root-config.json:73 +/tuning/clipboard/impls/Wayland/test -> root-config.json:71 +/tuning/clipboard/impls/Windows/general/write -> root-config.json:101 +/tuning/clipboard/impls/Windows/test -> root-config.json:99 +/tuning/clipboard/impls/X11-xclip/general/read -> root-config.json:81 +/tuning/clipboard/impls/X11-xclip/general/write -> root-config.json:80 +/tuning/clipboard/impls/X11-xclip/test -> root-config.json:78 +/tuning/clipboard/impls/tmux/general/read -> root-config.json:88 +/tuning/clipboard/impls/tmux/general/write -> root-config.json:87 +/tuning/clipboard/impls/tmux/test -> root-config.json:85 +/tuning/piper/max-size -> root-config.json:53 +/tuning/piper/rotations -> root-config.json:54 +/tuning/piper/ttl -> root-config.json:55 +/tuning/remote/ssh/command -> root-config.json:43 +/tuning/remote/ssh/config/BatchMode -> root-config.json:45 +/tuning/remote/ssh/config/ConnectTimeout -> root-config.json:46 +/tuning/remote/ssh/start-command -> root-config.json:48 +/tuning/remote/ssh/transfer-command -> root-config.json:49 +/tuning/url-scheme/docker-compose/handler -> root-config.json:111 +/tuning/url-scheme/docker/handler -> root-config.json:108 /tuning/url-scheme/hw/handler -> {test_dir}/configs/installed/hw-url-handler.json:6 -/tuning/url-scheme/journald/handler -> root-config.json:106 -/tuning/url-scheme/piper/handler -> root-config.json:109 -/tuning/url-scheme/podman/handler -> root-config.json:112 +/tuning/url-scheme/journald/handler -> root-config.json:114 +/tuning/url-scheme/piper/handler -> root-config.json:117 +/tuning/url-scheme/podman/handler -> root-config.json:120 /ui/clock-format -> root-config.json:4 /ui/default-colors -> root-config.json:6 /ui/dim-text -> root-config.json:5 diff --git a/test/expected/test_cli.sh_f2e41555f1a5f40f54ce241207af602ed1503a2b.out b/test/expected/test_cli.sh_f2e41555f1a5f40f54ce241207af602ed1503a2b.out index 2db5d3c4..a11b99e0 100644 --- a/test/expected/test_cli.sh_f2e41555f1a5f40f54ce241207af602ed1503a2b.out +++ b/test/expected/test_cli.sh_f2e41555f1a5f40f54ce241207af602ed1503a2b.out @@ -1,2 +1,2 @@ filepath  lines   -stdin  4 +stdin  6 diff --git a/test/expected/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.err b/test/expected/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.out b/test/expected/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.out new file mode 100644 index 00000000..5ed19c17 --- /dev/null +++ b/test/expected/test_demux.sh_090b34f84229c02aad7ab2f1cea20cfcf94446d5.out @@ -0,0 +1,22 @@ +2013-06-06T19:13:20.123+0000 * Serving Flask app 'app.py' +2013-06-06T19:13:20.123+0000 web-1 | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. +2013-06-06T19:13:20.123+0000 * Debug mode: on +2013-06-06T19:13:20.123+0000 * Running on all addresses (0.0.0.0) +2013-06-06T19:13:20.123+0000 * Running on http://127.0.0.1:5000 +2013-06-06T19:13:20.123+0000 web-1 | Press CTRL+C to quit +2013-06-06T19:13:20.123+0000 * Running on http://172.18.0.3:5000 +2013-06-06T19:13:20.123+0000 redis-1 | 1:C 25 Apr 2024 05:32:35.018 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo +2013-06-06T19:13:20.123+0000 * Restarting with stat +2013-06-06T19:13:20.123+0000 * Debugger is active! +2013-06-06T19:13:20.123+0000 * Debugger PIN: 593-762-075 +2013-06-06T19:13:20.123+0000 redis-1 | 1:C 25 Apr 2024 05:32:35.018 * Redis version=7.2.0, bits=64, commit=00000000, modified=0, pid=1, just started +2013-06-06T19:13:20.123+0000 redis-1 | 1:C 25 Apr 2024 05:32:35.018 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:32:35.019 * monotonic clock: POSIX clock_gettime +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:32:35.019 * Running mode=standalone, port=6379. +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:32:35.020 * Server initialized +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:32:35.022 * Ready to accept connections tcp +2013-06-06T19:13:20.123+0000 redis-1 | 1:signal-handler (1714024483) Received SIGTERM scheduling shutdown... +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:54:43.946 * User requested shutdown... +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:54:43.946 * Saving the final RDB snapshot before exiting. +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:54:43.948 * DB saved on disk +2013-06-06T19:13:20.123+0000 redis-1 | 1:M 25 Apr 2024 05:54:43.948 # Redis is now ready to exit, bye bye... diff --git a/test/expected/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.err b/test/expected/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.out b/test/expected/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.out new file mode 100644 index 00000000..37b931bd --- /dev/null +++ b/test/expected/test_demux.sh_babab3536a2fc7c2a99847fa355b50d40a51763d.out @@ -0,0 +1,22 @@ +1:C 25 Apr 2024 05:32:35.018 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo +1:C 25 Apr 2024 05:32:35.018 * Redis version=7.2.0, bits=64, commit=00000000, modified=0, pid=1, just started +1:C 25 Apr 2024 05:32:35.018 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf +1:M 25 Apr 2024 05:32:35.019 * monotonic clock: POSIX clock_gettime +1:M 25 Apr 2024 05:32:35.019 * Running mode=standalone, port=6379. +1:M 25 Apr 2024 05:32:35.020 * Server initialized +1:M 25 Apr 2024 05:32:35.022 * Ready to accept connections tcp +2024-04-25T05:32:35.584+0000 * Serving Flask app 'app.py' +2024-04-25T05:32:35.584+0000 * Debug mode: on +2024-04-25T05:32:35.600+0000 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. +2024-04-25T05:32:35.600+0000 * Running on all addresses (0.0.0.0) +2024-04-25T05:32:35.600+0000 * Running on http://127.0.0.1:5000 +2024-04-25T05:32:35.600+0000 * Running on http://172.18.0.3:5000 +2024-04-25T05:32:35.600+0000 Press CTRL+C to quit +2024-04-25T05:32:35.604+0000 * Restarting with stat +2024-04-25T05:32:35.812+0000 * Debugger is active! +2024-04-25T05:32:35.815+0000 * Debugger PIN: 593-762-075 +1:signal-handler (25 Apr 2024 05:54:43.000) Received SIGTERM scheduling shutdown... +1:M 25 Apr 2024 05:54:43.946 * User requested shutdown... +1:M 25 Apr 2024 05:54:43.946 * Saving the final RDB snapshot before exiting. +1:M 25 Apr 2024 05:54:43.948 * DB saved on disk +1:M 25 Apr 2024 05:54:43.948 # Redis is now ready to exit, bye bye... diff --git a/test/expected/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.err b/test/expected/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.err new file mode 100644 index 00000000..e69de29b diff --git a/test/expected/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.out b/test/expected/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.out new file mode 100644 index 00000000..37b931bd --- /dev/null +++ b/test/expected/test_demux.sh_f8cbb968fccbc0442a831c0f69c6dbdfe5413339.out @@ -0,0 +1,22 @@ +1:C 25 Apr 2024 05:32:35.018 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo +1:C 25 Apr 2024 05:32:35.018 * Redis version=7.2.0, bits=64, commit=00000000, modified=0, pid=1, just started +1:C 25 Apr 2024 05:32:35.018 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf +1:M 25 Apr 2024 05:32:35.019 * monotonic clock: POSIX clock_gettime +1:M 25 Apr 2024 05:32:35.019 * Running mode=standalone, port=6379. +1:M 25 Apr 2024 05:32:35.020 * Server initialized +1:M 25 Apr 2024 05:32:35.022 * Ready to accept connections tcp +2024-04-25T05:32:35.584+0000 * Serving Flask app 'app.py' +2024-04-25T05:32:35.584+0000 * Debug mode: on +2024-04-25T05:32:35.600+0000 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. +2024-04-25T05:32:35.600+0000 * Running on all addresses (0.0.0.0) +2024-04-25T05:32:35.600+0000 * Running on http://127.0.0.1:5000 +2024-04-25T05:32:35.600+0000 * Running on http://172.18.0.3:5000 +2024-04-25T05:32:35.600+0000 Press CTRL+C to quit +2024-04-25T05:32:35.604+0000 * Restarting with stat +2024-04-25T05:32:35.812+0000 * Debugger is active! +2024-04-25T05:32:35.815+0000 * Debugger PIN: 593-762-075 +1:signal-handler (25 Apr 2024 05:54:43.000) Received SIGTERM scheduling shutdown... +1:M 25 Apr 2024 05:54:43.946 * User requested shutdown... +1:M 25 Apr 2024 05:54:43.946 * Saving the final RDB snapshot before exiting. +1:M 25 Apr 2024 05:54:43.948 * DB saved on disk +1:M 25 Apr 2024 05:54:43.948 # Redis is now ready to exit, bye bye... diff --git a/test/expected/test_sessions.sh_6d87ff483d5785c58fb271a405ff1c35e4f83cd9.out b/test/expected/test_sessions.sh_6d87ff483d5785c58fb271a405ff1c35e4f83cd9.out index 8b72915a..2dff6db8 100644 --- a/test/expected/test_sessions.sh_6d87ff483d5785c58fb271a405ff1c35e4f83cd9.out +++ b/test/expected/test_sessions.sh_6d87ff483d5785c58fb271a405ff1c35e4f83cd9.out @@ -3,8 +3,8 @@ # '|/path/to/this/file' in lnav to execute this file and # restore the state of the session. -;SELECT raise_error('This session export was made with a newer version of lnav, please upgrade to ' || '0.12.2' || ' or later') - WHERE lnav_version() < '0.12.2' COLLATE naturalcase +;SELECT raise_error('This session export was made with a newer version of lnav, please upgrade to ' || '0.12.3' || ' or later') + WHERE lnav_version() < '0.12.3' COLLATE naturalcase # The files loaded into the session were: diff --git a/test/expected/test_sessions.sh_e988439404f2e97604641c8d087855f3efe052e4.out b/test/expected/test_sessions.sh_e988439404f2e97604641c8d087855f3efe052e4.out index 05b75053..973d20e7 100644 --- a/test/expected/test_sessions.sh_e988439404f2e97604641c8d087855f3efe052e4.out +++ b/test/expected/test_sessions.sh_e988439404f2e97604641c8d087855f3efe052e4.out @@ -3,8 +3,8 @@ # '|/path/to/this/file' in lnav to execute this file and # restore the state of the session. -;SELECT raise_error('This session export was made with a newer version of lnav, please upgrade to ' || '0.12.2' || ' or later') - WHERE lnav_version() < '0.12.2' COLLATE naturalcase +;SELECT raise_error('This session export was made with a newer version of lnav, please upgrade to ' || '0.12.3' || ' or later') + WHERE lnav_version() < '0.12.3' COLLATE naturalcase # The files loaded into the session were: diff --git a/test/expected/test_sql_views_vtab.sh_4363d60040424a573ed79ee4260a32e3cd72f62c.out b/test/expected/test_sql_views_vtab.sh_4363d60040424a573ed79ee4260a32e3cd72f62c.out index a4f45bcb..7d5deac1 100644 --- a/test/expected/test_sql_views_vtab.sh_4363d60040424a573ed79ee4260a32e3cd72f62c.out +++ b/test/expected/test_sql_views_vtab.sh_4363d60040424a573ed79ee4260a32e3cd72f62c.out @@ -1,5 +1,5 @@ 2023-03-24T14:26:16.243Z renovate[7] INFO Dependency extraction complete - Received Time: 2023-03-24T14:26:16.243 — in the future Format: %Y-%m-%dT%H:%M:%S.%L%z + Received Time: 2023-03-24T14:26:16.243+0000 — in the future Format: %Y-%m-%dT%H:%M:%S.%L%z Default Zone: none Known message fields for table bunyan_log: | ◆ 📊 name = renovate | ◇ 📊 hostname = renovate-gitlab-67c4bcb5-9ggbv diff --git a/test/expected/test_sql_views_vtab.sh_45dbef06572b43cb997682436e753a13e003f792.out b/test/expected/test_sql_views_vtab.sh_45dbef06572b43cb997682436e753a13e003f792.out index 74dfce6a..f99c1cdf 100644 --- a/test/expected/test_sql_views_vtab.sh_45dbef06572b43cb997682436e753a13e003f792.out +++ b/test/expected/test_sql_views_vtab.sh_45dbef06572b43cb997682436e753a13e003f792.out @@ -1,5 +1,5 @@ [2020-12-10 06:56:41,092] DEBUG [connect.client:69] Full request text: - Received Time: 2020-12-10T06:56:41.092 — in the future Format: %Y-%m-%d %H:%M:%S,%L + Received Time: 2020-12-10T06:56:41.092+0000 — in the future Format: %Y-%m-%d %H:%M:%S,%L Default Zone: none Pattern: /xml_msg_log/regex/std = ^\[(?<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})\]\s+(?<level>\w+)\s+\[(?<module>[^:]*):(?<line>\d+)\]\s*(?<body>[^\n]*)\n?(?<msg_data>.*) Known message fields for table xml_msg_log: | ◆ 📊 module = connect.client diff --git a/test/expected/test_text_file.sh_265a8a5825e6c7dbc85cbe496dab6be7a349f3db.out b/test/expected/test_text_file.sh_265a8a5825e6c7dbc85cbe496dab6be7a349f3db.out index a330ad5d..7adcf142 100644 --- a/test/expected/test_text_file.sh_265a8a5825e6c7dbc85cbe496dab6be7a349f3db.out +++ b/test/expected/test_text_file.sh_265a8a5825e6c7dbc85cbe496dab6be7a349f3db.out @@ -1 +1 @@ -2013-06-06T12:13:20.123 Hello, World! +2013-06-06T12:13:20.123-0700 Hello, World! diff --git a/test/logfile_docker_compose.0 b/test/logfile_docker_compose.0 new file mode 100644 index 00000000..d96dd2e9 --- /dev/null +++ b/test/logfile_docker_compose.0 @@ -0,0 +1,22 @@ +web-1 | * Serving Flask app 'app.py' +web-1 | * Debug mode: on +web-1 | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. +web-1 | * Running on all addresses (0.0.0.0) +web-1 | * Running on http://127.0.0.1:5000 +web-1 | * Running on http://172.18.0.3:5000 +web-1 | Press CTRL+C to quit +web-1 | * Restarting with stat +web-1 | * Debugger is active! +web-1 | * Debugger PIN: 593-762-075 +redis-1 | 1:C 25 Apr 2024 05:32:35.018 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo +redis-1 | 1:C 25 Apr 2024 05:32:35.018 * Redis version=7.2.0, bits=64, commit=00000000, modified=0, pid=1, just started +redis-1 | 1:C 25 Apr 2024 05:32:35.018 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf +redis-1 | 1:M 25 Apr 2024 05:32:35.019 * monotonic clock: POSIX clock_gettime +redis-1 | 1:M 25 Apr 2024 05:32:35.019 * Running mode=standalone, port=6379. +redis-1 | 1:M 25 Apr 2024 05:32:35.020 * Server initialized +redis-1 | 1:M 25 Apr 2024 05:32:35.022 * Ready to accept connections tcp +redis-1 | 1:signal-handler (1714024483) Received SIGTERM scheduling shutdown... +redis-1 | 1:M 25 Apr 2024 05:54:43.946 * User requested shutdown... +redis-1 | 1:M 25 Apr 2024 05:54:43.946 * Saving the final RDB snapshot before exiting. +redis-1 | 1:M 25 Apr 2024 05:54:43.948 * DB saved on disk +redis-1 | 1:M 25 Apr 2024 05:54:43.948 # Redis is now ready to exit, bye bye... diff --git a/test/logfile_docker_compose_with_ts.0 b/test/logfile_docker_compose_with_ts.0 new file mode 100644 index 00000000..09bbbab6 --- /dev/null +++ b/test/logfile_docker_compose_with_ts.0 @@ -0,0 +1,22 @@ +web-1 | 2024-04-25T05:32:35.584725130Z * Serving Flask app 'app.py' +web-1 | 2024-04-25T05:32:35.584799505Z * Debug mode: on +web-1 | 2024-04-25T05:32:35.600215839Z WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. +web-1 | 2024-04-25T05:32:35.600235130Z * Running on all addresses (0.0.0.0) +web-1 | 2024-04-25T05:32:35.600236672Z * Running on http://127.0.0.1:5000 +web-1 | 2024-04-25T05:32:35.600237922Z * Running on http://172.18.0.3:5000 +web-1 | 2024-04-25T05:32:35.600239005Z Press CTRL+C to quit +web-1 | 2024-04-25T05:32:35.604777422Z * Restarting with stat +web-1 | 2024-04-25T05:32:35.812839505Z * Debugger is active! +web-1 | 2024-04-25T05:32:35.815512297Z * Debugger PIN: 593-762-075 +redis-1 | 2024-04-25T05:32:35.019558005Z 1:C 25 Apr 2024 05:32:35.018 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo +redis-1 | 2024-04-25T05:32:35.019604088Z 1:C 25 Apr 2024 05:32:35.018 * Redis version=7.2.0, bits=64, commit=00000000, modified=0, pid=1, just started +redis-1 | 2024-04-25T05:32:35.019607672Z 1:C 25 Apr 2024 05:32:35.018 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf +redis-1 | 2024-04-25T05:32:35.019609713Z 1:M 25 Apr 2024 05:32:35.019 * monotonic clock: POSIX clock_gettime +redis-1 | 2024-04-25T05:32:35.020531422Z 1:M 25 Apr 2024 05:32:35.019 * Running mode=standalone, port=6379. +redis-1 | 2024-04-25T05:32:35.020550463Z 1:M 25 Apr 2024 05:32:35.020 * Server initialized +redis-1 | 2024-04-25T05:32:35.023599380Z 1:M 25 Apr 2024 05:32:35.022 * Ready to accept connections tcp +redis-1 | 2024-04-25T05:54:43.845483884Z 1:signal-handler (1714024483) Received SIGTERM scheduling shutdown... +redis-1 | 2024-04-25T05:54:43.946272551Z 1:M 25 Apr 2024 05:54:43.946 * User requested shutdown... +redis-1 | 2024-04-25T05:54:43.946283801Z 1:M 25 Apr 2024 05:54:43.946 * Saving the final RDB snapshot before exiting. +redis-1 | 2024-04-25T05:54:43.948428426Z 1:M 25 Apr 2024 05:54:43.948 * DB saved on disk +redis-1 | 2024-04-25T05:54:43.948541926Z 1:M 25 Apr 2024 05:54:43.948 # Redis is now ready to exit, bye bye... diff --git a/test/test_auto_fd.cc b/test/test_auto_fd.cc index ab454902..c6193f0f 100644 --- a/test/test_auto_fd.cc +++ b/test/test_auto_fd.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/test/test_demux.sh b/test/test_demux.sh new file mode 100644 index 00000000..5e074dd0 --- /dev/null +++ b/test/test_demux.sh @@ -0,0 +1,12 @@ +#! /bin/bash + +export YES_COLOR=1 +export TZ=UTC + +cat ${test_dir}/logfile_docker_compose.0 | run_cap_test env TEST_COMMENT="docker-demux-no-ts" \ + ${lnav_test} -n + +cat ${test_dir}/logfile_docker_compose_with_ts.0 | run_cap_test env TEST_COMMENT="docker-demux-with-ts" \ + ${lnav_test} -n + +run_cap_test ${lnav_test} -n ${test_dir}/logfile_docker_compose_with_ts.0 diff --git a/test/test_stubs.cc b/test/test_stubs.cc index ff18224d..088dd52b 100644 --- a/test/test_stubs.cc +++ b/test/test_stubs.cc @@ -59,7 +59,7 @@ wait_for_children() } size_t -rebuild_indexes(nonstd::optional deadline) +rebuild_indexes(std::optional deadline) { return 0; } @@ -70,7 +70,7 @@ rebuild_indexes_repeatedly() } void -wait_for_pipers(nonstd::optional) +wait_for_pipers(std::optional) { }