mirror of
https://github.com/tstack/lnav
synced 2024-11-01 21:40:34 +00:00
[debt] doing some cleanup
Defect Number: Reviewed By: Testing Done:
This commit is contained in:
parent
21e78670e2
commit
db8a3c4d38
@ -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)
|
||||
|
||||
|
@ -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
109
src/all_logs_vtab.cc
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
1129
src/data_parser.cc
1129
src/data_parser.cc
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
419
src/file_collection.cc
Normal 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
97
src/file_collection.hh
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) { };
|
||||
|
@ -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 ¶m : 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");
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
449
src/lnav.cc
449
src/lnav.cc
@ -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) {
|
||||
|
76
src/lnav.hh
76
src/lnav.hh
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
116
src/lnav_util.hh
116
src/lnav_util.hh
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
})
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
||||
}
|
||||
|
@ -29,9 +29,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "log_level.hh"
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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; };
|
||||
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "lnav.hh"
|
||||
#include "view_helpers.hh"
|
||||
|
||||
struct file_state {
|
||||
bool fs_is_visible{true};
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -31,8 +31,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sqlite3.h>
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
61
src/view_helpers.hh
Normal 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
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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; };
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
||||
*/
|
||||
class mouse_behavior {
|
||||
public:
|
||||
virtual ~mouse_behavior() { };
|
||||
virtual ~mouse_behavior() = default;
|
||||
|
||||
/**
|
||||
* Callback used to process mouse events.
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct _lnav_data lnav_data;
|
||||
struct lnav_data_t lnav_data;
|
||||
|
||||
void rebuild_hist()
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user