[build] try to optimize compile time

pull/968/head
Timothy Stack 2 years ago
parent f2256c7aab
commit 4564e162d0

@ -9,8 +9,9 @@ set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
include("cmake/HunterGate.cmake")
huntergate(URL "https://github.com/cpp-pm/hunter/archive/v0.23.314.tar.gz" SHA1
"95c47c92f68edb091b5d6d18924baabe02a6962a" LOCAL)
huntergate(URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
LOCAL)
set(CMAKE_CXX_STANDARD 14)
project(lnav VERSION 0.10.2)

@ -396,6 +396,7 @@ add_library(
pugixml/pugiconfig.hpp
pugixml/pugixml.hpp
readline_callbacks.hh
readline_context.hh
readline_possibilities.hh
regexp_vtab.hh
relative_time.hh
@ -407,8 +408,11 @@ add_library(
safe/safe.h
sequence_sink.hh
shlex.hh
shlex.resolver.hh
simdutf8check.h
spectro_source.hh
sqlitepp.hh
sql_help.hh
sql_util.hh
strong_int.hh
string_attr_type.hh
@ -426,6 +430,7 @@ add_library(
top_status_source.hh
url_loader.hh
view_helpers.hh
view_helpers.examples.hh
views_vtab.hh
vis_line.hh
vtab_module.hh

@ -233,6 +233,7 @@ noinst_HEADERS = \
preview_status_source.hh \
ptimec.hh \
readline_callbacks.hh \
readline_context.hh \
readline_curses.hh \
readline_highlighters.hh \
readline_possibilities.hh \
@ -243,14 +244,15 @@ noinst_HEADERS = \
safe/defaulttypes.h \
safe/mutableref.h \
safe/safe.h \
sequence_matcher.hh \
sequence_sink.hh \
service_tags.hh \
session_data.hh \
shared_buffer.hh \
shlex.hh \
shlex.resolver.hh \
simdutf8check.h \
spectro_source.hh \
sqlitepp.hh \
sql_help.hh \
sql_util.hh \
sqlite-extension-func.hh \
styling.hh \
@ -273,6 +275,7 @@ noinst_HEADERS = \
url_loader.hh \
view_curses.hh \
view_helpers.hh \
view_helpers.examples.hh \
views_vtab.hh \
vis_line.hh \
vt52_curses.hh \
@ -366,7 +369,6 @@ libdiag_a_SOURCES = \
regexp_vtab.cc \
relative_time.cc \
session_data.cc \
sequence_matcher.cc \
shared_buffer.cc \
shlex.cc \
spectro_source.cc \

@ -41,6 +41,7 @@
#include "auto_fd.hh"
#include "auto_mem.hh"
#include "fmt/format.h"
#include "base/fs_util.hh"
#include "base/injector.hh"
#include "base/lnav_log.hh"
#include "base/humanize.hh"
@ -83,7 +84,7 @@ public:
auto lock_path = archive_path;
lock_path += ".lck";
this->lh_fd = openp(lock_path, O_CREAT | O_RDWR, 0600);
this->lh_fd = lnav::filesystem::openp(lock_path, O_CREAT | O_RDWR, 0600);
log_perror(fcntl(this->lh_fd, F_SETFD, FD_CLOEXEC));
};
@ -176,7 +177,7 @@ filename_to_tmp_path(const std::string &filename)
hasher h;
h.update(basename);
auto fd = auto_fd(openp(filename, O_RDONLY));
auto fd = auto_fd(lnav::filesystem::openp(filename, O_RDONLY));
if (fd != -1) {
char buffer[1024];
int rc;

@ -3,6 +3,7 @@ add_library(
../config.h
auto_pid.cc
date_time_scanner.cc
fs_util.cc
humanize.cc
humanize.network.cc
humanize.time.cc
@ -19,6 +20,7 @@ add_library(
auto_pid.hh
date_time_scanner.hh
enum_util.hh
fs_util.hh
func_util.hh
future_util.hh
humanize.hh

@ -23,6 +23,7 @@ noinst_HEADERS = \
date_time_scanner.hh \
enum_util.hh \
file_range.hh \
fs_util.hh \
func_util.hh \
future_util.hh \
humanize.hh \
@ -48,6 +49,7 @@ noinst_HEADERS = \
libbase_a_SOURCES = \
auto_pid.cc \
date_time_scanner.cc \
fs_util.cc \
humanize.cc \
humanize.network.cc \
humanize.time.cc \

@ -0,0 +1,94 @@
/**
* Copyright (c) 2022, 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.
*/
#include "config.h"
#include "fmt/format.h"
#include "fs_util.hh"
#include "opt_util.hh"
namespace lnav {
namespace filesystem {
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern)
{
auto pattern_str = pattern.string();
char pattern_copy[pattern_str.size() + 1];
int fd;
strcpy(pattern_copy, pattern_str.c_str());
if ((fd = mkstemp(pattern_copy)) == -1) {
return Err(fmt::format("unable to create temporary file: {} -- {}",
pattern.string(), strerror(errno)));
}
return Ok(std::make_pair(ghc::filesystem::path(pattern_copy), fd));
}
Result<std::string, std::string> read_file(const ghc::filesystem::path &path)
{
try {
ghc::filesystem::ifstream file_stream(path);
if (!file_stream) {
return Err(std::string(strerror(errno)));
}
std::string retval;
retval.assign((std::istreambuf_iterator<char>(file_stream)),
std::istreambuf_iterator<char>());
return Ok(retval);
} catch (const std::exception& e) {
return Err(std::string(e.what()));
}
}
std::string build_path(const std::vector<ghc::filesystem::path> &paths)
{
std::string retval;
for (const auto &path : paths) {
if (path.empty()) {
continue;
}
if (!retval.empty()) {
retval += ":";
}
retval += path.string();
}
auto env_path = getenv_opt("PATH");
if (env_path) {
retval += ":" + std::string(*env_path);
}
return retval;
}
}
}

@ -0,0 +1,64 @@
/**
* Copyright (c) 2022, 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_fs_util_hh
#define lnav_fs_util_hh
#include <string>
#include <vector>
#include "result.h"
#include "ghc/filesystem.hpp"
namespace lnav {
namespace filesystem {
inline int statp(const ghc::filesystem::path &path, struct stat *buf) {
return stat(path.c_str(), buf);
}
inline int openp(const ghc::filesystem::path &path, int flags) {
return open(path.c_str(), flags);
}
inline int openp(const ghc::filesystem::path &path, int flags, mode_t mode) {
return open(path.c_str(), flags, mode);
}
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern);
Result<std::string, std::string> read_file(const ghc::filesystem::path &path);
std::string build_path(const std::vector<ghc::filesystem::path> &paths);
}
}
#endif

@ -118,3 +118,62 @@ const intern_string *intern_string::lookup(const std::string &str) noexcept
{
return lookup(str.c_str(), str.size());
}
bool intern_string::startswith(const char *prefix) const
{
const char *curr = this->is_str.data();
while (*prefix != '\0' && *prefix == *curr) {
prefix += 1;
curr += 1;
}
return *prefix == '\0';
}
void string_fragment::trim(const char *tokens)
{
while (this->sf_begin < this->sf_end) {
bool found = false;
for (int lpc = 0; tokens[lpc] != '\0'; lpc++) {
if (this->sf_string[this->sf_begin] == tokens[lpc]) {
found = true;
break;
}
}
if (!found) {
break;
}
this->sf_begin += 1;
}
while (this->sf_begin < this->sf_end) {
bool found = false;
for (int lpc = 0; tokens[lpc] != '\0'; lpc++) {
if (this->sf_string[this->sf_end - 1] == tokens[lpc]) {
found = true;
break;
}
}
if (!found) {
break;
}
this->sf_end -= 1;
}
}
nonstd::optional<string_fragment> string_fragment::consume_n(int amount) const
{
if (amount > this->length()) {
return nonstd::nullopt;
}
return string_fragment{
this->sf_string,
this->sf_begin + amount,
this->sf_end,
};
}

@ -176,17 +176,7 @@ struct string_fragment {
};
}
nonstd::optional<string_fragment> consume_n(int amount) const {
if (amount > this->length()) {
return nonstd::nullopt;
}
return string_fragment{
this->sf_string,
this->sf_begin + amount,
this->sf_end,
};
}
nonstd::optional<string_fragment> consume_n(int amount) const;
template<typename P>
string_fragment skip(P predicate) const {
@ -280,38 +270,7 @@ struct string_fragment {
this->sf_end = -1;
};
void trim(const char *tokens) {
while (this->sf_begin < this->sf_end) {
bool found = false;
for (int lpc = 0; tokens[lpc] != '\0'; lpc++) {
if (this->sf_string[this->sf_begin] == tokens[lpc]) {
found = true;
break;
}
}
if (!found) {
break;
}
this->sf_begin += 1;
}
while (this->sf_begin < this->sf_end) {
bool found = false;
for (int lpc = 0; tokens[lpc] != '\0'; lpc++) {
if (this->sf_string[this->sf_end - 1] == tokens[lpc]) {
found = true;
break;
}
}
if (!found) {
break;
}
this->sf_end -= 1;
}
}
void trim(const char *tokens);
const char *sf_string;
int sf_begin;
@ -352,16 +311,7 @@ public:
return string_fragment{this->is_str};
}
bool startswith(const char *prefix) const {
const char *curr = this->is_str.data();
while (*prefix != '\0' && *prefix == *curr) {
prefix += 1;
curr += 1;
}
return *prefix == '\0';
}
bool startswith(const char *prefix) const;
struct intern_table;
static std::shared_ptr<intern_table> get_table_lifetime();

@ -34,7 +34,6 @@
#include "grep_proc.hh"
#include "textview_curses.hh"
#include "logfile_sub_source.hh"
#include "statusview_curses.hh"
class bottom_status_source

@ -34,6 +34,8 @@
struct last_relative_time_tag {};
struct sqlite_db_tag {};
struct sql_cmd_map_tag {};
#endif

@ -33,6 +33,7 @@
#include <algorithm>
#include "base/string_util.hh"
#include "sql_util.hh"
#include "base/lnav_log.hh"
@ -93,7 +94,7 @@ std::string column_namer::add_column(const std::string &in_name)
num += 1;
}
this->cn_names.push_back(retval);
this->cn_names.emplace_back(retval);
return retval;
}

@ -31,6 +31,7 @@
#include <vector>
#include "base/fs_util.hh"
#include "base/string_util.hh"
#include "base/injector.hh"
#include "yajlpp/json_ptr.hh"
@ -155,7 +156,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
stmt_str = MSG_FORMAT_STMT;
}
ec.ec_accumulator.clear();
ec.ec_accumulator->clear();
pair<string, int> source = ec.ec_source.top();
sql_progress_guard progress_guard(sql_progress,
@ -339,8 +340,8 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
lnav_data.ld_views[LNV_DB].reload_data();
lnav_data.ld_views[LNV_DB].set_left(0);
if (!ec.ec_accumulator.empty()) {
retval = ec.ec_accumulator.get_string();
if (!ec.ec_accumulator->empty()) {
retval = ec.ec_accumulator->get_string();
}
else if (!dls.dls_rows.empty()) {
if (lnav_data.ld_flags & LNF_HEADLESS) {
@ -790,7 +791,7 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
});
} else {
auto pp = make_shared<piper_proc>(
fd, false, open_temp_file(ghc::filesystem::temp_directory_path() /
fd, false, lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.out.XXXXXX")
.map([](auto pair) {
ghc::filesystem::remove(pair.first);
@ -870,6 +871,19 @@ void exec_context::clear_output()
this->ec_output_stack.back() = std::make_pair("default", nonstd::nullopt);
}
exec_context::exec_context(std::vector<logline_value> *line_values,
sql_callback_t sql_callback,
pipe_callback_t pipe_callback)
: ec_line_values(line_values),
ec_accumulator(std::make_unique<attr_line_t>()),
ec_sql_callback(sql_callback),
ec_pipe_callback(pipe_callback) {
this->ec_local_vars.push(std::map<std::string, std::string>());
this->ec_path_stack.emplace_back(".");
this->ec_source.emplace("command", 1);
this->ec_output_stack.emplace_back("screen", nonstd::nullopt);
}
exec_context::output_guard::output_guard(exec_context &context,
std::string name,
const nonstd::optional<output_t> &file)

@ -38,12 +38,12 @@
#include "fmt/format.h"
#include "optional.hpp"
#include "auto_fd.hh"
#include "attr_line.hh"
#include "shlex.hh"
#include "log_format.hh"
#include "bookmarks.hh"
#include "shlex.resolver.hh"
struct exec_context;
class attr_line_t;
class logline_value;
typedef int (*sql_callback_t)(exec_context &ec, sqlite3_stmt *stmt);
int sql_callback(exec_context &ec, sqlite3_stmt *stmt);
@ -61,15 +61,7 @@ struct exec_context {
exec_context(std::vector<logline_value> *line_values = nullptr,
sql_callback_t sql_callback = ::sql_callback,
pipe_callback_t pipe_callback = nullptr)
: ec_line_values(line_values),
ec_sql_callback(sql_callback),
ec_pipe_callback(pipe_callback) {
this->ec_local_vars.push(std::map<std::string, std::string>());
this->ec_path_stack.emplace_back(".");
this->ec_source.emplace("command", 1);
this->ec_output_stack.emplace_back("screen", nonstd::nullopt);
}
pipe_callback_t pipe_callback = nullptr);
bool is_read_write() const {
return this->ec_perms == perm_t::READ_WRITE;
@ -133,7 +125,7 @@ struct exec_context {
source_guard enter_source(const std::string& path, int line_number) {
this->ec_source.emplace(path, line_number);
return source_guard(*this);
return {*this};
}
scoped_resolver create_resolver() {
@ -156,7 +148,7 @@ struct exec_context {
std::vector<std::pair<std::string, nonstd::optional<output_t>>> ec_output_stack;
attr_line_t ec_accumulator;
std::unique_ptr<attr_line_t> ec_accumulator;
sql_callback_t ec_sql_callback;
pipe_callback_t ec_pipe_callback;

@ -29,7 +29,6 @@
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -305,7 +304,7 @@ int register_environ_vtab(sqlite3 *db)
int rc;
rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
assert(rc == SQLITE_OK);
ensure(rc == SQLITE_OK);
if ((rc = sqlite3_exec(db,
"CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
NULL, NULL, errmsg.out())) != SQLITE_OK) {

@ -33,10 +33,10 @@
#include <unordered_map>
#include "base/fs_util.hh"
#include "base/intern_string.hh"
#include "base/lnav_log.hh"
#include "auto_fd.hh"
#include "lnav_util.hh"
#include "file_format.hh"
#include "archive_manager.hh"
@ -104,7 +104,7 @@ file_format_t detect_file_format(const ghc::filesystem::path &filename)
file_format_t retval = file_format_t::FF_UNKNOWN;
auto_fd fd;
if ((fd = openp(filename, O_RDONLY)) != -1) {
if ((fd = lnav::filesystem::openp(filename, O_RDONLY)) != -1) {
uint8_t buffer[32];
ssize_t rc;

@ -31,6 +31,7 @@
#include "base/humanize.hh"
#include "base/humanize.network.hh"
#include "base/opt_util.hh"
#include "base/string_util.hh"
#include "mapbox/variant.hpp"

@ -30,6 +30,7 @@
#include "config.h"
#include "lnav.hh"
#include "base/opt_util.hh"
#include "filter_status_source.hh"
#include "files_sub_source.hh"

@ -31,6 +31,7 @@
#include "base/enum_util.hh"
#include "base/func_util.hh"
#include "base/opt_util.hh"
#include "lnav.hh"

@ -129,3 +129,61 @@ void hist_source2::add_value(time_t row, hist_source2::hist_type_t htype,
bucket.b_time = row;
bucket.b_values[htype].hv_value += value;
}
void hist_source2::init()
{
view_colors &vc = view_colors::singleton();
this->hs_chart
.with_attrs_for_ident(HT_NORMAL,
vc.attrs_for_role(view_colors::VCR_TEXT))
.with_attrs_for_ident(HT_WARNING,
vc.attrs_for_role(view_colors::VCR_WARNING))
.with_attrs_for_ident(HT_ERROR,
vc.attrs_for_role(view_colors::VCR_ERROR))
.with_attrs_for_ident(HT_MARK,
vc.attrs_for_role(view_colors::VCR_KEYWORD));
}
void hist_source2::clear()
{
this->hs_line_count = 0;
this->hs_last_bucket = -1;
this->hs_last_row = -1;
this->hs_blocks.clear();
this->hs_chart.clear();
this->init();
}
void hist_source2::end_of_row()
{
if (this->hs_last_bucket >= 0) {
bucket_t &last_bucket = this->find_bucket(this->hs_last_bucket);
for (int lpc = 0; lpc < HT__MAX; lpc++) {
this->hs_chart.add_value(
(const hist_type_t) lpc,
last_bucket.b_values[lpc].hv_value);
}
}
}
nonstd::optional<struct timeval> hist_source2::time_for_row(vis_line_t row)
{
if (row < 0 || row > this->hs_line_count) {
return nonstd::nullopt;
}
bucket_t &bucket = this->find_bucket(row);
return timeval{ bucket.b_time, 0 };
}
hist_source2::bucket_t &hist_source2::find_bucket(int64_t index)
{
struct bucket_block &bb = this->hs_blocks[index / BLOCK_SIZE];
unsigned int intra_block_index = index % BLOCK_SIZE;
bb.bb_used = std::max(intra_block_index, bb.bb_used);
this->hs_line_count = std::max(this->hs_line_count, index + 1);
return bb.bb_buckets[intra_block_index];
}

@ -326,23 +326,11 @@ public:
HT__MAX
} hist_type_t;
hist_source2() : hs_time_slice(10 * 60) {
hist_source2() {
this->clear();
};
void init() {
view_colors &vc = view_colors::singleton();
this->hs_chart
.with_attrs_for_ident(HT_NORMAL,
vc.attrs_for_role(view_colors::VCR_TEXT))
.with_attrs_for_ident(HT_WARNING,
vc.attrs_for_role(view_colors::VCR_WARNING))
.with_attrs_for_ident(HT_ERROR,
vc.attrs_for_role(view_colors::VCR_ERROR))
.with_attrs_for_ident(HT_MARK,
vc.attrs_for_role(view_colors::VCR_KEYWORD));
};
void init();
void set_time_slice(int64_t slice) {
this->hs_time_slice = slice;
@ -352,61 +340,36 @@ public:
return this->hs_time_slice;
};
size_t text_line_count() {
size_t text_line_count() override {
return this->hs_line_count;
};
size_t text_line_width(textview_curses &curses) {
size_t text_line_width(textview_curses &curses) override {
return strlen(LINE_FORMAT) + 8 * 4;
};
void clear() {
this->hs_line_count = 0;
this->hs_last_bucket = -1;
this->hs_last_row = -1;
this->hs_blocks.clear();
this->hs_chart.clear();
this->init();
};
void clear();
void add_value(time_t row, hist_type_t htype, double value = 1.0);
void end_of_row() {
if (this->hs_last_bucket >= 0) {
bucket_t &last_bucket = this->find_bucket(this->hs_last_bucket);
for (int lpc = 0; lpc < HT__MAX; lpc++) {
this->hs_chart.add_value(
(const hist_type_t) lpc,
last_bucket.b_values[lpc].hv_value);
}
}
};
void end_of_row();
void text_value_for_line(textview_curses &tc,
int row,
std::string &value_out,
line_flags_t flags);
line_flags_t flags) override;
void text_attrs_for_line(textview_curses &tc,
int row,
string_attrs_t &value_out);
string_attrs_t &value_out) override;
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) {
size_t text_size_for_line(textview_curses &tc, int row, line_flags_t flags) override {
return 0;
};
nonstd::optional<struct timeval> time_for_row(vis_line_t row) {
if (row < 0 || row > this->hs_line_count) {
return nonstd::nullopt;
}
bucket_t &bucket = this->find_bucket(row);
nonstd::optional<struct timeval> time_for_row(vis_line_t row) override;
return timeval{ bucket.b_time, 0 };
};
nonstd::optional<vis_line_t> row_for_time(struct timeval tv_bucket);
nonstd::optional<vis_line_t> row_for_time(struct timeval tv_bucket) override;
private:
static const char *LINE_FORMAT;
@ -423,23 +386,17 @@ private:
static const int64_t BLOCK_SIZE = 100;
struct bucket_block {
bucket_block() : bb_used(0) {
bucket_block() {
memset(this->bb_buckets, 0, sizeof(this->bb_buckets));
};
unsigned int bb_used;
unsigned int bb_used{0};
bucket_t bb_buckets[BLOCK_SIZE];
};
bucket_t &find_bucket(int64_t index) {
struct bucket_block &bb = this->hs_blocks[index / BLOCK_SIZE];
unsigned int intra_block_index = index % BLOCK_SIZE;
bb.bb_used = std::max(intra_block_index, bb.bb_used);
this->hs_line_count = std::max(this->hs_line_count, index + 1);
return bb.bb_buckets[intra_block_index];
};
bucket_t &find_bucket(int64_t index);
int64_t hs_time_slice;
int64_t hs_time_slice{10 * 60};
int64_t hs_line_count;
int64_t hs_last_bucket;
time_t hs_last_row;

@ -43,7 +43,6 @@
#include "vtab_module.hh"
#include "vtab_module_json.hh"
#include "lnav_util.hh"
#include "yajl/api/yajl_gen.h"
#include "sqlite-extension-func.hh"

@ -82,6 +82,7 @@
#include "help-txt.h"
#include "init-sql.h"
#include "logfile.hh"
#include "base/fs_util.hh"
#include "base/func_util.hh"
#include "base/humanize.network.hh"
#include "base/humanize.time.hh"
@ -130,6 +131,8 @@
#include "base/future_util.hh"
#include "tailer/tailer.looper.hh"
#include "service_tags.hh"
#include "view_helpers.examples.hh"
#include "sql_help.hh"
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
@ -231,6 +234,9 @@ static auto bound_active_files =
return &lnav_data.ld_active_files;
});
static auto bound_sqlite_db =
injector::bind<auto_mem<sqlite3, sqlite_close_wrapper>, sqlite_db_tag>::to_instance(&lnav_data.ld_db);
static auto bound_last_rel_time =
injector::bind<relative_time, last_relative_time_tag>::to_singleton();
@ -261,6 +267,11 @@ void force_linking(last_relative_time_tag anno)
{
}
template<>
void force_linking(sqlite_db_tag anno)
{
}
template<>
void force_linking(services::curl_streamer_t anno)
{
@ -2332,7 +2343,7 @@ int main(int argc, char *argv[])
if ((in_fd = open(argv[lpc], O_RDONLY)) == -1) {
perror("unable to open file to install");
}
else if ((out_fd = openp(dst_path,
else if ((out_fd = lnav::filesystem::openp(dst_path,
O_WRONLY | O_CREAT | O_TRUNC,
0644)) == -1) {
fprintf(stderr, "error: unable to open destination: %s -- %s\n",
@ -2421,7 +2432,16 @@ int main(int argc, char *argv[])
log_fos->fos_contexts.emplace("", false, true);
lnav_data.ld_views[LNV_LOG]
.set_sub_source(&lnav_data.ld_log_source)
.set_delegate(new action_delegate(lnav_data.ld_log_source))
.set_delegate(std::make_shared<action_delegate>(
lnav_data.ld_log_source,
[](auto child_pid) {
lnav_data.ld_children.push_back(child_pid);
}, [](const auto &desc, auto pp) {
lnav_data.ld_pipers.push_back(pp);
lnav_data.ld_active_files.fc_file_names[desc]
.with_fd(pp->get_fd());
lnav_data.ld_files_to_front.template emplace_back(desc, 0);
}))
.add_input_delegate(lnav_data.ld_log_source)
.set_tail_space(2_vl)
.set_overlay_source(log_fos);
@ -2705,7 +2725,7 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
auto fifo_piper = make_shared<piper_proc>(
fifo_fd.release(),
false,
open_temp_file(ghc::filesystem::temp_directory_path() /
lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.fifo.XXXXXX")
.map([](auto pair) {
ghc::filesystem::remove(pair.first);
@ -2812,7 +2832,7 @@ SELECT tbl_name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE%'
if (stdin_out == nullptr) {
auto pattern = lnav::paths::dotlnav() / "stdin-captures/stdin.XXXXXX";
auto open_result = open_temp_file(pattern);
auto open_result = lnav::filesystem::open_temp_file(pattern);
if (open_result.isErr()) {
fprintf(stderr,
"Unable to open temporary file for stdin: %s",

@ -44,6 +44,7 @@
#include <yajl/api/yajl_tree.h>
#include "bound_tags.hh"
#include "base/fs_util.hh"
#include "base/humanize.network.hh"
#include "base/injector.hh"
#include "base/isc.hh"
@ -1341,7 +1342,7 @@ static Result<string, string> com_pipe_to(exec_context &ec, string cmdline, vect
}
}
setenv("PATH", build_path(path_v).c_str(), 1);
setenv("PATH", lnav::filesystem::build_path(path_v).c_str(), 1);
execvp(args[0], (char *const *) args);
_exit(1);
break;
@ -2294,7 +2295,7 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
auto fifo_piper = make_shared<piper_proc>(
fifo_fd.release(),
false,
open_temp_file(ghc::filesystem::temp_directory_path() /
lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.fifo.XXXXXX")
.map([](auto pair) {
ghc::filesystem::remove(pair.first);

@ -47,12 +47,12 @@
#include <fmt/format.h>
#include "auto_fd.hh"
#include "base/fs_util.hh"
#include "base/injector.hh"
#include "base/injector.bind.hh"
#include "base/paths.hh"
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "lnav_util.hh"
#include "auto_mem.hh"
#include "base/auto_pid.hh"
#include "lnav_config.hh"
@ -339,7 +339,7 @@ void install_extra_formats()
}
auto config_json = config_root / "remote-config.json";
if ((fd = openp(config_json, O_RDONLY)) == -1) {
if ((fd = lnav::filesystem::openp(config_json, O_RDONLY)) == -1) {
perror("Unable to open remote-config.json");
}
else {
@ -1120,7 +1120,7 @@ detect_config_file_type(const ghc::filesystem::path &path)
{
static const char *id_path[] = {"$schema", nullptr};
auto read_res = read_file(path);
auto read_res = lnav::filesystem::read_file(path);
if (read_res.isErr()) {
return Err(fmt::format("unable to open file: {} -- {}",
@ -1166,7 +1166,7 @@ static void load_config_from(_lnav_config& lconfig, const ghc::filesystem::path
ypc.with_obj(lconfig);
ypc.ypc_userdata = &ud;
ypc.with_error_reporter(config_error_reporter);
if ((fd = openp(path, O_RDONLY)) == -1) {
if ((fd = lnav::filesystem::openp(path, O_RDONLY)) == -1) {
if (errno != ENOENT) {
char errmsg[1024];
@ -1255,7 +1255,7 @@ void load_config(const vector<ghc::filesystem::path> &extra_paths, vector<string
"default" /
fmt::format("{}.sample", bsf.get_name());
auto fd = auto_fd(openp(sample_path, O_WRONLY|O_TRUNC|O_CREAT, 0644));
auto fd = auto_fd(lnav::filesystem::openp(sample_path, O_WRONLY|O_TRUNC|O_CREAT, 0644));
auto sf = bsf.to_string_fragment();
if (fd == -1 || write(fd.get(), sf.data(), sf.length()) == -1) {
fprintf(stderr,
@ -1335,7 +1335,7 @@ string save_config()
{
auto_fd fd;
if ((fd = openp(user_config_tmp,
if ((fd = lnav::filesystem::openp(user_config_tmp,
O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1) {
return "error: unable to save configuration -- " +
string(strerror(errno));

@ -34,10 +34,9 @@
#include "config.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>
#include "lnav_util.hh"
#include "base/opt_util.hh"
#include "base/result.h"
#include "ansi_scrubber.hh"
#include "fmt/format.h"
@ -65,60 +64,6 @@ bool change_to_parent_dir()
return retval;
}
string build_path(const vector<ghc::filesystem::path> &paths)
{
string retval;
for (const auto &path : paths) {
if (path.empty()) {
continue;
}
if (!retval.empty()) {
retval += ":";
}
retval += path.string();
}
auto env_path = getenv_opt("PATH");
if (env_path) {
retval += ":" + string(*env_path);
}
return retval;
}
Result<std::string, std::string> read_file(const ghc::filesystem::path &path)
{
try {
ghc::filesystem::ifstream file_stream(path);
if (!file_stream) {
return Err(std::string(strerror(errno)));
}
std::string retval;
retval.assign((std::istreambuf_iterator<char>(file_stream)),
std::istreambuf_iterator<char>());
return Ok(retval);
} catch (const std::exception& e) {
return Err(std::string(e.what()));
}
}
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern)
{
auto pattern_str = pattern.string();
char pattern_copy[pattern_str.size() + 1];
int fd;
strcpy(pattern_copy, pattern_str.c_str());
if ((fd = mkstemp(pattern_copy)) == -1) {
return Err(fmt::format("unable to create temporary file: {} -- {}",
pattern.string(), strerror(errno)));
}
return Ok(make_pair(ghc::filesystem::path(pattern_copy), fd));
}
bool is_dev_null(const struct stat &st)
{
struct stat null_stat;

@ -55,7 +55,6 @@
#include "base/result.h"
#include "base/intern_string.hh"
#include "fmt/format.h"
#include "ghc/filesystem.hpp"
#if SIZEOF_OFF_T == 8
#define FORMAT_OFF_T "%lld"
@ -123,10 +122,6 @@ inline bool is_glob(const char *fn)
strchr(fn, '[') != nullptr);
};
std::string build_path(const std::vector<ghc::filesystem::path> &paths);
Result<std::string, std::string> read_file(const ghc::filesystem::path &path);
inline short pollfd_revents(const std::vector<struct pollfd> &pollfds, int fd) {
auto iter = std::find_if(pollfds.begin(), pollfds.end(), [fd](const auto& entry) {
return entry.fd == fd;
@ -186,21 +181,6 @@ inline void rusageadd(const struct rusage &left, const struct rusage &right, str
diff_out.ru_nivcsw = left.ru_nivcsw + right.ru_nivcsw;
}
inline int statp(const ghc::filesystem::path &path, struct stat *buf) {
return stat(path.c_str(), buf);
}
inline int openp(const ghc::filesystem::path &path, int flags) {
return open(path.c_str(), flags);
}
inline int openp(const ghc::filesystem::path &path, int flags, mode_t mode) {
return open(path.c_str(), flags, mode);
}
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern);
bool is_dev_null(const struct stat &st);
bool is_dev_null(int fd);

@ -29,24 +29,23 @@
#include "config.h"
#include "lnav.hh"
#include "lnav_util.hh"
#include "base/fs_util.hh"
#include "log_actions.hh"
#include "piper_proc.hh"
using namespace std;
static string execute_action(log_data_helper &ldh,
int value_index,
const string &action_name)
string action_delegate::execute_action(const string &action_name)
{
std::map<string, log_format::action_def>::const_iterator iter;
auto& ldh = this->ad_log_helper;
auto value_index = this->ad_press_value;
logline_value &lv = ldh.ldh_line_values[value_index];
shared_ptr<logfile> lf = ldh.ldh_file;
const auto format = lf->get_format();
pid_t child_pid;
string retval;
iter = format->lf_action_defs.find(action_name);
auto iter = format->lf_action_defs.find(action_name);
const log_format::action_def &action = iter->second;
@ -112,7 +111,7 @@ static string execute_action(log_data_helper &ldh,
string value = lv.to_string();
lnav_data.ld_children.push_back(child_pid);
this->ad_child_cb(child_pid);
if (write(in_pipe.write_end(), value.c_str(), value.size()) == -1) {
perror("execute_action write");
@ -123,7 +122,7 @@ static string execute_action(log_data_helper &ldh,
auto pp = make_shared<piper_proc>(
out_pipe.read_end(),
false,
open_temp_file(ghc::filesystem::temp_directory_path() /
lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.action.XXXXXX")
.map([](auto pair) {
ghc::filesystem::remove(pair.first);
@ -132,16 +131,10 @@ static string execute_action(log_data_helper &ldh,
})
.expect("Cannot create temporary file for action")
.second);
char desc[128];
lnav_data.ld_pipers.push_back(pp);
snprintf(desc,
sizeof(desc), "[%d] Output of %s",
exec_count++,
action.ad_cmdline[0].c_str());
lnav_data.ld_active_files.fc_file_names[desc]
.with_fd(pp->get_fd());
lnav_data.ld_files_to_front.emplace_back( desc, 0 );
auto desc = fmt::format("[{}] Output of {}", exec_count++,
action.ad_cmdline[0]);
this->ad_piper_cb(desc, pp);
}
return "";
@ -212,10 +205,9 @@ bool action_delegate::text_handle_mouse(textview_curses &tc, mouse_event &me)
actions = lf->get_format()->get_actions(lv);
if (actions != nullptr && !actions->empty()) {
string rc = execute_action(
this->ad_log_helper, this->ad_press_value, actions->at(0));
const auto rc = execute_action(actions->at(0));
lnav_data.ld_rl_view->set_value(rc);
// lnav_data.ld_rl_view->set_value(rc);
}
}
retval = true;

@ -30,25 +30,36 @@
#ifndef log_actions_hh
#define log_actions_hh
#include <functional>
#include <utility>
#include "logfile_sub_source.hh"
#include "log_data_helper.hh"
class piper_proc;
class action_delegate : public text_delegate {
public:
action_delegate(logfile_sub_source &lss)
: ad_log_helper(lss),
ad_press_line(-1),
ad_press_value(-1),
ad_line_index(0) {
explicit action_delegate(logfile_sub_source &lss,
std::function<void(pid_t)> child_cb,
std::function<void(const std::string&,
std::shared_ptr<piper_proc>)> piper_cb)
: ad_log_helper(lss), ad_child_cb(std::move(child_cb)), ad_piper_cb(std::move(piper_cb)) {
};
virtual bool text_handle_mouse(textview_curses &tc, mouse_event &me);
bool text_handle_mouse(textview_curses &tc, mouse_event &me) override;
private:
std::string execute_action(const std::string &action_name);
log_data_helper ad_log_helper;
vis_line_t ad_press_line;
int ad_press_value;
size_t ad_line_index;
std::function<void(pid_t)> ad_child_cb;
std::function<void(const std::string&,
std::shared_ptr<piper_proc>)> ad_piper_cb;
vis_line_t ad_press_line{-1};
int ad_press_value{-1};
size_t ad_line_index{0};
};
#endif

@ -43,6 +43,7 @@
#include "fmt/format.h"
#include "file_format.hh"
#include "base/fs_util.hh"
#include "base/paths.hh"
#include "base/string_util.hh"
#include "yajlpp/yajlpp.hh"
@ -800,7 +801,7 @@ static void write_sample_file()
auto sf = bsf.to_string_fragment();
auto_fd sample_fd;
if ((sample_fd = openp(sample_path,
if ((sample_fd = lnav::filesystem::openp(sample_path,
O_WRONLY | O_TRUNC | O_CREAT,
0644)) == -1 ||
(write(sample_fd.get(), sf.data(), sf.length()) == -1)) {
@ -816,7 +817,7 @@ static void write_sample_file()
auto sf = bsf.to_string_fragment();
auto_fd sh_fd;
if ((sh_fd = openp(sh_path, O_WRONLY|O_TRUNC|O_CREAT, 0755)) == -1 ||
if ((sh_fd = lnav::filesystem::openp(sh_path, O_WRONLY|O_TRUNC|O_CREAT, 0755)) == -1 ||
write(sh_fd.get(), sf.data(), sf.length()) == -1) {
fprintf(stderr,
"error:unable to write default text file: %s -- %s\n",
@ -835,11 +836,11 @@ static void write_sample_file()
extract_metadata(sf.data(), sf.length(), meta);
snprintf(path, sizeof(path), "formats/default/%s.lnav", meta.sm_name.c_str());
auto script_path = lnav::paths::dotlnav() / path;
if (statp(script_path, &st) == 0 && st.st_size == sf.length()) {
if (lnav::filesystem::statp(script_path, &st) == 0 && st.st_size == sf.length()) {
// Assume it's the right contents and move on...
continue;
}
if ((script_fd = openp(script_path, O_WRONLY|O_TRUNC|O_CREAT, 0755)) == -1 ||
if ((script_fd = lnav::filesystem::openp(script_path, O_WRONLY|O_TRUNC|O_CREAT, 0755)) == -1 ||
write(script_fd.get(), sf.data(), sf.length()) == -1) {
fprintf(stderr,
"error:unable to write default text file: %s -- %s\n",
@ -877,7 +878,7 @@ load_format_file(const ghc::filesystem::path &filename,
yajlpp_parse_context ypc(filename, &root_format_handler);
ypc.ypc_userdata = &ud;
ypc.with_obj(ud);
if ((fd = openp(filename, O_RDONLY)) == -1) {
if ((fd = lnav::filesystem::openp(filename, O_RDONLY)) == -1) {
errors.emplace_back(fmt::format(
"error: unable to open format file '{}' -- {}",
filename.string(), strerror(errno)));
@ -1096,7 +1097,7 @@ static void exec_sql_in_path(sqlite3 *db, const ghc::filesystem::path &path, std
if (glob(format_path.c_str(), 0, nullptr, gl.inout()) == 0) {
for (int lpc = 0; lpc < (int)gl->gl_pathc; lpc++) {
auto filename = ghc::filesystem::path(gl->gl_pathv[lpc]);
auto read_res = read_file(filename);
auto read_res = lnav::filesystem::read_file(filename);
if (read_res.isOk()) {
log_info("Executing SQL file: %s", filename.c_str());
@ -1155,7 +1156,7 @@ void extract_metadata_from_file(struct script_metadata &meta_inout)
auto_mem<FILE> fp(fclose);
struct stat st;
if (statp(meta_inout.sm_path, &st) == -1) {
if (lnav::filesystem::statp(meta_inout.sm_path, &st) == -1) {
log_warning("unable to open script -- %s", meta_inout.sm_path.c_str());
} else if (!S_ISREG(st.st_mode)) {
log_warning("not a regular file -- %s", meta_inout.sm_path.c_str());

@ -44,6 +44,7 @@
#include <utility>
#include "base/fs_util.hh"
#include "base/string_util.hh"
#include "base/injector.hh"
#include "logfile.hh"
@ -144,7 +145,7 @@ bool logfile::exists() const
return true;
}
if (statp(this->lf_actual_path.value(), &st) == -1) {
if (lnav::filesystem::statp(this->lf_actual_path.value(), &st) == -1) {
log_error("%s: stat failed -- %s",
this->lf_actual_path.value().c_str(),
strerror(errno));

@ -41,8 +41,11 @@
using ui_clock = std::chrono::steady_clock;
class logfile;
class logline;
class logline_observer;
using logfile_const_iterator = std::vector<logline>::const_iterator;
enum class logfile_name_source {
USER,
ARCHIVE,

@ -60,8 +60,8 @@ static int pretty_sql_callback(exec_context &ec, sqlite3_stmt *stmt)
int ncols = sqlite3_column_count(stmt);
for (int lpc = 0; lpc < ncols; lpc++) {
if (!ec.ec_accumulator.empty()) {
ec.ec_accumulator.append(", ");
if (!ec.ec_accumulator->empty()) {
ec.ec_accumulator->append(", ");
}
const char *res = (const char *)sqlite3_column_text(stmt, lpc);
@ -69,7 +69,7 @@ static int pretty_sql_callback(exec_context &ec, sqlite3_stmt *stmt)
continue;
}
ec.ec_accumulator.append(res);
ec.ec_accumulator->append(res);
}
return 0;
@ -1529,6 +1529,168 @@ void logfile_sub_source::invalidate_sql_filter()
}
}
void
logfile_sub_source::text_mark(bookmark_type_t *bm, vis_line_t line, bool added)
{
if (line >= (int) this->lss_index.size()) {
return;
}
content_line_t cl = this->at(line);
std::vector<content_line_t>::iterator lb;
if (bm == &textview_curses::BM_USER) {
logline *ll = this->find_line(cl);
ll->set_mark(added);
}
lb = std::lower_bound(this->lss_user_marks[bm].begin(),
this->lss_user_marks[bm].end(),
cl);
if (added) {
if (lb == this->lss_user_marks[bm].end() || *lb != cl) {
this->lss_user_marks[bm].insert(lb, cl);
}
}
else if (lb != this->lss_user_marks[bm].end() && *lb == cl) {
require(lb != this->lss_user_marks[bm].end());
this->lss_user_marks[bm].erase(lb);
}
if (bm == &textview_curses::BM_META &&
this->lss_meta_grepper.gps_proc != nullptr) {
this->tss_view->search_range(line, line + 1_vl);
this->tss_view->search_new_data();
}
}
void logfile_sub_source::text_clear_marks(bookmark_type_t *bm)
{
std::vector<content_line_t>::iterator iter;
if (bm == &textview_curses::BM_USER) {
for (iter = this->lss_user_marks[bm].begin();
iter != this->lss_user_marks[bm].end();) {
auto bm_iter = this->lss_user_mark_metadata.find(*iter);
if (bm_iter != this->lss_user_mark_metadata.end()) {
++iter;
continue;
}
this->find_line(*iter)->set_mark(false);
iter = this->lss_user_marks[bm].erase(iter);
}
} else {
this->lss_user_marks[bm].clear();
}
}
void logfile_sub_source::remove_file(std::shared_ptr<logfile> lf)
{
iterator iter;
iter = std::find_if(this->lss_files.begin(),
this->lss_files.end(),
logfile_data_eq(lf));
if (iter != this->lss_files.end()) {
bookmarks<content_line_t>::type::iterator mark_iter;
int file_index = iter - this->lss_files.begin();
(*iter)->clear();
for (mark_iter = this->lss_user_marks.begin();
mark_iter != this->lss_user_marks.end();
++mark_iter) {
content_line_t mark_curr = content_line_t(
file_index * MAX_LINES_PER_FILE);
content_line_t mark_end = content_line_t(
(file_index + 1) * MAX_LINES_PER_FILE);
bookmark_vector<content_line_t>::iterator bv_iter;
bookmark_vector<content_line_t> & bv =
mark_iter->second;
while ((bv_iter =
std::lower_bound(bv.begin(), bv.end(),
mark_curr)) != bv.end()) {
if (*bv_iter >= mark_end) {
break;
}
mark_iter->second.erase(bv_iter);
}
}
this->lss_force_rebuild = true;
}
}
nonstd::optional<vis_line_t>
logfile_sub_source::find_from_content(content_line_t cl)
{
content_line_t line = cl;
std::shared_ptr<logfile> lf = this->find(line);
if (lf != nullptr) {
auto ll_iter = lf->begin() + line;
auto &ll = *ll_iter;
auto vis_start_opt = this->find_from_time(ll.get_timeval());
if (!vis_start_opt) {
return nonstd::nullopt;
}
auto vis_start = *vis_start_opt;
while (vis_start < vis_line_t(this->text_line_count())) {
content_line_t guess_cl = this->at(vis_start);
if (cl == guess_cl) {
return vis_start;
}
auto guess_line = this->find_line(guess_cl);
if (!guess_line || ll < *guess_line) {
return nonstd::nullopt;
}
++vis_start;
}
}
return nonstd::nullopt;
}
void logfile_sub_source::reload_index_delegate()
{
if (this->lss_index_delegate == nullptr) {
return;
}
this->lss_index_delegate->index_start(*this);
for (unsigned int index : this->lss_filtered_index) {
content_line_t cl = (content_line_t) this->lss_index[index];
uint64_t line_number;
auto ld = this->find_data(cl, line_number);
std::shared_ptr<logfile> lf = (*ld)->get_file();
this->lss_index_delegate->index_line(*this, lf.get(), lf->begin() + line_number);
}
this->lss_index_delegate->index_complete(*this);
}
nonstd::optional<std::shared_ptr<text_filter>>
logfile_sub_source::get_sql_filter()
{
auto iter = std::find_if(this->tss_filters.begin(),
this->tss_filters.end(),
[](const auto& filt) {
return filt->get_index() == 0;
});
if (iter != this->tss_filters.end()) {
return *iter;
}
return nonstd::nullopt;
}
void log_location_history::loc_history_append(vis_line_t top)
{
if (top >= vis_line_t(this->llh_log_source.text_line_count())) {
@ -1621,3 +1783,67 @@ std::string sql_filter::to_command()
{
return fmt::format("filter-expr {}", this->lf_id);
}
bool logfile_sub_source::meta_grepper::grep_value_for_line(vis_line_t line,
string &value_out)
{
content_line_t cl = this->lmg_source.at(vis_line_t(line));
std::map<content_line_t, bookmark_metadata> &user_mark_meta =
lmg_source.get_user_bookmark_metadata();
auto meta_iter = user_mark_meta.find(cl);
if (meta_iter == user_mark_meta.end()) {
value_out.clear();
} else {
bookmark_metadata &bm = meta_iter->second;
value_out.append(bm.bm_comment);
for (const auto &tag : bm.bm_tags) {
value_out.append(tag);
}
}
return !this->lmg_done;
}
vis_line_t logfile_sub_source::meta_grepper::grep_initial_line(vis_line_t start,
vis_line_t highest)
{
vis_bookmarks &bm = this->lmg_source.tss_view->get_bookmarks();
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_META];
if (bv.empty()) {
return -1_vl;
}
return *bv.begin();
}
void logfile_sub_source::meta_grepper::grep_next_line(vis_line_t &line)
{
vis_bookmarks &bm = this->lmg_source.tss_view->get_bookmarks();
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_META];
line = bv.next(vis_line_t(line));
if (line == -1) {
this->lmg_done = true;
}
}
void logfile_sub_source::meta_grepper::grep_begin(grep_proc<vis_line_t> &gp,
vis_line_t start,
vis_line_t stop)
{
this->lmg_source.tss_view->grep_begin(gp, start, stop);
}
void logfile_sub_source::meta_grepper::grep_end(grep_proc<vis_line_t> &gp)
{
this->lmg_source.tss_view->grep_end(gp);
}
void logfile_sub_source::meta_grepper::grep_match(grep_proc<vis_line_t> &gp,
vis_line_t line, int start,
int end)
{
this->lmg_source.tss_view->grep_match(gp, line, start, end);
}

@ -343,98 +343,13 @@ public:
return this->lss_line_size_cache[index].second;
};
void text_mark(bookmark_type_t *bm, vis_line_t line, bool added)
{
if (line >= (int) this->lss_index.size()) {
return;
}
content_line_t cl = this->at(line);
std::vector<content_line_t>::iterator lb;
if (bm == &textview_curses::BM_USER) {
logline *ll = this->find_line(cl);
ll->set_mark(added);
}
lb = std::lower_bound(this->lss_user_marks[bm].begin(),
this->lss_user_marks[bm].end(),
cl);
if (added) {
if (lb == this->lss_user_marks[bm].end() || *lb != cl) {
this->lss_user_marks[bm].insert(lb, cl);
}
}
else if (lb != this->lss_user_marks[bm].end() && *lb == cl) {
require(lb != this->lss_user_marks[bm].end());
void text_mark(bookmark_type_t *bm, vis_line_t line, bool added);
this->lss_user_marks[bm].erase(lb);
}
if (bm == &textview_curses::BM_META &&
this->lss_meta_grepper.gps_proc != nullptr) {
this->tss_view->search_range(line, line + 1_vl);
this->tss_view->search_new_data();
}
};
void text_clear_marks(bookmark_type_t *bm)
{
std::vector<content_line_t>::iterator iter;
if (bm == &textview_curses::BM_USER) {
for (iter = this->lss_user_marks[bm].begin();
iter != this->lss_user_marks[bm].end();) {
auto bm_iter = this->lss_user_mark_metadata.find(*iter);
if (bm_iter != this->lss_user_mark_metadata.end()) {
++iter;
continue;
}
this->find_line(*iter)->set_mark(false);
iter = this->lss_user_marks[bm].erase(iter);
}
} else {
this->lss_user_marks[bm].clear();
}
};
void text_clear_marks(bookmark_type_t *bm);
bool insert_file(const std::shared_ptr<logfile>& lf);
void remove_file(std::shared_ptr<logfile> lf)
{
iterator iter;
iter = std::find_if(this->lss_files.begin(),
this->lss_files.end(),
logfile_data_eq(lf));
if (iter != this->lss_files.end()) {
bookmarks<content_line_t>::type::iterator mark_iter;
int file_index = iter - this->lss_files.begin();
(*iter)->clear();
for (mark_iter = this->lss_user_marks.begin();
mark_iter != this->lss_user_marks.end();
++mark_iter) {
content_line_t mark_curr = content_line_t(
file_index * MAX_LINES_PER_FILE);
content_line_t mark_end = content_line_t(
(file_index + 1) * MAX_LINES_PER_FILE);
bookmark_vector<content_line_t>::iterator bv_iter;
bookmark_vector<content_line_t> & bv =
mark_iter->second;
while ((bv_iter =
std::lower_bound(bv.begin(), bv.end(),
mark_curr)) != bv.end()) {
if (*bv_iter >= mark_end) {
break;
}
mark_iter->second.erase(bv_iter);
}
}
this->lss_force_rebuild = true;
}
};
void remove_file(std::shared_ptr<logfile> lf);
enum class rebuild_result {
rr_no_change,
@ -540,40 +455,7 @@ public:
return this->find_from_time(etm.to_timeval());
};
nonstd::optional<vis_line_t> find_from_content(content_line_t cl) {
content_line_t line = cl;
std::shared_ptr<logfile> lf = this->find(line);
if (lf != nullptr) {
auto ll_iter = lf->begin() + line;
auto &ll = *ll_iter;
auto vis_start_opt = this->find_from_time(ll.get_timeval());
if (!vis_start_opt) {
return nonstd::nullopt;
}
auto vis_start = *vis_start_opt;
while (vis_start < vis_line_t(this->text_line_count())) {
content_line_t guess_cl = this->at(vis_start);
if (cl == guess_cl) {
return vis_start;
}
auto guess_line = this->find_line(guess_cl);
if (!guess_line || ll < *guess_line) {
return nonstd::nullopt;
}
++vis_start;
}
}
return nonstd::nullopt;
}
nonstd::optional<vis_line_t> find_from_content(content_line_t cl);
nonstd::optional<struct timeval> time_for_row(vis_line_t row) {
if (row < (ssize_t) this->text_line_count()) {
@ -721,22 +603,7 @@ public:
return this->lss_index_delegate;
};
void reload_index_delegate() {
if (this->lss_index_delegate == nullptr) {
return;
}
this->lss_index_delegate->index_start(*this);
for (unsigned int index : this->lss_filtered_index) {
content_line_t cl = (content_line_t) this->lss_index[index];
uint64_t line_number;
auto ld = this->find_data(cl, line_number);
std::shared_ptr<logfile> lf = (*ld)->get_file();
this->lss_index_delegate->index_line(*this, lf.get(), lf->begin() + line_number);
}
this->lss_index_delegate->index_complete(*this);
};
void reload_index_delegate();
class meta_grepper
: public grep_proc_source<vis_line_t>,
@ -746,60 +613,20 @@ public:
: lmg_source(source) {
};
bool grep_value_for_line(vis_line_t line, std::string &value_out) override {
content_line_t cl = this->lmg_source.at(vis_line_t(line));
std::map<content_line_t, bookmark_metadata> &user_mark_meta =
lmg_source.get_user_bookmark_metadata();
auto meta_iter = user_mark_meta.find(cl);
if (meta_iter == user_mark_meta.end()) {
value_out.clear();
} else {
bookmark_metadata &bm = meta_iter->second;
value_out.append(bm.bm_comment);
for (const auto &tag : bm.bm_tags) {
value_out.append(tag);
}
}
return !this->lmg_done;
};
vis_line_t grep_initial_line(vis_line_t start, vis_line_t highest) override {
vis_bookmarks &bm = this->lmg_source.tss_view->get_bookmarks();
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_META];
bool grep_value_for_line(vis_line_t line, std::string &value_out) override;
if (bv.empty()) {
return -1_vl;
}
return *bv.begin();
};
vis_line_t grep_initial_line(vis_line_t start, vis_line_t highest) override;
void grep_next_line(vis_line_t &line) override {
vis_bookmarks &bm = this->lmg_source.tss_view->get_bookmarks();
bookmark_vector<vis_line_t> &bv = bm[&textview_curses::BM_META];
void grep_next_line(vis_line_t &line) override;
line = bv.next(vis_line_t(line));
if (line == -1) {
this->lmg_done = true;
}
};
void grep_begin(grep_proc<vis_line_t> &gp, vis_line_t start, vis_line_t stop) override;
void grep_begin(grep_proc<vis_line_t> &gp, vis_line_t start, vis_line_t stop) override {
this->lmg_source.tss_view->grep_begin(gp, start, stop);
};
void grep_end(grep_proc<vis_line_t> &gp) override {
this->lmg_source.tss_view->grep_end(gp);
};
void grep_end(grep_proc<vis_line_t> &gp) override;
void grep_match(grep_proc<vis_line_t> &gp,
vis_line_t line,
int start,
int end) override {
this->lmg_source.tss_view->grep_match(gp, line, start, end);
};
int end) override;
logfile_sub_source &lmg_source;
bool lmg_done{false};
@ -960,18 +787,7 @@ private:
this->lss_line_size_cache[0].first = -1;
};
nonstd::optional<std::shared_ptr<text_filter>> get_sql_filter() {
auto iter = std::find_if(this->tss_filters.begin(),
this->tss_filters.end(),
[](const auto& filt) {
return filt->get_index() == 0;
});
if (iter != this->tss_filters.end()) {
return *iter;
}
return nonstd::nullopt;
}
nonstd::optional<std::shared_ptr<text_filter>> get_sql_filter();
bool check_extra_filters(iterator ld, logfile::iterator ll);

@ -37,8 +37,8 @@
#include <unistd.h>
#include "base/fs_util.hh"
#include "pcap_manager.hh"
#include "lnav_util.hh"
#include "line_buffer.hh"
namespace pcap_manager {
@ -48,7 +48,7 @@ convert(const std::string &filename)
{
log_info("attempting to convert pcap file -- %s", filename.c_str());
auto outfile = TRY(open_temp_file(
auto outfile = TRY(lnav::filesystem::open_temp_file(
ghc::filesystem::temp_directory_path() / "lnav.pcap.XXXXXX"));
ghc::filesystem::remove(outfile.first);
auto err_pipe = TRY(auto_pipe::for_child_fd(STDERR_FILENO));

@ -34,6 +34,7 @@
#include "lnav.hh"
#include "lnav_util.hh"
#include "lnav_config.hh"
#include "sql_help.hh"
#include "sysclip.hh"
#include "vtab_module.hh"
#include "plain_text_source.hh"
@ -47,6 +48,7 @@
#include "yajlpp/yajlpp.hh"
#include "tailer/tailer.looper.hh"
#include "service_tags.hh"
#include "view_helpers.examples.hh"
using namespace std;

@ -0,0 +1,172 @@
/**
* Copyright (c) 2022, 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 readline_context.hh
*/
#ifndef readline_context_hh
#define readline_context_hh
#include <string>
#include <set>
#include <readline/history.h>
#include "base/result.h"
#include "help_text.hh"
class attr_line_t;
struct exec_context;
typedef void (*readline_highlighter_t)(attr_line_t &line, int x);
/**
* Container for information related to different readline contexts. Since
* lnav uses readline for different inputs, we need a way to keep things like
* history and tab-completions separate.
*/
class readline_context {
public:
typedef Result<std::string, std::string> (*command_func_t)(exec_context &ec,
std::string cmdline, std::vector<std::string> &args);
typedef std::string (*prompt_func_t)(exec_context &ec,
const std::string &cmdline);
typedef struct _command_t {
const char *c_name;
command_func_t c_func;
struct help_text c_help;
prompt_func_t c_prompt{nullptr};
_command_t(const char *name,
command_func_t func,
help_text help = {},
prompt_func_t prompt = nullptr) noexcept
: c_name(name), c_func(func), c_help(std::move(help)), c_prompt(prompt) {};
_command_t(command_func_t func) noexcept
: c_name("anon"), c_func(func) {};
} command_t;
typedef std::map<std::string, command_t *> command_map_t;
readline_context(std::string name,
command_map_t *commands = nullptr,
bool case_sensitive = true);
const std::string &get_name() const { return this->rc_name; };
void load();
void save();
void add_possibility(const std::string& type, const std::string& value)
{
this->rc_possibilities[type].insert(value);
};
void rem_possibility(const std::string& type, const std::string& value)
{
this->rc_possibilities[type].erase(value);
};
void clear_possibilities(const std::string& type)
{
this->rc_possibilities[type].clear();
};
bool is_case_sensitive() const
{
return this->rc_case_sensitive;
};
readline_context &set_append_character(int ch) {
this->rc_append_character = ch;
return *this;
};
int get_append_character() const {
return this->rc_append_character;
}
readline_context &set_highlighter(readline_highlighter_t hl) {
this->rc_highlighter = hl;
return *this;
};
readline_context &set_quote_chars(const char *qc) {
this->rc_quote_chars = qc;
return *this;
};
readline_context &with_readline_var(char **var, const char *val) {
this->rc_vars.emplace_back(var, val);
return *this;
};
readline_highlighter_t get_highlighter() const {
return this->rc_highlighter;
};
static int command_complete(int, int);
std::map<std::string, std::string> rc_prefixes;
private:
static char **attempted_completion(const char *text, int start, int end);
static char *completion_generator(const char *text, int state);
static readline_context * loaded_context;
static std::set<std::string> *arg_possibilities;
struct readline_var {
readline_var(char **dst, const char *val) {
this->rv_dst.ch = dst;
this->rv_val.ch = val;
}
union {
char **ch;
} rv_dst;
union {
const char *ch;
} rv_val;
};
std::string rc_name;
HISTORY_STATE rc_history;
std::map<std::string, std::set<std::string>> rc_possibilities;
std::map<std::string, std::vector<std::string>> rc_prototypes;
bool rc_case_sensitive;
int rc_append_character;
const char *rc_quote_chars;
readline_highlighter_t rc_highlighter;
std::vector<readline_var> rc_vars;
};
#endif

@ -59,138 +59,10 @@
#include "vt52_curses.hh"
#include "log_format.hh"
#include "help_text_formatter.hh"
struct exec_context;
typedef void (*readline_highlighter_t)(attr_line_t &line, int x);
#include "readline_context.hh"
extern exec_context INIT_EXEC_CONTEXT;
/**
* Container for information related to different readline contexts. Since
* lnav uses readline for different inputs, we need a way to keep things like
* history and tab-completions separate.
*/
class readline_context {
public:
typedef Result<std::string, std::string> (*command_func_t)(exec_context &ec,
std::string cmdline, std::vector<std::string> &args);
typedef std::string (*prompt_func_t)(exec_context &ec,
const std::string &cmdline);
typedef struct _command_t {
const char *c_name;
command_func_t c_func;
struct help_text c_help;
prompt_func_t c_prompt{nullptr};
_command_t(const char *name,
command_func_t func,
help_text help = {},
prompt_func_t prompt = nullptr) noexcept
: c_name(name), c_func(func), c_help(std::move(help)), c_prompt(prompt) {};
_command_t(command_func_t func) noexcept
: c_name("anon"), c_func(func) {};
} command_t;
typedef std::map<std::string, command_t *> command_map_t;
readline_context(std::string name,
command_map_t *commands = nullptr,
bool case_sensitive = true);
const std::string &get_name() const { return this->rc_name; };
void load();
void save();
void add_possibility(const std::string& type, const std::string& value)
{
this->rc_possibilities[type].insert(value);
};
void rem_possibility(const std::string& type, const std::string& value)
{
this->rc_possibilities[type].erase(value);
};
void clear_possibilities(const std::string& type)
{
this->rc_possibilities[type].clear();
};
bool is_case_sensitive() const
{
return this->rc_case_sensitive;
};
readline_context &set_append_character(int ch) {
this->rc_append_character = ch;
return *this;
};
int get_append_character() const {
return this->rc_append_character;
}
readline_context &set_highlighter(readline_highlighter_t hl) {
this->rc_highlighter = hl;
return *this;
};
readline_context &set_quote_chars(const char *qc) {
this->rc_quote_chars = qc;
return *this;
};
readline_context &with_readline_var(char **var, const char *val) {
this->rc_vars.emplace_back(var, val);
return *this;
};
readline_highlighter_t get_highlighter() const {
return this->rc_highlighter;
};
static int command_complete(int, int);
std::map<std::string, std::string> rc_prefixes;
private:
static char **attempted_completion(const char *text, int start, int end);
static char *completion_generator(const char *text, int state);
static readline_context * loaded_context;
static std::set<std::string> *arg_possibilities;
struct readline_var {
readline_var(char **dst, const char *val) {
this->rv_dst.ch = dst;
this->rv_val.ch = val;
}
union {
char **ch;
} rv_dst;
union {
const char *ch;
} rv_val;
};
std::string rc_name;
HISTORY_STATE rc_history;
std::map<std::string, std::set<std::string> > rc_possibilities;
std::map<std::string, std::vector<std::string> > rc_prototypes;
bool rc_case_sensitive;
int rc_append_character;
const char *rc_quote_chars;
readline_highlighter_t rc_highlighter;
std::vector<readline_var> rc_vars;
};
/**
* Adapter between readline and curses. The curses and readline libraries
* normally do not get along. So, we need to put readline in another process

@ -33,6 +33,7 @@
#include "base/string_util.hh"
#include "pcrepp/pcrepp.hh"
#include "sql_help.hh"
#include "sql_util.hh"
#include "shlex.hh"

@ -33,8 +33,10 @@
#include <string>
#include "base/isc.hh"
#include "base/opt_util.hh"
#include "tailer/tailer.looper.hh"
#include "lnav.hh"
#include "sql_help.hh"
#include "sql_util.hh"
#include "data_parser.hh"
#include "sysclip.hh"

@ -31,6 +31,7 @@
#include "base/lnav_log.hh"
#include "pcrepp/pcrepp.hh"
#include "sql_help.hh"
#include "sql_util.hh"
#include "vtab_module.hh"

@ -29,7 +29,6 @@
#include "config.h"
#include <assert.h>
#include <unordered_set>
#include "base/time_util.hh"
@ -551,7 +550,7 @@ relative_time::from_str(const char *str, size_t len)
break;
case RTT__MAX:
assert(false);
ensure(false);
break;
}

@ -40,7 +40,9 @@
#include <utility>
#include <yajl/api/yajl_tree.h>
#include "base/fs_util.hh"
#include "base/isc.hh"
#include "base/opt_util.hh"
#include "base/paths.hh"
#include "tailer/tailer.looper.hh"
#include "yajlpp/yajlpp.hh"
@ -905,7 +907,7 @@ void load_session()
load_time_bookmarks();
if ((fd = openp(view_info_path, O_RDONLY)) < 0) {
if ((fd = lnav::filesystem::openp(view_info_path, O_RDONLY)) < 0) {
perror("cannot open session file");
}
else {

@ -40,6 +40,7 @@
#include "base/opt_util.hh"
#include "pcrepp/pcrepp.hh"
#include "shlex.resolver.hh"
enum class shlex_token_t {
ST_ERROR,
@ -54,33 +55,6 @@ enum class shlex_token_t {
ST_TILDE,
};
class scoped_resolver {
public:
scoped_resolver(std::initializer_list<std::map<std::string, std::string> *> l) {
this->sr_stack.insert(this->sr_stack.end(), l.begin(), l.end());
};
typedef std::map<std::string, std::string>::const_iterator const_iterator;
const_iterator find(const std::string &str) const {
const_iterator retval;
for (auto scope : this->sr_stack) {
if ((retval = scope->find(str)) != scope->end()) {
return retval;
}
}
return this->end();
};
const_iterator end() const {
return this->sr_stack.back()->end();
}
std::vector<const std::map<std::string, std::string> *> sr_stack;
};
class shlex {
public:
shlex(const char *str, size_t len)

@ -0,0 +1,66 @@
/**
* Copyright (c) 2015, 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 shlex.resolver.hh
*/
#ifndef lnav_shlex_resolver_hh
#define lnav_shlex_resolver_hh
#include <map>
#include <string>
#include <vector>
class scoped_resolver {
public:
scoped_resolver(std::initializer_list<std::map<std::string, std::string> *> l) {
this->sr_stack.insert(this->sr_stack.end(), l.begin(), l.end());
};
typedef std::map<std::string, std::string>::const_iterator const_iterator;
const_iterator find(const std::string &str) const {
const_iterator retval;
for (auto scope : this->sr_stack) {
if ((retval = scope->find(str)) != scope->end()) {
return retval;
}
}
return this->end();
};
const_iterator end() const {
return this->sr_stack.back()->end();
}
std::vector<const std::map<std::string, std::string> *> sr_stack;
};
#endif

@ -30,17 +30,24 @@
#include "config.h"
#include "base/lnav_log.hh"
#include "lnav.hh"
#include "lnav_util.hh"
#include "base/fs_util.hh"
#include "view_helpers.hh"
#include "bound_tags.hh"
#include "base/injector.bind.hh"
#include "readline_curses.hh"
#include "readline_context.hh"
#include "sqlite-extension-func.hh"
#include "command_executor.hh"
#include "sqlitepp.hh"
#include "auto_mem.hh"
#include "shlex.hh"
static
Result<std::string, std::string> sql_cmd_dump(
exec_context &ec, std::string cmdline, std::vector<std::string> &args)
{
static auto& lnav_db =
injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&, sqlite_db_tag>();
std::string retval;
if (args.empty()) {
@ -61,7 +68,7 @@ Result<std::string, std::string> sql_cmd_dump(
}
for (size_t lpc = 2; lpc < args.size(); lpc++) {
sqlite3_db_dump(lnav_data.ld_db.in(),
sqlite3_db_dump(lnav_db.in(),
"main",
args[lpc].c_str(),
(int (*)(const char *, void*)) fputs,
@ -76,6 +83,8 @@ static
Result<std::string, std::string> sql_cmd_read(
exec_context &ec, std::string cmdline, std::vector<std::string> &args)
{
static auto& lnav_db = injector::get<auto_mem<sqlite3, sqlite_close_wrapper>&, sqlite_db_tag>();
std::string retval;
if (args.empty()) {
@ -91,7 +100,7 @@ Result<std::string, std::string> sql_cmd_read(
}
for (size_t lpc = 1; lpc < split_args.size(); lpc++) {
auto read_res = read_file(split_args[lpc]);
auto read_res = lnav::filesystem::read_file(split_args[lpc]);
if (read_res.isErr()) {
return ec.make_error("unable to read script file: {} -- {}",
@ -105,14 +114,14 @@ Result<std::string, std::string> sql_cmd_read(
do {
const char *tail;
auto rc = sqlite3_prepare_v2(lnav_data.ld_db.in(),
auto rc = sqlite3_prepare_v2(lnav_db.in(),
start,
-1,
stmt.out(),
&tail);
if (rc != SQLITE_OK) {
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
const char *errmsg = sqlite3_errmsg(lnav_db.in());
return ec.make_error("{}", errmsg);
}
@ -131,13 +140,6 @@ Result<std::string, std::string> sql_cmd_read(
} while (start[0]);
}
if (lnav_data.ld_flags & LNF_HEADLESS) {
if (ec.ec_local_vars.size() == 1) {
ensure_view(&lnav_data.ld_views[LNV_DB]);
}
} else if (lnav_data.ld_db_row_source.dls_rows.size() > 1) {
ensure_view(&lnav_data.ld_views[LNV_DB]);
}
return Ok(retval);
}
@ -151,7 +153,7 @@ Result<std::string, std::string> sql_cmd_schema(
return Ok(retval);
}
ensure_view(&lnav_data.ld_views[LNV_SCHEMA]);
ensure_view(LNV_SCHEMA);
return Ok(retval);
}
@ -190,9 +192,10 @@ static readline_context::command_t sql_commands[] = {
".read",
sql_cmd_read,
help_text(".read",
"Switch to the SCHEMA view that contains a dump of the "
"current database schema")
.sql_command(),
"Execute the SQLite statements in the given file")
.sql_command()
.with_parameter({"path", "The path to the file to write"})
.with_tags({"io",}),
},
{
".schema",

@ -0,0 +1,56 @@
/**
* Copyright (c) 2022, 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 sql_help.hh
*/
#ifndef sql_help_hh
#define sql_help_hh
#include <map>
#include "help_text.hh"
#include "attr_line.hh"
extern string_attr_type SQL_COMMAND_ATTR;
extern string_attr_type SQL_KEYWORD_ATTR;
extern string_attr_type SQL_IDENTIFIER_ATTR;
extern string_attr_type SQL_FUNCTION_ATTR;
extern string_attr_type SQL_STRING_ATTR;
extern string_attr_type SQL_OPERATOR_ATTR;
extern string_attr_type SQL_PAREN_ATTR;
extern string_attr_type SQL_GARBAGE_ATTR;
void annotate_sql_statement(attr_line_t &al_inout);
extern std::multimap<std::string, help_text *> sqlite_function_help;
std::string sql_keyword_re();
std::vector<const help_text *> find_sql_help_for_line(const attr_line_t &al, size_t x);
#endif

@ -41,12 +41,13 @@
#include "auto_mem.hh"
#include "sql_util.hh"
#include "sql_help.hh"
#include "base/injector.hh"
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "base/time_util.hh"
#include "pcrepp/pcrepp.hh"
#include "readline_curses.hh"
#include "readline_context.hh"
#include "bound_tags.hh"
#include "sqlite-extension-func.hh"

@ -41,9 +41,9 @@
#include <string>
#include <vector>
#include "base/intern_string.hh"
#include "base/time_util.hh"
#include "attr_line.hh"
#include "help_text.hh"
#include "sqlitepp.hh"
extern const char *sql_keywords[145];
extern const char *sql_function_names[];
@ -102,27 +102,8 @@ void sql_execute_script(sqlite3 *db,
int guess_type_from_pcre(const std::string &pattern, std::string &collator);
/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem);
int sqlite_authorizer(void* pUserData, int action_code, const char *detail1,
const char *detail2, const char *detail3,
const char *detail4);
extern string_attr_type SQL_COMMAND_ATTR;
extern string_attr_type SQL_KEYWORD_ATTR;
extern string_attr_type SQL_IDENTIFIER_ATTR;
extern string_attr_type SQL_FUNCTION_ATTR;
extern string_attr_type SQL_STRING_ATTR;
extern string_attr_type SQL_OPERATOR_ATTR;
extern string_attr_type SQL_PAREN_ATTR;
extern string_attr_type SQL_GARBAGE_ATTR;
void annotate_sql_statement(attr_line_t &al_inout);
extern std::multimap<std::string, help_text *> sqlite_function_help;
std::string sql_keyword_re();
std::vector<const help_text *> find_sql_help_for_line(const attr_line_t &al, size_t x);
#endif

@ -31,12 +31,10 @@
#include "config.h"
#include <assert.h>
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "auto_mem.hh"
#include "sql_util.hh"
#include "sql_help.hh"
#include "sqlite-extension-func.hh"
@ -68,8 +66,8 @@ int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
{
int lpc;
assert(db != nullptr);
assert(reg_funcs != nullptr);
require(db != nullptr);
require(reg_funcs != nullptr);
{
auto_mem<char> errmsg(sqlite3_free);

@ -38,7 +38,7 @@
#include <string>
#include <map>
#include "help_text_formatter.hh"
#include "help_text.hh"
struct FuncDef {
const char *zName{nullptr};

@ -0,0 +1,38 @@
/**
* Copyright (c) 2022, 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 sqlitepp.hh
*/
#ifndef lnav_sqlitepp_hh
#define lnav_sqlitepp_hh
/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem);
#endif

@ -37,6 +37,7 @@
#include "sqlite3.h"
#include "base/opt_util.hh"
#include "lnav.hh"
#include "sql_util.hh"
#include "vtab_module.hh"

@ -38,6 +38,7 @@
#include "data_parser.hh"
#include "ansi_scrubber.hh"
#include "log_format.hh"
#include "logfile.hh"
#include "textview_curses.hh"
#include "view_curses.hh"
#include "lnav_config.hh"

@ -42,12 +42,11 @@
#include "listview_curses.hh"
#include "base/lnav_log.hh"
#include "text_format.hh"
#include "logfile.hh"
#include "logfile_fwd.hh"
#include "highlighter.hh"
#include "lnav_config_fwd.hh"
#include "textview_curses_fwd.hh"
class logline;
class textview_curses;
using vis_bookmarks = bookmarks<vis_line_t>::type;
@ -164,11 +163,11 @@ public:
void revert_to_last(logfile_filter_state &lfs, size_t rollback_size);
void add_line(logfile_filter_state &lfs, logfile::const_iterator ll, shared_buffer_ref &line);
void add_line(logfile_filter_state &lfs, logfile_const_iterator ll, shared_buffer_ref &line);
void end_of_message(logfile_filter_state &lfs);
virtual bool matches(const logfile &lf, logfile::const_iterator ll, shared_buffer_ref &line) = 0;
virtual bool matches(const logfile &lf, logfile_const_iterator ll, shared_buffer_ref &line) = 0;
virtual std::string to_command() = 0;
@ -192,7 +191,7 @@ public:
: text_filter(type, filter_lang_t::REGEX, "", index) {
}
bool matches(const logfile &lf, logfile::const_iterator ll,
bool matches(const logfile &lf, logfile_const_iterator ll,
shared_buffer_ref &line) override;
std::string to_command() override;
@ -653,13 +652,13 @@ public:
text_sub_source *get_sub_source() const { return this->tc_sub_source; };
textview_curses &set_delegate(text_delegate *del) {
textview_curses &set_delegate(std::shared_ptr<text_delegate> del) {
this->tc_delegate = del;
return *this;
};
text_delegate *get_delegate() const { return this->tc_delegate; };
std::shared_ptr<text_delegate> get_delegate() const { return this->tc_delegate; };
void horiz_shift(vis_line_t start, vis_line_t end,
int off_start,
@ -883,7 +882,7 @@ protected:
};
text_sub_source *tc_sub_source{nullptr};
text_delegate *tc_delegate{nullptr};
std::shared_ptr<text_delegate> tc_delegate;
vis_bookmarks tc_bookmarks;

@ -46,11 +46,11 @@ class unique_path_source {
public:
virtual ~unique_path_source() = default;
virtual void set_unique_path(const std::string &path) {
void set_unique_path(const std::string &path) {
this->ups_unique_path = path;
}
virtual std::string get_unique_path() const {
std::string get_unique_path() const {
return this->ups_unique_path;
}

@ -34,12 +34,13 @@
#include <paths.h>
#include <curl/curl.h>
#include "base/fs_util.hh"
#include "curl_looper.hh"
class url_loader : public curl_request {
public:
url_loader(const std::string &url) : curl_request(url), ul_resume_offset(0) {
auto tmp_res = open_temp_file(ghc::filesystem::temp_directory_path() /
auto tmp_res = lnav::filesystem::open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.url.XXXXXX");
if (tmp_res.isErr()) {
return;

@ -61,6 +61,7 @@
#include "base/lnav_log.hh"
#include "base/lrucache.hpp"
#include "base/opt_util.hh"
#include "attr_line.hh"
#include "optional.hpp"
#include "styling.hh"

@ -30,6 +30,7 @@
#include "config.h"
#include "lnav.hh"
#include "sql_help.hh"
#include "sql_util.hh"
#include "pretty_printer.hh"
#include "environ_vtab.hh"
@ -37,6 +38,7 @@
#include "shlex.hh"
#include "help-txt.h"
#include "view_helpers.hh"
#include "view_helpers.examples.hh"
using namespace std;
@ -515,6 +517,11 @@ bool ensure_view(textview_curses *expected_tc)
return retval;
}
bool ensure_view(lnav_view_t expected)
{
return ensure_view(&lnav_data.ld_views[expected]);
}
nonstd::optional<vis_line_t> next_cluster(
vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t) const,
bookmark_type_t *bt,

@ -0,0 +1,41 @@
/**
* Copyright (c) 2022, 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 view_helpers.examples.hh
*/
#ifndef lnav_view_helpers_examples_hh
#define lnav_view_helpers_examples_hh
#include "help_text.hh"
#include "attr_line.hh"
void execute_examples();
attr_line_t eval_example(const help_text &ht, const help_example &ex);
#endif

@ -33,7 +33,6 @@
#define lnav_view_helpers_hh
#include "help_text.hh"
#include "attr_line.hh"
#include "vis_line.hh"
#include "bookmarks.hh"
@ -58,12 +57,10 @@ extern const char *lnav_view_strings[LNV__MAX + 1];
nonstd::optional<lnav_view_t> view_from_string(const char *name);
bool ensure_view(textview_curses *expected_tc);
bool ensure_view(lnav_view_t expected);
bool toggle_view(textview_curses *toggle_tc);
void layout_views();
void execute_examples();
attr_line_t eval_example(const help_text &ht, const help_example &ex);
nonstd::optional<vis_line_t> next_cluster(
vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t) const,
bookmark_type_t *bt,

@ -29,13 +29,13 @@
#include "config.h"
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "lnav.hh"
#include "base/injector.bind.hh"
#include "base/lnav_log.hh"
#include "base/opt_util.hh"
#include "sql_util.hh"
#include "views_vtab.hh"
#include "view_curses.hh"

@ -38,6 +38,7 @@
#include "optional.hpp"
#include "base/lnav_log.hh"
#include "base/intern_string.hh"
#include "base/string_util.hh"
#include "auto_mem.hh"
#include "mapbox/variant.hpp"

@ -34,6 +34,7 @@
#include "base/lnav_log.hh"
#include "pugixml/pugixml.hpp"
#include "sql_help.hh"
#include "sql_util.hh"
#include "xml_util.hh"
#include "vtab_module.hh"

@ -53,7 +53,6 @@ check_PROGRAMS = \
drive_listview \
drive_logfile \
drive_mvwattrline \
drive_sequencer \
drive_shlexer \
drive_sql \
drive_sql_anno \
@ -149,8 +148,6 @@ drive_listview_SOURCES = drive_listview.cc
drive_logfile_SOURCES = drive_logfile.cc
drive_sequencer_SOURCES = drive_sequencer.cc
drive_shlexer_SOURCES = drive_shlexer.cc
drive_data_scanner_SOURCES = \

@ -33,6 +33,7 @@
#include <stdlib.h>
#include "lnav.hh"
#include "sql_help.hh"
#include "sql_util.hh"
#include "sqlite-extension-func.hh"

@ -32,6 +32,7 @@
#include "lnav.hh"
#include "base/injector.hh"
#include "service_tags.hh"
#include "bound_tags.hh"
struct lnav_data_t lnav_data;
@ -71,6 +72,11 @@ textview_curses *get_textview_for_mode(ln_mode_t mode)
readline_context::command_map_t lnav_commands;
namespace injector {
template<>
void force_linking(sqlite_db_tag anno)
{
}
template<>
void force_linking(services::curl_streamer_t anno)
{

Loading…
Cancel
Save