diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d112b0a0..84b64154 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -532,6 +532,7 @@ add_library( spectro_impls.hh spectro_source.hh sqlitepp.hh + sql_execute.hh sql_help.hh sql_util.hh static_file_vtab.hh diff --git a/src/Makefile.am b/src/Makefile.am index c95cb59f..296bb3d5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -291,6 +291,7 @@ noinst_HEADERS = \ spectro_source.hh \ sqlitepp.hh \ sqlitepp.client.hh \ + sql_execute.hh \ sql_help.hh \ sql_util.hh \ sqlite-extension-func.hh \ diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index aa4143f6..14ef5c09 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -4,6 +4,7 @@ add_library( ansi_scrubber.cc attr_line.cc attr_line.builder.cc + auto_fd.cc auto_pid.cc date_time_scanner.cc fs_util.cc @@ -25,6 +26,7 @@ add_library( time_util.cc ansi_scrubber.hh + ansi_vars.hh attr_line.hh attr_line.builder.hh auto_fd.hh @@ -57,6 +59,7 @@ add_library( string_attr_type.hh strnatcmp.h time_util.hh + types.hh ../third-party/xxHash/xxhash.h ../third-party/xxHash/xxhash.c diff --git a/src/base/Makefile.am b/src/base/Makefile.am index 4a459a63..5695e34e 100644 --- a/src/base/Makefile.am +++ b/src/base/Makefile.am @@ -22,6 +22,7 @@ noinst_LIBRARIES = libbase.a noinst_HEADERS = \ ansi_scrubber.hh \ + ansi_vars.hh \ attr_line.hh \ attr_line.builder.hh \ auto_fd.hh \ @@ -58,12 +59,14 @@ noinst_HEADERS = \ string_attr_type.hh \ string_util.hh \ strnatcmp.h \ - time_util.hh + time_util.hh \ + types.hh libbase_a_SOURCES = \ ansi_scrubber.cc \ attr_line.cc \ attr_line.builder.cc \ + auto_fd.cc \ auto_pid.cc \ date_time_scanner.cc \ fs_util.cc \ diff --git a/src/base/ansi_scrubber.cc b/src/base/ansi_scrubber.cc index 98f6c967..3dc090a8 100644 --- a/src/base/ansi_scrubber.cc +++ b/src/base/ansi_scrubber.cc @@ -33,6 +33,7 @@ #include "ansi_scrubber.hh" +#include "ansi_vars.hh" #include "base/opt_util.hh" #include "config.h" #include "pcrepp/pcre2pp.hh" diff --git a/src/base/ansi_scrubber.hh b/src/base/ansi_scrubber.hh index b832e17c..ce4eadf1 100644 --- a/src/base/ansi_scrubber.hh +++ b/src/base/ansi_scrubber.hh @@ -36,7 +36,6 @@ #include #include "attr_line.hh" -#include "shlex.resolver.hh" #define ANSI_CSI "\x1b[" #define ANSI_CHAR_ATTR "m" @@ -66,10 +65,4 @@ void scrub_ansi_string(std::string& str, string_attrs_t* sa); size_t erase_ansi_escapes(string_fragment input); -/** - * Populate a variable map with strings that contain escape sequences that - * might be useful to script writers. - */ -void add_ansi_vars(std::map& vars); - #endif diff --git a/src/base/ansi_vars.hh b/src/base/ansi_vars.hh new file mode 100644 index 00000000..e6d8f03d --- /dev/null +++ b/src/base/ansi_vars.hh @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2023, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lnav_ansi_vars_hh +#define lnav_ansi_vars_hh + +#include "shlex.resolver.hh" + +/** + * Populate a variable map with strings that contain escape sequences that + * might be useful to script writers. + */ +void add_ansi_vars(std::map& vars); + +#endif diff --git a/src/base/auto_fd.cc b/src/base/auto_fd.cc new file mode 100644 index 00000000..47a17eb5 --- /dev/null +++ b/src/base/auto_fd.cc @@ -0,0 +1,206 @@ +/** + * Copyright (c) 2023, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file auto_fd.cc + */ + +#include "auto_fd.hh" + +#include +#include + +#include "lnav_log.hh" + +int +auto_fd::pipe(auto_fd* af) +{ + int retval, fd[2]; + + require(af != nullptr); + + if ((retval = ::pipe(fd)) == 0) { + af[0] = fd[0]; + af[1] = fd[1]; + } + + return retval; +} + +auto_fd +auto_fd::dup_of(int fd) +{ + if (fd == -1) { + return auto_fd{}; + } + + auto new_fd = ::dup(fd); + + if (new_fd == -1) { + throw std::bad_alloc(); + } + + return auto_fd(new_fd); +} + +auto_fd::auto_fd(int fd) : af_fd(fd) +{ + require(fd >= -1); +} + +auto_fd::auto_fd(auto_fd&& af) noexcept : af_fd(af.release()) {} + +auto_fd +auto_fd::dup() const +{ + int new_fd; + + if (this->af_fd == -1 || (new_fd = ::dup(this->af_fd)) == -1) { + throw std::bad_alloc(); + } + + return auto_fd{new_fd}; +} + +auto_fd::~auto_fd() +{ + this->reset(); +} + +void +auto_fd::reset(int fd) +{ + require(fd >= -1); + + if (this->af_fd != fd) { + if (this->af_fd != -1) { + switch (this->af_fd) { + case STDIN_FILENO: + case STDOUT_FILENO: + case STDERR_FILENO: + break; + default: + close(this->af_fd); + break; + } + } + this->af_fd = fd; + } +} + +void +auto_fd::close_on_exec() const +{ + if (this->af_fd == -1) { + return; + } + log_perror(fcntl(this->af_fd, F_SETFD, FD_CLOEXEC)); +} + +auto_fd& +auto_fd::operator=(int fd) +{ + require(fd >= -1); + + this->reset(fd); + return *this; +} + +Result +auto_pipe::for_child_fd(int child_fd) +{ + auto_pipe retval(child_fd); + + if (retval.open() == -1) { + return Err(std::string(strerror(errno))); + } + + return Ok(std::move(retval)); +} + +auto_pipe::auto_pipe(int child_fd, int child_flags) + : ap_child_flags(child_flags), ap_child_fd(child_fd) +{ + switch (child_fd) { + case STDIN_FILENO: + this->ap_child_flags = O_RDONLY; + break; + case STDOUT_FILENO: + case STDERR_FILENO: + this->ap_child_flags = O_WRONLY; + break; + } +} + +void +auto_pipe::after_fork(pid_t child_pid) +{ + int new_fd; + + switch (child_pid) { + case -1: + this->close(); + break; + case 0: + if (this->ap_child_flags == O_RDONLY) { + this->write_end().reset(); + if (this->read_end().get() == -1) { + this->read_end() = ::open("/dev/null", O_RDONLY); + } + new_fd = this->read_end().get(); + } else { + this->read_end().reset(); + if (this->write_end().get() == -1) { + this->write_end() = ::open("/dev/null", O_WRONLY); + } + new_fd = this->write_end().get(); + } + if (this->ap_child_fd != -1) { + if (new_fd != this->ap_child_fd) { + dup2(new_fd, this->ap_child_fd); + this->close(); + } + } + break; + default: + if (this->ap_child_flags == O_RDONLY) { + this->read_end().reset(); + } else { + this->write_end().reset(); + } + break; + } +} + +int +auto_pipe::open() +{ + int retval = auto_fd::pipe(this->ap_fd); + this->ap_fd[0].close_on_exec(); + this->ap_fd[1].close_on_exec(); + return retval; +} diff --git a/src/base/auto_fd.hh b/src/base/auto_fd.hh index 667b0f40..b53edc75 100644 --- a/src/base/auto_fd.hh +++ b/src/base/auto_fd.hh @@ -32,16 +32,10 @@ #ifndef auto_fd_hh #define auto_fd_hh -#include -#include #include -#include #include -#include -#include -#include "base/lnav_log.hh" #include "base/result.h" /** @@ -59,19 +53,7 @@ public: * contains the reader end of the pipe and the second contains the writer. * @return The result of the pipe(2) function. */ - static int pipe(auto_fd* af) - { - int retval, fd[2]; - - require(af != nullptr); - - if ((retval = ::pipe(fd)) == 0) { - af[0] = fd[0]; - af[1] = fd[1]; - } - - return retval; - } + static int pipe(auto_fd* af); /** * dup(2) the given file descriptor and wrap it in an auto_fd. @@ -79,27 +61,14 @@ public: * @param fd The file descriptor to duplicate. * @return A new auto_fd that contains the duplicated file descriptor. */ - static auto_fd dup_of(int fd) - { - if (fd == -1) { - return auto_fd{}; - } - - auto new_fd = ::dup(fd); - - if (new_fd == -1) { - throw std::bad_alloc(); - } - - return auto_fd(new_fd); - } + static auto_fd dup_of(int fd); /** * Construct an auto_fd to manage the given file descriptor. * * @param fd The file descriptor to be managed. */ - explicit auto_fd(int fd = -1) : af_fd(fd) { require(fd >= -1); } + explicit auto_fd(int fd = -1); /** * Non-const copy constructor. Management of the file descriptor will be @@ -108,7 +77,7 @@ public: * * @param af The source of the file descriptor. */ - auto_fd(auto_fd&& af) noexcept : af_fd(af.release()) {} + auto_fd(auto_fd&& af) noexcept; /** * Const copy constructor. The file descriptor from the source will be @@ -118,21 +87,12 @@ public: */ auto_fd(const auto_fd& af) = delete; - auto_fd dup() const - { - int new_fd; - - if (this->af_fd == -1 || (new_fd = ::dup(this->af_fd)) == -1) { - throw std::bad_alloc(); - } - - return auto_fd{new_fd}; - } + auto_fd dup() const; /** * Destructor that will close the file descriptor managed by this object. */ - ~auto_fd() { this->reset(); } + ~auto_fd(); /** @return The file descriptor as a plain integer. */ operator int() const { return this->af_fd; } @@ -144,13 +104,7 @@ public: * @param fd The file descriptor to store in this object. * @return *this */ - auto_fd& operator=(int fd) - { - require(fd >= -1); - - this->reset(fd); - return *this; - } + auto_fd& operator=(int fd); /** * Transfer management of the given file descriptor to this object. @@ -202,33 +156,9 @@ public: * * @param fd The new file descriptor to be managed. */ - void reset(int fd = -1) - { - require(fd >= -1); + void reset(int fd = -1); - if (this->af_fd != fd) { - if (this->af_fd != -1) { - switch (this->af_fd) { - case STDIN_FILENO: - case STDOUT_FILENO: - case STDERR_FILENO: - break; - default: - close(this->af_fd); - break; - } - } - this->af_fd = fd; - } - } - - void close_on_exec() const - { - if (this->af_fd == -1) { - return; - } - log_perror(fcntl(this->af_fd, F_SETFD, FD_CLOEXEC)); - } + void close_on_exec() const; private: int af_fd; /*< The managed file descriptor. */ @@ -236,38 +166,11 @@ private: class auto_pipe { public: - static Result for_child_fd(int child_fd) - { - auto_pipe retval(child_fd); - - if (retval.open() == -1) { - return Err(std::string(strerror(errno))); - } - - return Ok(std::move(retval)); - } + static Result for_child_fd(int child_fd); - explicit auto_pipe(int child_fd = -1, int child_flags = O_RDONLY) - : ap_child_flags(child_flags), ap_child_fd(child_fd) - { - switch (child_fd) { - case STDIN_FILENO: - this->ap_child_flags = O_RDONLY; - break; - case STDOUT_FILENO: - case STDERR_FILENO: - this->ap_child_flags = O_WRONLY; - break; - } - } + explicit auto_pipe(int child_fd = -1, int child_flags = O_RDONLY); - int open() - { - int retval = auto_fd::pipe(this->ap_fd); - this->ap_fd[0].close_on_exec(); - this->ap_fd[1].close_on_exec(); - return retval; - } + int open(); void close() { @@ -279,44 +182,7 @@ public: auto_fd& write_end() { return this->ap_fd[1]; } - void after_fork(pid_t child_pid) - { - int new_fd; - - switch (child_pid) { - case -1: - this->close(); - break; - case 0: - if (this->ap_child_flags == O_RDONLY) { - this->write_end().reset(); - if (this->read_end().get() == -1) { - this->read_end() = ::open("/dev/null", O_RDONLY); - } - new_fd = this->read_end().get(); - } else { - this->read_end().reset(); - if (this->write_end().get() == -1) { - this->write_end() = ::open("/dev/null", O_WRONLY); - } - new_fd = this->write_end().get(); - } - if (this->ap_child_fd != -1) { - if (new_fd != this->ap_child_fd) { - dup2(new_fd, this->ap_child_fd); - this->close(); - } - } - break; - default: - if (this->ap_child_flags == O_RDONLY) { - this->read_end().reset(); - } else { - this->write_end().reset(); - } - break; - } - } + void after_fork(pid_t child_pid); int ap_child_flags; int ap_child_fd; diff --git a/src/base/network.tcp.hh b/src/base/network.tcp.hh index 49fc3920..c046bb6f 100644 --- a/src/base/network.tcp.hh +++ b/src/base/network.tcp.hh @@ -33,6 +33,7 @@ #include #include "auto_fd.hh" +#include "optional.hpp" #include "result.h" namespace network { diff --git a/src/base/types.hh b/src/base/types.hh new file mode 100644 index 00000000..ba6f9148 --- /dev/null +++ b/src/base/types.hh @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2023, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lnav_base_types_hh +#define lnav_base_types_hh + +struct null_value_t {}; + +#endif diff --git a/src/big_array.hh b/src/big_array.hh index 8401ead8..73e687f5 100644 --- a/src/big_array.hh +++ b/src/big_array.hh @@ -41,11 +41,6 @@ template struct big_array { static const size_t DEFAULT_INCREMENT = 100 * 1000; - big_array() - : ba_ptr(nullptr), ba_size(0), ba_capacity(0){ - - }; - bool reserve(size_t size) { if (size < this->ba_capacity) { @@ -71,17 +66,11 @@ struct big_array { this->ba_ptr = (T*) result; return true; - }; + } - void clear() - { - this->ba_size = 0; - }; + void clear() { this->ba_size = 0; } - size_t size() const - { - return this->ba_size; - }; + size_t size() const { return this->ba_size; } void shrink_to(size_t new_size) { @@ -90,47 +79,29 @@ struct big_array { this->ba_size = new_size; } - bool empty() const - { - return this->ba_size == 0; - }; + bool empty() const { return this->ba_size == 0; } void push_back(const T& val) { this->ba_ptr[this->ba_size] = val; this->ba_size += 1; - }; + } - T& operator[](size_t index) - { - return this->ba_ptr[index]; - }; + T& operator[](size_t index) { return this->ba_ptr[index]; } - const T& operator[](size_t index) const - { - return this->ba_ptr[index]; - }; + const T& operator[](size_t index) const { return this->ba_ptr[index]; } - T& back() - { - return this->ba_ptr[this->ba_size - 1]; - } + T& back() { return this->ba_ptr[this->ba_size - 1]; } - typedef T* iterator; + using iterator = T*; - iterator begin() - { - return this->ba_ptr; - }; + iterator begin() { return this->ba_ptr; } - iterator end() - { - return this->ba_ptr + this->ba_size; - }; + iterator end() { return this->ba_ptr + this->ba_size; } - T* ba_ptr; - size_t ba_size; - size_t ba_capacity; + T* ba_ptr{nullptr}; + size_t ba_size{0}; + size_t ba_capacity{0}; }; #endif diff --git a/src/command_executor.cc b/src/command_executor.cc index 6c522f3c..28ec5bab 100644 --- a/src/command_executor.cc +++ b/src/command_executor.cc @@ -32,6 +32,7 @@ #include "command_executor.hh" #include "base/ansi_scrubber.hh" +#include "base/ansi_vars.hh" #include "base/fs_util.hh" #include "base/injector.hh" #include "base/itertools.hh" @@ -608,7 +609,7 @@ execute_file(exec_context& ec, const std::string& path_and_args, bool multiline) log_info("Executing file: %s", path_and_args.c_str()); - if (!lexer.split(split_args, ec.ec_local_vars.top())) { + if (!lexer.split(split_args, scoped_resolver{&ec.ec_local_vars.top()})) { return ec.make_error("unable to parse path"); } if (split_args.empty()) { @@ -1021,7 +1022,7 @@ add_global_vars(exec_context& ec) shlex subber(iter.second); std::string str; - if (!subber.eval(str, ec.ec_global_vars)) { + if (!subber.eval(str, scoped_resolver{&ec.ec_global_vars})) { log_error("Unable to evaluate global variable value: %s", iter.second.c_str()); continue; diff --git a/src/command_executor.hh b/src/command_executor.hh index 2052c5fb..d215021d 100644 --- a/src/command_executor.hh +++ b/src/command_executor.hh @@ -38,7 +38,6 @@ #include "base/auto_fd.hh" #include "base/lnav.console.hh" -#include "bookmarks.hh" #include "fmt/format.h" #include "ghc/filesystem.hpp" #include "help_text.hh" diff --git a/src/filter_observer.hh b/src/filter_observer.hh index 1e1c302f..763e6bda 100644 --- a/src/filter_observer.hh +++ b/src/filter_observer.hh @@ -50,7 +50,7 @@ public: } void logline_new_lines(const logfile& lf, - logfile::const_iterator ll_begin, + logfile::const_iterator ll_baegin, logfile::const_iterator ll_end, const shared_buffer_ref& sbr) override; diff --git a/src/line_buffer.hh b/src/line_buffer.hh index 5714a27c..b4ddca69 100644 --- a/src/line_buffer.hh +++ b/src/line_buffer.hh @@ -46,7 +46,6 @@ #include "base/auto_mem.hh" #include "base/file_range.hh" #include "base/is_utf8.hh" -#include "base/lnav_log.hh" #include "base/result.h" #include "log_level.hh" #include "safe/safe.h" diff --git a/src/lnav.cc b/src/lnav.cc index bc6437c7..77d2588a 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -75,6 +75,7 @@ #include "all_logs_vtab.hh" #include "base/ansi_scrubber.hh" +#include "base/ansi_vars.hh" #include "base/fs_util.hh" #include "base/func_util.hh" #include "base/future_util.hh" diff --git a/src/log_format.cc b/src/log_format.cc index 2bbd108f..f8183dba 100644 --- a/src/log_format.cc +++ b/src/log_format.cc @@ -1877,7 +1877,7 @@ detect_mime_type(const ghc::filesystem::path& filename) auto hexbuf = auto_buffer::alloc(buffer_size * 2); - for (int lpc = 0; lpc < buffer_size; lpc++) { + for (size_t lpc = 0; lpc < buffer_size; lpc++) { fmt::format_to( std::back_inserter(hexbuf), FMT_STRING("{:02x}"), buffer[lpc]); } diff --git a/src/log_format_loader.cc b/src/log_format_loader.cc index 7ff102db..dc105cce 100644 --- a/src/log_format_loader.cc +++ b/src/log_format_loader.cc @@ -53,6 +53,7 @@ #include "fmt/format.h" #include "lnav_config.hh" #include "log_format_ext.hh" +#include "sql_execute.hh" #include "sql_util.hh" #include "yajlpp/yajlpp.hh" #include "yajlpp/yajlpp_def.hh" diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index bb93f7bb..1ab80482 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -35,8 +35,7 @@ #include #include "base/ansi_scrubber.hh" -#include "base/humanize.time.hh" -#include "base/injector.hh" +#include "base/ansi_vars.hh" #include "base/itertools.hh" #include "base/string_util.hh" #include "bound_tags.hh" @@ -140,6 +139,30 @@ logfile_sub_source::find(const char* fn, content_line_t& line_base) return retval; } +struct filtered_logline_cmp { + filtered_logline_cmp(const logfile_sub_source& lc) : llss_controller(lc) {} + + bool operator()(const uint32_t& lhs, const uint32_t& rhs) const + { + content_line_t cl_lhs = (content_line_t) llss_controller.lss_index[lhs]; + content_line_t cl_rhs = (content_line_t) llss_controller.lss_index[rhs]; + logline* ll_lhs = this->llss_controller.find_line(cl_lhs); + logline* ll_rhs = this->llss_controller.find_line(cl_rhs); + + return (*ll_lhs) < (*ll_rhs); + } + + bool operator()(const uint32_t& lhs, const struct timeval& rhs) const + { + content_line_t cl_lhs = (content_line_t) llss_controller.lss_index[lhs]; + logline* ll_lhs = this->llss_controller.find_line(cl_lhs); + + return (*ll_lhs) < rhs; + } + + const logfile_sub_source& llss_controller; +}; + nonstd::optional logfile_sub_source::find_from_time(const struct timeval& start) const { @@ -596,6 +619,53 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv, } } +struct logline_cmp { + logline_cmp(logfile_sub_source& lc) : llss_controller(lc) {} + + bool operator()(const content_line_t& lhs, const content_line_t& rhs) const + { + logline* ll_lhs = this->llss_controller.find_line(lhs); + logline* ll_rhs = this->llss_controller.find_line(rhs); + + return (*ll_lhs) < (*ll_rhs); + } + + bool operator()(const uint32_t& lhs, const uint32_t& rhs) const + { + content_line_t cl_lhs = (content_line_t) llss_controller.lss_index[lhs]; + content_line_t cl_rhs = (content_line_t) llss_controller.lss_index[rhs]; + logline* ll_lhs = this->llss_controller.find_line(cl_lhs); + logline* ll_rhs = this->llss_controller.find_line(cl_rhs); + + return (*ll_lhs) < (*ll_rhs); + } +#if 0 + bool operator()(const indexed_content &lhs, const indexed_content &rhs) + { + logline *ll_lhs = this->llss_controller.find_line(lhs.ic_value); + logline *ll_rhs = this->llss_controller.find_line(rhs.ic_value); + + return (*ll_lhs) < (*ll_rhs); + } +#endif + + bool operator()(const content_line_t& lhs, const time_t& rhs) const + { + logline* ll_lhs = this->llss_controller.find_line(lhs); + + return *ll_lhs < rhs; + } + + bool operator()(const content_line_t& lhs, const struct timeval& rhs) const + { + logline* ll_lhs = this->llss_controller.find_line(lhs); + + return *ll_lhs < rhs; + } + + logfile_sub_source& llss_controller; +}; + logfile_sub_source::rebuild_result logfile_sub_source::rebuild_index( nonstd::optional deadline) @@ -1211,6 +1281,24 @@ logfile_sub_source::get_grepper() (grep_proc_sink*) &this->lss_meta_grepper); } +/** + * Functor for comparing the ld_file field of the logfile_data struct. + */ +struct logfile_data_eq { + explicit logfile_data_eq(std::shared_ptr lf) + : lde_file(std::move(lf)) + { + } + + bool operator()( + const std::unique_ptr& ld) const + { + return this->lde_file == ld->get_file(); + } + + std::shared_ptr lde_file; +}; + bool logfile_sub_source::insert_file(const std::shared_ptr& lf) { @@ -2418,3 +2506,113 @@ logfile_sub_source::clear_bookmark_metadata() ld->get_file_ptr()->get_bookmark_metadata().clear(); } } + +void +logfile_sub_source::increase_line_context() +{ + auto old_flags = this->lss_flags; + + if (this->lss_flags & F_FILENAME) { + // Nothing to do + } else if (this->lss_flags & F_BASENAME) { + this->lss_flags &= ~F_NAME_MASK; + this->lss_flags |= F_FILENAME; + } else { + this->lss_flags |= F_BASENAME; + } + if (old_flags != this->lss_flags) { + this->clear_line_size_cache(); + } +} + +bool +logfile_sub_source::decrease_line_context() +{ + auto old_flags = this->lss_flags; + + if (this->lss_flags & F_FILENAME) { + this->lss_flags &= ~F_NAME_MASK; + this->lss_flags |= F_BASENAME; + } else if (this->lss_flags & F_BASENAME) { + this->lss_flags &= ~F_NAME_MASK; + } + if (old_flags != this->lss_flags) { + this->clear_line_size_cache(); + + return true; + } + + return false; +} + +size_t +logfile_sub_source::get_filename_offset() const +{ + if (this->lss_flags & F_FILENAME) { + return this->lss_filename_width; + } else if (this->lss_flags & F_BASENAME) { + return this->lss_basename_width; + } + + return 0; +} + +void +logfile_sub_source::clear_min_max_log_times() +{ + if (this->lss_min_log_time.tv_sec != 0 + || this->lss_min_log_time.tv_usec != 0 + || this->lss_max_log_time.tv_sec != std::numeric_limits::max() + || this->lss_max_log_time.tv_usec != 0) + { + memset(&this->lss_min_log_time, 0, sizeof(this->lss_min_log_time)); + this->lss_max_log_time.tv_sec = std::numeric_limits::max(); + this->lss_max_log_time.tv_usec = 0; + this->text_filters_changed(); + } +} + +size_t +logfile_sub_source::file_count() const +{ + size_t retval = 0; + const_iterator iter; + + for (iter = this->cbegin(); iter != this->cend(); ++iter) { + if (*iter != nullptr && (*iter)->get_file() != nullptr) { + retval += 1; + } + } + + return retval; +} + +size_t +logfile_sub_source::text_size_for_line(textview_curses& tc, + int row, + text_sub_source::line_flags_t flags) +{ + size_t index = row % LINE_SIZE_CACHE_SIZE; + + if (this->lss_line_size_cache[index].first != row) { + std::string value; + + this->text_value_for_line(tc, row, value, flags); + this->lss_line_size_cache[index].second = value.size(); + this->lss_line_size_cache[index].first = row; + } + return this->lss_line_size_cache[index].second; +} + +int +logfile_sub_source::get_filtered_count_for(size_t filter_index) const +{ + int retval = 0; + + for (const auto& ld : this->lss_files) { + retval += ld->ld_filter_state.lfo_filter_state + .tfs_filter_hits[filter_index]; + } + + return retval; +} diff --git a/src/logfile_sub_source.hh b/src/logfile_sub_source.hh index a7e65816..240549a2 100644 --- a/src/logfile_sub_source.hh +++ b/src/logfile_sub_source.hh @@ -253,52 +253,11 @@ public: ~logfile_sub_source() = default; - void increase_line_context() - { - auto old_flags = this->lss_flags; - - if (this->lss_flags & F_FILENAME) { - // Nothing to do - } else if (this->lss_flags & F_BASENAME) { - this->lss_flags &= ~F_NAME_MASK; - this->lss_flags |= F_FILENAME; - } else { - this->lss_flags |= F_BASENAME; - } - if (old_flags != this->lss_flags) { - this->clear_line_size_cache(); - } - } - - bool decrease_line_context() - { - auto old_flags = this->lss_flags; + void increase_line_context(); - if (this->lss_flags & F_FILENAME) { - this->lss_flags &= ~F_NAME_MASK; - this->lss_flags |= F_BASENAME; - } else if (this->lss_flags & F_BASENAME) { - this->lss_flags &= ~F_NAME_MASK; - } - if (old_flags != this->lss_flags) { - this->clear_line_size_cache(); - - return true; - } - - return false; - } - - size_t get_filename_offset() const - { - if (this->lss_flags & F_FILENAME) { - return this->lss_filename_width; - } else if (this->lss_flags & F_BASENAME) { - return this->lss_basename_width; - } + bool decrease_line_context(); - return 0; - } + size_t get_filename_offset() const; bool is_filename_enabled() const { @@ -353,20 +312,7 @@ public: } } - void clear_min_max_log_times() - { - if (this->lss_min_log_time.tv_sec != 0 - || this->lss_min_log_time.tv_usec != 0 - || this->lss_max_log_time.tv_sec - != std::numeric_limits::max() - || this->lss_max_log_time.tv_usec != 0) - { - memset(&this->lss_min_log_time, 0, sizeof(this->lss_min_log_time)); - this->lss_max_log_time.tv_sec = std::numeric_limits::max(); - this->lss_max_log_time.tv_usec = 0; - this->text_filters_changed(); - } - } + void clear_min_max_log_times(); bool list_input_handle_key(listview_curses& lv, int ch); @@ -387,19 +333,7 @@ public: return this->lss_longest_line; } - size_t file_count() const - { - size_t retval = 0; - const_iterator iter; - - for (iter = this->cbegin(); iter != this->cend(); ++iter) { - if (*iter != nullptr && (*iter)->get_file() != nullptr) { - retval += 1; - } - } - - return retval; - } + size_t file_count() const; bool empty() const { return this->lss_filtered_index.empty(); } @@ -412,19 +346,7 @@ public: int row, string_attrs_t& value_out); - size_t text_size_for_line(textview_curses& tc, int row, line_flags_t flags) - { - size_t index = row % LINE_SIZE_CACHE_SIZE; - - if (this->lss_line_size_cache[index].first != row) { - std::string value; - - this->text_value_for_line(tc, row, value, flags); - this->lss_line_size_cache[index].second = value.size(); - this->lss_line_size_cache[index].first = row; - } - return this->lss_line_size_cache[index].second; - } + size_t text_size_for_line(textview_curses& tc, int row, line_flags_t flags); void text_mark(const bookmark_type_t* bm, vis_line_t line, bool added); @@ -485,17 +407,7 @@ public: return this->lss_index.size() - this->lss_filtered_index.size(); } - int get_filtered_count_for(size_t filter_index) const - { - int retval = 0; - - for (const auto& ld : this->lss_files) { - retval += ld->ld_filter_state.lfo_filter_state - .tfs_filter_hits[filter_index]; - } - - return retval; - } + int get_filtered_count_for(size_t filter_index) const; Result set_sql_filter( std::string stmt_str, sqlite3_stmt* stmt); @@ -813,6 +725,21 @@ public: void quiesce(); + struct __attribute__((__packed__)) indexed_content { + indexed_content() = default; + + indexed_content(content_line_t cl) : ic_value(cl) {} + + operator content_line_t() const + { + return content_line_t(this->ic_value); + } + + uint64_t ic_value : 40; + }; + + big_array lss_index; + protected: void text_accel_display_changed() { this->clear_line_size_cache(); } @@ -838,116 +765,6 @@ private: F_NAME_MASK = (F_FILENAME | F_BASENAME), }; - struct __attribute__((__packed__)) indexed_content { - indexed_content() = default; - - indexed_content(content_line_t cl) : ic_value(cl) {} - - operator content_line_t() const - { - return content_line_t(this->ic_value); - } - - uint64_t ic_value : 40; - }; - - struct logline_cmp { - logline_cmp(logfile_sub_source& lc) : llss_controller(lc) {} - - bool operator()(const content_line_t& lhs, - const content_line_t& rhs) const - { - logline* ll_lhs = this->llss_controller.find_line(lhs); - logline* ll_rhs = this->llss_controller.find_line(rhs); - - return (*ll_lhs) < (*ll_rhs); - } - - bool operator()(const uint32_t& lhs, const uint32_t& rhs) const - { - content_line_t cl_lhs - = (content_line_t) llss_controller.lss_index[lhs]; - content_line_t cl_rhs - = (content_line_t) llss_controller.lss_index[rhs]; - logline* ll_lhs = this->llss_controller.find_line(cl_lhs); - logline* ll_rhs = this->llss_controller.find_line(cl_rhs); - - return (*ll_lhs) < (*ll_rhs); - } -#if 0 - bool operator()(const indexed_content &lhs, const indexed_content &rhs) - { - logline *ll_lhs = this->llss_controller.find_line(lhs.ic_value); - logline *ll_rhs = this->llss_controller.find_line(rhs.ic_value); - - return (*ll_lhs) < (*ll_rhs); - } -#endif - - bool operator()(const content_line_t& lhs, const time_t& rhs) const - { - logline* ll_lhs = this->llss_controller.find_line(lhs); - - return *ll_lhs < rhs; - } - - bool operator()(const content_line_t& lhs, - const struct timeval& rhs) const - { - logline* ll_lhs = this->llss_controller.find_line(lhs); - - return *ll_lhs < rhs; - } - - logfile_sub_source& llss_controller; - }; - - struct filtered_logline_cmp { - filtered_logline_cmp(const logfile_sub_source& lc) : llss_controller(lc) - { - } - - bool operator()(const uint32_t& lhs, const uint32_t& rhs) const - { - content_line_t cl_lhs - = (content_line_t) llss_controller.lss_index[lhs]; - content_line_t cl_rhs - = (content_line_t) llss_controller.lss_index[rhs]; - logline* ll_lhs = this->llss_controller.find_line(cl_lhs); - logline* ll_rhs = this->llss_controller.find_line(cl_rhs); - - return (*ll_lhs) < (*ll_rhs); - } - - bool operator()(const uint32_t& lhs, const struct timeval& rhs) const - { - content_line_t cl_lhs - = (content_line_t) llss_controller.lss_index[lhs]; - logline* ll_lhs = this->llss_controller.find_line(cl_lhs); - - return (*ll_lhs) < rhs; - } - - const logfile_sub_source& llss_controller; - }; - - /** - * Functor for comparing the ld_file field of the logfile_data struct. - */ - struct logfile_data_eq { - explicit logfile_data_eq(std::shared_ptr lf) - : lde_file(std::move(lf)) - { - } - - bool operator()(const std::unique_ptr& ld) const - { - return this->lde_file == ld->get_file(); - } - - std::shared_ptr lde_file; - }; - void clear_line_size_cache() { this->lss_line_size_cache.fill(std::make_pair(0, 0)); @@ -962,7 +779,6 @@ private: bool lss_force_rebuild{false}; std::vector> lss_files; - big_array lss_index; std::vector lss_filtered_index; auto_mem lss_preview_filter_stmt{sqlite3_finalize}; diff --git a/src/piper.looper.cc b/src/piper.looper.cc index 230b38f4..33654a3d 100644 --- a/src/piper.looper.cc +++ b/src/piper.looper.cc @@ -52,12 +52,12 @@ write_timestamp(int fd, log_level_t level, off_t woff) struct timeval tv; gettimeofday(&tv, nullptr); - snprintf(time_str, - sizeof(time_str), - "%ld.%d:%c;", - tv.tv_sec, - tv.tv_usec, - level_names[level][0]); + fmt::format_to_n(time_str, + sizeof(time_str), + FMT_STRING("{}.{}:{};"), + tv.tv_sec, + tv.tv_usec, + level_names[level][0]); return pwrite(fd, time_str, strlen(time_str), woff); } diff --git a/src/readline_curses.cc b/src/readline_curses.cc index bae23093..6bb424b7 100644 --- a/src/readline_curses.cc +++ b/src/readline_curses.cc @@ -235,10 +235,10 @@ readline_context::completion_generator(const char* text_in, int state) if (arg_needs_shlex) { shlex arg_lexer(text_str); - std::map scope; + std::map scope; std::string result; - if (arg_lexer.eval(result, scope)) { + if (arg_lexer.eval(result, scoped_resolver{&scope})) { text_str = result; } } @@ -381,11 +381,11 @@ readline_context::attempted_completion(const char* text, int start, int end) point -= 1; } shlex lexer(rl_line_buffer, point); - std::map scope; + std::map scope; arg_possibilities = nullptr; rl_completion_append_character = 0; - if (lexer.split(prefix, scope)) { + if (lexer.split(prefix, scoped_resolver{&scope})) { auto prefix2 = fmt::format(FMT_STRING("{}"), fmt::join(prefix, "\x1f")); auto prefix_iter = loaded_context->rc_prefixes.find(prefix2); @@ -425,7 +425,7 @@ readline_context::attempted_completion(const char* text, int start, int end) shlex fn_lexer(rl_line_buffer, rl_point); std::vector fn_list; - fn_lexer.split(fn_list, scope); + fn_lexer.split(fn_list, scoped_resolver{&scope}); const auto& last_fn = fn_list.size() <= 1 ? "" : fn_list.back(); @@ -450,7 +450,7 @@ readline_context::attempted_completion(const char* text, int start, int end) std::vector fn_list; int found = 0; - fn_lexer.split(fn_list, scope); + fn_lexer.split(fn_list, scoped_resolver{&scope}); const auto& last_fn = fn_list.size() <= 1 ? "" : fn_list.back(); diff --git a/src/shared_buffer.hh b/src/shared_buffer.hh index e0029e9b..71be2a16 100644 --- a/src/shared_buffer.hh +++ b/src/shared_buffer.hh @@ -194,20 +194,6 @@ public: std::vector sb_refs; }; -struct tmp_shared_buffer { - explicit tmp_shared_buffer(const char* str, size_t len = -1) - { - if (len == (size_t) -1) { - len = strlen(str); - } - - this->tsb_ref.share(this->tsb_manager, (char*) str, len); - }; - - shared_buffer tsb_manager; - shared_buffer_ref tsb_ref; -}; - inline std::string to_string(const shared_buffer_ref& sbr) { diff --git a/src/shlex.cc b/src/shlex.cc index 8da44bb4..4bdbdc3a 100644 --- a/src/shlex.cc +++ b/src/shlex.cc @@ -216,3 +216,125 @@ shlex::resolve_home_dir(std::string& result, string_fragment cap) const } } } + +bool +shlex::eval(std::string& result, const scoped_resolver& vars) +{ + result.clear(); + + string_fragment cap; + shlex_token_t token; + int last_index = 0; + + while (this->tokenize(cap, token)) { + result.append(&this->s_str[last_index], cap.sf_begin - last_index); + switch (token) { + case shlex_token_t::ST_ERROR: + return false; + case shlex_token_t::ST_ESCAPE: + result.append(1, this->s_str[cap.sf_begin + 1]); + break; + case shlex_token_t::ST_WHITESPACE: + result.append(&this->s_str[cap.sf_begin], cap.length()); + break; + case shlex_token_t::ST_VARIABLE_REF: + case shlex_token_t::ST_QUOTED_VARIABLE_REF: { + int extra = token == shlex_token_t::ST_VARIABLE_REF ? 0 : 1; + const std::string var_name( + &this->s_str[cap.sf_begin + 1 + extra], + cap.length() - 1 - extra * 2); + auto local_var = vars.find(var_name); + const char* var_value = getenv(var_name.c_str()); + + if (local_var != vars.end()) { + result.append(fmt::to_string(local_var->second)); + } else if (var_value != nullptr) { + result.append(var_value); + } + break; + } + case shlex_token_t::ST_TILDE: + this->resolve_home_dir(result, cap); + break; + case shlex_token_t::ST_DOUBLE_QUOTE_START: + case shlex_token_t::ST_DOUBLE_QUOTE_END: + result.append("\""); + break; + case shlex_token_t::ST_SINGLE_QUOTE_START: + case shlex_token_t::ST_SINGLE_QUOTE_END: + result.append("'"); + break; + default: + break; + } + last_index = cap.sf_end; + } + + result.append(&this->s_str[last_index], this->s_len - last_index); + + return true; +} + +bool +shlex::split(std::vector& result, const scoped_resolver& vars) +{ + result.clear(); + + string_fragment cap; + shlex_token_t token; + int last_index = 0; + bool start_new = true; + + while (isspace(this->s_str[this->s_index])) { + this->s_index += 1; + } + while (this->tokenize(cap, token)) { + if (start_new) { + result.emplace_back(""); + start_new = false; + } + result.back().append(&this->s_str[last_index], + cap.sf_begin - last_index); + switch (token) { + case shlex_token_t::ST_ERROR: + return false; + case shlex_token_t::ST_ESCAPE: + result.back().append(1, this->s_str[cap.sf_begin + 1]); + break; + case shlex_token_t::ST_WHITESPACE: + start_new = true; + break; + case shlex_token_t::ST_VARIABLE_REF: + case shlex_token_t::ST_QUOTED_VARIABLE_REF: { + int extra = token == shlex_token_t::ST_VARIABLE_REF ? 0 : 1; + std::string var_name(&this->s_str[cap.sf_begin + 1 + extra], + cap.length() - 1 - extra * 2); + auto local_var = vars.find(var_name); + const char* var_value = getenv(var_name.c_str()); + + if (local_var != vars.end()) { + result.back().append(fmt::to_string(local_var->second)); + } else if (var_value != nullptr) { + result.back().append(var_value); + } + break; + } + case shlex_token_t::ST_TILDE: + this->resolve_home_dir(result.back(), cap); + break; + default: + break; + } + last_index = cap.sf_end; + } + + if (last_index < this->s_len) { + if (start_new || result.empty()) { + result.emplace_back(""); + } + result.back().append(&this->s_str[last_index], + this->s_len - last_index); + } + + return true; +} diff --git a/src/shlex.hh b/src/shlex.hh index 2317a2c3..a4644537 100644 --- a/src/shlex.hh +++ b/src/shlex.hh @@ -75,126 +75,9 @@ public: bool tokenize(string_fragment& cap_out, shlex_token_t& token_out); - template - bool eval(std::string& result, const Resolver& vars) - { - result.clear(); - - string_fragment cap; - shlex_token_t token; - int last_index = 0; - - while (this->tokenize(cap, token)) { - result.append(&this->s_str[last_index], cap.sf_begin - last_index); - switch (token) { - case shlex_token_t::ST_ERROR: - return false; - case shlex_token_t::ST_ESCAPE: - result.append(1, this->s_str[cap.sf_begin + 1]); - break; - case shlex_token_t::ST_WHITESPACE: - result.append(&this->s_str[cap.sf_begin], cap.length()); - break; - case shlex_token_t::ST_VARIABLE_REF: - case shlex_token_t::ST_QUOTED_VARIABLE_REF: { - int extra = token == shlex_token_t::ST_VARIABLE_REF ? 0 : 1; - std::string var_name(&this->s_str[cap.sf_begin + 1 + extra], - cap.length() - 1 - extra * 2); - auto local_var = vars.find(var_name); - const char* var_value = getenv(var_name.c_str()); - - if (local_var != vars.end()) { - result.append(fmt::to_string(local_var->second)); - } else if (var_value != nullptr) { - result.append(var_value); - } - break; - } - case shlex_token_t::ST_TILDE: - this->resolve_home_dir(result, cap); - break; - case shlex_token_t::ST_DOUBLE_QUOTE_START: - case shlex_token_t::ST_DOUBLE_QUOTE_END: - result.append("\""); - break; - case shlex_token_t::ST_SINGLE_QUOTE_START: - case shlex_token_t::ST_SINGLE_QUOTE_END: - result.append("'"); - break; - default: - break; - } - last_index = cap.sf_end; - } - - result.append(&this->s_str[last_index], this->s_len - last_index); - - return true; - } + bool eval(std::string& result, const scoped_resolver& vars); - template - bool split(std::vector& result, const Resolver& vars) - { - result.clear(); - - string_fragment cap; - shlex_token_t token; - int last_index = 0; - bool start_new = true; - - while (isspace(this->s_str[this->s_index])) { - this->s_index += 1; - } - while (this->tokenize(cap, token)) { - if (start_new) { - result.emplace_back(""); - start_new = false; - } - result.back().append(&this->s_str[last_index], - cap.sf_begin - last_index); - switch (token) { - case shlex_token_t::ST_ERROR: - return false; - case shlex_token_t::ST_ESCAPE: - result.back().append(1, this->s_str[cap.sf_begin + 1]); - break; - case shlex_token_t::ST_WHITESPACE: - start_new = true; - break; - case shlex_token_t::ST_VARIABLE_REF: - case shlex_token_t::ST_QUOTED_VARIABLE_REF: { - int extra = token == shlex_token_t::ST_VARIABLE_REF ? 0 : 1; - std::string var_name(&this->s_str[cap.sf_begin + 1 + extra], - cap.length() - 1 - extra * 2); - auto local_var = vars.find(var_name); - const char* var_value = getenv(var_name.c_str()); - - if (local_var != vars.end()) { - result.back().append(fmt::to_string(local_var->second)); - } else if (var_value != nullptr) { - result.back().append(var_value); - } - break; - } - case shlex_token_t::ST_TILDE: - this->resolve_home_dir(result.back(), cap); - break; - default: - break; - } - last_index = cap.sf_end; - } - - if (last_index < this->s_len) { - if (start_new || result.empty()) { - result.emplace_back(""); - } - result.back().append(&this->s_str[last_index], - this->s_len - last_index); - } - - return true; - } + bool split(std::vector& result, const scoped_resolver& vars); void reset() { diff --git a/src/shlex.resolver.hh b/src/shlex.resolver.hh index 404d142f..50afa240 100644 --- a/src/shlex.resolver.hh +++ b/src/shlex.resolver.hh @@ -37,10 +37,10 @@ #include #include "base/intern_string.hh" +#include "base/types.hh" #include "fmt/format.h" #include "mapbox/variant.hpp" -struct null_value_t {}; using scoped_value_t = mapbox::util:: variant; @@ -65,7 +65,7 @@ struct formatter : formatter { class scoped_resolver { public: scoped_resolver( - std::initializer_list*> l) + std::initializer_list*> l) { this->sr_stack.insert(this->sr_stack.end(), l.begin(), l.end()); } diff --git a/src/sql_execute.hh b/src/sql_execute.hh new file mode 100644 index 00000000..48d6d0bc --- /dev/null +++ b/src/sql_execute.hh @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2023, Timothy Stack + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Timothy Stack nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lnav_sql_execute_hh +#define lnav_sql_execute_hh + +#include + +#include + +#include "base/lnav.console.hh" +#include "shlex.resolver.hh" + +void sql_execute_script( + sqlite3* db, + const std::map& global_vars, + const char* src_name, + const char* script, + std::vector& errors); + +#endif diff --git a/src/sql_util.cc b/src/sql_util.cc index 97a5344b..82e78e45 100644 --- a/src/sql_util.cc +++ b/src/sql_util.cc @@ -36,7 +36,6 @@ #include "sql_util.hh" #include -#include #include #include "base/auto_mem.hh" @@ -50,7 +49,7 @@ #include "pcrepp/pcre2pp.hh" #include "readline_context.hh" #include "readline_highlighters.hh" -#include "shlex.resolver.hh" +#include "sql_execute.hh" #include "sql_help.hh" #include "sqlite-extension-func.hh" diff --git a/src/sql_util.hh b/src/sql_util.hh index 361942c2..c6f67b7b 100644 --- a/src/sql_util.hh +++ b/src/sql_util.hh @@ -109,13 +109,6 @@ char* sql_quote_ident(const char* ident); std::string sql_safe_ident(const string_fragment& ident); -void sql_execute_script( - sqlite3* db, - const std::map& global_vars, - const char* src_name, - const char* script, - std::vector& errors); - int guess_type_from_pcre(const std::string& pattern, std::string& collator); const char* sqlite3_type_to_string(int type); diff --git a/src/sqlitepp.hh b/src/sqlitepp.hh index 7845a232..0db20208 100644 --- a/src/sqlitepp.hh +++ b/src/sqlitepp.hh @@ -37,8 +37,9 @@ #include #include "base/auto_mem.hh" +#include "base/intern_string.hh" +#include "base/types.hh" #include "optional.hpp" -#include "shlex.resolver.hh" /* XXX figure out how to do this with the template */ void sqlite_close_wrapper(void* mem); diff --git a/src/textview_curses.cc b/src/textview_curses.cc index 5290417c..87660881 100644 --- a/src/textview_curses.cc +++ b/src/textview_curses.cc @@ -208,11 +208,13 @@ textview_curses::reload_config(error_reporter& reporter) iter = this->tc_highlights.erase(iter); } - std::map vars; + std::map vars; auto curr_theme_iter = lnav_config.lc_ui_theme_defs.find(lnav_config.lc_ui_theme); if (curr_theme_iter != lnav_config.lc_ui_theme_defs.end()) { - vars = curr_theme_iter->second.lt_vars; + for (const auto& vpair : curr_theme_iter->second.lt_vars) { + vars[vpair.first] = vpair.second; + } } for (const auto& theme_name : {DEFAULT_THEME_NAME, lnav_config.lc_ui_theme}) @@ -247,8 +249,8 @@ textview_curses::reload_config(error_reporter& reporter) fg1 = sc.sc_color; bg1 = sc.sc_background_color; - shlex(fg1).eval(fg_color, vars); - shlex(bg1).eval(bg_color, vars); + shlex(fg1).eval(fg_color, scoped_resolver{&vars}); + shlex(bg1).eval(bg_color, scoped_resolver{&vars}); auto fg = styling::color_unit::from_str(fg_color).unwrapOrElse( [&](const auto& msg) { diff --git a/src/top_status_source.cc b/src/top_status_source.cc index 59b95e57..85b68b86 100644 --- a/src/top_status_source.cc +++ b/src/top_status_source.cc @@ -35,7 +35,6 @@ #include "md2attr_line.hh" #include "md4cpp.hh" #include "shlex.hh" -#include "shlex.resolver.hh" #include "sql_util.hh" #include "sqlitepp.client.hh" #include "top_status_source.cfg.hh" @@ -99,7 +98,8 @@ top_status_source::update_user_msg() std::string user_note; lexer.with_ignore_quotes(true).eval( - user_note, lnav_data.ld_exec_context.ec_global_vars); + user_note, + scoped_resolver{&lnav_data.ld_exec_context.ec_global_vars}); md2attr_line mdal; auto parse_res = md4cpp::parse(user_note, mdal); diff --git a/src/view_curses.cc b/src/view_curses.cc index 3e0bcd32..c4b812ac 100644 --- a/src/view_curses.cc +++ b/src/view_curses.cc @@ -619,8 +619,12 @@ view_colors::to_attrs(const lnav_theme& lt, fg1 = sc.sc_color; bg1 = sc.sc_background_color; - shlex(fg1).eval(fg_color, lt.lt_vars); - shlex(bg1).eval(bg_color, lt.lt_vars); + std::map vars; + for (const auto& vpair : lt.lt_vars) { + vars[vpair.first] = vpair.second; + } + shlex(fg1).eval(fg_color, scoped_resolver{&vars}); + shlex(bg1).eval(bg_color, scoped_resolver{&vars}); auto fg = styling::color_unit::from_str(fg_color).unwrapOrElse( [&](const auto& msg) { diff --git a/src/view_helpers.cc b/src/view_helpers.cc index c11f535f..a93c04d6 100644 --- a/src/view_helpers.cc +++ b/src/view_helpers.cc @@ -461,7 +461,8 @@ build_all_help_text() std::string sub_help_text; lexer.with_ignore_quotes(true).eval( - sub_help_text, lnav_data.ld_exec_context.ec_global_vars); + sub_help_text, + scoped_resolver{&lnav_data.ld_exec_context.ec_global_vars}); md2attr_line mdal; auto parse_res = md4cpp::parse(sub_help_text, mdal); diff --git a/src/vtab_module.hh b/src/vtab_module.hh index a45594c0..7ae1ed59 100644 --- a/src/vtab_module.hh +++ b/src/vtab_module.hh @@ -41,11 +41,11 @@ #include "base/lnav.console.hh" #include "base/lnav_log.hh" #include "base/string_util.hh" +#include "base/types.hh" #include "fmt/format.h" #include "help_text_formatter.hh" #include "mapbox/variant.hpp" #include "optional.hpp" -#include "shlex.resolver.hh" #include "sqlite-extension-func.hh" lnav::console::user_message sqlite3_error_to_user_message(sqlite3*); @@ -67,10 +67,7 @@ struct sqlite_func_error : std::exception { { } - const char* what() const noexcept override - { - return this->e_what.c_str(); - } + const char* what() const noexcept override { return this->e_what.c_str(); } const std::string e_what; }; @@ -83,12 +80,10 @@ struct nullable { }; template -struct is_nullable : std::false_type { -}; +struct is_nullable : std::false_type {}; template -struct is_nullable> : std::true_type { -}; +struct is_nullable> : std::true_type {}; } // namespace vtab_types @@ -296,7 +291,7 @@ to_sqlite(sqlite3_context* ctx, double val) inline void to_sqlite(sqlite3_context* ctx, auto_mem str) { - auto free_func = str.get_free_func(); + auto free_func = str.get_free_func(); sqlite3_result_text(ctx, str.release(), -1, free_func); } @@ -372,8 +367,7 @@ struct optional_counter { }; template -struct optional_counter : optional_counter { -}; +struct optional_counter : optional_counter {}; template struct variadic_counter { @@ -391,8 +385,7 @@ struct variadic_counter { }; template -struct variadic_counter : variadic_counter { -}; +struct variadic_counter : variadic_counter {}; template struct sqlite_func_adapter; @@ -821,10 +814,7 @@ struct vtab_module : public vtab_module_base { return sqlite3_exec(db, create_stmt.c_str(), nullptr, nullptr, nullptr); } - int create(sqlite3* db) override - { - return this->create(db, T::NAME); - } + int create(sqlite3* db) override { return this->create(db, T::NAME); } sqlite3_module vm_module; T vm_impl; diff --git a/test/drive_shlexer.cc b/test/drive_shlexer.cc index fe6f15fc..42ad1b9d 100644 --- a/test/drive_shlexer.cc +++ b/test/drive_shlexer.cc @@ -80,12 +80,13 @@ main(int argc, char* argv[]) lexer.reset(); std::string result; - if (lexer.eval(result, map())) { + std::map vars; + if (lexer.eval(result, scoped_resolver{&vars})) { printf("eval -- %s\n", result.c_str()); } lexer.reset(); std::vector sresult; - if (lexer.split(sresult, map())) { + if (lexer.split(sresult, scoped_resolver{&vars})) { printf("split:\n"); for (size_t lpc = 0; lpc < sresult.size(); lpc++) { printf(" %zu -- %s\n", lpc, sresult[lpc].c_str());