[debt] doing some cleanup

Defect Number:
    Reviewed By:
   Testing Done:
This commit is contained in:
Timothy Stack 2020-11-09 22:17:17 -08:00
parent 21e78670e2
commit db8a3c4d38
91 changed files with 2419 additions and 2255 deletions

View File

@ -228,6 +228,7 @@ add_library(diag STATIC
config.h
all_logs_vtab.cc
ansi_scrubber.cc
archive_manager.cc
bin2c.h
@ -242,6 +243,7 @@ add_library(diag STATIC
environ_vtab.cc
extension-functions.cc
field_overlay_source.cc
file_collection.cc
file_vtab.cc
files_sub_source.cc
filter_observer.cc
@ -352,6 +354,7 @@ add_library(diag STATIC
base/enum_util.hh
base/future_util.hh
field_overlay_source.hh
file_collection.hh
file_vtab.hh
files_sub_source.hh
filter_observer.hh
@ -409,6 +412,7 @@ add_library(diag STATIC
timer.hh
top_status_source.hh
url_loader.hh
view_helpers.hh
views_vtab.hh
vtab_module.hh
yajlpp/yajlpp.hh
@ -470,6 +474,9 @@ add_executable(test_yajlpp yajlpp/test_yajlpp.cc)
target_link_libraries(test_yajlpp diag ${lnav_LIBS})
add_test(NAME test_yajlpp COMMAND test_yajlpp)
add_executable(drive_json_op yajlpp/drive_json_op.cc)
target_link_libraries(drive_json_op diag ${lnav_LIBS})
add_executable(lnav ${lnav_SRCS})
target_link_libraries(lnav diag)

View File

@ -268,6 +268,7 @@ noinst_HEADERS = \
elem_to_json.hh \
environ_vtab.hh \
field_overlay_source.hh \
file_collection.hh \
file_vtab.hh \
files_sub_source.hh \
filter_observer.hh \
@ -352,6 +353,7 @@ noinst_HEADERS = \
unique_path.hh \
url_loader.hh \
view_curses.hh \
view_helpers.hh \
views_vtab.hh \
vt52_curses.hh \
vtab_module.hh \
@ -381,6 +383,7 @@ nodist_libdiag_a_SOURCES = \
$(LNAV_BUILT_FILES)
libdiag_a_SOURCES = \
all_logs_vtab.cc \
ansi_scrubber.cc \
archive_manager.cc \
bookmarks.cc \
@ -394,6 +397,7 @@ libdiag_a_SOURCES = \
environ_vtab.cc \
extension-functions.cc \
field_overlay_source.cc \
file_collection.cc \
file_vtab.cc \
files_sub_source.cc \
filter_observer.cc \

109
src/all_logs_vtab.cc Normal file
View File

@ -0,0 +1,109 @@
/**
* Copyright (c) 2020, 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 "all_logs_vtab.hh"
all_logs_vtab::all_logs_vtab()
: log_vtab_impl(intern_string::lookup("all_logs")),
alv_value_name(intern_string::lookup("log_format")),
alv_msg_name(intern_string::lookup("log_msg_format")),
alv_schema_name(intern_string::lookup("log_msg_schema")) {
}
void all_logs_vtab::get_columns(std::vector<vtab_column> &cols) const
{
cols.emplace_back(this->alv_value_name.get());
cols.emplace_back(this->alv_msg_name.get());
cols.emplace_back(this->alv_schema_name.get(), SQLITE3_TEXT, "", true);
}
void all_logs_vtab::extract(std::shared_ptr<logfile> lf, uint64_t line_number,
shared_buffer_ref &line,
std::vector<logline_value> &values)
{
auto *format = lf->get_format();
values.emplace_back(this->alv_value_name, format->get_name(), 0);
std::vector<logline_value> sub_values;
this->vi_attrs.clear();
format->annotate(line_number, line, this->vi_attrs, sub_values, false);
auto body = find_string_attr_range(this->vi_attrs, &textview_curses::SA_BODY);
if (body.lr_start == -1) {
body.lr_start = 0;
body.lr_end = line.length();
}
data_scanner ds(line, body.lr_start, body.lr_end);
data_parser dp(&ds);
std::string str;
dp.dp_msg_format = &str;
dp.parse();
tmp_shared_buffer tsb(str.c_str());
values.emplace_back(this->alv_msg_name, tsb.tsb_ref, 1);
this->alv_schema_manager.invalidate_refs();
dp.dp_schema_id.to_string(this->alv_schema_buffer.data());
shared_buffer_ref schema_ref;
schema_ref.share(this->alv_schema_manager,
this->alv_schema_buffer.data(),
data_parser::schema_id_t::STRING_SIZE - 1);
values.emplace_back(this->alv_schema_name, schema_ref, 2);
}
bool all_logs_vtab::is_valid(log_cursor &lc, logfile_sub_source &lss)
{
auto cl = lss.at(lc.lc_curr_line);
auto lf = lss.find(cl);
auto lf_iter = lf->begin() + cl;
if (lf_iter->is_continued()) {
return false;
}
return true;
}
bool all_logs_vtab::next(log_cursor &lc, logfile_sub_source &lss)
{
lc.lc_curr_line = lc.lc_curr_line + vis_line_t(1);
lc.lc_sub_index = 0;
if (lc.is_eof()) {
return true;
}
return this->is_valid(lc, lss);
}

View File

@ -27,103 +27,39 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LNAV_ALL_LOGS_VTAB_HH
#define LNAV_ALL_LOGS_VTAB_HH
#ifndef lnav_all_logs_vtab_hh
#define lnav_all_logs_vtab_hh
#include <array>
#include "log_vtab_impl.hh"
#include "data_parser.hh"
/**
* A virtual table that provides access to all log messages from all formats.
*/
class all_logs_vtab : public log_vtab_impl {
public:
all_logs_vtab() : log_vtab_impl(intern_string::lookup("all_logs")) {
this->alv_value_name = intern_string::lookup("log_format");
this->alv_msg_name = intern_string::lookup("log_msg_format");
this->alv_schema_name = intern_string::lookup("log_msg_schema");
}
all_logs_vtab();
void get_columns(std::vector<vtab_column> &cols) const {
cols.emplace_back(this->alv_value_name.get());
cols.emplace_back(this->alv_msg_name.get());
cols.emplace_back(this->alv_schema_name.get(), SQLITE3_TEXT, "", true);
};
void get_columns(std::vector<vtab_column> &cols) const override;
void extract(std::shared_ptr<logfile> lf,
uint64_t line_number,
shared_buffer_ref &line,
std::vector<logline_value> &values) {
log_format *format = lf->get_format();
values.emplace_back(this->alv_value_name, format->get_name(), 0);
std::vector<logline_value> &values) override;
std::vector<logline_value> sub_values;
struct line_range body;
bool is_valid(log_cursor &lc, logfile_sub_source &lss) override;
this->vi_attrs.clear();
format->annotate(line_number, line, this->vi_attrs, sub_values, false);
body = find_string_attr_range(this->vi_attrs, &textview_curses::SA_BODY);
if (body.lr_start == -1) {
body.lr_start = 0;
body.lr_end = line.length();
}
data_scanner ds(line, body.lr_start, body.lr_end);
data_parser dp(&ds);
std::string str;
dp.dp_msg_format = &str;
dp.parse();
tmp_shared_buffer tsb(str.c_str());
values.emplace_back(this->alv_msg_name, tsb.tsb_ref, 1);
this->alv_schema_manager.invalidate_refs();
dp.dp_schema_id.to_string(this->alv_schema_buffer);
shared_buffer_ref schema_ref;
schema_ref.share(this->alv_schema_manager,
this->alv_schema_buffer,
data_parser::schema_id_t::STRING_SIZE - 1);
values.emplace_back(this->alv_schema_name, schema_ref, 2);
}
bool is_valid(log_cursor &lc, logfile_sub_source &lss) {
content_line_t cl(lss.at(lc.lc_curr_line));
std::shared_ptr<logfile> lf = lss.find(cl);
auto lf_iter = lf->begin() + cl;
if (lf_iter->is_continued()) {
return false;
}
return true;
};
bool next(log_cursor &lc, logfile_sub_source &lss) {
lc.lc_curr_line = lc.lc_curr_line + vis_line_t(1);
lc.lc_sub_index = 0;
if (lc.is_eof()) {
return true;
}
content_line_t cl(lss.at(lc.lc_curr_line));
std::shared_ptr<logfile> lf = lss.find(cl);
auto lf_iter = lf->begin() + cl;
if (lf_iter->is_continued()) {
return false;
}
return true;
};
bool next(log_cursor &lc, logfile_sub_source &lss) override;
private:
intern_string_t alv_value_name;
intern_string_t alv_msg_name;
intern_string_t alv_schema_name;
const intern_string_t alv_value_name;
const intern_string_t alv_msg_name;
const intern_string_t alv_schema_name;
shared_buffer alv_schema_manager;
char alv_schema_buffer[data_parser::schema_id_t::STRING_SIZE];
std::array<char, data_parser::schema_id_t::STRING_SIZE> alv_schema_buffer{};
};
#endif //LNAV_ALL_LOGS_VTAB_HH

View File

@ -173,16 +173,16 @@ void scrub_ansi_string(std::string &str, string_attrs_t &sa)
void add_ansi_vars(std::map<std::string, std::string> &vars)
{
vars["ansi_csi"] = "\x1b[";
vars["ansi_norm"] = "\x1b[0m";
vars["ansi_bold"] = "\x1b[1m";
vars["ansi_underline"] = "\x1b[4m";
vars["ansi_black"] = "\x1b[30m";
vars["ansi_red"] = "\x1b[31m";
vars["ansi_green"] = "\x1b[32m";
vars["ansi_yellow"] = "\x1b[33m";
vars["ansi_blue"] = "\x1b[34m";
vars["ansi_magenta"] = "\x1b[35m";
vars["ansi_cyan"] = "\x1b[36m";
vars["ansi_white"] = "\x1b[37m";
vars["ansi_csi"] = ANSI_CSI;
vars["ansi_norm"] = ANSI_NORM;
vars["ansi_bold"] = ANSI_BOLD_START;
vars["ansi_underline"] = ANSI_UNDERLINE_START;
vars["ansi_black"] = ANSI_COLOR(COLOR_BLACK);
vars["ansi_red"] = ANSI_COLOR(COLOR_RED);
vars["ansi_green"] = ANSI_COLOR(COLOR_GREEN);
vars["ansi_yellow"] = ANSI_COLOR(COLOR_YELLOW);
vars["ansi_blue"] = ANSI_COLOR(COLOR_BLUE);
vars["ansi_magenta"] = ANSI_COLOR(COLOR_MAGENTA);
vars["ansi_cyan"] = ANSI_COLOR(COLOR_CYAN);
vars["ansi_white"] = ANSI_COLOR(COLOR_WHITE);
}

View File

@ -43,6 +43,7 @@
#include "auto_mem.hh"
#include "fmt/format.h"
#include "base/lnav_log.hh"
#include "lnav_util.hh"
#include "archive_manager.hh"
@ -81,14 +82,14 @@ public:
auto lock_path = archive_path;
lock_path += ".lck";
this->lh_fd = open(lock_path.c_str(), O_CREAT | O_RDWR, 0600);
this->lh_fd = openp(lock_path, O_CREAT | O_RDWR, 0600);
log_perror(fcntl(this->lh_fd, F_SETFD, FD_CLOEXEC));
};
auto_fd lh_fd;
};
bool is_archive(const std::string &filename)
bool is_archive(const ghc::filesystem::path& filename)
{
#if HAVE_ARCHIVE_H
auto_mem<archive> arc(archive_read_free);

View File

@ -56,7 +56,7 @@ struct extract_progress {
using extract_cb = std::function<extract_progress *(
const ghc::filesystem::path &, ssize_t)>;
bool is_archive(const std::string &filename);
bool is_archive(const ghc::filesystem::path& filename);
ghc::filesystem::path filename_to_tmp_path(const std::string &filename);

View File

@ -182,7 +182,7 @@ struct string_attr {
require(type);
};
string_attr() : sa_type(NULL) { };
string_attr() : sa_type(nullptr) { };
bool operator<(const struct string_attr &rhs) const
{

View File

@ -61,7 +61,7 @@ public:
{
int retval, fd[2];
require(fd != NULL);
require(af != nullptr);
if ((retval = ::pipe(fd)) == 0) {
af[0] = fd[0];
@ -76,7 +76,7 @@ public:
*
* @param fd The file descriptor to be managed.
*/
auto_fd(int fd = -1)
explicit auto_fd(int fd = -1)
: af_fd(fd)
{
require(fd >= -1);
@ -89,7 +89,7 @@ public:
*
* @param af The source of the file descriptor.
*/
auto_fd(auto_fd && af)
auto_fd(auto_fd && af) noexcept
: af_fd(af.release()) {
};
@ -116,7 +116,7 @@ public:
};
/** @return The file descriptor as a plain integer. */
operator int() const { return this->af_fd; };
operator int() const { return this->af_fd; };
/**
* Replace the current descriptor with the given one. The current
@ -125,7 +125,7 @@ public:
* @param fd The file descriptor to store in this object.
* @return *this
*/
auto_fd &operator =(int fd)
auto_fd &operator=(int fd)
{
require(fd >= -1);
@ -139,8 +139,7 @@ public:
* @param af The old manager of the file descriptor.
* @return *this
*/
auto_fd &operator =(auto_fd & af)
{
auto_fd &operator=(auto_fd && af) noexcept {
this->reset(af.release());
return *this;
};
@ -209,7 +208,7 @@ private:
class auto_pipe {
public:
auto_pipe(int child_fd = -1, int child_flags = O_RDONLY)
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) {
@ -250,17 +249,17 @@ public:
case 0:
if (this->ap_child_flags == O_RDONLY) {
this->write_end().reset();
if (this->read_end() == -1) {
if (this->read_end().get() == -1) {
this->read_end() = ::open("/dev/null", O_RDONLY);
}
new_fd = this->read_end();
new_fd = this->read_end().get();
}
else {
this->read_end().reset();
if (this->write_end() == -1) {
if (this->write_end().get() == -1) {
this->write_end() = ::open("/dev/null", O_WRONLY);
}
new_fd = this->write_end();
new_fd = this->write_end().get();
}
if (this->ap_child_fd != -1) {
if (new_fd != this->ap_child_fd) {

View File

@ -70,7 +70,7 @@ public:
this->reset();
};
operator T *(void) const { return this->am_ptr; };
operator T *() const { return this->am_ptr; };
auto_mem &operator =(T *ptr)
{
@ -85,7 +85,7 @@ public:
return *this;
};
T *release(void)
T *release()
{
T *retval = this->am_ptr;
@ -93,12 +93,12 @@ public:
return retval;
};
T *in(void) const
T *in() const
{
return this->am_ptr;
};
T **out(void)
T **out()
{
this->reset();
return &this->am_ptr;

View File

@ -39,49 +39,59 @@
class auto_pid {
public:
auto_pid(pid_t child = -1) : ap_child(child), ap_status(0) {};
explicit auto_pid(pid_t child = -1) : ap_child(child)
{};
auto_pid(auto_pid &other) : ap_child(other.release()), ap_status(0) { };
auto_pid(const auto_pid &other) = delete;
~auto_pid() { this->reset(); };
auto_pid(auto_pid &&other) noexcept : ap_child(other.release())
{};
auto_pid &operator =(auto_pid &other) {
~auto_pid()
{ this->reset(); };
auto_pid &operator=(auto_pid &&other) noexcept {
this->reset(other.release());
this->ap_status = other.ap_status;
return *this;
};
bool in_child() const {
bool in_child() const
{
return this->ap_child == 0;
};
pid_t release() {
pid_t release()
{
pid_t retval = this->ap_child;
this->ap_child = -1;
return retval;
};
int status() const {
int status() const
{
return this->ap_status;
};
bool was_normal_exit() const {
bool was_normal_exit() const
{
return WIFEXITED(this->ap_status);
}
int exit_status() const {
int exit_status() const
{
return WEXITSTATUS(this->ap_status);
}
bool wait_for_child(int options = 0) {
bool wait_for_child(int options = 0)
{
if (this->ap_child != -1) {
int rc;
while ((rc = waitpid(this->ap_child,
&this->ap_status,
options)) < 0 && (errno == EINTR)) {
;
options)) < 0 && (errno == EINTR)) { ;
}
if (rc > 0) {
this->ap_child = -1;
@ -91,7 +101,8 @@ public:
return this->ap_child == -1;
};
void reset(pid_t child = -1) {
void reset(pid_t child = -1)
{
if (this->ap_child != child) {
this->ap_status = 0;
if (this->ap_child != -1) {
@ -103,10 +114,8 @@ public:
};
private:
auto_pid(const auto_pid &other) { };
pid_t ap_child;
int ap_status;
int ap_status{0};
};
#endif

View File

@ -30,6 +30,7 @@
#ifndef lnav_future_util_hh
#define lnav_future_util_hh
#include <deque>
#include <future>
template<class T>
@ -43,7 +44,7 @@ std::future<std::decay_t<T>> make_ready_future( T&& t ) {
template<typename T>
class future_queue {
public:
future_queue(std::function<void(const T&)> processor)
explicit future_queue(std::function<void(const T&)> processor)
: fq_processor(processor) {};
~future_queue() {

View File

@ -103,6 +103,8 @@ nonstd::optional<FILE *> lnav_log_file;
lnav_log_level_t lnav_log_level = lnav_log_level_t::DEBUG;
const char *lnav_log_crash_dir;
nonstd::optional<const struct termios *> lnav_log_orig_termios;
// NOTE: This mutex is leaked so that it is not destroyed during exit.
// Otherwise, any attempts to log will fail.
static std::mutex *lnav_log_mutex = new std::mutex();
std::vector<log_state_dumper*> log_state_dumper::DUMPER_LIST;
@ -111,7 +113,7 @@ std::vector<log_crash_recoverer*> log_crash_recoverer::CRASH_LIST;
struct thid {
static uint32_t COUNTER;
thid() : t_id(COUNTER++) {}
thid() noexcept : t_id(COUNTER++) {}
uint32_t t_id;
};

View File

@ -30,6 +30,9 @@
#ifndef lnav_opt_util_hh
#define lnav_opt_util_hh
#include <stdlib.h>
#include "intern_string.hh"
#include "optional.hpp"
namespace detail {
@ -82,4 +85,8 @@ nonstd::optional<T> cget(const C<T> &container, size_t index)
return nonstd::nullopt;
}
inline nonstd::optional<const char *> getenv_opt(const char *name) {
return make_optional_from_nullable(getenv(name));
}
#endif

View File

@ -74,4 +74,46 @@ inline bool endswith(const std::string& str, const char (&suffix) [N])
void truncate_to(std::string &str, size_t len);
inline std::string trim(const std::string &str)
{
std::string::size_type start, end;
for (start = 0; start < str.size() && isspace(str[start]); start++);
for (end = str.size(); end > 0 && isspace(str[end - 1]); end--);
return str.substr(start, end - start);
}
inline std::string tolower(const char *str)
{
std::string retval;
for (int lpc = 0; str[lpc]; lpc++) {
retval.push_back(::tolower(str[lpc]));
}
return retval;
}
inline std::string tolower(const std::string &str)
{
return tolower(str.c_str());
}
inline std::string toupper(const char *str)
{
std::string retval;
for (int lpc = 0; str[lpc]; lpc++) {
retval.push_back(::toupper(str[lpc]));
}
return retval;
}
inline std::string toupper(const std::string &str)
{
return toupper(str.c_str());
}
#endif

View File

@ -68,7 +68,7 @@ struct bookmark_metadata {
return retval;
};
bool empty() {
bool empty() const {
return this->bm_name.empty() &&
this->bm_comment.empty() &&
this->bm_tags.empty();
@ -189,7 +189,7 @@ public:
return all_types;
};
bookmark_type_t(std::string name) : bt_name(std::move(name)) {
explicit bookmark_type_t(std::string name) : bt_name(std::move(name)) {
get_all_types().push_back(this);
};
@ -199,7 +199,7 @@ public:
private:
struct mark_eq {
mark_eq(const std::string &name) : me_name(name) { };
explicit mark_eq(const std::string &name) : me_name(name) { };
bool operator()(bookmark_type_t *bt) {
return bt->bt_name == this->me_name;

View File

@ -31,7 +31,6 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
@ -39,8 +38,6 @@
#include <netinet/in.h>
#include <sys/socket.h>
#include <algorithm>
#include "log_level.hh"
#include "strnatcmp.h"

View File

@ -33,8 +33,8 @@
#include <algorithm>
#include "base/string_util.hh"
#include "sql_util.hh"
#include "lnav_util.hh"
#include "base/lnav_log.hh"
#include "column_namer.hh"

View File

@ -31,6 +31,7 @@
#include <vector>
#include "base/string_util.hh"
#include "yajlpp/json_ptr.hh"
#include "pcrecpp.h"
#include "lnav.hh"
@ -48,9 +49,12 @@ exec_context INIT_EXEC_CONTEXT;
bookmark_type_t BM_QUERY("query");
static const string MSG_FORMAT_STMT =
"SELECT count(*) as total, min(log_line) as log_line, log_msg_format "
"FROM all_logs GROUP BY log_msg_format ORDER BY total desc";
static const string MSG_FORMAT_STMT = R"(
SELECT count(*) AS total, min(log_line) AS log_line, log_msg_format
FROM all_logs
GROUP BY log_msg_format
ORDER BY total DESC
)";
int sql_progress(const struct log_cursor &lc)
{
@ -147,19 +151,19 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
sql_progress_finished,
source.first,
source.second);
gettimeofday(&start_tv, NULL);
gettimeofday(&start_tv, nullptr);
retcode = sqlite3_prepare_v2(lnav_data.ld_db.in(),
stmt_str.c_str(),
-1,
stmt.out(),
NULL);
nullptr);
if (retcode != SQLITE_OK) {
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
alt_msg = "";
return ec.make_error("{}", errmsg);
}
else if (stmt == NULL) {
else if (stmt == nullptr) {
alt_msg = "";
return ec.make_error("No statement given");
}
@ -215,11 +219,11 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
global_var->second.c_str(), -1,
SQLITE_TRANSIENT);
}
else if ((env_value = getenv(&name[1])) != NULL) {
else if ((env_value = getenv(&name[1])) != nullptr) {
sqlite3_bind_text(stmt.in(), lpc + 1, env_value, -1, SQLITE_STATIC);
}
}
else if (name[0] == ':' && ec.ec_line_values != NULL) {
else if (name[0] == ':' && ec.ec_line_values != nullptr) {
vector<logline_value> &lvalues = *ec.ec_line_values;
vector<logline_value>::iterator iter;
@ -256,7 +260,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
}
}
if (lnav_data.ld_rl_view != NULL) {
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_value("Executing query: " + sql + " ...");
}
@ -305,7 +309,7 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
}
}
gettimeofday(&end_tv, NULL);
gettimeofday(&end_tv, nullptr);
if (retcode == SQLITE_DONE) {
lnav_data.ld_filter_view.reload_data();
lnav_data.ld_files_view.reload_data();
@ -379,6 +383,8 @@ Result<string, string> execute_sql(exec_context &ec, const string &sql, string &
ensure_view(&lnav_data.ld_views[LNV_DB]);
}
}
} else {
lnav_data.ld_log_source.text_filters_changed();
}
#endif
}
@ -777,7 +783,8 @@ 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(system_tmpdir() / "lnav.out.XXXXXX")
fd, false, open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.out.XXXXXX")
.then([](auto pair) {
ghc::filesystem::remove(pair.first);
})
@ -801,11 +808,7 @@ future<string> pipe_callback(exec_context &ec, const string &cmdline, auto_fd &f
HELP_MSG_1(X, "to close the file"));
}
packaged_task<string()> task([]() { return ""; });
task();
return task.get_future();
return make_ready_future(std::string());
}
}

View File

@ -2,6 +2,8 @@
#define HAVE_PCRE_H
#define HAVE_NCURSESW_CURSES_H
#define HAVE_LIBCURL
#cmakedefine SIZEOF_OFF_T @SIZEOF_OFF_T@
#cmakedefine VCS_PACKAGE_STRING "@VCS_PACKAGE_STRING@"
@ -10,6 +12,8 @@
#cmakedefine HAVE_UTIL_H
#define HAVE_SQLITE3_STMT_READONLY
#define _XOPEN_SOURCE_EXTENDED 1
#define PACKAGE_BUGREPORT "lnav@googlegroups.com"

File diff suppressed because it is too large Load Diff

View File

@ -76,9 +76,9 @@ enum data_format_state_t {
};
struct data_format {
data_format(const char *name = NULL,
data_format(const char *name = nullptr,
data_token_t appender = DT_INVALID,
data_token_t terminator = DT_INVALID)
data_token_t terminator = DT_INVALID) noexcept
: df_name(name),
df_appender(appender),
df_terminator(terminator),
@ -314,154 +314,31 @@ public:
};
struct element {
element()
: e_capture(-1, -1),
e_token(DT_INVALID),
e_sub_elements(nullptr) {
};
element();
element(element_list_t &subs,
data_token_t token,
bool assign_subs_elements = true)
: e_capture(subs.front().e_capture.c_begin,
subs.back().e_capture.c_end),
e_token(token),
e_sub_elements(nullptr)
{
if (assign_subs_elements) {
this->assign_elements(subs);
}
};
bool assign_subs_elements = true);
element(const element &other)
{
/* require(other.e_sub_elements == nullptr); */
element(const element &other);
this->e_capture = other.e_capture;
this->e_token = other.e_token;
this->e_sub_elements = nullptr;
if (other.e_sub_elements != nullptr) {
this->assign_elements(*other.e_sub_elements);
}
};
~element();
~element()
{
delete this->e_sub_elements;
this->e_sub_elements = nullptr;
};
element & operator=(const element &other);
element & operator=(const element &other)
{
this->e_capture = other.e_capture;
this->e_token = other.e_token;
this->e_sub_elements = NULL;
if (other.e_sub_elements != NULL) {
this->assign_elements(*other.e_sub_elements);
}
return *this;
};
void assign_elements(element_list_t &subs);
void assign_elements(element_list_t &subs)
{
if (this->e_sub_elements == NULL) {
this->e_sub_elements = new element_list_t("_sub_", __FILE__,
__LINE__);
this->e_sub_elements->el_format = subs.el_format;
}
this->e_sub_elements->SWAP(subs);
this->update_capture();
};
void update_capture();
void update_capture(void)
{
if (this->e_sub_elements != NULL && !this->e_sub_elements->empty()) {
this->e_capture.c_begin =
this->e_sub_elements->front().e_capture.c_begin;
this->e_capture.c_end =
this->e_sub_elements->back().e_capture.c_end;
}
};
const element &get_pair_value() const;
const element &get_pair_value(void) const
{
require(this->e_token == DNT_PAIR);
data_token_t value_token() const;
return this->e_sub_elements->back();
};
const element &get_value_elem() const;
data_token_t value_token(void) const
{
data_token_t retval = DT_INVALID;
const element &get_pair_elem() const;
if (this->e_token == DNT_VALUE) {
if (this->e_sub_elements != NULL &&
this->e_sub_elements->size() == 1) {
retval = this->e_sub_elements->front().e_token;
}
else {
retval = DT_SYMBOL;
}
}
else {
retval = this->e_token;
}
return retval;
};
const element &get_value_elem() const {
if (this->e_token == DNT_VALUE) {
if (this->e_sub_elements != NULL &&
this->e_sub_elements->size() == 1) {
return this->e_sub_elements->front();
}
}
return *this;
};
const element &get_pair_elem() const {
if (this->e_token == DNT_VALUE) {
return this->e_sub_elements->front();
}
return *this;
}
void print(FILE *out, pcre_input &pi, int offset =
0) const
{
int lpc;
if (this->e_sub_elements != nullptr) {
for (auto & e_sub_element : *this->e_sub_elements) {
e_sub_element.print(out, pi, offset + 1);
}
}
fprintf(out, "%4s %3d:%-3d ",
data_scanner::token2name(this->e_token),
this->e_capture.c_begin,
this->e_capture.c_end);
for (lpc = 0; lpc < this->e_capture.c_end; lpc++) {
if (lpc == this->e_capture.c_begin) {
fputc('^', out);
}
else if (lpc == (this->e_capture.c_end - 1)) {
fputc('^', out);
}
else if (lpc > this->e_capture.c_begin) {
fputc('-', out);
}
else{
fputc(' ', out);
}
}
for (; lpc < (int)pi.pi_length; lpc++) {
fputc(' ', out);
}
std::string sub = pi.get_substr(&this->e_capture);
fprintf(out, " %s\n", sub.c_str());
};
void print(FILE *out, pcre_input &pi, int offset = 0) const;
pcre_context::capture_t e_capture;
data_token_t e_token;
@ -494,59 +371,11 @@ private:
};
struct discover_format_state {
discover_format_state() {
memset(this->dfs_hist, 0, sizeof(this->dfs_hist));
this->dfs_prefix_state = DFS_INIT;
this->dfs_semi_state = DFS_INIT;
this->dfs_comma_state = DFS_INIT;
}
discover_format_state();
void update_for_element(const element &elem) {
this->dfs_prefix_state = dfs_prefix_next(this->dfs_prefix_state, elem.e_token);
this->dfs_semi_state = dfs_semi_next(this->dfs_semi_state, elem.e_token);
this->dfs_comma_state = dfs_comma_next(this->dfs_comma_state, elem.e_token);
if (this->dfs_prefix_state != DFS_ERROR) {
if (this->dfs_semi_state == DFS_ERROR) {
this->dfs_semi_state = DFS_INIT;
}
if (this->dfs_comma_state == DFS_ERROR) {
this->dfs_comma_state = DFS_INIT;
}
}
this->dfs_hist[elem.e_token] += 1;
}
void update_for_element(const element &elem);
void finalize() {
data_token_t qualifier = this->dfs_format.df_qualifier;
data_token_t separator = this->dfs_format.df_separator;
data_token_t prefix_term = this->dfs_format.df_prefix_terminator;
this->dfs_format = FORMAT_PLAIN;
if (this->dfs_hist[DT_EQUALS]) {
qualifier = DT_COLON;
separator = DT_EQUALS;
}
if (this->dfs_semi_state != DFS_ERROR && this->dfs_hist[DT_SEMI]) {
this->dfs_format = FORMAT_SEMI;
}
else if (this->dfs_comma_state != DFS_ERROR) {
this->dfs_format = FORMAT_COMMA;
if (separator == DT_COLON && this->dfs_hist[DT_COMMA] > 0) {
if (!((this->dfs_hist[DT_COLON] == this->dfs_hist[DT_COMMA]) ||
((this->dfs_hist[DT_COLON] - 1) == this->dfs_hist[DT_COMMA]))) {
separator = DT_INVALID;
if (this->dfs_hist[DT_COLON] == 1) {
prefix_term = DT_COLON;
}
}
}
}
this->dfs_format.df_qualifier = qualifier;
this->dfs_format.df_separator = separator;
this->dfs_format.df_prefix_terminator = prefix_term;
};
void finalize();
data_format_state_t dfs_prefix_state;
data_format_state_t dfs_semi_state;
@ -556,646 +385,28 @@ private:
data_format dfs_format;
};
data_parser(data_scanner *ds)
: dp_errors("dp_errors", __FILE__, __LINE__),
dp_pairs("dp_pairs", __FILE__, __LINE__),
dp_msg_format(NULL),
dp_msg_format_begin(ds->get_input().pi_offset),
dp_scanner(ds)
{
if (TRACE_FILE != NULL) {
fprintf(TRACE_FILE, "input %s\n", ds->get_input().get_string());
}
};
data_parser(data_scanner *ds);
void pairup(schema_id_t *schema, element_list_t &pairs_out,
element_list_t &in_list, int group_depth = 0)
{
element_list_t ELEMENT_LIST_T(el_stack), ELEMENT_LIST_T(free_row),
ELEMENT_LIST_T(key_comps), ELEMENT_LIST_T(value),
ELEMENT_LIST_T(prefix);
SpookyHash context;
element_list_t &in_list, int group_depth = 0);
require(in_list.el_format.df_name != NULL);
POINT_TRACE("pairup_start");
FORMAT_TRACE(in_list);
for (element_list_t::iterator iter = in_list.begin();
iter != in_list.end();
++iter) {
if (iter->e_token == DNT_GROUP) {
element_list_t ELEMENT_LIST_T(group_pairs);
this->pairup(NULL, group_pairs, *iter->e_sub_elements, group_depth + 1);
if (!group_pairs.empty()) {
iter->assign_elements(group_pairs);
}
}
if (in_list.el_format.df_prefix_terminator != DT_INVALID) {
if (iter->e_token == in_list.el_format.df_prefix_terminator) {
in_list.el_format.df_prefix_terminator = DT_INVALID;
}
else {
el_stack.PUSH_BACK(*iter);
}
}
else if (iter->e_token == in_list.el_format.df_terminator) {
this->end_of_value(el_stack, key_comps, value, in_list, group_depth);
key_comps.PUSH_BACK(*iter);
}
else if (iter->e_token == in_list.el_format.df_qualifier) {
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_comps.end());
strip(value, element_if(DT_WHITE));
if (!value.empty()) {
el_stack.PUSH_BACK(element(value, DNT_VALUE));
}
}
else if (iter->e_token == in_list.el_format.df_separator) {
element_list_t::iterator key_iter = key_comps.end();
bool found = false, key_is_values = true;
if (!key_comps.empty()) {
do {
--key_iter;
if (key_iter->e_token ==
in_list.el_format.df_appender) {
++key_iter;
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_iter);
key_comps.POP_FRONT();
found = true;
}
else if (key_iter->e_token ==
in_list.el_format.df_terminator) {
std::vector<element> key_copy;
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_iter);
key_comps.POP_FRONT();
strip(key_comps, element_if(DT_WHITE));
if (key_comps.empty()) {
key_iter = key_comps.end();
} else {
key_iter = key_comps.begin();
}
found = true;
}
if (key_iter != key_comps.end()) {
switch (key_iter->e_token) {
case DT_WORD:
case DT_SYMBOL:
key_is_values = false;
break;
default:
break;
}
}
} while (key_iter != key_comps.begin() && !found);
}
if (!found && !el_stack.empty() && !key_comps.empty()) {
element_list_t::iterator value_iter;
if (el_stack.size() > 1 &&
in_list.el_format.df_appender != DT_INVALID &&
in_list.el_format.df_terminator != DT_INVALID) {
/* If we're expecting a terminator and haven't found it */
/* then this is part of the value. */
continue;
}
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_comps.end());
value_iter = value.end();
std::advance(value_iter, -1);
key_comps.SPLICE(key_comps.begin(),
value,
value_iter,
value.end());
key_comps.resize(1);
}
strip(value, element_if(DT_WHITE));
value.remove_if(element_if(DT_COMMA));
if (!value.empty()) {
el_stack.PUSH_BACK(element(value, DNT_VALUE));
}
strip(key_comps, element_if(DT_WHITE));
if (!key_comps.empty()) {
if (key_is_values) {
el_stack.PUSH_BACK(element(key_comps, DNT_VALUE));
}
else {
el_stack.PUSH_BACK(element(key_comps, DNT_KEY, false));
}
}
key_comps.CLEAR();
value.CLEAR();
}
else {
key_comps.PUSH_BACK(*iter);
}
POINT_TRACE("pairup_loop");
}
POINT_TRACE("pairup_eol");
CONSUMED_TRACE(in_list);
// Only perform the free-row logic at the top level, if we're in a group
// assume it is a list.
if (group_depth < 1 && el_stack.empty()) {
free_row.SPLICE(free_row.begin(),
key_comps, key_comps.begin(), key_comps.end());
}
else {
this->end_of_value(el_stack, key_comps, value, in_list, group_depth);
}
POINT_TRACE("pairup_stack");
context.Init(0, 0);
while (!el_stack.empty()) {
element_list_t::iterator kv_iter = el_stack.begin();
if (kv_iter->e_token == DNT_VALUE) {
if (pairs_out.empty()) {
free_row.PUSH_BACK(el_stack.front());
}
else {
element_list_t ELEMENT_LIST_T(free_pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
el_stack.front().e_capture.
c_begin;
blank.e_token = DNT_KEY;
free_pair_subs.PUSH_BACK(blank);
free_pair_subs.PUSH_BACK(el_stack.front());
pairs_out.PUSH_BACK(element(free_pair_subs, DNT_PAIR));
}
}
if (kv_iter->e_token != DNT_KEY) {
el_stack.POP_FRONT();
continue;
}
++kv_iter;
if (kv_iter == el_stack.end()) {
el_stack.POP_FRONT();
continue;
}
element_list_t ELEMENT_LIST_T(pair_subs);
if (schema != NULL) {
size_t key_len;
const char *key_val =
this->get_element_string(el_stack.front(), key_len);
context.Update(key_val, key_len);
}
while (!free_row.empty()) {
element_list_t ELEMENT_LIST_T(free_pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
free_row.front().e_capture.
c_begin;
blank.e_token = DNT_KEY;
free_pair_subs.PUSH_BACK(blank);
free_pair_subs.PUSH_BACK(free_row.front());
pairs_out.PUSH_BACK(element(free_pair_subs, DNT_PAIR));
free_row.POP_FRONT();
}
bool has_value = false;
if (kv_iter->e_token == DNT_VALUE) {
++kv_iter;
has_value = true;
}
pair_subs.SPLICE(pair_subs.begin(),
el_stack,
el_stack.begin(),
kv_iter);
if (!has_value) {
element_list_t ELEMENT_LIST_T(blank_value);
pcre_input &pi = this->dp_scanner->get_input();
const char *str = pi.get_string();
struct element blank;
blank.e_token = DT_QUOTED_STRING;
blank.e_capture.c_begin = blank.e_capture.c_end = pair_subs.front().e_capture.c_end;
if ((blank.e_capture.c_begin >= 0) &&
((size_t) blank.e_capture.c_begin < pi.pi_length)) {
switch (str[blank.e_capture.c_begin]) {
case '=':
case ':':
blank.e_capture.c_begin += 1;
blank.e_capture.c_end += 1;
break;
}
}
blank_value.PUSH_BACK(blank);
pair_subs.PUSH_BACK(element(blank_value, DNT_VALUE));
}
pairs_out.PUSH_BACK(element(pair_subs, DNT_PAIR));
}
if (pairs_out.size() == 1) {
element &pair = pairs_out.front();
element &evalue = pair.e_sub_elements->back();
if (evalue.e_token == DNT_VALUE &&
evalue.e_sub_elements != NULL &&
evalue.e_sub_elements->size() > 1) {
element_list_t::iterator next_sub;
next_sub = pair.e_sub_elements->begin();
++next_sub;
prefix.SPLICE(prefix.begin(),
*pair.e_sub_elements,
pair.e_sub_elements->begin(),
next_sub);
free_row.CLEAR();
free_row.SPLICE(free_row.begin(),
*evalue.e_sub_elements,
evalue.e_sub_elements->begin(),
evalue.e_sub_elements->end());
pairs_out.CLEAR();
context.Init(0, 0);
}
}
if (group_depth >= 1 && pairs_out.empty() && !free_row.empty()) {
pairs_out.SWAP(free_row);
}
if (pairs_out.empty() && !free_row.empty()) {
while (!free_row.empty()) {
switch (free_row.front().e_token) {
case DNT_GROUP:
case DNT_VALUE:
case DT_EMAIL:
case DT_CONSTANT:
case DT_NUMBER:
case DT_SYMBOL:
case DT_HEX_NUMBER:
case DT_OCTAL_NUMBER:
case DT_VERSION_NUMBER:
case DT_QUOTED_STRING:
case DT_IPV4_ADDRESS:
case DT_IPV6_ADDRESS:
case DT_MAC_ADDRESS:
case DT_HEX_DUMP:
case DT_XML_OPEN_TAG:
case DT_XML_CLOSE_TAG:
case DT_XML_EMPTY_TAG:
case DT_UUID:
case DT_URL:
case DT_PATH:
case DT_DATE:
case DT_TIME:
case DT_PERCENTAGE: {
element_list_t ELEMENT_LIST_T(pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
free_row.front().e_capture.
c_begin;
blank.e_token = DNT_KEY;
pair_subs.PUSH_BACK(blank);
pair_subs.PUSH_BACK(free_row.front());
pairs_out.PUSH_BACK(element(pair_subs, DNT_PAIR));
// Throw something into the hash so that the number of
// columns is significant. I don't think we want to
// use the token ID since some columns values might vary
// between rows.
context.Update(" ", 1);
}
break;
default: {
size_t key_len;
const char *key_val = this->get_element_string(
free_row.front(), key_len);
context.Update(key_val, key_len);
}
break;
}
free_row.POP_FRONT();
}
}
if (!prefix.empty()) {
element_list_t ELEMENT_LIST_T(pair_subs);
struct element blank;
blank.e_capture.c_begin = blank.e_capture.c_end =
prefix.front().e_capture.c_begin;
blank.e_token = DNT_KEY;
pair_subs.PUSH_BACK(blank);
pair_subs.PUSH_BACK(prefix.front());
pairs_out.PUSH_FRONT(element(pair_subs, DNT_PAIR));
}
if (schema != nullptr) {
context.Final(schema->out(0), schema->out(1));
}
if (schema != nullptr && this->dp_msg_format != nullptr) {
pcre_input &pi = this->dp_scanner->get_input();
for (auto & fiter : pairs_out) {
*(this->dp_msg_format) += this->get_string_up_to_value(fiter);
this->dp_msg_format->append("#");
}
if ((size_t) this->dp_msg_format_begin < pi.pi_length) {
const char *str = pi.get_string();
pcre_context::capture_t last(this->dp_msg_format_begin,
pi.pi_length);
switch (str[last.c_begin]) {
case '\'':
case '"':
last.c_begin += 1;
break;
}
*(this->dp_msg_format) += pi.get_substr(&last);
}
}
if (pairs_out.size() > 1000) {
pairs_out.resize(1000);
}
};
void discover_format()
{
pcre_context_static<30> pc;
std::stack<discover_format_state> state_stack;
struct element elem;
this->dp_group_token.push_back(DT_INVALID);
this->dp_group_stack.resize(1);
state_stack.push(discover_format_state());
while (this->dp_scanner->tokenize2(pc, elem.e_token)) {
pcre_context::iterator pc_iter;
pc_iter = std::find_if(pc.begin(), pc.end(), capture_if_not(-1));
require(pc_iter != pc.end());
elem.e_capture = *pc_iter;
require(elem.e_capture.c_begin != -1);
require(elem.e_capture.c_end != -1);
state_stack.top().update_for_element(elem);
switch (elem.e_token) {
case DT_LPAREN:
case DT_LANGLE:
case DT_LCURLY:
case DT_LSQUARE:
this->dp_group_token.push_back(elem.e_token);
this->dp_group_stack.emplace_back("_anon_", __FILE__, __LINE__);
state_stack.push(discover_format_state());
break;
case DT_EMPTY_CONTAINER: {
auto &curr_group = this->dp_group_stack.back();
auto empty_list = element_list_t("_anon_", __FILE__, __LINE__);
discover_format_state dfs;
dfs.finalize();
empty_list.el_format = dfs.dfs_format;
curr_group.PUSH_BACK(element());
auto &empty = curr_group.back();
empty.e_capture.c_begin = elem.e_capture.c_begin + 1;
empty.e_capture.c_end = elem.e_capture.c_begin + 1;
empty.e_token = DNT_GROUP;
empty.assign_elements(empty_list);
break;
}
case DT_RPAREN:
case DT_RANGLE:
case DT_RCURLY:
case DT_RSQUARE:
if (this->dp_group_token.back() == (elem.e_token - 1)) {
this->dp_group_token.pop_back();
auto riter = this->dp_group_stack.rbegin();
++riter;
state_stack.top().finalize();
this->dp_group_stack.back().el_format = state_stack.top().dfs_format;
state_stack.pop();
if (!this->dp_group_stack.back().empty()) {
(*riter).PUSH_BACK(element(this->dp_group_stack.back(),
DNT_GROUP));
}
else {
(*riter).PUSH_BACK(element());
riter->back().e_capture.c_begin = elem.e_capture.c_begin;
riter->back().e_capture.c_end = elem.e_capture.c_begin;
riter->back().e_token = DNT_GROUP;
riter->back().assign_elements(this->dp_group_stack.back());
}
this->dp_group_stack.pop_back();
}
else {
this->dp_group_stack.back().PUSH_BACK(elem);
}
break;
default:
this->dp_group_stack.back().PUSH_BACK(elem);
break;
}
}
while (this->dp_group_stack.size() > 1) {
this->dp_group_token.pop_back();
auto riter = this->dp_group_stack.rbegin();
++riter;
if (!this->dp_group_stack.back().empty()) {
state_stack.top().finalize();
this->dp_group_stack.back().el_format = state_stack.top().dfs_format;
state_stack.pop();
(*riter).PUSH_BACK(element(this->dp_group_stack.back(),
DNT_GROUP));
}
this->dp_group_stack.pop_back();
}
state_stack.top().finalize();
this->dp_group_stack.back().el_format = state_stack.top().dfs_format;
};
void discover_format();
void end_of_value(element_list_t &el_stack,
element_list_t &key_comps,
element_list_t &value,
const element_list_t &in_list,
int group_depth) {
key_comps.remove_if(element_if(in_list.el_format.df_terminator));
key_comps.remove_if(element_if(DT_COMMA));
value.remove_if(element_if(in_list.el_format.df_terminator));
value.remove_if(element_if(DT_COMMA));
strip(key_comps, element_if(DT_WHITE));
strip(value, element_if(DT_WHITE));
if ((el_stack.empty() || el_stack.back().e_token != DNT_KEY) &&
value.empty() && key_comps.size() > 1 &&
(key_comps.front().e_token == DT_WORD ||
key_comps.front().e_token == DT_SYMBOL)) {
element_list_t::iterator key_iter, key_end;
bool found_value = false;
int word_count = 0;
key_iter = key_comps.begin();
key_end = key_comps.begin();
for (; key_iter != key_comps.end(); ++key_iter) {
if (key_iter->e_token == DT_WORD ||
key_iter->e_token == DT_SYMBOL) {
word_count += 1;
if (found_value) {
key_end = key_comps.begin();
}
}
else if (key_iter->e_token == DT_WHITE) {
int group_depth);
}
else {
if (!found_value) {
key_end = key_iter;
}
found_value = true;
}
}
if (word_count != 1) {
key_end = key_comps.begin();
}
value.SPLICE(value.end(),
key_comps,
key_end,
key_comps.end());
strip(key_comps, element_if(DT_WHITE));
if (!key_comps.empty()) {
el_stack.PUSH_BACK(element(key_comps, DNT_KEY, false));
}
key_comps.CLEAR();
}
else {
value.SPLICE(value.end(),
key_comps,
key_comps.begin(),
key_comps.end());
}
strip(value, element_if(DT_WHITE));
strip(value, element_if(DT_COLON));
strip(value, element_if(DT_WHITE));
if (!value.empty()) {
if (value.size() == 2 && value.back().e_token == DNT_GROUP) {
element_list_t ELEMENT_LIST_T(group_pair);
void parse();
group_pair.PUSH_BACK(element(value, DNT_PAIR));
el_stack.PUSH_BACK(element(group_pair, DNT_VALUE));
}
else {
el_stack.PUSH_BACK(element(value, DNT_VALUE));
}
}
value.CLEAR();
};
std::string get_element_string(const element &elem) const;
void parse()
{
this->discover_format();
std::string get_string_up_to_value(const element &elem);
this->pairup(&this->dp_schema_id,
this->dp_pairs,
this->dp_group_stack.front());
};
const char *get_element_string(const element &elem, size_t &len_out);
std::string get_element_string(const element &elem) const
{
pcre_input &pi = this->dp_scanner->get_input();
return pi.get_substr(&elem.e_capture);
};
std::string get_string_up_to_value(const element &elem) {
pcre_input &pi = this->dp_scanner->get_input();
const element &val_elem = elem.e_token == DNT_PAIR ?
elem.e_sub_elements->back() : elem;
if (this->dp_msg_format_begin <= val_elem.e_capture.c_begin) {
pcre_context::capture_t leading_and_key = pcre_context::capture_t(
this->dp_msg_format_begin, val_elem.e_capture.c_begin);
const char *str = pi.get_string();
if (leading_and_key.length() >= 2) {
switch (str[leading_and_key.c_end - 1]) {
case '\'':
case '"':
leading_and_key.c_end -= 1;
switch (str[leading_and_key.c_end - 1]) {
case 'r':
case 'u':
leading_and_key.c_end -= 1;
break;
}
break;
}
switch (str[leading_and_key.c_begin]) {
case '\'':
case '"':
leading_and_key.c_begin += 1;
break;
}
}
this->dp_msg_format_begin = val_elem.e_capture.c_end;
return pi.get_substr(&leading_and_key);
}
else {
this->dp_msg_format_begin = val_elem.e_capture.c_end;
}
return "";
};
const char *get_element_string(const element &elem, size_t &len_out) {
pcre_input &pi = this->dp_scanner->get_input();
len_out = elem.e_capture.length();
return pi.get_substr_start(&elem.e_capture);
};
void print(FILE *out, element_list_t &el)
{
fprintf(out, " %s\n",
this->dp_scanner->get_input().get_string());
for (auto & iter : el) {
iter.print(out, this->dp_scanner->get_input());
}
};
void print(FILE *out, element_list_t &el);
std::vector<data_token_t> dp_group_token;
std::list<element_list_t> dp_group_stack;

View File

@ -262,7 +262,7 @@ size_t db_overlay_source::list_overlay_count(const listview_curses &lv)
.with_margins(3, 0);
for (auto &jpw_value : jpw.jpw_values) {
this->dos_lines.push_back(" " + jpw_value.wt_ptr + " = " +
this->dos_lines.emplace_back(" " + jpw_value.wt_ptr + " = " +
jpw_value.wt_value);
string_attrs_t &sa = this->dos_lines.back().get_attrs();

View File

@ -42,12 +42,6 @@
class db_label_source : public text_sub_source, public text_time_translator {
public:
db_label_source() : dls_time_column_index(-1) {
};
~db_label_source() { };
bool has_log_time_column() const {
return !this->dls_time_column.empty();
};
@ -118,7 +112,7 @@ public:
};
struct header_meta {
header_meta(std::string name)
explicit header_meta(std::string name)
: hm_name(std::move(name)),
hm_column_type(SQLITE3_TEXT),
hm_graphable(false),
@ -143,26 +137,22 @@ public:
std::vector<header_meta> dls_headers;
std::vector<std::vector<const char *> > dls_rows;
std::vector<struct timeval> dls_time_column;
int dls_time_column_index;
int dls_time_column_index{-1};
static const char *NULL_STR;
};
class db_overlay_source : public list_overlay_source {
public:
db_overlay_source() : dos_active(false), dos_labels(nullptr) {
};
size_t list_overlay_count(const listview_curses &lv);
bool list_value_for_overlay(const listview_curses &lv,
int y, int bottom,
vis_line_t row,
attr_line_t &value_out);
attr_line_t &value_out) override;
bool dos_active;
db_label_source *dos_labels;
bool dos_active{false};
db_label_source *dos_labels{nullptr};
std::vector<attr_line_t> dos_lines;
};
#endif

View File

@ -210,7 +210,7 @@ static int vt_update(sqlite3_vtab *tab,
sqlite_int64 *rowid)
{
const char *name = (
argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : NULL);
argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : nullptr);
vtab *p_vt = (vtab *)tab;
int retval = SQLITE_ERROR;
@ -225,7 +225,7 @@ static int vt_update(sqlite3_vtab *tab,
return SQLITE_ERROR;
}
if (name != NULL && strchr(name, '=') != NULL) {
if (name != nullptr && strchr(name, '=') != nullptr) {
tab->zErrMsg = sqlite3_mprintf(
"Environment variable names cannot contain an equals sign (=)");
@ -244,7 +244,7 @@ static int vt_update(sqlite3_vtab *tab,
unsetenv(name);
retval = SQLITE_OK;
} else if (name != NULL && getenv(name) != NULL) {
} else if (name != nullptr && getenv(name) != nullptr) {
#ifdef SQLITE_FAIL
int rc;
@ -266,7 +266,7 @@ static int vt_update(sqlite3_vtab *tab,
#endif
}
if (name != NULL && argc == 4) {
if (name != nullptr && argc == 4) {
const unsigned char *value = sqlite3_value_text(argv[3]);
setenv((const char *)name, (const char *)value, 1);

View File

@ -29,7 +29,7 @@
#include "config.h"
#include "lnav.hh"
#include "ansi_scrubber.hh"
#include "vtab_module.hh"
#include "relative_time.hh"
#include "field_overlay_source.hh"
@ -41,7 +41,8 @@ json_string extract(const char *str);
void field_overlay_source::build_summary_lines(const listview_curses &lv)
{
textfile_sub_source &tss = lnav_data.ld_text_source;
auto& tc = dynamic_cast<const textview_curses &>(lv);
textfile_sub_source &tss = this->fos_tss;
logfile_sub_source &lss = this->fos_lss;
this->fos_summary_lines.clear();
@ -55,7 +56,7 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
lv.get_dimensions(height, width);
free_rows = height - filled_rows - vis_line_t(this->fos_lines.size());
if (free_rows < 2 || lnav_data.ld_flags & LNF_HEADLESS) {
if (free_rows < 2 || !this->fos_show_status) {
this->fos_summary_lines.clear();
}
else {
@ -68,7 +69,7 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
}
else {
logline *first_line, *last_line;
time_t now = time(NULL);
time_t now = time(nullptr);
first_line = lss.find_line(lss.at(vis_line_t(0)));
last_line = lss.find_line(lss.at(lv.get_bottom()));
@ -84,11 +85,12 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
vis_line_t from_five_min_ago = lss.find_from_time(five_minutes_ago);
vis_line_t from_ten_secs_ago = lss.find_from_time(ten_secs_ago);
vis_bookmarks &bm = lnav_data.ld_views[LNV_LOG].get_bookmarks();
bookmark_vector<vis_line_t> &error_bookmarks =
bm[&logfile_sub_source::BM_ERRORS];
auto &bm = tc.get_bookmarks();
auto error_bm_iter = bm.find(&logfile_sub_source::BM_ERRORS);
if (now > last_line->get_time() && from_five_min_ago != -1) {
if (now > last_line->get_time() && from_five_min_ago != -1 &&
error_bm_iter != bm.end()) {
auto& error_bookmarks = error_bm_iter->second;
auto five_min_lower =
lower_bound(error_bookmarks.begin(),
error_bookmarks.end(),
@ -369,7 +371,7 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
this->fos_lines.emplace_back(" No known message fields");
}
const log_format *last_format = NULL;
const log_format *last_format = nullptr;
for (auto & lv : this->fos_log_helper.ldh_line_values) {
string format_name = lv.lv_format->get_name().to_string();

View File

@ -35,18 +35,19 @@
#include "listview_curses.hh"
#include "log_data_helper.hh"
#include "logfile_sub_source.hh"
#include "textfile_sub_source.hh"
class field_overlay_source : public list_overlay_source {
public:
field_overlay_source(logfile_sub_source &lss)
: fos_lss(lss), fos_log_helper(lss) {
explicit field_overlay_source(logfile_sub_source &lss, textfile_sub_source &tss)
: fos_lss(lss), fos_tss(tss), fos_log_helper(lss) {
};
void add_key_line_attrs(int key_size, bool last_line = false) {
string_attrs_t &sa = this->fos_lines.back().get_attrs();
struct line_range lr(1, 2);
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE));
sa.emplace_back(lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE);
lr.lr_start = 3 + key_size + 3;
lr.lr_end = -1;
@ -93,9 +94,11 @@ public:
std::vector<attr_line_t> &dst,
vis_line_t row);
bool fos_show_status{true};
bool fos_active{false};
bool fos_active_prev{false};
logfile_sub_source &fos_lss;
textfile_sub_source &fos_tss;
log_data_helper fos_log_helper;
int fos_known_key_size{0};
int fos_unknown_key_size{0};

419
src/file_collection.cc Normal file
View File

@ -0,0 +1,419 @@
/**
* Copyright (c) 2020, 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 file_collection.cc
*/
#include "config.h"
#include <glob.h>
#include "file_collection.hh"
static std::mutex REALPATH_CACHE_MUTEX;
static std::unordered_map<std::string, std::string> REALPATH_CACHE;
void file_collection::close_file(const std::shared_ptr<logfile> &lf)
{
if (lf->is_valid_filename()) {
std::lock_guard<std::mutex> lg(REALPATH_CACHE_MUTEX);
REALPATH_CACHE.erase(lf->get_filename());
} else {
this->fc_file_names.erase(lf->get_filename());
}
auto file_iter = find(this->fc_files.begin(),
this->fc_files.end(),
lf);
if (file_iter != this->fc_files.end()) {
this->fc_files.erase(file_iter);
this->fc_files_generation += 1;
}
this->regenerate_unique_file_names();
}
void file_collection::regenerate_unique_file_names()
{
unique_path_generator upg;
for (const auto &lf : this->fc_files) {
upg.add_source(lf);
}
upg.generate();
this->fc_largest_path_length = 0;
for (const auto &lf : this->fc_files) {
const auto &path = lf->get_unique_path();
if (path.length() > this->fc_largest_path_length) {
this->fc_largest_path_length = path.length();
}
}
for (const auto &pair : this->fc_other_files) {
auto bn = ghc::filesystem::path(pair.first).filename().string();
if (bn.length() > this->fc_largest_path_length) {
this->fc_largest_path_length = bn.length();
}
}
}
void file_collection::merge(const file_collection &other)
{
this->fc_recursive = other.fc_recursive;
this->fc_rotated = other.fc_rotated;
this->fc_name_to_errors.insert(other.fc_name_to_errors.begin(),
other.fc_name_to_errors.end());
this->fc_file_names.insert(other.fc_file_names.begin(),
other.fc_file_names.end());
if (!other.fc_files.empty()) {
this->fc_files.insert(this->fc_files.end(),
other.fc_files.begin(),
other.fc_files.end());
this->fc_files_generation += 1;
}
for (auto &pair : other.fc_renamed_files) {
pair.first->set_filename(pair.second);
}
this->fc_closed_files.insert(other.fc_closed_files.begin(),
other.fc_closed_files.end());
this->fc_other_files.insert(other.fc_other_files.begin(),
other.fc_other_files.end());
}
/**
* Functor used to compare files based on their device and inode number.
*/
struct same_file {
explicit same_file(const struct stat &stat) : sf_stat(stat) {};
/**
* Compare the given log file against the 'stat' given in the constructor.
* @param lf The log file to compare.
* @return True if the dev/inode values in the stat given in the
* constructor matches the stat in the logfile object.
*/
bool operator()(const std::shared_ptr<logfile> &lf) const
{
return this->sf_stat.st_dev == lf->get_stat().st_dev &&
this->sf_stat.st_ino == lf->get_stat().st_ino;
};
const struct stat &sf_stat;
};
/**
* Try to load the given file as a log file. If the file has not already been
* loaded, it will be loaded. If the file has already been loaded, the file
* name will be updated.
*
* @param filename The file name to check.
* @param fd An already-opened descriptor for 'filename'.
* @param required Specifies whether or not the file must exist and be valid.
*/
std::future<file_collection>
file_collection::watch_logfile(const std::string &filename,
logfile_open_options &loo, bool required)
{
file_collection retval;
struct stat st;
int rc;
if (this->fc_closed_files.count(filename)) {
return make_ready_future(retval);
}
if (loo.loo_fd != -1) {
rc = fstat(loo.loo_fd, &st);
} else {
rc = stat(filename.c_str(), &st);
}
if (rc == 0) {
if (S_ISDIR(st.st_mode) && this->fc_recursive) {
std::string wilddir = filename + "/*";
if (this->fc_file_names.find(wilddir) ==
this->fc_file_names.end()) {
retval.fc_file_names.emplace(wilddir, logfile_open_options());
}
return make_ready_future(retval);
}
if (!S_ISREG(st.st_mode)) {
if (required) {
rc = -1;
errno = EINVAL;
} else {
return make_ready_future(retval);
}
}
}
if (rc == -1) {
if (required) {
retval.fc_name_to_errors[filename] = strerror(errno);
}
return make_ready_future(retval);
}
auto file_iter = find_if(this->fc_files.begin(),
this->fc_files.end(),
same_file(st));
if (file_iter == this->fc_files.end()) {
if (this->fc_other_files.find(filename) != this->fc_other_files.end()) {
return make_ready_future(retval);
}
auto func = [filename, loo, prog = this->fc_progress, errs = this->fc_name_to_errors]() mutable {
file_collection retval;
if (errs.find(filename) != errs.end()) {
// The file is broken, no reason to try and reopen
return retval;
}
auto ff = detect_file_format(filename);
switch (ff) {
case file_format_t::FF_SQLITE_DB:
retval.fc_other_files[filename] = ff;
break;
case file_format_t::FF_ARCHIVE: {
nonstd::optional<std::list<archive_manager::extract_progress>::iterator>
prog_iter_opt;
auto res = archive_manager::walk_archive_files(
filename,
[prog, &prog_iter_opt](
const auto &path,
const auto total) {
safe::WriteAccess<safe_scan_progress> sp(
*prog);
prog_iter_opt |
[&sp](auto prog_iter) {
sp->sp_extractions.erase(
prog_iter);
};
auto prog_iter = sp->sp_extractions.emplace(
sp->sp_extractions.begin(),
path, total);
prog_iter_opt = prog_iter;
return &(*prog_iter);
},
[&filename, &retval](
const auto &tmp_path,
const auto &entry) {
auto ext = entry.path().extension();
if (ext == ".jar" ||
ext == ".war" ||
ext == ".zip") {
return;
}
auto arc_path = ghc::filesystem::relative(
entry.path(), tmp_path);
auto custom_name =
filename / arc_path;
bool is_visible = true;
if (entry.file_size() == 0) {
log_info(
"hiding empty archive file: %s",
entry.path().c_str());
is_visible = false;
}
log_info(
"adding file from archive: %s/%s",
filename.c_str(),
entry.path().c_str());
retval.fc_file_names[entry.path().string()]
.with_filename(
custom_name.string())
.with_visibility(is_visible)
.with_non_utf_visibility(
false)
.with_visible_size_limit(
128 * 1024);
});
if (res.isErr()) {
log_error(
"archive extraction failed: %s",
res.unwrapErr().c_str());
retval.clear();
retval.fc_name_to_errors[filename] = res.unwrapErr();
} else {
retval.fc_other_files[filename] = ff;
}
{
prog_iter_opt |
[&prog](auto prog_iter) {
prog->writeAccess()->sp_extractions.erase(
prog_iter);
};
}
break;
}
default:
log_info("loading new file: filename=%s",
filename.c_str());
/* It's a new file, load it in. */
try {
auto lf = std::make_shared<logfile>(
filename, loo);
retval.fc_files.push_back(lf);
} catch (logfile::error &e) {
retval.fc_name_to_errors[filename] = e.what();
}
break;
}
return retval;
};
return std::async(std::launch::async, func);
} else {
auto lf = *file_iter;
if (lf->is_valid_filename() && lf->get_filename() != filename) {
/* The file is already loaded, but has been found under a different
* name. We just need to update the stored file name.
*/
retval.fc_renamed_files.emplace_back(lf, filename);
}
}
return make_ready_future(retval);
}
/**
* Expand a glob pattern and call watch_logfile with the file names that match
* the pattern.
* @param path The glob pattern to expand.
* @param required Passed to watch_logfile.
*/
void file_collection::expand_filename(future_queue<file_collection> &fq,
const std::string &path,
logfile_open_options &loo,
bool required)
{
static_root_mem<glob_t, globfree> gl;
{
std::lock_guard<std::mutex> lg(REALPATH_CACHE_MUTEX);
if (REALPATH_CACHE.find(path) != REALPATH_CACHE.end()) {
return;
}
}
if (is_url(path.c_str())) {
return;
} else if (glob(path.c_str(), GLOB_NOCHECK, nullptr, gl.inout()) == 0) {
int lpc;
if (gl->gl_pathc == 1 /*&& gl.gl_matchc == 0*/) {
/* It's a pattern that doesn't match any files
* yet, allow it through since we'll load it in
* dynamically.
*/
if (access(path.c_str(), F_OK) == -1) {
required = false;
}
}
if (gl->gl_pathc > 1 ||
strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
required = false;
}
std::lock_guard<std::mutex> lg(REALPATH_CACHE_MUTEX);
for (lpc = 0; lpc < (int) gl->gl_pathc; lpc++) {
auto path_str = std::string(gl->gl_pathv[lpc]);
auto iter = REALPATH_CACHE.find(path_str);
if (iter == REALPATH_CACHE.end()) {
auto_mem<char> abspath;
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) ==
nullptr) {
if (required) {
fprintf(stderr, "Cannot find file: %s -- %s",
gl->gl_pathv[lpc], strerror(errno));
}
continue;
} else {
auto p = REALPATH_CACHE.emplace(path_str, abspath.in());
iter = p.first;
}
}
if (required || access(iter->second.c_str(), R_OK) == 0) {
fq.push_back(watch_logfile(iter->second, loo, required));
}
}
}
}
file_collection file_collection::rescan_files(bool required)
{
file_collection retval;
future_queue<file_collection> fq([&retval](auto &fc) {
retval.merge(fc);
});
for (auto &pair : this->fc_file_names) {
if (pair.second.loo_fd == -1) {
this->expand_filename(fq, pair.first, pair.second, required);
if (this->fc_rotated) {
std::string path = pair.first + ".*";
this->expand_filename(fq, path, pair.second, false);
}
} else {
fq.push_back(watch_logfile(pair.first, pair.second, required));
}
if (retval.fc_files.size() >= 100) {
log_debug("too many new files, breaking...");
break;
}
}
fq.pop_to();
return retval;
}

97
src/file_collection.hh Normal file
View File

@ -0,0 +1,97 @@
/**
* Copyright (c) 2020, 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 file_collection.hh
*/
#ifndef lnav_file_collection_hh
#define lnav_file_collection_hh
#include <map>
#include <string>
#include "safe/safe.h"
#include "base/future_util.hh"
#include "logfile.hh"
#include "archive_manager.hh"
#include "lnav_util.hh"
struct scan_progress {
std::list<archive_manager::extract_progress> sp_extractions;
};
using safe_scan_progress = safe::Safe<scan_progress>;
struct file_collection {
bool fc_recursive{false};
bool fc_rotated{false};
std::map<std::string, std::string> fc_name_to_errors;
std::map<std::string, logfile_open_options> fc_file_names;
std::vector<std::shared_ptr<logfile>> fc_files;
int fc_files_generation{0};
std::vector<std::pair<std::shared_ptr<logfile>, std::string>>
fc_renamed_files;
std::set<std::string> fc_closed_files;
std::map<std::string, file_format_t> fc_other_files;
std::shared_ptr<safe_scan_progress> fc_progress;
size_t fc_largest_path_length{0};
file_collection()
: fc_progress(std::make_shared<safe::Safe<scan_progress>>())
{}
void clear()
{
this->fc_name_to_errors.clear();
this->fc_file_names.clear();
this->fc_files.clear();
this->fc_closed_files.clear();
this->fc_other_files.clear();
}
file_collection rescan_files(bool required = false);
void
expand_filename(future_queue<file_collection> &fq, const std::string &path,
logfile_open_options &loo, bool required);
std::future<file_collection>
watch_logfile(const std::string &filename, logfile_open_options &loo,
bool required);
void merge(const file_collection &other);
void close_file(const std::shared_ptr<logfile> &lf);
void regenerate_unique_file_names();
};
#endif

View File

@ -32,7 +32,6 @@
#include <unistd.h>
#include <string.h>
#include "lnav.hh"
#include "base/lnav_log.hh"
#include "file_vtab.hh"
#include "session_data.hh"
@ -56,20 +55,15 @@ CREATE TABLE lnav_file (
);
)";
struct vtab {
sqlite3_vtab base;
explicit operator sqlite3_vtab *() {
return &this->base;
};
};
lnav_file(file_collection& fc) : lf_collection(fc) {
}
iterator begin() {
return lnav_data.ld_active_files.fc_files.begin();
return this->lf_collection.fc_files.begin();
}
iterator end() {
return lnav_data.ld_active_files.fc_files.end();
return this->lf_collection.fc_files.end();
}
int get_column(const cursor &vc, sqlite3_context *ctx, int col) {
@ -135,7 +129,7 @@ CREATE TABLE lnav_file (
int64_t lines,
int64_t time_offset,
bool visible) {
auto lf = lnav_data.ld_active_files.fc_files[rowid];
auto lf = this->lf_collection.fc_files[rowid];
struct timeval tv = {
(int) (time_offset / 1000LL),
(int) (time_offset / (1000LL * 1000LL)),
@ -149,15 +143,15 @@ CREATE TABLE lnav_file (
"real file paths cannot be updated, only symbolic ones");
}
auto iter = lnav_data.ld_active_files.fc_file_names.find(lf->get_filename());
auto iter = this->lf_collection.fc_file_names.find(lf->get_filename());
if (iter != lnav_data.ld_active_files.fc_file_names.end()) {
auto loo = iter->second;
if (iter != this->lf_collection.fc_file_names.end()) {
auto loo = std::move(iter->second);
lnav_data.ld_active_files.fc_file_names.erase(iter);
this->lf_collection.fc_file_names.erase(iter);
loo.loo_include_in_session = true;
lnav_data.ld_active_files.fc_file_names[path] = loo;
this->lf_collection.fc_file_names[path] = std::move(loo);
lf->set_filename(path);
init_session();
@ -167,21 +161,21 @@ CREATE TABLE lnav_file (
if (lf->is_visible() != visible) {
lf->set_visibility(visible);
lnav_data.ld_log_source.text_filters_changed();
}
return SQLITE_OK;
};
file_collection &lf_collection;
};
int register_file_vtab(sqlite3 *db)
int register_file_vtab(sqlite3 *db, file_collection &fc)
{
static vtab_module<lnav_file> LNAV_FILE_MODULE;
auto mod = new vtab_module<lnav_file>(fc);
int rc;
rc = LNAV_FILE_MODULE.create(db, "lnav_file");
rc = mod->create(db, "lnav_file");
ensure(rc == SQLITE_OK);

View File

@ -32,6 +32,8 @@
#include <sqlite3.h>
int register_file_vtab(sqlite3 *db);
#include "file_collection.hh"
int register_file_vtab(sqlite3 *db, file_collection &fc);
#endif

View File

@ -31,11 +31,8 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <unistd.h>
#include <string>
@ -158,7 +155,7 @@ string sql_realpath(const char *path)
{
char resolved_path[PATH_MAX];
if (realpath(path, resolved_path) == NULL) {
if (realpath(path, resolved_path) == nullptr) {
throw sqlite_func_error("Could not get real path for {} -- {}",
path, strerror(errno));
}
@ -280,11 +277,11 @@ int fs_extension_functions(struct FuncDef **basic_funcs,
* TODO: add other functions like normpath, ...
*/
{ NULL }
{ nullptr }
};
*basic_funcs = fs_funcs;
*agg_funcs = NULL;
*agg_funcs = nullptr;
return SQLITE_OK;
}

View File

@ -89,14 +89,6 @@ CREATE TABLE fstat (
);
)";
struct vtab {
sqlite3_vtab base;
operator sqlite3_vtab *() {
return &this->base;
};
};
struct cursor {
sqlite3_vtab_cursor base;
string c_pattern;

View File

@ -34,11 +34,9 @@
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "base/lnav_log.hh"
@ -47,8 +45,6 @@
#include "grep_proc.hh"
#include "listview_curses.hh"
#include "time_T.hh"
using namespace std;
template<typename LineType>
@ -132,7 +128,7 @@ void grep_proc<LineType>::start()
log_perror(fcntl(err_pipe.read_end(), F_SETFL, O_NONBLOCK));
log_perror(fcntl(err_pipe.read_end(), F_SETFD, 1));
require(this->gp_err_pipe.get() == -1);
this->gp_err_pipe = err_pipe.read_end();
this->gp_err_pipe = std::move(err_pipe.read_end());
this->gp_child_started = true;
this->gp_child_queue_size = this->gp_queue.size();

View File

@ -100,7 +100,7 @@ public:
class grep_proc_control {
public:
virtual ~grep_proc_control() { };
virtual ~grep_proc_control() = default;
/** @param msg The error encountered while attempting the grep. */
virtual void grep_error(std::string msg) { };

View File

@ -30,9 +30,9 @@
#include "config.h"
#include <algorithm>
#include <regex>
#include <pcrecpp.h>
#include "base/string_util.hh"
#include "fmt/format.h"
#include "ansi_scrubber.hh"
#include "help_text_formatter.hh"
@ -451,7 +451,7 @@ void format_example_text_for_term(const help_text &ht,
static std::string link_name(const help_text &ht)
{
const static pcrecpp::RE SCRUBBER("[^\\w_]");
const static std::regex SCRUBBER("[^\\w_]");
auto scrubbed_name = string(ht.ht_name);
for (auto &param : ht.ht_parameters) {
@ -462,7 +462,7 @@ static std::string link_name(const help_text &ht)
scrubbed_name += "_";
scrubbed_name += param.ht_flag_name;
}
SCRUBBER.GlobalReplace("_", &scrubbed_name);
scrubbed_name = std::regex_replace(scrubbed_name, SCRUBBER, "_");
return tolower(scrubbed_name);
}
@ -600,8 +600,8 @@ void format_help_text_for_rst(const help_text &ht,
}
stable_sort(related_refs.begin(), related_refs.end());
fprintf(rst_file, " **See Also:**\n\n %s\n",
join(related_refs.begin(), related_refs.end(), ", ").c_str());
fmt::print(rst_file, " **See Also:**\n\n {}\n",
fmt::join(related_refs, ", "));
}
fprintf(rst_file, "\n----\n\n");

View File

@ -1,3 +1,31 @@
/**
* Copyright (c) 2020, 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"

View File

@ -73,7 +73,7 @@ void hist_source2::text_value_for_line(textview_curses &tc, int row,
char tm_buffer[128];
char line[256];
if (gmtime_r(&bucket.b_time, &bucket_tm) != NULL) {
if (gmtime_r(&bucket.b_time, &bucket_tm) != nullptr) {
strftime(tm_buffer, sizeof(tm_buffer),
" %a %b %d %H:%M:%S ",
&bucket_tm);

View File

@ -37,15 +37,11 @@
#include "pretty_printer.hh"
#include "sysclip.hh"
#include "log_data_helper.hh"
#include "session_data.hh"
#include "command_executor.hh"
#include "termios_guard.hh"
#include "readline_callbacks.hh"
#include "readline_possibilities.hh"
#include "readline_highlighters.hh"
#include "field_overlay_source.hh"
#include "hotkeys.hh"
#include "log_format_loader.hh"
#include "base/opt_util.hh"
#include "shlex.hh"
@ -408,7 +404,7 @@ bool handle_paging_key(int ch)
tc->get_dimensions(height, width);
if (lnav_data.ld_last_user_mark[tc] > (tc->get_bottom() - 2) &&
tc->get_top() + height < tc->get_inner_height()) {
tc->shift_top(vis_line_t(1));
tc->shift_top(1_vl);
}
if (lnav_data.ld_last_user_mark[tc] + 1 >=
tc->get_inner_height()) {
@ -441,7 +437,7 @@ bool handle_paging_key(int ch)
tc->toggle_user_mark(&textview_curses::BM_USER,
vis_line_t(new_mark));
if (new_mark == tc->get_top()) {
tc->shift_top(vis_line_t(-1));
tc->shift_top(-1_vl);
}
if (new_mark > 0) {
lnav_data.ld_last_user_mark[tc] = new_mark - 1;
@ -872,7 +868,6 @@ bool handle_paging_key(int ch)
auto index = distance(fc.fc_files.begin(), iter);
auto index_vl = vis_line_t(index);
log_debug("index %d", index);
lnav_data.ld_files_view.set_top(index_vl);
lnav_data.ld_files_view.set_selection(index_vl);
}

View File

@ -274,7 +274,7 @@ line_buffer::line_buffer()
lb_seekable(false),
lb_last_line_offset(-1)
{
if ((this->lb_buffer = (char *)malloc(this->lb_buffer_max)) == NULL) {
if ((this->lb_buffer = (char *)malloc(this->lb_buffer_max)) == nullptr) {
throw bad_alloc();
}
@ -283,11 +283,11 @@ line_buffer::line_buffer()
line_buffer::~line_buffer()
{
auto_fd fd = -1;
auto empty_fd = auto_fd();
// Make sure any shared refs take ownership of the data.
this->lb_share_manager.invalidate_refs();
this->set_fd(fd);
this->set_fd(empty_fd);
}
void line_buffer::set_fd(auto_fd &fd)
@ -356,7 +356,7 @@ void line_buffer::set_fd(auto_fd &fd)
}
this->lb_file_offset = newoff;
this->lb_buffer_size = 0;
this->lb_fd = fd;
this->lb_fd = std::move(fd);
ensure(this->invariant());
}

View File

@ -238,7 +238,7 @@ public:
};
/** Check the invariants for this object. */
bool invariant(void)
bool invariant()
{
require(this->lb_buffer != NULL);
require(this->lb_buffer_size <= this->lb_buffer_max);

View File

@ -202,7 +202,7 @@ void listview_curses::do_update()
while (y < bottom) {
lr.lr_start = this->lv_left;
lr.lr_end = this->lv_left + wrap_width;
if (this->lv_overlay_source != NULL &&
if (this->lv_overlay_source != nullptr &&
this->lv_overlay_source->list_value_for_overlay(
*this,
y - this->lv_y, bottom - this->lv_y,

View File

@ -487,12 +487,12 @@ public:
/** @return The number of rows of data in this view's source data. */
vis_line_t get_inner_height() const
{
return vis_line_t(this->lv_source == NULL ? 0 :
return vis_line_t(this->lv_source == nullptr ? 0 :
this->lv_source->listview_rows(*this));
};
size_t get_inner_width() const {
return this->lv_source == NULL ? 0 :
return this->lv_source == nullptr ? 0 :
this->lv_source->listview_width(*this);
};

View File

@ -67,9 +67,6 @@
#include <set>
#include <stack>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
@ -147,7 +144,6 @@
#include "readline_possibilities.hh"
#include "field_overlay_source.hh"
#include "url_loader.hh"
#include "log_search_table.hh"
#include "shlex.hh"
#include "log_actions.hh"
#include "archive_manager.hh"
@ -161,7 +157,7 @@ using namespace std::literals::chrono_literals;
static multimap<lnav_flags_t, string> DEFAULT_FILES;
struct _lnav_data lnav_data;
struct lnav_data_t lnav_data;
const int ZOOM_LEVELS[] = {
1,
@ -258,7 +254,7 @@ bool setup_logline_table(exec_context &ec)
textview_curses &log_view = lnav_data.ld_views[LNV_LOG];
bool retval = false;
bool update_possibilities = (
lnav_data.ld_rl_view != NULL &&
lnav_data.ld_rl_view != nullptr &&
ec.ec_local_vars.size() == 1);
if (update_possibilities) {
@ -559,7 +555,7 @@ void rebuild_indexes()
if (tss->current_file() != cb.front_file) {
tss->to_front(cb.front_file);
old_bottoms[LNV_TEXT] = vis_line_t(-1);
old_bottoms[LNV_TEXT] = -1_vl;
}
if (cb.front_top < 0) {
@ -659,31 +655,31 @@ static bool append_default_files(lnav_flags_t flag)
bool retval = true;
if (lnav_data.ld_flags & flag) {
auto cwd = ghc::filesystem::current_path();
pair<multimap<lnav_flags_t, string>::iterator,
multimap<lnav_flags_t, string>::iterator> range;
for (range = DEFAULT_FILES.equal_range(flag);
range.first != range.second;
range.first++) {
string path = range.first->second;
string path = range.first->second;
struct stat st;
if (access(path.c_str(), R_OK) == 0) {
auto_mem<char> abspath;
path = get_current_dir() + range.first->second;
if ((abspath = realpath(path.c_str(), NULL)) == NULL) {
path = cwd / range.first->second;
if ((abspath = realpath(path.c_str(), nullptr)) == nullptr) {
perror("Unable to resolve path");
}
else {
logfile_open_options default_loo;
lnav_data.ld_active_files.fc_file_names[abspath.in()] = default_loo;
lnav_data.ld_active_files.fc_file_names[abspath.in()];
}
}
else if (stat(path.c_str(), &st) == 0) {
fprintf(stderr,
"error: cannot read -- %s%s\n",
get_current_dir().c_str(),
cwd.c_str(),
path.c_str());
retval = false;
}
@ -751,7 +747,7 @@ vis_line_t next_cluster(
return last_top;
}
return vis_line_t(-1);
return -1_vl;
}
bool moveto_cluster(vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t) const,
@ -806,7 +802,7 @@ void previous_cluster(bookmark_type_t *bt, textview_curses *tc)
initial_top < (krh.krh_start_line - (1.5 * height)) &&
(initial_top - new_top) < height) {
bookmark_vector<vis_line_t> &bv = tc->get_bookmarks()[bt];
new_top = bv.next(std::max(vis_line_t(0), initial_top - height));
new_top = bv.next(std::max(0_vl, initial_top - height));
}
if (new_top != -1) {
@ -937,380 +933,23 @@ static void clear_last_user_mark(void *, listview_curses *lv)
}
}
/**
* Functor used to compare files based on their device and inode number.
*/
struct same_file {
same_file(const struct stat &stat) : sf_stat(stat) { };
/**
* Compare the given log file against the 'stat' given in the constructor.
* @param lf The log file to compare.
* @return True if the dev/inode values in the stat given in the
* constructor matches the stat in the logfile object.
*/
bool operator()(const shared_ptr<logfile> &lf) const
{
return this->sf_stat.st_dev == lf->get_stat().st_dev &&
this->sf_stat.st_ino == lf->get_stat().st_ino;
};
const struct stat &sf_stat;
};
static std::mutex REALPATH_CACHE_MUTEX;
static std::unordered_map<std::string, std::string> REALPATH_CACHE;
void file_collection::close_file(const std::shared_ptr<logfile> &lf)
{
if (lf->is_valid_filename()) {
std::lock_guard<std::mutex> lg(REALPATH_CACHE_MUTEX);
REALPATH_CACHE.erase(lf->get_filename());
} else {
this->fc_file_names.erase(lf->get_filename());
}
auto file_iter = find(this->fc_files.begin(),
this->fc_files.end(),
lf);
if (file_iter != this->fc_files.end()) {
this->fc_files.erase(file_iter);
this->fc_files_generation += 1;
}
this->regenerate_unique_file_names();
}
void file_collection::regenerate_unique_file_names()
{
unique_path_generator upg;
for (const auto& lf : this->fc_files) {
upg.add_source(lf);
}
upg.generate();
this->fc_largest_path_length = 0;
for (const auto& lf : this->fc_files) {
const auto& path = lf->get_unique_path();
if (path.length() > this->fc_largest_path_length) {
this->fc_largest_path_length = path.length();
}
}
for (const auto& pair : this->fc_other_files) {
auto bn = ghc::filesystem::path(pair.first).filename().string();
if (bn.length() > this->fc_largest_path_length) {
this->fc_largest_path_length = bn.length();
}
}
}
void file_collection::merge(const file_collection& other)
{
this->fc_name_to_errors.insert(other.fc_name_to_errors.begin(),
other.fc_name_to_errors.end());
this->fc_file_names.insert(other.fc_file_names.begin(),
other.fc_file_names.end());
if (!other.fc_files.empty()) {
this->fc_files.insert(this->fc_files.end(),
other.fc_files.begin(),
other.fc_files.end());
this->fc_files_generation += 1;
}
for (auto& pair : other.fc_renamed_files) {
pair.first->set_filename(pair.second);
}
this->fc_closed_files.insert(other.fc_closed_files.begin(),
other.fc_closed_files.end());
this->fc_other_files.insert(other.fc_other_files.begin(),
other.fc_other_files.end());
}
/**
* Try to load the given file as a log file. If the file has not already been
* loaded, it will be loaded. If the file has already been loaded, the file
* name will be updated.
*
* @param filename The file name to check.
* @param fd An already-opened descriptor for 'filename'.
* @param required Specifies whether or not the file must exist and be valid.
*/
std::future<file_collection>
file_collection::watch_logfile(const string& filename, logfile_open_options &loo, bool required)
bool update_active_files(const file_collection& new_files)
{
static loading_observer obs;
file_collection retval;
struct stat st;
int rc;
if (this->fc_closed_files.count(filename)) {
return make_ready_future(retval);
}
if (loo.loo_fd != -1) {
rc = fstat(loo.loo_fd, &st);
}
else {
rc = stat(filename.c_str(), &st);
}
if (rc == 0) {
if (S_ISDIR(st.st_mode) && lnav_data.ld_flags & LNF_RECURSIVE) {
string wilddir = filename + "/*";
if (this->fc_file_names.find(wilddir) == this->fc_file_names.end()) {
logfile_open_options default_loo;
retval.fc_file_names[wilddir] = default_loo;
}
return make_ready_future(retval);
}
if (!S_ISREG(st.st_mode)) {
if (required) {
rc = -1;
errno = EINVAL;
}
else {
return make_ready_future(retval);
}
}
}
if (rc == -1) {
if (required) {
retval.fc_name_to_errors[filename] = strerror(errno);
}
return make_ready_future(retval);
}
auto file_iter = find_if(this->fc_files.begin(),
this->fc_files.end(),
same_file(st));
if (file_iter == this->fc_files.end()) {
if (this->fc_other_files.find(filename) != this->fc_other_files.end()) {
return make_ready_future(retval);
}
return std::async(std::launch::async, [filename, &loo, prog=this->fc_progress, errs=this->fc_name_to_errors]() {
file_collection retval;
if (errs.find(filename) != errs.end()) {
// The file is broken, no reason to try and reopen
return retval;
}
file_format_t ff = detect_file_format(filename);
switch (ff) {
case file_format_t::FF_SQLITE_DB:
attach_sqlite_db(lnav_data.ld_db.in(), filename);
retval.fc_other_files[filename] = "SQLite Database";
break;
case file_format_t::FF_ARCHIVE: {
nonstd::optional<std::list<archive_manager::extract_progress>::iterator>
prog_iter_opt;
auto res = archive_manager::walk_archive_files(
filename,
[prog, &prog_iter_opt](
const auto& path, const auto total) {
safe::WriteAccess<safe_scan_progress> sp(*prog);
prog_iter_opt | [&sp](auto prog_iter) {
sp->sp_extractions.erase(prog_iter);
};
auto prog_iter = sp->sp_extractions.emplace(
sp->sp_extractions.begin(), path, total);
prog_iter_opt = prog_iter;
return &(*prog_iter);
},
[&filename, &retval](const auto& tmp_path,
const auto& entry) {
auto ext = entry.path().extension();
if (ext == ".jar" || ext == ".war" || ext == ".zip") {
return;
}
auto arc_path = ghc::filesystem::relative(
entry.path(), tmp_path);
auto custom_name = filename / arc_path;
bool is_visible = true;
if (entry.file_size() == 0) {
log_info("hiding empty archive file: %s",
entry.path().c_str());
is_visible = false;
}
log_info("adding file from archive: %s/%s",
filename.c_str(),
entry.path().c_str());
retval.fc_file_names[entry.path().string()] =
logfile_open_options()
.with_filename(custom_name.string())
.with_visibility(is_visible)
.with_non_utf_visibility(false)
.with_visible_size_limit(128 * 1024);
});
if (res.isErr()) {
log_error("archive extraction failed: %s",
res.unwrapErr().c_str());
retval.clear();
retval.fc_name_to_errors[filename] = res.unwrapErr();
} else {
retval.fc_other_files[filename] = "Archive";
}
{
prog_iter_opt | [&prog](auto prog_iter) {
prog->writeAccess()->sp_extractions.erase(prog_iter);
};
}
break;
}
default:
log_info("loading new file: filename=%s",
filename.c_str());
/* It's a new file, load it in. */
try {
shared_ptr<logfile> lf = make_shared<logfile>(filename,
loo);
lf->set_logfile_observer(&obs);
retval.fc_files.push_back(lf);
} catch (logfile::error& e) {
retval.fc_name_to_errors[filename] = e.what();
}
break;
}
return retval;
});
}
else {
auto lf = *file_iter;
if (lf->is_valid_filename() && lf->get_filename() != filename) {
/* The file is already loaded, but has been found under a different
* name. We just need to update the stored file name.
*/
retval.fc_renamed_files.emplace_back(lf, filename);
}
}
return make_ready_future(retval);
}
/**
* Expand a glob pattern and call watch_logfile with the file names that match
* the pattern.
* @param path The glob pattern to expand.
* @param required Passed to watch_logfile.
*/
void file_collection::expand_filename(future_queue<file_collection> &fq,
const string& path,
logfile_open_options &loo,
bool required)
{
static_root_mem<glob_t, globfree> gl;
{
std::lock_guard<std::mutex> lg(REALPATH_CACHE_MUTEX);
if (REALPATH_CACHE.find(path) != REALPATH_CACHE.end()) {
return;
}
}
if (is_url(path.c_str())) {
return;
}
else if (glob(path.c_str(), GLOB_NOCHECK, nullptr, gl.inout()) == 0) {
int lpc;
if (gl->gl_pathc == 1 /*&& gl.gl_matchc == 0*/) {
/* It's a pattern that doesn't match any files
* yet, allow it through since we'll load it in
* dynamically.
*/
if (access(path.c_str(), F_OK) == -1) {
required = false;
}
}
if (gl->gl_pathc > 1 ||
strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
required = false;
}
std::lock_guard<std::mutex> lg(REALPATH_CACHE_MUTEX);
for (lpc = 0; lpc < (int)gl->gl_pathc; lpc++) {
auto path_str = std::string(gl->gl_pathv[lpc]);
auto iter = REALPATH_CACHE.find(path_str);
if (iter == REALPATH_CACHE.end()) {
auto_mem<char> abspath;
if ((abspath = realpath(gl->gl_pathv[lpc], nullptr)) ==
nullptr) {
if (required) {
fprintf(stderr, "Cannot find file: %s -- %s",
gl->gl_pathv[lpc], strerror(errno));
}
continue;
} else {
auto p = REALPATH_CACHE.emplace(path_str, abspath.in());
iter = p.first;
}
}
if (required || access(iter->second.c_str(), R_OK) == 0) {
fq.push_back(watch_logfile(iter->second, loo, required));
}
}
}
}
file_collection file_collection::rescan_files(bool required)
{
file_collection retval;
future_queue<file_collection> fq([&retval](auto& fc) {
retval.merge(fc);
});
for (auto& pair : this->fc_file_names) {
if (pair.second.loo_fd == -1) {
this->expand_filename(fq, pair.first, pair.second, required);
if (lnav_data.ld_flags & LNF_ROTATED) {
string path = pair.first + ".*";
this->expand_filename(fq, path, pair.second, false);
}
} else {
fq.push_back(watch_logfile(pair.first, pair.second, required));
}
if (retval.fc_files.size() >= 100) {
log_debug("too many new files, breaking...");
break;
}
}
fq.pop_to();
return retval;
}
bool update_active_files(const file_collection& new_files)
{
for (const auto& lf : new_files.fc_files) {
lf->set_logfile_observer(&obs);
lnav_data.ld_text_source.push_back(lf);
}
for (const auto& other_pair : new_files.fc_other_files) {
switch (other_pair.second) {
case file_format_t::FF_SQLITE_DB:
attach_sqlite_db(lnav_data.ld_db.in(), other_pair.first);
break;
default:
break;
}
}
lnav_data.ld_active_files.merge(new_files);
if (!new_files.fc_files.empty()) {
lnav_data.ld_active_files.regenerate_unique_file_names();
@ -2055,7 +1694,7 @@ static void looper()
lnav_data.ld_log_source.text_line_count() == 0 &&
lnav_data.ld_text_source.text_line_count() > 0) {
ensure_view(&lnav_data.ld_views[LNV_TEXT]);
lnav_data.ld_views[LNV_TEXT].set_top(vis_line_t(0));
lnav_data.ld_views[LNV_TEXT].set_top(0_vl);
lnav_data.ld_rl_view->set_alt_value(
HELP_MSG_2(f, F,
"to switch to the next/previous file"));
@ -2377,11 +2016,11 @@ int main(int argc, char *argv[])
break;
case 'R':
lnav_data.ld_flags |= LNF_ROTATED;
lnav_data.ld_active_files.fc_rotated = true;
break;
case 'r':
lnav_data.ld_flags |= LNF_RECURSIVE;
lnav_data.ld_active_files.fc_recursive = true;
break;
case 't':
@ -2555,7 +2194,7 @@ int main(int argc, char *argv[])
register_environ_vtab(lnav_data.ld_db.in());
register_views_vtab(lnav_data.ld_db.in());
register_file_vtab(lnav_data.ld_db.in());
register_file_vtab(lnav_data.ld_db.in(), lnav_data.ld_active_files);
register_regexp_vtab(lnav_data.ld_db.in());
register_fstat_vtab(lnav_data.ld_db.in());
@ -2613,12 +2252,17 @@ int main(int argc, char *argv[])
lnav_data.ld_views[LNV_HELP]
.set_sub_source(&lnav_data.ld_help_source)
.set_word_wrap(true);
auto log_fos = new field_overlay_source(lnav_data.ld_log_source,
lnav_data.ld_text_source);
if (lnav_data.ld_flags & LNF_HEADLESS) {
log_fos->fos_show_status = false;
}
lnav_data.ld_views[LNV_LOG]
.set_sub_source(&lnav_data.ld_log_source)
.set_delegate(new action_delegate(lnav_data.ld_log_source))
.add_input_delegate(lnav_data.ld_log_source)
.set_tail_space(vis_line_t(2))
.set_overlay_source(new field_overlay_source(lnav_data.ld_log_source));
.set_tail_space(2_vl)
.set_overlay_source(log_fos);
lnav_data.ld_views[LNV_TEXT]
.set_sub_source(&lnav_data.ld_text_source);
lnav_data.ld_views[LNV_HISTOGRAM]
@ -2632,7 +2276,7 @@ int main(int argc, char *argv[])
.set_sub_source(&lnav_data.ld_spectro_source)
.set_overlay_source(&lnav_data.ld_spectro_source)
.add_input_delegate(lnav_data.ld_spectro_source)
.set_tail_space(vis_line_t(2));
.set_tail_space(2_vl);
lnav_data.ld_doc_view.set_sub_source(&lnav_data.ld_doc_source);
lnav_data.ld_example_view.set_sub_source(&lnav_data.ld_example_source);
@ -2741,7 +2385,6 @@ int main(int argc, char *argv[])
}
for (lpc = 0; lpc < argc; lpc++) {
logfile_open_options default_loo;
auto_mem<char> abspath;
struct stat st;
@ -2763,7 +2406,8 @@ int main(int argc, char *argv[])
}
#endif
else if (is_glob(argv[lpc])) {
lnav_data.ld_active_files.fc_file_names[argv[lpc]] = default_loo;
lnav_data.ld_active_files.fc_file_names
.emplace(argv[lpc], logfile_open_options());
}
else if (stat(argv[lpc], &st) == -1) {
fprintf(stderr,
@ -2792,13 +2436,14 @@ int main(int argc, char *argv[])
auto fifo_piper = make_shared<piper_proc>(
fifo_fd.release(),
false,
open_temp_file(system_tmpdir() / "lnav.fifo.XXXXXX")
open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.fifo.XXXXXX")
.then([](auto pair) {
ghc::filesystem::remove(pair.first);
})
.expect("Cannot create temporary file for FIFO")
.second);
int fifo_out_fd = fifo_piper->get_fd();
auto fifo_out_fd = fifo_piper->get_fd();
char desc[128];
snprintf(desc, sizeof(desc),
@ -2819,10 +2464,12 @@ int main(int argc, char *argv[])
if (dir_wild[dir_wild.size() - 1] == '/') {
dir_wild.resize(dir_wild.size() - 1);
}
lnav_data.ld_active_files.fc_file_names[dir_wild + "/*"] = default_loo;
lnav_data.ld_active_files.fc_file_names
.emplace(dir_wild + "/*", logfile_open_options());
}
else {
lnav_data.ld_active_files.fc_file_names[abspath.in()] = default_loo;
lnav_data.ld_active_files.fc_file_names
.emplace(abspath.in(), logfile_open_options());
}
}
@ -2915,7 +2562,7 @@ int main(int argc, char *argv[])
stdin_reader = make_shared<piper_proc>(
STDIN_FILENO, lnav_data.ld_flags & LNF_TIMESTAMP, stdin_out_fd);
lnav_data.ld_active_files.fc_file_names["stdin"]
.with_fd(stdin_out_fd)
.with_fd(auto_fd(stdin_out_fd))
.with_include_in_session(false);
lnav_data.ld_pipers.push_back(stdin_reader);
}
@ -2993,15 +2640,15 @@ int main(int argc, char *argv[])
alerter::singleton().enabled(false);
log_tc = &lnav_data.ld_views[LNV_LOG];
log_tc->set_height(vis_line_t(24));
log_tc->set_height(24_vl);
lnav_data.ld_view_stack.vs_views.push_back(log_tc);
// Read all of stdin
wait_for_pipers();
rebuild_indexes();
log_tc->set_top(vis_line_t(0));
log_tc->set_top(0_vl);
text_tc = &lnav_data.ld_views[LNV_TEXT];
text_tc->set_top(vis_line_t(0));
text_tc->set_top(0_vl);
text_tc->set_height(vis_line_t(text_tc->get_inner_height()));
if (lnav_data.ld_log_source.text_line_count() == 0 &&
lnav_data.ld_text_source.text_line_count() > 0) {

View File

@ -73,6 +73,8 @@
#include "preview_status_source.hh"
#include "sql_util.hh"
#include "archive_manager.hh"
#include "file_collection.hh"
#include "view_helpers.hh"
/** The command modes that are available while viewing a file. */
typedef enum {
@ -97,8 +99,6 @@ enum {
LNB_HELP,
LNB_HEADLESS,
LNB_QUIET,
LNB_ROTATED,
LNB_RECURSIVE,
LNB_CHECK_CONFIG,
LNB_INSTALL,
LNB_UPDATE_FORMATS,
@ -110,9 +110,6 @@ enum {
typedef enum {
LNF_SYSLOG = (1L << LNB_SYSLOG),
LNF_ROTATED = (1L << LNB_ROTATED),
LNF_RECURSIVE = (1L << LNB_RECURSIVE),
LNF_TIMESTAMP = (1L << LNB_TIMESTAMP),
LNF_HELP = (1L << LNB_HELP),
LNF_HEADLESS = (1L << LNB_HEADLESS),
@ -126,22 +123,6 @@ typedef enum {
LNF__ALL = (LNF_SYSLOG|LNF_HELP),
} lnav_flags_t;
/** The different views available. */
typedef enum {
LNV_LOG,
LNV_TEXT,
LNV_HELP,
LNV_HISTOGRAM,
LNV_DB,
LNV_SCHEMA,
LNV_PRETTY,
LNV_SPECTRO,
LNV__MAX
} lnav_view_t;
extern const char *lnav_view_strings[LNV__MAX + 1];
extern const char *lnav_zoom_strings[];
/** The status bars. */
@ -157,7 +138,7 @@ typedef enum {
} lnav_status_t;
typedef std::pair<int, int> ppid_time_pair_t;
typedef std::pair<ppid_time_pair_t, std::string> session_pair_t;
typedef std::pair<ppid_time_pair_t, ghc::filesystem::path> session_pair_t;
class input_state_tracker : public log_state_dumper {
public:
@ -165,7 +146,7 @@ public:
memset(this->ist_recent_key_presses, 0, sizeof(this->ist_recent_key_presses));
};
void log_state() {
void log_state() override {
log_info("recent_key_presses: index=%d", this->ist_index);
for (int lpc = 0; lpc < COUNT; lpc++) {
log_msg_extra(" 0x%x (%c)", this->ist_recent_key_presses[lpc],
@ -195,7 +176,7 @@ struct key_repeat_history {
void update(int ch, vis_line_t top) {
struct timeval now, diff;
gettimeofday(&now, NULL);
gettimeofday(&now, nullptr);
timersub(&now, &this->krh_last_press_time, &diff);
if (diff.tv_sec >= 1 || diff.tv_usec > (750 * 1000)) {
this->krh_key = 0;
@ -213,44 +194,7 @@ struct key_repeat_history {
};
};
struct scan_progress {
std::list<archive_manager::extract_progress> sp_extractions;
};
using safe_scan_progress = safe::Safe<scan_progress>;
struct file_collection {
std::map<std::string, std::string> fc_name_to_errors;
std::map<std::string, logfile_open_options> fc_file_names;
std::vector<std::shared_ptr<logfile>> fc_files;
int fc_files_generation{0};
std::vector<std::pair<std::shared_ptr<logfile>, std::string>>
fc_renamed_files;
std::set<std::string> fc_closed_files;
std::map<std::string, std::string> fc_other_files;
std::shared_ptr<safe_scan_progress> fc_progress;
size_t fc_largest_path_length{0};
file_collection()
: fc_progress(std::make_shared<safe::Safe<scan_progress>>()) {}
void clear() {
this->fc_name_to_errors.clear();
this->fc_file_names.clear();
this->fc_files.clear();
this->fc_closed_files.clear();
this->fc_other_files.clear();
}
file_collection rescan_files(bool required = false);
void expand_filename(future_queue<file_collection> &fq, const std::string& path, logfile_open_options &loo, bool required);
std::future<file_collection>
watch_logfile(const std::string& filename, logfile_open_options &loo, bool required);
void merge(const file_collection &other);
void close_file(const std::shared_ptr<logfile> &lf);
void regenerate_unique_file_names();
};
struct _lnav_data {
struct lnav_data_t {
std::map<std::string, std::list<session_pair_t>> ld_session_id;
time_t ld_session_time;
time_t ld_session_load_time;
@ -353,7 +297,7 @@ struct _lnav_data {
struct key_repeat_history ld_key_repeat_history;
};
extern struct _lnav_data lnav_data;
extern struct lnav_data_t lnav_data;
extern readline_context::command_map_t lnav_commands;
extern const int ZOOM_LEVELS[];
@ -367,12 +311,6 @@ extern const ssize_t ZOOM_COUNT;
void rebuild_hist();
void rebuild_indexes();
void execute_examples();
attr_line_t eval_example(const help_text &ht, const help_example &ex);
bool ensure_view(textview_curses *expected_tc);
bool toggle_view(textview_curses *toggle_tc);
void layout_views();
bool setup_logline_table(exec_context &ec);

View File

@ -610,10 +610,7 @@ static void write_line_to(FILE *outfile, const attr_line_t &al)
fprintf(outfile, " // %s\n", bm->bm_comment.c_str());
}
if (!bm->bm_tags.empty()) {
fprintf(outfile, " -- %s\n",
join(bm->bm_tags.begin(),
bm->bm_tags.end(),
" ").c_str());
fmt::print(outfile, " -- {}\n", fmt::join(bm->bm_tags, " "));
}
}
}
@ -921,7 +918,7 @@ static Result<string, string> com_save_to(exec_context &ec, string cmdline, vect
lnav_data.ld_preview_source
.replace_with(al)
.set_text_format(detect_text_format(buffer, rc))
.set_text_format(detect_text_format(al.get_string()))
.truncate_to(10);
lnav_data.ld_preview_status_source.get_description()
.set_value("First lines of file: %s", fn.c_str());
@ -1827,7 +1824,6 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
}
}
if (file_iter == lnav_data.ld_active_files.fc_files.end()) {
logfile_open_options default_loo;
auto_mem<char> abspath;
struct stat st;
@ -1849,7 +1845,7 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
#endif
}
else if (is_glob(fn.c_str())) {
file_names[fn] = default_loo;
file_names.emplace(fn, logfile_open_options());
retval = "info: watching -- " + fn;
}
else if (stat(fn.c_str(), &st) == -1) {
@ -1871,13 +1867,14 @@ 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(system_tmpdir() / "lnav.fifo.XXXXXX")
open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.fifo.XXXXXX")
.then([](auto pair) {
ghc::filesystem::remove(pair.first);
})
.expect("Cannot create temporary file for FIFO")
.second);
int fifo_out_fd = fifo_piper->get_fd();
auto fifo_out_fd = fifo_piper->get_fd();
char desc[128];
snprintf(desc, sizeof(desc),
@ -1888,7 +1885,7 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
lnav_data.ld_pipers.push_back(fifo_piper);
}
}
else if ((abspath = realpath(fn.c_str(), NULL)) == NULL) {
else if ((abspath = realpath(fn.c_str(), nullptr)) == nullptr) {
return ec.make_error("cannot find file -- {}", fn);
}
else if (S_ISDIR(st.st_mode)) {
@ -1897,7 +1894,7 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
if (dir_wild[dir_wild.size() - 1] == '/') {
dir_wild.resize(dir_wild.size() - 1);
}
file_names[dir_wild + "/*"] = default_loo;
file_names.emplace(dir_wild + "/*", logfile_open_options());
retval = "info: watching -- " + dir_wild;
}
else if (!S_ISREG(st.st_mode)) {
@ -1910,12 +1907,12 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
}
else {
fn = abspath.in();
file_names[fn] = default_loo;
file_names.emplace(fn, logfile_open_options());
retval = "info: opened -- " + fn;
files_to_front.emplace_back(fn, top);
closed_files.push_back(fn);
if (lnav_data.ld_rl_view != NULL) {
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
X, "to close the file"));
}
@ -1933,7 +1930,7 @@ static Result<string, string> com_open(exec_context &ec, string cmdline, vector<
if (is_glob(fn.c_str())) {
static_root_mem<glob_t, globfree> gl;
if (glob(fn.c_str(), GLOB_NOCHECK, NULL, gl.inout()) == 0) {
if (glob(fn.c_str(), GLOB_NOCHECK, nullptr, gl.inout()) == 0) {
attr_line_t al;
for (size_t lpc = 0; lpc < gl->gl_pathc && lpc < 10; lpc++) {
@ -2547,7 +2544,7 @@ static Result<string, string> com_pt_time(exec_context &ec, string cmdline, vect
new_time.tv_sec = timegm(&tm.et_tm);
}
else {
dts.scan(args[1].c_str(), args[1].size(), NULL, &tm, new_time);
dts.scan(args[1].c_str(), args[1].size(), nullptr, &tm, new_time);
}
if (ec.ec_dry_run) {
retval = "";
@ -2607,7 +2604,7 @@ static Result<string, string> com_summarize(exec_context &ec, string cmdline, ve
query.c_str(),
-1,
stmt.out(),
NULL);
nullptr);
if (retcode != SQLITE_OK) {
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
@ -2729,14 +2726,14 @@ static Result<string, string> com_summarize(exec_context &ec, string cmdline, ve
query.c_str(),
-1,
stmt.out(),
NULL);
nullptr);
if (retcode != SQLITE_OK) {
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
return ec.make_error("{}", errmsg);
}
else if (stmt == NULL) {
else if (stmt == nullptr) {
retval = "";
}
else {
@ -2814,7 +2811,7 @@ static Result<string, string> com_add_test(exec_context &ec, string cmdline, vec
getenv("LNAV_SRC"),
hash_string(line).c_str());
if ((file = fopen(path, "w")) == NULL) {
if ((file = fopen(path, "w")) == nullptr) {
perror("fopen failed");
}
else {
@ -3041,7 +3038,7 @@ static Result<string, string> com_toggle_field(exec_context &ec, string cmdline,
if (format->hide_field(name, hide)) {
found_fields.push_back(args[lpc]);
if (hide) {
if (lnav_data.ld_rl_view != NULL) {
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_alt_value(
HELP_MSG_1(x, "to quickly show hidden fields"));
}
@ -3053,21 +3050,13 @@ static Result<string, string> com_toggle_field(exec_context &ec, string cmdline,
}
if (missing_fields.empty()) {
string all_fields = join(found_fields.begin(),
found_fields.end(),
", ");
if (hide) {
retval = "info: hiding field(s) -- " + all_fields;
} else {
retval = "info: showing field(s) -- " + all_fields;
}
auto visibility = hide ? "hiding" : "showing";
retval = fmt::format("info: {} field(s) -- {}",
visibility,
fmt::join(found_fields, ", "));
} else {
string all_fields = join(missing_fields.begin(),
missing_fields.end(),
", ");
return ec.make_error("unknown field(s) -- {}", all_fields);
return ec.make_error("unknown field(s) -- {}",
fmt::join(missing_fields, ", "));
}
}
}
@ -3349,7 +3338,7 @@ static Result<string, string> com_alt_msg(exec_context &ec, string cmdline, vect
retval = "";
}
else if (args.size() == 1) {
if (lnav_data.ld_rl_view != NULL) {
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_alt_value("");
}
retval = "";
@ -3357,7 +3346,7 @@ static Result<string, string> com_alt_msg(exec_context &ec, string cmdline, vect
else {
string msg = remaining_args(cmdline, args);
if (lnav_data.ld_rl_view != NULL) {
if (lnav_data.ld_rl_view != nullptr) {
lnav_data.ld_rl_view->set_alt_value(msg);
}
@ -3474,8 +3463,7 @@ static Result<string, string> com_config(exec_context &ec, string cmdline, vecto
lnav_data.ld_preview_source
.replace_with(al)
.set_text_format(detect_text_format(old_value.c_str(),
old_value.size()))
.set_text_format(detect_text_format(old_value))
.truncate_to(10);
lnav_data.ld_preview_status_source.get_description()
.set_value("Value of option: %s", option.c_str());
@ -3580,7 +3568,7 @@ static Result<string, string> com_reset_config(exec_context &ec, string cmdline,
ypc.ypc_active_paths.insert(option);
ypc.update_callbacks();
if (option == "*" || (ypc.ypc_current_handler != NULL ||
if (option == "*" || (ypc.ypc_current_handler != nullptr ||
!ypc.ypc_handler_stack.empty())) {
if (!ec.ec_dry_run) {
reset_config(option);
@ -4181,9 +4169,7 @@ static void sql_prompt(vector<string> &args)
lnav_data.ld_bottom_source.update_loading(0, 0);
lnav_data.ld_status[LNS_BOTTOM].do_update();
field_overlay_source *fos;
fos = (field_overlay_source *) log_view.get_overlay_source();
auto* fos = (field_overlay_source *) log_view.get_overlay_source();
fos->fos_active_prev = fos->fos_active;
if (!fos->fos_active) {
fos->fos_active = true;

View File

@ -37,18 +37,15 @@
#include <fcntl.h>
#include <ctype.h>
#include <stdarg.h>
#include <paths.h>
#include <fstream>
#include "auto_fd.hh"
#include "lnav_util.hh"
#include "pcrepp/pcrepp.hh"
#include "lnav_config.hh"
#include "base/result.h"
#include "ansi_scrubber.hh"
#include "view_curses.hh"
#include "archive_manager.hh"
#include "fmt/format.h"
using namespace std;
@ -83,11 +80,11 @@ std::string hash_bytes(const char *str1, size_t s1len, ...)
va_start(args, s1len);
context.Init(0, 0);
while (str1 != NULL) {
while (str1 != nullptr) {
context.Update(str1, s1len);
str1 = va_arg(args, const char *);
if (str1 == NULL) {
if (str1 == nullptr) {
break;
}
s1len = va_arg(args, size_t);
@ -101,7 +98,7 @@ std::string hash_bytes(const char *str1, size_t s1len, ...)
std::string time_ago(time_t last_time, bool convert_local)
{
time_t delta, current_time = time(NULL);
time_t delta, current_time = time(nullptr);
const char *fmt;
char buffer[64];
int amount;
@ -155,7 +152,7 @@ std::string precise_time_ago(const struct timeval &tv, bool convert_local)
{
struct timeval now, diff;
gettimeofday(&now, NULL);
gettimeofday(&now, nullptr);
if (convert_local) {
now.tv_sec = convert_log_time_to_local(now.tv_sec);
}
@ -194,31 +191,12 @@ std::string precise_time_ago(const struct timeval &tv, bool convert_local)
}
}
std::string get_current_dir(void)
{
char cwd[FILENAME_MAX];
std::string retval = ".";
if (getcwd(cwd, sizeof(cwd)) == NULL) {
perror("getcwd");
}
else {
retval = std::string(cwd);
}
if (retval != "/") {
retval += "/";
}
return retval;
}
bool change_to_parent_dir(void)
bool change_to_parent_dir()
{
bool retval = false;
char cwd[3] = "";
if (getcwd(cwd, sizeof(cwd)) == NULL) {
if (getcwd(cwd, sizeof(cwd)) == nullptr) {
/* perror("getcwd"); */
}
if (strcmp(cwd, "/") != 0) {
@ -243,28 +221,7 @@ void split_ws(const std::string &str, std::vector<std::string> &toks_out)
}
}
std::pair<std::string, std::string> split_path(const char *path, ssize_t len)
{
ssize_t dir_len = len;
while (dir_len >= 0 && (path[dir_len] == '/' || path[dir_len] == '\\')) {
dir_len -= 1;
}
while (dir_len >= 0) {
if (path[dir_len] == '/' || path[dir_len] == '\\') {
return make_pair(string(path, dir_len),
string(&path[dir_len + 1], len - dir_len));
}
dir_len -= 1;
}
return make_pair(path[0] == '/' ? "/" : ".",
path[0] == '/' ? string(&path[1], len - 1) : string(path, len));
}
file_format_t detect_file_format(const std::string &filename)
file_format_t detect_file_format(const ghc::filesystem::path &filename)
{
if (archive_manager::is_archive(filename)) {
return file_format_t::FF_ARCHIVE;
@ -273,7 +230,7 @@ file_format_t detect_file_format(const std::string &filename)
file_format_t retval = file_format_t::FF_UNKNOWN;
auto_fd fd;
if ((fd = open(filename.c_str(), O_RDONLY)) != -1) {
if ((fd = openp(filename, O_RDONLY)) != -1) {
char buffer[32];
ssize_t rc;
@ -446,7 +403,7 @@ bool next_format(const char * const fmt[], int &index, int &locked_index)
if (locked_index == -1) {
index += 1;
if (fmt[index] == NULL) {
if (fmt[index] == nullptr) {
retval = false;
}
}
@ -469,7 +426,7 @@ const char *date_time_scanner::scan(const char *time_dest,
{
int curr_time_fmt = -1;
bool found = false;
const char *retval = NULL;
const char *retval = nullptr;
if (!time_fmt) {
time_fmt = PTIMEC_FORMAT_STR;
@ -486,7 +443,7 @@ const char *date_time_scanner::scan(const char *time_dest,
char time_cp[time_len + 1];
int gmt_int, off;
retval = NULL;
retval = nullptr;
memcpy(time_cp, time_dest, time_len);
time_cp[time_len] = '\0';
if (sscanf(time_cp, "+%d%n", &gmt_int, &off) == 1) {
@ -495,7 +452,7 @@ const char *date_time_scanner::scan(const char *time_dest,
if (convert_local && this->dts_local_time) {
localtime_r(&gmt, &tm_out->et_tm);
#ifdef HAVE_STRUCT_TM_TM_ZONE
tm_out->et_tm.tm_zone = NULL;
tm_out->et_tm.tm_zone = nullptr;
#endif
tm_out->et_tm.tm_isdst = 0;
gmt = tm2sec(&tm_out->et_tm);
@ -517,7 +474,7 @@ const char *date_time_scanner::scan(const char *time_dest,
#ifdef HAVE_STRUCT_TM_TM_ZONE
if (!this->dts_keep_base_tz) {
tm_out->et_tm.tm_zone = NULL;
tm_out->et_tm.tm_zone = nullptr;
}
#endif
if (func(tm_out, time_dest, off, time_len)) {
@ -548,7 +505,7 @@ const char *date_time_scanner::scan(const char *time_dest,
#ifdef HAVE_STRUCT_TM_TM_ZONE
if (!this->dts_keep_base_tz) {
tm_out->et_tm.tm_zone = NULL;
tm_out->et_tm.tm_zone = nullptr;
}
#endif
if (ptime_fmt(time_fmt[curr_time_fmt], tm_out, time_dest, off, time_len) &&
@ -563,7 +520,7 @@ const char *date_time_scanner::scan(const char *time_dest,
this->to_localtime(gmt, *tm_out);
#ifdef HAVE_STRUCT_TM_TM_ZONE
tm_out->et_tm.tm_zone = NULL;
tm_out->et_tm.tm_zone = nullptr;
#endif
tm_out->et_tm.tm_isdst = 0;
}
@ -582,10 +539,10 @@ const char *date_time_scanner::scan(const char *time_dest,
}
if (!found) {
retval = NULL;
retval = nullptr;
}
if (retval != NULL) {
if (retval != nullptr) {
/* Try to pull out the milli/micro-second value. */
if (retval[0] == '.' || retval[0] == ',') {
off_t off = (retval - time_dest) + 1;
@ -649,7 +606,10 @@ string build_path(const vector<ghc::filesystem::path> &paths)
}
retval += path.string();
}
retval += ":" + string(getenv("PATH"));
auto env_path = getenv_opt("PATH");
if (env_path) {
retval += ":" + string(*env_path);
}
return retval;
}
@ -695,17 +655,6 @@ size_t abbreviate_str(char *str, size_t len, size_t max_len)
return len;
}
ghc::filesystem::path system_tmpdir()
{
const char *tmpdir;
if ((tmpdir = getenv("TMPDIR")) == nullptr) {
tmpdir = _PATH_VARTMP;
}
return ghc::filesystem::path(tmpdir);
}
Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern)
{
@ -715,7 +664,8 @@ open_temp_file(const ghc::filesystem::path &pattern)
strcpy(pattern_copy, pattern_str.c_str());
if ((fd = mkstemp(pattern_copy)) == -1) {
throw Err(strerror(errno));
return Err(fmt::format("unable to create temporary file: {} -- {}",
pattern.string(), strerror(errno)));
}
return Ok(make_pair(ghc::filesystem::path(pattern_copy), fd));

View File

@ -55,50 +55,9 @@
#include "byte_array.hh"
#include "optional.hpp"
#include "base/result.h"
#include "fmt/format.h"
#include "ghc/filesystem.hpp"
inline std::string trim(const std::string &str)
{
std::string::size_type start, end;
for (start = 0; start < str.size() && isspace(str[start]); start++);
for (end = str.size(); end > 0 && isspace(str[end - 1]); end--);
return str.substr(start, end - start);
}
inline std::string tolower(const char *str)
{
std::string retval;
for (int lpc = 0; str[lpc]; lpc++) {
retval.push_back(::tolower(str[lpc]));
}
return retval;
}
inline std::string tolower(const std::string &str)
{
return tolower(str.c_str());
}
inline std::string toupper(const char *str)
{
std::string retval;
for (int lpc = 0; str[lpc]; lpc++) {
retval.push_back(::toupper(str[lpc]));
}
return retval;
}
inline std::string toupper(const std::string &str)
{
return toupper(str.c_str());
}
#undef rounddown
/**
@ -205,26 +164,36 @@ object_field_t<UnaryFunction, Member> object_field(UnaryFunction &func,
return object_field_t<UnaryFunction, Member>(func, mem);
}
std::string get_current_dir(void);
bool change_to_parent_dir(void);
bool change_to_parent_dir();
void split_ws(const std::string &str, std::vector<std::string> &toks_out);
std::pair<std::string, std::string> split_path(const char *path, ssize_t len);
inline
std::pair<std::string, std::string> split_path(const std::string &path) {
return split_path(path.c_str(), path.size());
};
enum class file_format_t {
FF_UNKNOWN,
FF_SQLITE_DB,
FF_ARCHIVE,
};
file_format_t detect_file_format(const std::string &filename);
file_format_t detect_file_format(const ghc::filesystem::path& filename);
template<>
struct fmt::formatter<file_format_t> : fmt::formatter<fmt::string_view> {
template<typename FormatContext>
auto format(file_format_t ff, FormatContext& ctx) {
fmt::string_view name = "unknown";
switch (ff) {
case file_format_t::FF_SQLITE_DB:
name = "SQLite Database";
break;
case file_format_t::FF_ARCHIVE:
name = "Archive";
break;
default:
break;
}
return fmt::formatter<fmt::string_view>::format(name, ctx);
}
};
bool next_format(const char * const fmt[], int &index, int &locked_index);
@ -233,23 +202,11 @@ namespace std {
inline string to_string(const char *s) { return s; }
}
template<class InputIt>
inline std::string join(InputIt first, InputIt last, const std::string &delim)
{
std::string retval;
return std::accumulate(first, last, retval, [&] (
auto l, auto r) {
std::string lstr = std::to_string(l);
return lstr + (lstr.empty() ? "" : delim) + std::to_string(r);
});
}
inline bool is_glob(const char *fn)
{
return (strchr(fn, '*') != NULL ||
strchr(fn, '?') != NULL ||
strchr(fn, '[') != NULL);
return (strchr(fn, '*') != nullptr ||
strchr(fn, '?') != nullptr ||
strchr(fn, '[') != nullptr);
};
bool is_url(const char *fn);
@ -313,14 +270,14 @@ struct date_time_scanner {
this->clear();
};
void clear(void) {
void clear() {
this->dts_base_time = 0;
memset(&this->dts_base_tm, 0, sizeof(this->dts_base_tm));
this->dts_fmt_lock = -1;
this->dts_fmt_len = -1;
};
void unlock(void) {
void unlock() {
this->dts_fmt_lock = -1;
this->dts_fmt_len = -1;
}
@ -423,16 +380,13 @@ struct date_time_scanner {
template<typename T>
size_t strtonum(T &num_out, const char *data, size_t len);
inline bool pollfd_ready(const std::vector<struct pollfd> &pollfds, int fd, short events = POLLIN|POLLHUP) {
for (std::vector<struct pollfd>::const_iterator iter = pollfds.begin();
iter != pollfds.end();
++iter) {
if (iter->fd == fd && iter->revents & events) {
return true;
}
}
return false;
inline bool pollfd_ready(const std::vector<struct pollfd> &pollfds, int fd,
short events = POLLIN | POLLHUP)
{
return std::any_of(pollfds.begin(), pollfds.end(),
[fd, events](const auto &entry) {
return entry.fd == fd && entry.revents & events;
});
};
inline void rusagesub(const struct rusage &left, const struct rusage &right, struct rusage &diff_out)
@ -475,8 +429,6 @@ inline void rusageadd(const struct rusage &left, const struct rusage &right, str
size_t abbreviate_str(char *str, size_t len, size_t max_len);
ghc::filesystem::path system_tmpdir();
inline int statp(const ghc::filesystem::path &path, struct stat *buf) {
return stat(path.c_str(), buf);
}

View File

@ -122,7 +122,8 @@ static string execute_action(log_data_helper &ldh,
auto pp = make_shared<piper_proc>(
out_pipe.read_end(),
false,
open_temp_file(system_tmpdir() / "lnav.action.XXXXXX")
open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.action.XXXXXX")
.then([](auto pair) {
ghc::filesystem::remove(pair.first);
})

View File

@ -39,6 +39,7 @@
#include <inttypes.h>
#include <sys/types.h>
#include <memory>
#include <set>
#include <list>
#include <string>
@ -168,7 +169,7 @@ public:
}
};
bool is_marked(void) const { return this->ll_level & LEVEL_MARK; };
bool is_marked() const { return this->ll_level & LEVEL_MARK; };
void set_time_skew(bool val) {
if (val) {
@ -227,7 +228,7 @@ public:
/**
* @return True if there is a schema value set for this log line.
*/
bool has_schema(void) const
bool has_schema() const
{
return (this->ll_schema[0] != 0 ||
this->ll_schema[1] != 0);
@ -508,7 +509,7 @@ public:
/**
* @return The collection of builtin log formats.
*/
static std::vector<log_format *> &get_root_formats(void);
static std::vector<log_format *> &get_root_formats();
/**
* Template used to register log formats during initialization.
@ -531,7 +532,7 @@ public:
return lf;
}
}
return NULL;
return nullptr;
}
struct action_def {
@ -618,20 +619,20 @@ public:
};
virtual const logline_value_stats *stats_for_value(const intern_string_t &name) const {
return NULL;
return nullptr;
};
virtual std::unique_ptr<log_format> specialized(int fmt_lock = -1) = 0;
virtual log_vtab_impl *get_vtab_impl(void) const {
return NULL;
virtual log_vtab_impl *get_vtab_impl() const {
return nullptr;
};
virtual void get_subline(const logline &ll, shared_buffer_ref &sbr, bool full_message = false) {
};
virtual const std::vector<std::string> *get_actions(const logline_value &lv) const {
return NULL;
return nullptr;
};
virtual const std::set<std::string> get_source_path() const {
@ -648,7 +649,7 @@ public:
const char * const *get_timestamp_formats() const {
if (this->lf_timestamp_format.empty()) {
return NULL;
return nullptr;
}
return &this->lf_timestamp_format[0];
@ -705,7 +706,7 @@ protected:
this->pf_timestamp_index = this->pcre.name_index("timestamp");
};
pcre_format() : name(NULL), pcre("") { };
pcre_format() : name(nullptr), pcre("") { };
const char *name;
pcrepp pcre;
@ -773,36 +774,23 @@ public:
};
struct pattern {
pattern() : p_pcre(NULL),
p_timestamp_field_index(-1),
p_level_field_index(-1),
p_module_field_index(-1),
p_opid_field_index(-1),
p_body_field_index(-1),
p_timestamp_end(-1),
p_module_format(false) {
};
std::string p_config_path;
std::string p_string;
pcrepp *p_pcre;
pcrepp *p_pcre{nullptr};
std::vector<indexed_value_def> p_value_by_index;
std::vector<int> p_numeric_value_indexes;
int p_timestamp_field_index;
int p_level_field_index;
int p_module_field_index;
int p_opid_field_index;
int p_body_field_index;
int p_timestamp_end;
bool p_module_format;
int p_timestamp_field_index{-1};
int p_level_field_index{-1};
int p_module_field_index{-1};
int p_opid_field_index{-1};
int p_body_field_index{-1};
int p_timestamp_end{-1};
bool p_module_format{false};
};
struct level_pattern {
level_pattern() : lp_pcre(NULL) { };
std::string lp_regex;
pcrepp *lp_pcre;
pcrepp *lp_pcre{nullptr};
};
external_log_format(const intern_string_t name)
@ -824,7 +812,7 @@ public:
this->jlf_line_offsets.reserve(128);
};
const intern_string_t get_name(void) const {
const intern_string_t get_name() const {
return this->elf_name;
};
@ -879,10 +867,10 @@ public:
}
if (this->elf_type == ELF_TYPE_JSON) {
this->jlf_parse_context.reset(new yajlpp_parse_context(this->elf_name.to_string()));
this->jlf_parse_context = std::make_shared<yajlpp_parse_context>(this->elf_name.to_string());
this->jlf_yajl_handle.reset(yajl_alloc(
&this->jlf_parse_context->ypc_callbacks,
NULL,
nullptr,
this->jlf_parse_context.get()));
yajl_config(this->jlf_yajl_handle.in(), yajl_dont_validate_strings, 1);
this->jlf_cached_line.reserve(16 * 1024);
@ -895,7 +883,7 @@ public:
};
const logline_value_stats *stats_for_value(const intern_string_t &name) const {
const logline_value_stats *retval = NULL;
const logline_value_stats *retval = nullptr;
for (size_t lpc = 0; lpc < this->elf_numeric_value_defs.size(); lpc++) {
value_def &vd = *this->elf_numeric_value_defs[lpc];
@ -911,10 +899,10 @@ public:
void get_subline(const logline &ll, shared_buffer_ref &sbr, bool full_message);
log_vtab_impl *get_vtab_impl(void) const;
log_vtab_impl *get_vtab_impl() const;
const std::vector<std::string> *get_actions(const logline_value &lv) const {
const std::vector<std::string> *retval = NULL;
const std::vector<std::string> *retval = nullptr;
const auto iter = this->elf_value_defs.find(lv.lv_name);
if (iter != this->elf_value_defs.end()) {
@ -998,7 +986,7 @@ public:
long value_line_count(const intern_string_t ist,
bool top_level,
const unsigned char *str = NULL,
const unsigned char *str = nullptr,
ssize_t len = -1) const {
const auto iter = this->elf_value_defs.find(ist);
long line_count = (str != NULL) ? std::count(&str[0], &str[len], '\n') + 1 : 1;
@ -1161,11 +1149,7 @@ private:
class module_format {
public:
module_format() : mf_mod_format(NULL) {
};
external_log_format *mf_mod_format;
external_log_format *mf_mod_format{nullptr};
};
#endif

View File

@ -65,7 +65,7 @@ typedef map<intern_string_t, external_log_format *> log_formats_map_t;
static log_formats_map_t LOG_FORMATS;
struct userdata {
std::string ud_format_path;
ghc::filesystem::path ud_format_path;
vector<intern_string_t> *ud_format_names{nullptr};
std::vector<std::string> *ud_errors{nullptr};
};
@ -81,7 +81,7 @@ static external_log_format *ensure_format(const yajlpp_provider_context &ypc, us
LOG_FORMATS[name] = retval = new external_log_format(name);
log_debug("Loading format -- %s", name.get());
}
retval->elf_source_path.insert(ud->ud_format_path.substr(0, ud->ud_format_path.rfind('/')));
retval->elf_source_path.insert(ud->ud_format_path.filename().string());
if (find(formats->begin(), formats->end(), name) == formats->end()) {
formats->push_back(name);
@ -810,7 +810,9 @@ static void format_error_reporter(const yajlpp_parse_context &ypc,
}
}
std::vector<intern_string_t> load_format_file(const string &filename, std::vector<string> &errors)
std::vector<intern_string_t>
load_format_file(const ghc::filesystem::path &filename,
std::vector<string> &errors)
{
std::vector<intern_string_t> retval;
struct userdata ud;
@ -823,14 +825,10 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
yajlpp_parse_context ypc(filename, &root_format_handler);
ypc.ypc_userdata = &ud;
ypc.with_obj(ud);
if ((fd = open(filename.c_str(), O_RDONLY)) == -1) {
char errmsg[1024];
snprintf(errmsg, sizeof(errmsg),
"error:unable to open format file '%s' -- %s",
filename.c_str(),
strerror(errno));
errors.emplace_back(errmsg);
if ((fd = openp(filename, O_RDONLY)) == -1) {
errors.emplace_back(fmt::format(
"error: unable to open format file '{}' -- {}",
filename.string(), strerror(errno)));
}
else {
auto_mem<yajl_handle_t> handle(yajl_free);
@ -838,7 +836,7 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
off_t offset = 0;
ssize_t rc = -1;
handle = yajl_alloc(&ypc.ypc_callbacks, NULL, &ypc);
handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc);
ypc.with_handle(handle)
.with_error_reporter(format_error_reporter);
yajl_config(handle, yajl_allow_comments, 1);
@ -848,11 +846,10 @@ std::vector<intern_string_t> load_format_file(const string &filename, std::vecto
break;
}
else if (rc == -1) {
errors.push_back(
"error:" +
filename +
":unable to read file -- " +
string(strerror(errno)));
errors.push_back(fmt::format(
"error:{}:unable to read file -- {}",
filename.string(),
strerror(errno)));
break;
}
if (offset == 0 && (rc > 2) &&
@ -1105,7 +1102,7 @@ void extract_metadata_from_file(struct script_metadata &meta_inout)
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());
} else if ((fp = fopen(meta_inout.sm_path.c_str(), "r")) != NULL) {
} else if ((fp = fopen(meta_inout.sm_path.c_str(), "r")) != nullptr) {
size_t len;
len = fread(buffer, 1, sizeof(buffer), fp.in());

View File

@ -37,10 +37,13 @@
#include <vector>
#include <string>
#include "ghc/filesystem.hpp"
class log_vtab_manager;
std::vector<intern_string_t> load_format_file(
const std::string &filename, std::vector<std::string> &errors);
const ghc::filesystem::path &filename,
std::vector<std::string> &errors);
void load_formats(const std::vector<ghc::filesystem::path> &extra_paths,
std::vector<std::string> &errors);

View File

@ -1,4 +1,4 @@
/* Generated by re2c 1.1.1 on Thu Apr 18 18:55:08 2019 */
/* Generated by re2c 2.0.3 on Tue Nov 3 13:27:28 2020 */
#line 1 "../../lnav2/src/log_level_re.re"
/**
* Copyright (c) 2018, Timothy Stack
@ -31,9 +31,7 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "log_level.hh"
@ -66,14 +64,14 @@ log_level_t string2level(const char *levelstr, ssize_t len, bool exact)
# define YYRESTORE() YYCURSOR = YYMARKER
# define YYSTAGP(x) x = YYCURSOR - 1
const unsigned char *yyt1;
loop:
#line 73 "../../lnav2/src/log_level_re.cc"
#line 71 "../../lnav2/src/log_level_re.cc"
{
YYCTYPE yych;
unsigned int yyaccept = 0;
yych = YYPEEK ();
yych = YYPEEK();
switch (yych) {
case 0x00: goto yy2;
case 'C':
@ -97,21 +95,21 @@ log_level_t string2level(const char *levelstr, ssize_t len, bool exact)
default: goto yy4;
}
yy2:
YYSKIP ();
#line 75 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 73 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_UNKNOWN); }
#line 104 "../../lnav2/src/log_level_re.cc"
#line 102 "../../lnav2/src/log_level_re.cc"
yy4:
YYSKIP ();
YYSKIP();
yy5:
#line 102 "../../lnav2/src/log_level_re.re"
#line 100 "../../lnav2/src/log_level_re.re"
{ goto loop; }
#line 110 "../../lnav2/src/log_level_re.cc"
#line 108 "../../lnav2/src/log_level_re.cc"
yy6:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy15;
@ -119,9 +117,9 @@ yy6:
}
yy7:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'E':
case 'e': goto yy17;
@ -129,9 +127,9 @@ yy7:
}
yy8:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy18;
@ -139,9 +137,9 @@ yy8:
}
yy9:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'A':
case 'a': goto yy19;
@ -149,9 +147,9 @@ yy9:
}
yy10:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'N':
case 'n': goto yy20;
@ -159,9 +157,9 @@ yy10:
}
yy11:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'O':
case 'o': goto yy21;
@ -169,9 +167,9 @@ yy11:
}
yy12:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'E':
case 'e': goto yy22;
@ -181,9 +179,9 @@ yy12:
}
yy13:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy24;
@ -191,112 +189,115 @@ yy13:
}
yy14:
yyaccept = 0;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'A':
case 'a': goto yy25;
default: goto yy5;
}
yy15:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'I':
case 'i': goto yy26;
default: goto yy16;
}
yy16:
YYRESTORE ();
YYRESTORE();
switch (yyaccept) {
case 0: goto yy5;
case 1: goto yy29;
default: goto yy48;
case 0:
goto yy5;
case 1:
goto yy29;
default:
goto yy48;
}
yy17:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'B':
case 'b': goto yy27;
default: goto yy16;
}
yy18:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy28;
default: goto yy16;
}
yy19:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'T':
case 't': goto yy30;
default: goto yy16;
}
yy20:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'F':
case 'f': goto yy31;
default: goto yy16;
}
yy21:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'T':
case 't': goto yy32;
default: goto yy16;
}
yy22:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'V':
case 'v': goto yy33;
default: goto yy16;
}
yy23:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'A':
case 'a': goto yy34;
default: goto yy16;
}
yy24:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'A':
case 'a': goto yy35;
default: goto yy16;
}
yy25:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy36;
default: goto yy16;
}
yy26:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'T':
case 't': goto yy37;
default: goto yy16;
}
yy27:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'U':
case 'u': goto yy38;
@ -304,138 +305,138 @@ yy27:
}
yy28:
yyaccept = 1;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'O':
case 'o': goto yy39;
default: goto yy29;
}
yy29:
#line 98 "../../lnav2/src/log_level_re.re"
#line 96 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_ERROR); }
#line 319 "../../lnav2/src/log_level_re.cc"
#line 320 "../../lnav2/src/log_level_re.cc"
yy30:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'A':
case 'a': goto yy40;
default: goto yy16;
}
yy31:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'O':
case 'o': goto yy41;
default: goto yy16;
}
yy32:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'I':
case 'i': goto yy43;
default: goto yy16;
}
yy33:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'E':
case 'e': goto yy44;
default: goto yy16;
}
yy34:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'T':
case 't': goto yy45;
default: goto yy16;
}
yy35:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'C':
case 'c': goto yy46;
default: goto yy16;
}
yy36:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'N':
case 'n': goto yy47;
default: goto yy16;
}
yy37:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'I':
case 'i': goto yy49;
default: goto yy16;
}
yy38:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'G':
case 'g': goto yy50;
default: goto yy16;
}
yy39:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy52;
default: goto yy16;
}
yy40:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'L':
case 'l': goto yy53;
default: goto yy16;
}
yy41:
YYSKIP ();
#line 94 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 92 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_INFO); }
#line 412 "../../lnav2/src/log_level_re.cc"
#line 413 "../../lnav2/src/log_level_re.cc"
yy43:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'C':
case 'c': goto yy55;
default: goto yy16;
}
yy44:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'R':
case 'r': goto yy56;
default: goto yy16;
}
yy45:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'S':
case 's': goto yy57;
default: goto yy16;
}
yy46:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'E':
case 'e': goto yy59;
@ -443,41 +444,39 @@ yy46:
}
yy47:
yyaccept = 2;
YYSKIP ();
YYBACKUP ();
yych = YYPEEK ();
YYSKIP();
YYBACKUP();
yych = YYPEEK();
switch (yych) {
case 'I':
case 'i': goto yy61;
default: goto yy48;
}
yy48:
#line 97 "../../lnav2/src/log_level_re.re"
#line 95 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_WARNING); }
#line 458 "../../lnav2/src/log_level_re.cc"
#line 459 "../../lnav2/src/log_level_re.cc"
yy49:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'C':
case 'c': goto yy62;
default: goto yy16;
}
yy50:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case '2':
case '3':
case '4':
case '5': goto yy63;
default:
YYSTAGP (yyt1);
goto yy51;
default: goto yy51;
}
yy51:
debug_level = yyt1;
#line 77 "../../lnav2/src/log_level_re.re"
YYSTAGP(debug_level);
#line 75 "../../lnav2/src/log_level_re.re"
{
if (debug_level == nullptr) {
RET(LEVEL_DEBUG);
@ -495,96 +494,95 @@ yy51:
RET(LEVEL_DEBUG);
}
}
#line 499 "../../lnav2/src/log_level_re.cc"
#line 498 "../../lnav2/src/log_level_re.cc"
yy52:
YYSKIP ();
YYSKIP();
goto yy29;
yy53:
YYSKIP ();
#line 101 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 99 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_FATAL); }
#line 507 "../../lnav2/src/log_level_re.cc"
#line 506 "../../lnav2/src/log_level_re.cc"
yy55:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'E':
case 'e': goto yy64;
default: goto yy16;
}
yy56:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'E':
case 'e': goto yy66;
default: goto yy16;
}
yy57:
YYSKIP ();
#line 96 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 94 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_STATS); }
#line 528 "../../lnav2/src/log_level_re.cc"
#line 527 "../../lnav2/src/log_level_re.cc"
yy59:
YYSKIP ();
#line 76 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 74 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_TRACE); }
#line 533 "../../lnav2/src/log_level_re.cc"
#line 532 "../../lnav2/src/log_level_re.cc"
yy61:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'N':
case 'n': goto yy68;
default: goto yy16;
}
yy62:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'A':
case 'a': goto yy69;
default: goto yy16;
}
yy63:
YYSKIP ();
YYSTAGP (yyt1);
YYSKIP();
goto yy51;
yy64:
YYSKIP ();
#line 95 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 93 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_NOTICE); }
#line 558 "../../lnav2/src/log_level_re.cc"
#line 556 "../../lnav2/src/log_level_re.cc"
yy66:
YYSKIP ();
#line 100 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 98 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_CRITICAL); }
#line 563 "../../lnav2/src/log_level_re.cc"
#line 561 "../../lnav2/src/log_level_re.cc"
yy68:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'G':
case 'g': goto yy70;
default: goto yy16;
}
yy69:
YYSKIP ();
yych = YYPEEK ();
YYSKIP();
yych = YYPEEK();
switch (yych) {
case 'L':
case 'l': goto yy71;
default: goto yy16;
}
yy70:
YYSKIP ();
YYSKIP();
goto yy48;
yy71:
YYSKIP ();
#line 99 "../../lnav2/src/log_level_re.re"
YYSKIP();
#line 97 "../../lnav2/src/log_level_re.re"
{ RET(LEVEL_CRITICAL); }
#line 587 "../../lnav2/src/log_level_re.cc"
#line 585 "../../lnav2/src/log_level_re.cc"
}
#line 104 "../../lnav2/src/log_level_re.re"
#line 102 "../../lnav2/src/log_level_re.re"
}

View File

@ -29,9 +29,7 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "log_level.hh"

View File

@ -117,7 +117,7 @@ public:
content_line_t cl;
cl = lss.at(lc.lc_curr_line);
std::shared_ptr<logfile> lf = lss.find(cl);
auto lf = lss.find(cl);
auto lf_iter = lf->begin() + cl;
if (lf_iter->is_continued()) {

View File

@ -856,8 +856,8 @@ static int vt_update(sqlite3_vtab *tab,
ypc.parse(log_tags, strlen((const char *) log_tags));
ypc.complete_parse();
if (!errors.empty()) {
tab->zErrMsg = sqlite3_mprintf("%s",
join(errors.begin(), errors.end(), "\n").c_str());
auto all_errors = fmt::format("{}", fmt::join(errors, "\n"));
tab->zErrMsg = sqlite3_mprintf("%s", all_errors.c_str());
return SQLITE_ERROR;
}
}

View File

@ -103,12 +103,12 @@ public:
};
virtual ~log_vtab_impl() { };
const intern_string_t get_name(void) const
const intern_string_t get_name() const
{
return this->vi_name;
};
std::string get_table_statement(void);
std::string get_table_statement();
virtual bool is_valid(log_cursor &lc, logfile_sub_source &lss) {
content_line_t cl(lss.at(lc.lc_curr_line));

View File

@ -33,12 +33,9 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/resource.h>
@ -59,7 +56,7 @@ logfile::logfile(const string &filename, logfile_open_options &loo)
{
require(!filename.empty());
this->lf_options = loo;
this->lf_options = std::move(loo);
memset(&this->lf_stat, 0, sizeof(this->lf_stat));
if (this->lf_options.loo_fd == -1) {
char resolved_path[PATH_MAX];

View File

@ -84,7 +84,7 @@ struct logfile_open_options {
};
logfile_open_options &with_fd(auto_fd fd) {
this->loo_fd = fd;
this->loo_fd = std::move(fd);
return *this;
};

View File

@ -193,7 +193,7 @@ bool pcrepp::match(pcre_context &pc, pcre_input &pi, int options) const
return rc > 0;
}
void pcrepp::study(void)
void pcrepp::study()
{
const char *errptr;
@ -237,7 +237,7 @@ void pcrepp::study(void)
}
#ifdef PCRE_STUDY_JIT_COMPILE
pcre_jit_stack *pcrepp::jit_stack(void)
pcre_jit_stack *pcrepp::jit_stack()
{
static pcre_jit_stack *retval = NULL;

View File

@ -34,15 +34,11 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <paths.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <poll.h>
#include "base/lnav_log.hh"

View File

@ -72,7 +72,7 @@ public:
virtual ~piper_proc();
/** @return The file descriptor for the temporary file. */
int get_fd() { return this->pp_fd.release(); };
auto_fd get_fd() { return std::move(this->pp_fd); };
pid_t get_child_pid() const { return this->pp_child; };

View File

@ -39,11 +39,9 @@
class plain_text_source
: public text_sub_source, public vis_location_history {
public:
plain_text_source()
: tds_text_format(text_format_t::TF_UNKNOWN), tds_longest_line(0) {
};
plain_text_source() = default;
plain_text_source(const std::string &text) : tds_text_format(text_format_t::TF_UNKNOWN) {
plain_text_source(const std::string &text) {
size_t start = 0, end;
while ((end = text.find('\n', start)) != std::string::npos) {
@ -57,13 +55,11 @@ public:
this->tds_longest_line = this->compute_longest_line();
};
plain_text_source(const std::vector<std::string> &text_lines)
: tds_text_format(text_format_t::TF_UNKNOWN) {
plain_text_source(const std::vector<std::string> &text_lines) {
this->replace_with(text_lines);
};
plain_text_source(const std::vector<attr_line_t> &text_lines)
: tds_text_format(text_format_t::TF_UNKNOWN) {
plain_text_source(const std::vector<attr_line_t> &text_lines) {
this->tds_lines = text_lines;
this->tds_longest_line = this->compute_longest_line();
};
@ -148,8 +144,8 @@ private:
};
std::vector<attr_line_t> tds_lines;
text_format_t tds_text_format;
size_t tds_longest_line;
text_format_t tds_text_format{text_format_t::TF_UNKNOWN};
size_t tds_longest_line{0};
};
#endif //LNAV_PLAIN_TEXT_SOURCE_HH

View File

@ -62,9 +62,9 @@ public:
this->tss_fields[TSF_TOGGLE].right_justify(true);
};
size_t statusview_fields(void) { return TSF__MAX; };
size_t statusview_fields() override { return TSF__MAX; };
status_field &statusview_value_for_field(int field) {
status_field &statusview_value_for_field(int field) override {
return this->tss_fields[field];
};

View File

@ -32,12 +32,10 @@
#include "config.h"
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
@ -56,8 +54,8 @@
#include <string>
#include "base/string_util.hh"
#include "fmt/format.h"
#include "lnav_config.hh"
#include "pcrepp/pcrepp.hh"
#include "shlex.hh"
#include "auto_mem.hh"
#include "base/lnav_log.hh"
@ -354,7 +352,7 @@ char **readline_context::attempted_completion(const char *text,
arg_possibilities = nullptr;
rl_completion_append_character = 0;
if (lexer.split(prefix, scope)) {
string prefix2 = join(prefix.begin(), prefix.end(), "\x1f");
auto prefix2 = fmt::format("{}", fmt::join(prefix, "\x1f"));
auto prefix_iter = loaded_context->rc_prefixes.find(prefix2);
if (prefix_iter != loaded_context->rc_prefixes.end()) {
@ -1058,7 +1056,7 @@ void readline_curses::add_prefix(int context,
const string &value)
{
char buffer[1024];
string prefix_wire = join(prefix.begin(), prefix.end(), "\x1f");
auto prefix_wire = fmt::format("{}", fmt::join(prefix, "\x1f"));
snprintf(buffer, sizeof(buffer),
"apre:%d:%s\x1d%s",

View File

@ -35,7 +35,6 @@
#include "pcrepp/pcrepp.hh"
#include "sql_util.hh"
#include "shlex.hh"
#include "lnav_util.hh"
#include "readline_highlighters.hh"
@ -183,7 +182,7 @@ static void readline_regex_highlighter_int(attr_line_t &al, int x, int skip)
"()",
"QE",
NULL
nullptr
};
string &line = al.get_string();
@ -449,7 +448,7 @@ void readline_sqlite_highlighter(attr_line_t &al, int x)
"[]",
"()",
NULL
nullptr
};
view_colors &vc = view_colors::singleton();

View File

@ -65,14 +65,6 @@ CREATE TABLE regexp_capture (
);
)";
struct vtab {
sqlite3_vtab base;
operator sqlite3_vtab *() {
return &this->base;
};
};
struct cursor {
sqlite3_vtab_cursor base;
unique_ptr<pcrepp> c_pattern;

View File

@ -31,10 +31,7 @@
#include <assert.h>
#include <cstdlib>
#include "pcrepp/pcrepp.hh"
#include "lnav_util.hh"
#include "relative_time.hh"
using namespace std;
@ -151,7 +148,7 @@ bool relative_time::parse(const char *str, size_t len, struct parse_error &pe_ou
struct timeval tv;
struct exttm tm;
gettimeofday(&tv, NULL);
gettimeofday(&tv, nullptr);
localtime_r(&tv.tv_sec, &tm.et_tm);
tm.et_nsec = tv.tv_usec * 1000;
this->add(tm);
@ -519,7 +516,7 @@ size_t duration2str(int64_t millis, std::string &value_out)
{ 60, "%qd%s", "m" },
{ 24, "%qd%s", "h" },
{ 0, "%qd%s", "d" },
{ 0, NULL, NULL }
{ 0, nullptr, nullptr }
};
struct rel_interval *curr_interval = intervals;
@ -538,7 +535,7 @@ size_t duration2str(int64_t millis, std::string &value_out)
curr_interval += 1;
}
for (; curr_interval->symbol != NULL; curr_interval++) {
for (; curr_interval->symbol != nullptr; curr_interval++) {
long long amount;
char segment[32];

View File

@ -867,22 +867,22 @@ void load_session()
lnav_data.ld_session_load_time = pair.first.second;
session_data.sd_save_time = pair.first.second;
const string &view_info_name = pair.second;
const auto& view_info_path = pair.second;
yajlpp_parse_context ypc(view_info_name, &view_info_handlers);
yajlpp_parse_context ypc(view_info_path, &view_info_handlers);
ypc.with_obj(session_data);
handle = yajl_alloc(&ypc.ypc_callbacks, nullptr, &ypc);
load_time_bookmarks();
if ((fd = open(view_info_name.c_str(), O_RDONLY)) < 0) {
if ((fd = openp(view_info_path, O_RDONLY)) < 0) {
perror("cannot open session file");
}
else {
unsigned char buffer[1024];
ssize_t rc;
log_info("loading session file: %s", view_info_name.c_str());
log_info("loading session file: %s", view_info_path.c_str());
while ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
yajl_parse(handle, buffer, rc);
}

View File

@ -35,7 +35,7 @@
#include <map>
#include <string>
#include "lnav.hh"
#include "view_helpers.hh"
struct file_state {
bool fs_is_visible{true};

View File

@ -217,13 +217,7 @@ public:
void resolve_home_dir(std::string& result, const pcre_context::capture_t cap) const {
if (cap.length() == 1) {
const char *home_dir = getenv("HOME");
if (home_dir != nullptr) {
result.append(home_dir);
} else {
result.append("~");
}
result.append(getenv_opt("HOME").value_or("~"));
} else {
auto username = (char *) alloca(cap.length());

View File

@ -40,9 +40,10 @@
#include "auto_mem.hh"
#include "sql_util.hh"
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "lnav_util.hh"
#include "pcrepp/pcrepp.hh"
#include "lnav_util.hh"
#include "sqlite-extension-func.hh"
using namespace std;
@ -727,7 +728,7 @@ void sql_execute_script(sqlite3 *db,
sqlite3_bind_text(stmt, lpc + 1,
iter->second.c_str(), -1,
SQLITE_TRANSIENT);
} else if ((env_value = getenv(&name[1])) != NULL) {
} else if ((env_value = getenv(&name[1])) != nullptr) {
sqlite3_bind_text(stmt, lpc + 1,
env_value, -1,
SQLITE_TRANSIENT);

View File

@ -76,7 +76,7 @@ inline ssize_t sql_strftime(char *buffer, size_t buffer_size,
return sql_strftime(buffer, buffer_size, tv.tv_sec, tv.tv_usec / 1000, sep);
}
void sql_install_logger(void);
void sql_install_logger();
bool sql_ident_needs_quote(const char *ident);
@ -120,7 +120,7 @@ void annotate_sql_statement(attr_line_t &al_inout);
extern std::multimap<std::string, help_text *> sqlite_function_help;
std::string sql_keyword_re(void);
std::string sql_keyword_re();
std::vector<const help_text *> find_sql_help_for_line(const attr_line_t &al, size_t x);
#endif

View File

@ -31,10 +31,9 @@
#include "config.h"
#include <stdio.h>
#include <assert.h>
#include "lnav_util.hh"
#include "base/string_util.hh"
#include "base/lnav_log.hh"
#include "sql_util.hh"

View File

@ -31,8 +31,6 @@
#include "config.h"
#include <stdio.h>
#include <sys/types.h>
#include <stdint.h>
#include <string>

View File

@ -9,7 +9,6 @@
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

View File

@ -616,6 +616,8 @@ public:
vis_bookmarks &get_bookmarks() { return this->tc_bookmarks; };
const vis_bookmarks &get_bookmarks() const { return this->tc_bookmarks; };
void toggle_user_mark(bookmark_type_t *bm,
vis_line_t start_line,
vis_line_t end_line = vis_line_t(-1))

View File

@ -86,7 +86,7 @@ public:
lv_functor_t filename_wire;
lv_functor_t view_name_wire;
size_t statusview_fields(void) { return TSF__MAX; };
size_t statusview_fields() { return TSF__MAX; };
status_field &statusview_value_for_field(int field)
{

View File

@ -66,7 +66,7 @@ public:
this->tss_fields[TSF_TRAF].set_role(view_colors::VCR_ACTIVE_STATUS);
};
size_t statusview_fields(void) { return TSF__MAX; };
size_t statusview_fields() { return TSF__MAX; };
status_field &statusview_value_for_field(int field)
{

View File

@ -37,20 +37,15 @@
class url_loader : public curl_request {
public:
url_loader(const std::string &url) : curl_request(url), ul_resume_offset(0) {
char piper_tmpname[PATH_MAX];
const char *tmpdir;
if ((tmpdir = getenv("TMPDIR")) == NULL) {
tmpdir = _PATH_VARTMP;
}
snprintf(piper_tmpname, sizeof(piper_tmpname),
"%s/lnav.url.XXXXXX",
tmpdir);
if ((this->ul_fd = mkstemp(piper_tmpname)) == -1) {
auto tmp_res = open_temp_file(ghc::filesystem::temp_directory_path() /
"lnav.url.XXXXXX");
if (tmp_res.isErr()) {
return;
}
unlink(piper_tmpname);
auto tmp_pair = tmp_res.unwrap();
ghc::filesystem::remove(tmp_pair.first);
this->ul_fd = tmp_pair.second;
curl_easy_setopt(this->cr_handle, CURLOPT_URL, this->cr_name.c_str());
curl_easy_setopt(this->cr_handle, CURLOPT_WRITEFUNCTION, write_cb);

View File

@ -36,6 +36,7 @@
#include "vtab_module.hh"
#include "shlex.hh"
#include "help-txt.h"
#include "view_helpers.hh"
using namespace std;
@ -61,7 +62,7 @@ static void open_schema_view()
schema_tc->set_sub_source(pts);
}
static void open_pretty_view(void)
static void open_pretty_view()
{
static const char *NOTHING_MSG =
"Nothing to pretty-print";

61
src/view_helpers.hh Normal file
View File

@ -0,0 +1,61 @@
/**
* Copyright (c) 2020, 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.hh
*/
#ifndef lnav_view_helpers_hh
#define lnav_view_helpers_hh
#include "help_text.hh"
#include "textview_curses.hh"
/** The different views available. */
typedef enum {
LNV_LOG,
LNV_TEXT,
LNV_HELP,
LNV_HISTOGRAM,
LNV_DB,
LNV_SCHEMA,
LNV_PRETTY,
LNV_SPECTRO,
LNV__MAX
} lnav_view_t;
extern const char *lnav_view_strings[LNV__MAX + 1];
bool ensure_view(textview_curses *expected_tc);
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);
#endif

View File

@ -106,14 +106,6 @@ struct from_sqlite<pair<string, pcre *>> {
};
struct lnav_views : public tvt_iterator_cursor<lnav_views> {
struct vtab {
sqlite3_vtab base;
operator sqlite3_vtab *() {
return &this->base;
};
};
static constexpr const char *CREATE_STMT = R"(
-- Access lnav's views through this table.
CREATE TABLE lnav_views (
@ -272,14 +264,6 @@ CREATE TABLE lnav_view_stack (
);
)";
struct vtab {
sqlite3_vtab base;
operator sqlite3_vtab *() {
return &this->base;
};
};
iterator begin() {
return lnav_data.ld_view_stack.vs_views.begin();
}
@ -290,7 +274,7 @@ CREATE TABLE lnav_view_stack (
int get_column(cursor &vc, sqlite3_context *ctx, int col) {
textview_curses *tc = *vc.iter;
lnav_view_t view = lnav_view_t(tc - lnav_data.ld_views);
auto view = lnav_view_t(tc - lnav_data.ld_views);
switch (col) {
case 0:
@ -341,15 +325,6 @@ CREATE TABLE lnav_view_stack (
};
struct lnav_view_filter_base {
struct vtab {
sqlite3_vtab base;
operator sqlite3_vtab *() {
return &this->base;
};
};
struct iterator {
using difference_type = int;
using value_type = text_filter;
@ -528,7 +503,7 @@ CREATE TABLE lnav_view_filters (
bool enabled,
text_filter::type_t type,
pair<string, pcre *> pattern) {
lnav_view_t view_index = lnav_view_t(rowid >> 32);
auto view_index = lnav_view_t(rowid >> 32);
int filter_index = rowid & 0xffffffffLL;
textview_curses &tc = lnav_data.ld_views[view_index];
text_sub_source *tss = tc.get_sub_source();

View File

@ -162,9 +162,6 @@ vt52_curses::vt52_curses()
vc_map_buffer(0)
{ }
vt52_curses::~vt52_curses()
{ }
const char *vt52_curses::map_input(int ch, int &len_out)
{
const char *esc, *retval;

View File

@ -55,7 +55,6 @@ class vt52_curses
: public view_curses {
public:
vt52_curses();
virtual ~vt52_curses();
/** @param win The curses window this view is attached to. */
void set_window(WINDOW *win) { this->vc_window = win; };

View File

@ -38,6 +38,7 @@
#include "optional.hpp"
#include "base/lnav_log.hh"
#include "base/string_util.hh"
#include "lnav_util.hh"
#include "auto_mem.hh"
#include "yajl/api/yajl_gen.h"
@ -58,12 +59,12 @@ struct from_sqlite_conversion_error : std::exception {
struct sqlite_func_error : std::exception {
template<typename ...Args>
sqlite_func_error(
explicit sqlite_func_error(
fmt::string_view format_str, const Args& ...args) :
e_what(fmt::vformat(format_str, fmt::make_format_args(args...))) {
}
const char *what() const noexcept {
const char *what() const noexcept override {
return this->e_what.c_str();
}
@ -436,11 +437,11 @@ public:
};
const_iterator begin() {
return const_iterator(this);
return {this};
};
const_iterator end() {
return const_iterator(this, this->vic_index_info.nConstraint);
return {this, this->vic_index_info.nConstraint};
};
private:
@ -497,14 +498,26 @@ private:
template<typename T>
struct vtab_module {
struct vtab {
explicit vtab(T& impl) : v_impl(impl) {};
explicit operator sqlite3_vtab *() {
return &this->base;
};
sqlite3_vtab v_base{};
T &v_impl;
};
static int tvt_create(sqlite3 *db,
void *pAux,
int argc, const char *const *argv,
sqlite3_vtab **pp_vt,
char **pzErr) {
static typename T::vtab vt;
auto* mod = static_cast<vtab_module<T> *>(pAux);
auto vt = new vtab(mod->vm_impl);
*pp_vt = (sqlite3_vtab *) vt;
*pp_vt = (sqlite3_vtab *) &vt->v_base;
return sqlite3_declare_vtab(db, T::CREATE_STMT);
};
@ -558,7 +571,7 @@ struct vtab_module {
auto *p_cur = new (typename T::cursor)(p_svt);
if (p_cur == NULL) {
if (p_cur == nullptr) {
return SQLITE_NOMEM;
} else {
*pp_cursor = (sqlite3_vtab_cursor *) p_cur;
@ -598,10 +611,10 @@ struct vtab_module {
};
static int tvt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col) {
auto *mod_vt = (typename vtab_module<T>::vtab *) cur->pVtab;
auto *p_cur = (typename T::cursor *) cur;
T handler;
return handler.get_column(*p_cur, ctx, col);
return mod_vt->v_impl.get_column(*p_cur, ctx, col);
};
static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info) {
@ -620,17 +633,17 @@ struct vtab_module {
int argc,
sqlite3_value **argv,
sqlite_int64 *rowid) {
T handler;
auto *mod_vt = (typename vtab_module<T>::vtab *) tab;
if (argc <= 1) {
sqlite3_int64 rowid = sqlite3_value_int64(argv[0]);
return handler.delete_row(tab, rowid);
return mod_vt->v_impl.delete_row(tab, rowid);
}
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
sqlite3_int64 *rowid2 = rowid;
return vtab_module<T>::apply(handler, &T::insert_row, tab, *rowid2, argc - 2, argv + 2);
return vtab_module<T>::apply(mod_vt->v_impl, &T::insert_row, tab, *rowid2, argc - 2, argv + 2);
}
sqlite3_int64 index = sqlite3_value_int64(argv[0]);
@ -641,7 +654,7 @@ struct vtab_module {
return SQLITE_ERROR;
}
return vtab_module<T>::apply(handler, &T::update_row, tab, index, argc - 2, argv + 2);
return vtab_module<T>::apply(mod_vt->v_impl, &T::update_row, tab, index, argc - 2, argv + 2);
};
template<typename U>
@ -653,7 +666,8 @@ struct vtab_module {
void addUpdate(...) {
};
vtab_module() noexcept {
template<typename ...Args>
vtab_module(Args& ...args) noexcept : vm_impl(args...) {
memset(&this->vm_module, 0, sizeof(this->vm_module));
this->vm_module.iVersion = 0;
this->vm_module.xCreate = tvt_create;
@ -668,52 +682,53 @@ struct vtab_module {
this->vm_module.xBestIndex = vt_best_index;
this->vm_module.xFilter = vt_filter;
this->vm_module.xColumn = tvt_column;
this->addUpdate<T>(T());
this->addUpdate<T>(this->vm_impl);
};
int create(sqlite3 *db, const char *name) {
std::string impl_name = name;
int create(sqlite3 *db, const char *name)
{
auto impl_name = std::string(name);
vtab_module_schemas += T::CREATE_STMT;
vtab_module_ddls[intern_string::lookup(name)] = trim(T::CREATE_STMT);
// XXX Eponymous tables don't seem to work in older sqlite versions
impl_name += "_impl";
int rc = sqlite3_create_module(db, impl_name.c_str(), &this->vm_module, NULL);
int rc = sqlite3_create_module(
db, impl_name.c_str(), &this->vm_module, this);
ensure(rc == SQLITE_OK);
std::string create_stmt = std::string("CREATE VIRTUAL TABLE ") + name + " USING " + impl_name + "()";
return sqlite3_exec(db, create_stmt.c_str(), NULL, NULL, NULL);
auto create_stmt = fmt::format("CREATE VIRTUAL TABLE {} USING {}()",
name, impl_name);
return sqlite3_exec(db, create_stmt.c_str(), nullptr, nullptr, nullptr);
};
sqlite3_module vm_module;
T vm_impl;
};
template<typename T>
struct tvt_iterator_cursor {
struct cursor {
sqlite3_vtab_cursor base;
sqlite3_vtab_cursor base{};
typename T::iterator iter;
cursor(sqlite3_vtab *vt)
explicit cursor(sqlite3_vtab *vt)
{
T handler;
auto* mod_vt = (typename vtab_module<T>::vtab *) vt;
this->base.pVtab = vt;
this->iter = handler.begin();
this->iter = mod_vt->v_impl.begin();
};
int reset() {
T handler;
this->iter = handler.begin();
this->iter = get_handler().begin();
return SQLITE_OK;
};
int next()
{
T handler;
if (this->iter != handler.end()) {
if (this->iter != get_handler().end()) {
++this->iter;
}
@ -722,9 +737,7 @@ struct tvt_iterator_cursor {
int eof()
{
T handler;
return this->iter == handler.end();
return this->iter == get_handler().end();
};
template< bool cond, typename U >
@ -734,9 +747,7 @@ struct tvt_iterator_cursor {
resolvedType< std::is_same<std::random_access_iterator_tag,
typename std::iterator_traits<typename T::iterator>::iterator_category>::value, U >
get_rowid(sqlite_int64 &rowid_out) {
T handler;
rowid_out = std::distance(handler.begin(), this->iter);
rowid_out = std::distance(get_handler().begin(), this->iter);
return SQLITE_OK;
}
@ -745,12 +756,17 @@ struct tvt_iterator_cursor {
resolvedType< !std::is_same<std::random_access_iterator_tag,
typename std::iterator_traits<typename T::iterator>::iterator_category>::value, U >
get_rowid(sqlite_int64 &rowid_out) {
T handler;
rowid_out = handler.get_rowid(this->iter);
rowid_out = get_handler().get_rowid(this->iter);
return SQLITE_OK;
}
private:
T &get_handler() {
auto* mod_vt = (typename vtab_module<T>::vtab *) this->base.pVtab;
return mod_vt->v_impl;
}
};
};

View File

@ -59,7 +59,7 @@
*/
class mouse_behavior {
public:
virtual ~mouse_behavior() { };
virtual ~mouse_behavior() = default;
/**
* Callback used to process mouse events.

View File

@ -36,18 +36,15 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <random>
#include <tuple>
#include <string>
#include <vector>
#include <algorithm>
#include "base/string_util.hh"
#include "lnav_util.hh"
#include "auto_fd.hh"
#include "line_buffer.hh"
@ -57,7 +54,7 @@ int main(int argc, char *argv[])
{
int c, rnd_iters = 5, retval = EXIT_SUCCESS;
vector<tuple<int, off_t, ssize_t> > index;
auto_fd fd = STDIN_FILENO, fd_cmp;
auto_fd fd = auto_fd(STDIN_FILENO), fd_cmp;
int offseti = 0;
off_t offset = 0;
int count = 1000;

View File

@ -16,7 +16,7 @@ struct callback_state {
int cs_row;
};
struct _lnav_data lnav_data;
struct lnav_data_t lnav_data;
static int sql_callback(void *ptr,
int ncols,

View File

@ -38,7 +38,7 @@
using namespace std;
struct _lnav_data lnav_data;
struct lnav_data_t lnav_data;
void rebuild_hist()
{

View File

@ -30,7 +30,6 @@
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
@ -50,7 +49,7 @@ int main(int argc, char *argv[])
fd1 = tmp;
fd1 = tmp;
assert(fcntl(tmp, F_GETFL) >= 0);
fd1 = fd2;
fd1 = std::move(fd2);
assert(fcntl(tmp, F_GETFL) == -1);
assert(errno == EBADF);
assert(fd1 == -1);