2011-06-11 17:26:52 +00:00
|
|
|
/**
|
2013-05-03 06:02:03 +00:00
|
|
|
* Copyright (c) 2007-2012, Timothy Stack
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-05-03 06:02:03 +00:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-05-03 06:02:03 +00:00
|
|
|
* * 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.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-05-03 06:02:03 +00:00
|
|
|
* 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.
|
|
|
|
*
|
2011-06-11 17:26:52 +00:00
|
|
|
* @file lnav.cc
|
|
|
|
*
|
|
|
|
* XXX This file has become a dumping ground for code and needs to be broken up
|
|
|
|
* a bit.
|
|
|
|
*/
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2013-01-20 06:28:21 +00:00
|
|
|
#include <math.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <time.h>
|
|
|
|
#include <glob.h>
|
2013-05-24 14:55:56 +00:00
|
|
|
#include <locale.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-17 21:53:01 +00:00
|
|
|
#include <fcntl.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2012-04-19 02:30:53 +00:00
|
|
|
#include <termios.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
2012-04-24 21:31:35 +00:00
|
|
|
#include <sys/time.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <sys/socket.h>
|
2013-10-11 13:31:17 +00:00
|
|
|
#include <sys/wait.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
#include <readline/readline.h>
|
|
|
|
|
|
|
|
#include <map>
|
2011-06-11 17:26:52 +00:00
|
|
|
#include <set>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <stack>
|
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
2011-06-11 18:24:23 +00:00
|
|
|
#include <fstream>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <sstream>
|
2011-06-11 18:24:23 +00:00
|
|
|
#include <iostream>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
|
|
|
|
2009-10-06 21:14:49 +00:00
|
|
|
#include <sqlite3.h>
|
|
|
|
|
2014-11-04 04:02:22 +00:00
|
|
|
#ifdef HAVE_BZLIB_H
|
|
|
|
#include <bzlib.h>
|
|
|
|
#endif
|
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
#include "lnav.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "help.hh"
|
2013-06-12 04:10:59 +00:00
|
|
|
#include "init-sql.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "logfile.hh"
|
2014-03-02 00:35:30 +00:00
|
|
|
#include "lnav_log.hh"
|
2014-03-16 22:07:08 +00:00
|
|
|
#include "log_accel.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "lnav_util.hh"
|
2013-06-14 13:49:00 +00:00
|
|
|
#include "ansi_scrubber.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "listview_curses.hh"
|
|
|
|
#include "statusview_curses.hh"
|
|
|
|
#include "vt52_curses.hh"
|
|
|
|
#include "readline_curses.hh"
|
|
|
|
#include "textview_curses.hh"
|
|
|
|
#include "logfile_sub_source.hh"
|
2010-11-22 05:44:45 +00:00
|
|
|
#include "textfile_sub_source.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "grep_proc.hh"
|
|
|
|
#include "bookmarks.hh"
|
|
|
|
#include "hist_source.hh"
|
|
|
|
#include "top_status_source.hh"
|
|
|
|
#include "bottom_status_source.hh"
|
|
|
|
#include "piper_proc.hh"
|
|
|
|
#include "log_vtab_impl.hh"
|
|
|
|
#include "db_sub_source.hh"
|
|
|
|
#include "pcrecpp.h"
|
2009-10-14 19:42:58 +00:00
|
|
|
#include "termios_guard.hh"
|
2011-06-18 20:42:07 +00:00
|
|
|
#include "data_parser.hh"
|
2012-04-24 21:31:35 +00:00
|
|
|
#include "xterm_mouse.hh"
|
2012-07-13 16:26:47 +00:00
|
|
|
#include "lnav_commands.hh"
|
2013-05-24 14:55:56 +00:00
|
|
|
#include "column_namer.hh"
|
2013-05-28 14:08:49 +00:00
|
|
|
#include "log_data_table.hh"
|
2013-06-29 13:22:24 +00:00
|
|
|
#include "log_format_loader.hh"
|
2013-05-31 15:01:31 +00:00
|
|
|
#include "session_data.hh"
|
2013-06-06 14:01:32 +00:00
|
|
|
#include "lnav_config.hh"
|
|
|
|
#include "sql_util.hh"
|
|
|
|
#include "sqlite-extension-func.h"
|
2014-11-19 14:12:43 +00:00
|
|
|
#include "sysclip.hh"
|
2014-02-10 15:25:28 +00:00
|
|
|
#include "term_extra.hh"
|
2013-10-11 13:22:29 +00:00
|
|
|
#include "log_data_helper.hh"
|
2014-03-04 15:38:33 +00:00
|
|
|
#include "readline_highlighters.hh"
|
2014-05-07 04:26:05 +00:00
|
|
|
#include "environ_vtab.hh"
|
2015-03-17 06:10:34 +00:00
|
|
|
#include "pretty_printer.hh"
|
2013-05-31 15:01:31 +00:00
|
|
|
|
|
|
|
#include "yajlpp.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
static multimap<lnav_flags_t, string> DEFAULT_FILES;
|
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
struct _lnav_data lnav_data;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
struct hist_level {
|
|
|
|
int hl_bucket_size;
|
|
|
|
int hl_group_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct hist_level HIST_ZOOM_VALUES[] = {
|
|
|
|
{ 24 * 60 * 60, 7 * 24 * 60 * 60 },
|
|
|
|
{ 4 * 60 * 60, 24 * 60 * 60 },
|
|
|
|
{ 60 * 60, 24 * 60 * 60 },
|
|
|
|
{ 10 * 60, 60 * 60 },
|
|
|
|
{ 60, 60 * 60 },
|
|
|
|
};
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
static const int HIST_ZOOM_LEVELS = sizeof(HIST_ZOOM_VALUES) /
|
|
|
|
sizeof(struct hist_level);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2015-03-29 21:50:34 +00:00
|
|
|
static bookmark_type_t BM_EXAMPLE("");
|
|
|
|
static bookmark_type_t BM_QUERY("query");
|
2011-06-11 17:26:52 +00:00
|
|
|
|
2014-03-02 16:55:00 +00:00
|
|
|
const char *lnav_view_strings[LNV__MAX + 1] = {
|
2013-05-31 15:01:31 +00:00
|
|
|
"log",
|
|
|
|
"text",
|
|
|
|
"help",
|
|
|
|
"histogram",
|
|
|
|
"graph",
|
|
|
|
"db",
|
|
|
|
"example",
|
2014-02-24 19:43:50 +00:00
|
|
|
"schema",
|
2015-03-17 06:10:34 +00:00
|
|
|
"pretty",
|
2014-03-02 16:55:00 +00:00
|
|
|
|
|
|
|
NULL
|
2013-05-31 15:01:31 +00:00
|
|
|
};
|
|
|
|
|
2015-04-04 20:36:53 +00:00
|
|
|
const char *lnav_zoom_strings[] = {
|
|
|
|
"day",
|
|
|
|
"4-hour",
|
|
|
|
"hour",
|
|
|
|
"10-minute",
|
|
|
|
"minute",
|
|
|
|
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2014-02-10 15:25:28 +00:00
|
|
|
static const char *view_titles[LNV__MAX] = {
|
|
|
|
"LOG",
|
|
|
|
"TEXT",
|
|
|
|
"HELP",
|
|
|
|
"HIST",
|
|
|
|
"GRAPH",
|
|
|
|
"DB",
|
|
|
|
"EXAMPLE",
|
2014-02-24 19:43:50 +00:00
|
|
|
"SCHEMA",
|
2015-03-17 06:10:34 +00:00
|
|
|
"PRETTY",
|
2014-02-10 15:25:28 +00:00
|
|
|
};
|
|
|
|
|
2014-03-13 06:20:18 +00:00
|
|
|
static bool rescan_files(bool required = false);
|
|
|
|
|
2014-02-21 04:00:51 +00:00
|
|
|
class log_gutter_source : public list_gutter_source {
|
|
|
|
public:
|
2014-03-09 09:29:28 +00:00
|
|
|
void listview_gutter_value_for_range(
|
|
|
|
const listview_curses &lv, int start, int end, chtype &ch, int &fg_out) {
|
2014-02-21 04:00:51 +00:00
|
|
|
textview_curses *tc = (textview_curses *)&lv;
|
|
|
|
vis_bookmarks &bm = tc->get_bookmarks();
|
|
|
|
vis_line_t next;
|
2014-02-21 04:22:20 +00:00
|
|
|
bool search_hit = false;
|
|
|
|
|
|
|
|
start -= 1;
|
|
|
|
|
|
|
|
next = bm[&textview_curses::BM_SEARCH].next(vis_line_t(start));
|
|
|
|
search_hit = (next != -1 && next <= end);
|
2014-02-21 04:00:51 +00:00
|
|
|
|
2014-02-23 06:52:21 +00:00
|
|
|
next = bm[&BM_QUERY].next(vis_line_t(start));
|
|
|
|
search_hit = search_hit || (next != -1 && next <= end);
|
|
|
|
|
2014-02-21 04:00:51 +00:00
|
|
|
next = bm[&textview_curses::BM_USER].next(vis_line_t(start));
|
2014-03-07 13:20:49 +00:00
|
|
|
if (next == -1) {
|
|
|
|
next = bm[&textview_curses::BM_PARTITION].next(vis_line_t(start));
|
|
|
|
}
|
2014-02-21 04:00:51 +00:00
|
|
|
if (next != -1 && next <= end) {
|
2014-02-21 04:22:20 +00:00
|
|
|
ch = search_hit ? ACS_PLUS : ACS_LTEE;
|
2014-02-21 04:00:51 +00:00
|
|
|
}
|
|
|
|
else {
|
2014-02-21 04:22:20 +00:00
|
|
|
ch = search_hit ? ACS_RTEE : ACS_VLINE;
|
2014-02-21 04:00:51 +00:00
|
|
|
}
|
|
|
|
next = bm[&logfile_sub_source::BM_ERRORS].next(vis_line_t(start));
|
|
|
|
if (next != -1 && next <= end) {
|
2014-02-23 06:52:21 +00:00
|
|
|
fg_out = COLOR_RED;
|
2014-02-21 04:00:51 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
next = bm[&logfile_sub_source::BM_WARNINGS].next(vis_line_t(start));
|
|
|
|
if (next != -1 && next <= end) {
|
2014-02-23 06:52:21 +00:00
|
|
|
fg_out = COLOR_YELLOW;
|
2014-02-21 04:00:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2013-05-24 14:55:56 +00:00
|
|
|
class field_overlay_source : public list_overlay_source {
|
|
|
|
public:
|
2013-10-11 13:22:29 +00:00
|
|
|
field_overlay_source(logfile_sub_source &lss)
|
2013-05-28 04:35:00 +00:00
|
|
|
: fos_active(false),
|
|
|
|
fos_active_prev(false),
|
2014-03-13 05:50:11 +00:00
|
|
|
fos_log_helper(lss) {
|
|
|
|
|
|
|
|
};
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
size_t list_overlay_count(const listview_curses &lv)
|
|
|
|
{
|
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
2014-05-05 13:44:58 +00:00
|
|
|
view_colors &vc = view_colors::singleton();
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
if (!this->fos_active) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lss.text_line_count() == 0) {
|
2014-01-16 14:37:02 +00:00
|
|
|
this->fos_log_helper.clear();
|
2013-05-28 04:35:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
content_line_t cl = lss.at(lv.get_top());
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
if (!this->fos_log_helper.parse_line(cl)) {
|
2013-09-10 13:20:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
this->fos_known_key_size = 0;
|
2014-11-07 06:41:48 +00:00
|
|
|
this->fos_unknown_key_size = 0;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
for (std::vector<logline_value>::iterator iter =
|
2013-10-11 13:22:29 +00:00
|
|
|
this->fos_log_helper.ldh_line_values.begin();
|
|
|
|
iter != this->fos_log_helper.ldh_line_values.end();
|
2013-05-28 04:35:00 +00:00
|
|
|
++iter) {
|
2014-05-05 13:44:58 +00:00
|
|
|
this->fos_known_key_size = max(this->fos_known_key_size,
|
2014-10-28 14:02:27 +00:00
|
|
|
(int)iter->lv_name.size());
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (data_parser::element_list_t::iterator iter =
|
2013-10-11 13:22:29 +00:00
|
|
|
this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
|
|
|
iter != this->fos_log_helper.ldh_parser->dp_pairs.end();
|
2013-05-28 04:35:00 +00:00
|
|
|
++iter) {
|
2013-10-11 13:22:29 +00:00
|
|
|
std::string colname = this->fos_log_helper.ldh_parser->get_element_string(
|
2013-05-28 04:35:00 +00:00
|
|
|
iter->e_sub_elements->front());
|
|
|
|
|
2014-03-13 05:50:11 +00:00
|
|
|
colname = this->fos_log_helper.ldh_namer->add_column(colname);
|
2014-05-05 13:44:58 +00:00
|
|
|
this->fos_unknown_key_size = max(
|
|
|
|
this->fos_unknown_key_size, (int)colname.length());
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
this->fos_lines.clear();
|
|
|
|
|
|
|
|
char old_timestamp[64], curr_timestamp[64];
|
|
|
|
struct timeval curr_tv, offset_tv, orig_tv;
|
|
|
|
char log_time[256];
|
|
|
|
|
|
|
|
sql_strftime(curr_timestamp, sizeof(curr_timestamp),
|
|
|
|
this->fos_log_helper.ldh_line->get_time(),
|
|
|
|
this->fos_log_helper.ldh_line->get_millis(),
|
|
|
|
'T');
|
|
|
|
curr_tv = this->fos_log_helper.ldh_line->get_timeval();
|
|
|
|
offset_tv = this->fos_log_helper.ldh_file->get_time_offset();
|
|
|
|
timersub(&curr_tv, &offset_tv, &orig_tv);
|
|
|
|
sql_strftime(old_timestamp, sizeof(old_timestamp),
|
|
|
|
orig_tv.tv_sec, orig_tv.tv_usec / 1000,
|
|
|
|
'T');
|
|
|
|
snprintf(log_time, sizeof(log_time),
|
|
|
|
" Current Time: %s Original Time: %s Offset: %+d.%03d",
|
|
|
|
curr_timestamp,
|
|
|
|
old_timestamp,
|
2015-03-29 01:20:44 +00:00
|
|
|
(int)offset_tv.tv_sec, (int)(offset_tv.tv_usec / 1000));
|
2014-05-05 13:44:58 +00:00
|
|
|
this->fos_lines.push_back(log_time);
|
|
|
|
|
|
|
|
if (this->fos_log_helper.ldh_line_values.empty()) {
|
|
|
|
this->fos_lines.push_back(" No known message fields");
|
|
|
|
}
|
|
|
|
else{
|
2015-04-07 13:09:49 +00:00
|
|
|
this->fos_lines.push_back(" Known message fields: (SQL table -- " +
|
|
|
|
this->fos_log_helper.ldh_file->get_format()->get_name() +
|
|
|
|
")");
|
2014-05-05 13:44:58 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
for (size_t lpc = 0; lpc < this->fos_log_helper.ldh_line_values.size(); lpc++) {
|
|
|
|
logline_value &lv = this->fos_log_helper.ldh_line_values[lpc];
|
|
|
|
attr_line_t al;
|
|
|
|
string str;
|
2014-03-04 15:38:33 +00:00
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
str = " " + lv.lv_name.to_string();
|
2014-05-05 13:44:58 +00:00
|
|
|
str.append(this->fos_known_key_size - lv.lv_name.size() + 3, ' ');
|
|
|
|
str += " = " + lv.to_string();
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
al.with_string(str)
|
|
|
|
.with_attr(string_attr(
|
2014-10-28 14:02:27 +00:00
|
|
|
line_range(3, 3 + lv.lv_name.size()),
|
2014-05-05 13:44:58 +00:00
|
|
|
&view_curses::VC_STYLE,
|
2014-10-28 14:02:27 +00:00
|
|
|
vc.attrs_for_ident(lv.lv_name.to_string())));
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
this->fos_lines.push_back(al);
|
|
|
|
this->add_key_line_attrs(this->fos_known_key_size);
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, json_ptr_walk::pair_list_t>::iterator json_iter;
|
2014-03-04 15:38:33 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
if (!this->fos_log_helper.ldh_json_pairs.empty()) {
|
|
|
|
this->fos_lines.push_back(" JSON fields:");
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
for (json_iter = this->fos_log_helper.ldh_json_pairs.begin();
|
|
|
|
json_iter != this->fos_log_helper.ldh_json_pairs.end();
|
|
|
|
++json_iter) {
|
|
|
|
json_ptr_walk::pair_list_t &jpairs = json_iter->second;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
for (size_t lpc = 0; lpc < jpairs.size(); lpc++) {
|
|
|
|
this->fos_lines.push_back(" " +
|
|
|
|
this->fos_log_helper.format_json_getter(json_iter->first, lpc) + " = " +
|
|
|
|
jpairs[lpc].second);
|
|
|
|
this->add_key_line_attrs(0);
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
if (this->fos_log_helper.ldh_parser->dp_pairs.empty()) {
|
|
|
|
this->fos_lines.push_back(" No discovered message fields");
|
|
|
|
}
|
|
|
|
else {
|
2015-04-07 13:09:49 +00:00
|
|
|
this->fos_lines.push_back(" Discovered message fields: (SQL table -- logline)");
|
2014-05-05 13:44:58 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
data_parser::element_list_t::iterator iter;
|
2014-03-04 15:38:33 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
iter = this->fos_log_helper.ldh_parser->dp_pairs.begin();
|
|
|
|
for (size_t lpc = 0;
|
|
|
|
lpc < this->fos_log_helper.ldh_parser->dp_pairs.size(); lpc++, ++iter) {
|
|
|
|
string &name = this->fos_log_helper.ldh_namer->cn_names[lpc];
|
|
|
|
string val = this->fos_log_helper.ldh_parser->get_element_string(
|
|
|
|
iter->e_sub_elements->back());
|
|
|
|
attr_line_t al(" " + name + " = " + val);
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
al.with_attr(string_attr(
|
2014-03-04 15:38:33 +00:00
|
|
|
line_range(3, 3 + name.length()),
|
|
|
|
&view_curses::VC_STYLE,
|
|
|
|
vc.attrs_for_ident(name)));
|
2014-05-05 13:44:58 +00:00
|
|
|
|
|
|
|
this->fos_lines.push_back(al);
|
|
|
|
this->add_key_line_attrs(this->fos_unknown_key_size,
|
|
|
|
lpc == (this->fos_log_helper.ldh_parser->dp_pairs.size() - 1));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
return this->fos_lines.size();
|
|
|
|
};
|
|
|
|
|
|
|
|
void add_key_line_attrs(int key_size, bool last_line = false) {
|
|
|
|
string_attrs_t &sa = this->fos_lines.back().get_attrs();
|
2013-10-11 13:22:29 +00:00
|
|
|
struct line_range lr(1, 2);
|
2014-01-25 17:29:35 +00:00
|
|
|
sa.push_back(string_attr(lr, &view_curses::VC_GRAPHIC, last_line ? ACS_LLCORNER : ACS_LTEE));
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
lr.lr_start = 3 + key_size + 3;
|
2013-05-28 04:35:00 +00:00
|
|
|
lr.lr_end = -1;
|
2014-01-25 17:29:35 +00:00
|
|
|
sa.push_back(string_attr(lr, &view_curses::VC_STYLE, A_BOLD));
|
2014-05-05 13:44:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
bool list_value_for_overlay(const listview_curses &lv,
|
|
|
|
vis_line_t y,
|
|
|
|
attr_line_t &value_out)
|
|
|
|
{
|
|
|
|
if (!this->fos_active || this->fos_log_helper.ldh_parser.get() == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int row = (int)y - 1;
|
|
|
|
|
|
|
|
if (row < 0 || row >= (int)this->fos_lines.size()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
value_out = this->fos_lines[row];
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool fos_active;
|
|
|
|
bool fos_active_prev;
|
2013-10-11 13:22:29 +00:00
|
|
|
log_data_helper fos_log_helper;
|
2014-05-05 13:44:58 +00:00
|
|
|
int fos_known_key_size;
|
|
|
|
int fos_unknown_key_size;
|
|
|
|
vector<attr_line_t> fos_lines;
|
2013-05-24 14:55:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int handle_collation_list(void *ptr,
|
|
|
|
int ncols,
|
|
|
|
char **colvalues,
|
|
|
|
char **colnames)
|
|
|
|
{
|
2014-03-01 04:35:07 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
return 0;
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_db_list(void *ptr,
|
|
|
|
int ncols,
|
|
|
|
char **colvalues,
|
|
|
|
char **colnames)
|
|
|
|
{
|
2014-03-01 04:35:07 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
return 0;
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_table_list(void *ptr,
|
|
|
|
int ncols,
|
|
|
|
char **colvalues,
|
|
|
|
char **colnames)
|
|
|
|
{
|
2014-03-01 04:35:07 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[0]);
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
return 0;
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_table_info(void *ptr,
|
|
|
|
int ncols,
|
|
|
|
char **colvalues,
|
|
|
|
char **colnames)
|
|
|
|
{
|
2014-03-01 04:35:07 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
if (strcmp(colvalues[5], "1") == 0) {
|
|
|
|
lnav_data.ld_db_key_names.push_back(colvalues[1]);
|
|
|
|
}
|
|
|
|
return 0;
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_foreign_key_list(void *ptr,
|
|
|
|
int ncols,
|
|
|
|
char **colvalues,
|
|
|
|
char **colnames)
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_db_key_names.push_back(colvalues[3]);
|
|
|
|
lnav_data.ld_db_key_names.push_back(colvalues[4]);
|
|
|
|
return 0;
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 14:01:32 +00:00
|
|
|
struct sqlite_metadata_callbacks lnav_sql_meta_callbacks = {
|
|
|
|
handle_collation_list,
|
|
|
|
handle_db_list,
|
|
|
|
handle_table_list,
|
|
|
|
handle_table_info,
|
|
|
|
handle_foreign_key_list,
|
|
|
|
};
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2014-10-30 15:37:06 +00:00
|
|
|
static void add_text_possibilities(
|
|
|
|
int context, const string &type, const std::string &str)
|
2014-02-23 06:52:21 +00:00
|
|
|
{
|
|
|
|
static pcrecpp::RE re_escape("([.\\^$*+?()\\[\\]{}\\\\|])");
|
|
|
|
static pcrecpp::RE re_escape_no_dot("([\\^$*+?()\\[\\]{}\\\\|])");
|
|
|
|
|
|
|
|
readline_curses *rlc = lnav_data.ld_rl_view;
|
|
|
|
pcre_context_static<30> pc;
|
|
|
|
data_scanner ds(str);
|
|
|
|
data_token_t dt;
|
|
|
|
|
|
|
|
while (ds.tokenize(pc, dt)) {
|
|
|
|
if (pc[0]->length() < 4) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (dt) {
|
|
|
|
case DT_DATE:
|
|
|
|
case DT_TIME:
|
2014-03-09 09:29:28 +00:00
|
|
|
case DT_WHITE:
|
2014-02-23 06:52:21 +00:00
|
|
|
continue;
|
2014-03-09 09:29:28 +00:00
|
|
|
default:
|
2014-02-23 06:52:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (context) {
|
2014-10-30 15:37:06 +00:00
|
|
|
case LNM_SEARCH:
|
|
|
|
case LNM_COMMAND: {
|
2014-02-23 06:52:21 +00:00
|
|
|
string token_value, token_value_no_dot;
|
|
|
|
|
|
|
|
token_value_no_dot = token_value =
|
|
|
|
ds.get_input().get_substr(pc.all());
|
|
|
|
re_escape.GlobalReplace("\\\\\\1", &token_value);
|
|
|
|
re_escape_no_dot.GlobalReplace("\\\\\\1", &token_value_no_dot);
|
2014-10-30 15:37:06 +00:00
|
|
|
rlc->add_possibility(context, type, token_value);
|
2014-02-23 06:52:21 +00:00
|
|
|
if (token_value != token_value_no_dot) {
|
2014-10-30 15:37:06 +00:00
|
|
|
rlc->add_possibility(context, type, token_value_no_dot);
|
2014-02-23 06:52:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LNM_SQL: {
|
|
|
|
string token_value = ds.get_input().get_substr(pc.all());
|
2014-02-24 19:43:50 +00:00
|
|
|
auto_mem<char, sqlite3_free> quoted_token;
|
2014-02-23 06:52:21 +00:00
|
|
|
|
2014-02-24 19:43:50 +00:00
|
|
|
quoted_token = sqlite3_mprintf("%Q", token_value.c_str());
|
2014-10-30 15:37:06 +00:00
|
|
|
rlc->add_possibility(context, type, std::string(quoted_token));
|
2014-02-23 06:52:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (dt) {
|
|
|
|
case DT_QUOTED_STRING:
|
2014-10-30 15:37:06 +00:00
|
|
|
add_text_possibilities(context, type, ds.get_input().get_substr(pc[0]));
|
2014-02-23 06:52:21 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-30 15:37:06 +00:00
|
|
|
static void add_view_text_possibilities(
|
|
|
|
int context, const string &type, textview_curses *tc)
|
2014-02-23 06:52:21 +00:00
|
|
|
{
|
|
|
|
text_sub_source *tss = tc->get_sub_source();
|
|
|
|
readline_curses *rlc = lnav_data.ld_rl_view;
|
|
|
|
|
2014-10-30 15:37:06 +00:00
|
|
|
rlc->clear_possibilities(context, type);
|
2014-11-19 14:12:43 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
auto_mem<FILE> pfile(pclose);
|
|
|
|
|
|
|
|
pfile = open_clipboard(CT_FIND, CO_READ);
|
|
|
|
if (pfile.in() != NULL) {
|
|
|
|
char buffer[64];
|
|
|
|
|
|
|
|
if (fgets(buffer, sizeof(buffer), pfile) != NULL) {
|
|
|
|
char *nl;
|
|
|
|
|
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
|
|
|
if ((nl = strchr(buffer, '\n')) != NULL) {
|
|
|
|
*nl = '\0';
|
|
|
|
}
|
|
|
|
rlc->add_possibility(context, type, std::string(buffer));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-23 06:52:21 +00:00
|
|
|
for (vis_line_t curr_line = tc->get_top();
|
2014-11-19 14:12:43 +00:00
|
|
|
curr_line <= tc->get_bottom();
|
2014-02-23 06:52:21 +00:00
|
|
|
++curr_line) {
|
|
|
|
string line;
|
|
|
|
|
|
|
|
tss->text_value_for_line(*tc, curr_line, line);
|
|
|
|
|
2014-10-30 15:37:06 +00:00
|
|
|
add_text_possibilities(context, type, line);
|
2014-02-23 06:52:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 11:32:37 +00:00
|
|
|
static void add_env_possibilities(int context)
|
|
|
|
{
|
|
|
|
extern char **environ;
|
|
|
|
readline_curses *rlc = lnav_data.ld_rl_view;
|
|
|
|
|
|
|
|
for (char **var = environ; *var != NULL; var++) {
|
|
|
|
rlc->add_possibility(context, "*", "$" + string(*var, strchr(*var, '=')));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
static void add_filter_possibilities(textview_curses *tc)
|
|
|
|
{
|
|
|
|
readline_curses *rc = lnav_data.ld_rl_view;
|
|
|
|
text_sub_source *tss = tc->get_sub_source();
|
|
|
|
filter_stack &fs = tss->get_filters();
|
|
|
|
|
|
|
|
rc->clear_possibilities(LNM_COMMAND, "disabled-filter");
|
|
|
|
rc->clear_possibilities(LNM_COMMAND, "enabled-filter");
|
|
|
|
for (filter_stack::iterator iter = fs.begin();
|
|
|
|
iter != fs.end();
|
|
|
|
++iter) {
|
|
|
|
text_filter *tf = *iter;
|
|
|
|
|
|
|
|
if (tf->is_enabled()) {
|
|
|
|
rc->add_possibility(LNM_COMMAND, "enabled-filter", tf->get_id());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rc->add_possibility(LNM_COMMAND, "disabled-filter", tf->get_id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-29 21:50:34 +00:00
|
|
|
static void add_mark_possibilities()
|
|
|
|
{
|
|
|
|
readline_curses *rc = lnav_data.ld_rl_view;
|
|
|
|
|
|
|
|
rc->clear_possibilities(LNM_COMMAND, "mark-type");
|
|
|
|
for (bookmark_type_t::type_iterator iter = bookmark_type_t::type_begin();
|
|
|
|
iter != bookmark_type_t::type_end();
|
|
|
|
++iter) {
|
|
|
|
bookmark_type_t *bt = (*iter);
|
|
|
|
|
|
|
|
if (bt->get_name().empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rc->add_possibility(LNM_COMMAND, "mark-type", bt->get_name());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 02:34:48 +00:00
|
|
|
bool setup_logline_table()
|
|
|
|
{
|
2013-06-22 17:19:30 +00:00
|
|
|
// Hidden columns don't show up in the table_info pragma.
|
|
|
|
static const char *hidden_table_columns[] = {
|
|
|
|
"log_path",
|
|
|
|
"log_text",
|
2013-08-28 15:16:26 +00:00
|
|
|
|
|
|
|
NULL
|
2013-06-22 17:19:30 +00:00
|
|
|
};
|
|
|
|
|
2014-02-24 19:43:50 +00:00
|
|
|
static const char *commands[] = {
|
|
|
|
".schema",
|
|
|
|
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2013-06-06 02:34:48 +00:00
|
|
|
textview_curses &log_view = lnav_data.ld_views[LNV_LOG];
|
2013-06-16 01:07:50 +00:00
|
|
|
bool retval = false;
|
2013-06-06 02:34:48 +00:00
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
lnav_data.ld_rl_view->clear_possibilities(LNM_SQL, "*");
|
2014-10-30 15:37:06 +00:00
|
|
|
add_view_text_possibilities(LNM_SQL, "*", &log_view);
|
2014-05-05 13:44:58 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 02:34:48 +00:00
|
|
|
if (log_view.get_inner_height()) {
|
|
|
|
vis_line_t vl = log_view.get_top();
|
2014-02-20 04:23:19 +00:00
|
|
|
content_line_t cl = lnav_data.ld_log_source.at_base(vl);
|
2013-06-06 02:34:48 +00:00
|
|
|
|
|
|
|
lnav_data.ld_vtab_manager->unregister_vtab("logline");
|
|
|
|
lnav_data.ld_vtab_manager->register_vtab(new log_data_table(cl));
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
log_data_helper ldh(lnav_data.ld_log_source);
|
|
|
|
|
|
|
|
ldh.parse_line(cl);
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, json_ptr_walk::pair_list_t>::const_iterator pair_iter;
|
2014-05-05 13:44:58 +00:00
|
|
|
for (pair_iter = ldh.ldh_json_pairs.begin();
|
|
|
|
pair_iter != ldh.ldh_json_pairs.end();
|
|
|
|
++pair_iter) {
|
2015-04-02 08:48:21 +00:00
|
|
|
for (size_t lpc = 0; lpc < pair_iter->second.size(); lpc++) {
|
2014-05-05 13:44:58 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*",
|
|
|
|
ldh.format_json_getter(pair_iter->first, lpc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 02:34:48 +00:00
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
|
2013-06-06 14:01:32 +00:00
|
|
|
lnav_data.ld_db_key_names.clear();
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
2014-04-18 11:32:37 +00:00
|
|
|
add_env_possibilities(LNM_SQL);
|
2013-06-06 14:01:32 +00:00
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", sql_keywords);
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", sql_function_names);
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*",
|
|
|
|
hidden_table_columns);
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", commands);
|
2013-06-22 14:55:49 +00:00
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
for (int lpc = 0; sqlite_registration_funcs[lpc]; lpc++) {
|
|
|
|
const struct FuncDef *basic_funcs;
|
|
|
|
const struct FuncDefAgg *agg_funcs;
|
|
|
|
|
|
|
|
sqlite_registration_funcs[lpc](&basic_funcs, &agg_funcs);
|
|
|
|
for (int lpc2 = 0; basic_funcs && basic_funcs[lpc2].zName; lpc2++) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL,
|
|
|
|
"*",
|
|
|
|
basic_funcs[lpc2].zName);
|
|
|
|
}
|
|
|
|
for (int lpc2 = 0; agg_funcs && agg_funcs[lpc2].zName; lpc2++) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_SQL,
|
|
|
|
"*",
|
|
|
|
agg_funcs[lpc2].zName);
|
|
|
|
}
|
2013-06-22 14:55:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 14:01:32 +00:00
|
|
|
walk_sqlite_metadata(lnav_data.ld_db.in(), lnav_sql_meta_callbacks);
|
|
|
|
|
2013-06-12 13:59:48 +00:00
|
|
|
{
|
|
|
|
log_vtab_manager::iterator iter;
|
|
|
|
|
|
|
|
for (iter = lnav_data.ld_vtab_manager->begin();
|
|
|
|
iter != lnav_data.ld_vtab_manager->end();
|
|
|
|
++iter) {
|
|
|
|
iter->second->get_foreign_keys(lnav_data.ld_db_key_names);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 14:01:32 +00:00
|
|
|
stable_sort(lnav_data.ld_db_key_names.begin(),
|
|
|
|
lnav_data.ld_db_key_names.end());
|
2013-06-06 02:34:48 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2012-11-28 16:39:39 +00:00
|
|
|
/**
|
|
|
|
* Observer for loading progress that updates the bottom status bar.
|
|
|
|
*/
|
2009-09-14 01:07:32 +00:00
|
|
|
class loading_observer
|
2014-11-03 14:07:36 +00:00
|
|
|
: public logfile_observer {
|
2009-09-14 01:07:32 +00:00
|
|
|
public:
|
|
|
|
loading_observer()
|
2014-11-03 14:07:36 +00:00
|
|
|
: lo_last_offset(0) {
|
|
|
|
|
|
|
|
};
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
void logfile_indexing(logfile &lf, off_t off, size_t total)
|
|
|
|
{
|
2014-01-25 20:13:41 +00:00
|
|
|
static sig_atomic_t index_counter = 0;
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
if (lnav_data.ld_flags & LNF_HEADLESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-06 14:58:49 +00:00
|
|
|
/* XXX require(off <= total); */
|
2013-05-28 04:35:00 +00:00
|
|
|
if (off > (off_t)total) {
|
|
|
|
off = total;
|
|
|
|
}
|
|
|
|
|
2014-03-15 11:40:58 +00:00
|
|
|
if ((((size_t)off == total) && (this->lo_last_offset != off)) ||
|
2014-01-25 20:13:41 +00:00
|
|
|
ui_periodic_timer::singleton().time_to_update(index_counter)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_bottom_source.update_loading(off, total);
|
|
|
|
this->do_update();
|
|
|
|
this->lo_last_offset = off;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lnav_data.ld_looping) {
|
|
|
|
throw logfile::error(lf.get_filename(), EINTR);
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
void do_update(void)
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_top_source.update_time();
|
|
|
|
lnav_data.ld_status[LNS_TOP].do_update();
|
|
|
|
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
|
|
|
refresh();
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
off_t lo_last_offset;
|
|
|
|
};
|
|
|
|
|
2015-04-04 20:36:53 +00:00
|
|
|
class hist_index_delegate : public index_delegate {
|
|
|
|
public:
|
|
|
|
hist_index_delegate(hist_source &hs, textview_curses &tc)
|
|
|
|
: hid_source(hs), hid_view(tc) {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
void index_start(logfile_sub_source &lss) {
|
|
|
|
this->hid_source.clear();
|
|
|
|
};
|
|
|
|
|
|
|
|
void index_line(logfile_sub_source &lss, logfile *lf, logfile::iterator ll) {
|
|
|
|
if (ll->get_level() & logline::LEVEL_CONTINUED) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->hid_source.add_value(ll->get_time(),
|
|
|
|
bucket_type_t(ll->get_level() & ~logline::LEVEL__FLAGS));
|
|
|
|
};
|
|
|
|
|
|
|
|
void index_complete(logfile_sub_source &lss) {
|
|
|
|
this->hid_view.reload_data();
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
hist_source &hid_source;
|
|
|
|
textview_curses &hid_view;
|
|
|
|
};
|
|
|
|
|
|
|
|
void rebuild_hist(size_t old_count, bool force)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2013-06-16 01:07:50 +00:00
|
|
|
textview_curses & hist_view = lnav_data.ld_views[LNV_HISTOGRAM];
|
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
|
|
|
size_t new_count = lss.text_line_count();
|
2013-05-28 04:35:00 +00:00
|
|
|
hist_source &hs = lnav_data.ld_hist_source;
|
|
|
|
int zoom_level = lnav_data.ld_hist_zoom;
|
|
|
|
time_t old_time;
|
|
|
|
int lpc;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
old_time = hs.value_for_row(hist_view.get_top());
|
|
|
|
hs.set_bucket_size(HIST_ZOOM_VALUES[zoom_level].hl_bucket_size);
|
|
|
|
hs.set_group_size(HIST_ZOOM_VALUES[zoom_level].hl_group_size);
|
|
|
|
if (force) {
|
2013-05-28 04:35:00 +00:00
|
|
|
hs.clear();
|
2015-03-22 18:49:37 +00:00
|
|
|
old_count = 0;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2009-10-14 19:42:58 +00:00
|
|
|
for (lpc = old_count; lpc < (int)new_count; lpc++) {
|
2013-05-28 04:35:00 +00:00
|
|
|
logline *ll = lss.find_line(lss.at(vis_line_t(lpc)));
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (!(ll->get_level() & logline::LEVEL_CONTINUED)) {
|
|
|
|
hs.add_value(ll->get_time(),
|
|
|
|
bucket_type_t(ll->get_level() &
|
|
|
|
~logline::LEVEL__FLAGS));
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
hist_view.reload_data();
|
|
|
|
hist_view.set_top(hs.row_for_value(old_time));
|
|
|
|
}
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
class textfile_callback {
|
|
|
|
public:
|
|
|
|
textfile_callback() : force(false), front_file(NULL), front_top(-1) { };
|
|
|
|
|
|
|
|
void closed_file(logfile *lf) {
|
2015-04-07 13:09:49 +00:00
|
|
|
log_info("closed text file: %s", lf->get_filename().c_str());
|
2015-03-28 13:30:30 +00:00
|
|
|
lnav_data.ld_file_names.erase(make_pair(lf->get_filename(), lf->get_fd()));
|
|
|
|
lnav_data.ld_files.remove(lf);
|
|
|
|
delete lf;
|
|
|
|
};
|
|
|
|
|
|
|
|
void promote_file(logfile *lf) {
|
|
|
|
if (lnav_data.ld_log_source.insert_file(lf)) {
|
|
|
|
force = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->closed_file(lf);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void scanned_file(logfile *lf) {
|
|
|
|
if (!lnav_data.ld_files_to_front.empty() &&
|
|
|
|
lnav_data.ld_files_to_front.front().first ==
|
|
|
|
lf->get_filename()) {
|
|
|
|
front_file = lf;
|
|
|
|
front_top = lnav_data.ld_files_to_front.front().second;
|
|
|
|
|
|
|
|
lnav_data.ld_files_to_front.pop_front();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool force;
|
|
|
|
logfile *front_file;
|
|
|
|
int front_top;
|
|
|
|
};
|
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
void rebuild_indexes(bool force)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
|
|
|
textview_curses & log_view = lnav_data.ld_views[LNV_LOG];
|
|
|
|
textview_curses & text_view = lnav_data.ld_views[LNV_TEXT];
|
2013-11-06 15:29:20 +00:00
|
|
|
vis_line_t old_bottom(0);
|
2013-05-28 04:35:00 +00:00
|
|
|
content_line_t top_content = content_line_t(-1);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
bool scroll_down;
|
|
|
|
size_t old_count;
|
|
|
|
time_t old_time;
|
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
old_count = lss.text_line_count();
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (old_count) {
|
|
|
|
top_content = lss.at(log_view.get_top());
|
|
|
|
}
|
2012-07-13 16:26:47 +00:00
|
|
|
|
2010-11-22 05:44:45 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
textfile_sub_source * tss = &lnav_data.ld_text_source;
|
|
|
|
std::list<logfile *>::iterator iter;
|
2015-03-28 13:30:30 +00:00
|
|
|
bool new_data;
|
2010-12-28 17:39:57 +00:00
|
|
|
|
2013-11-06 15:29:20 +00:00
|
|
|
old_bottom = text_view.get_top_for_last_row();
|
2014-03-13 06:20:18 +00:00
|
|
|
scroll_down = (text_view.get_top() >= old_bottom &&
|
|
|
|
!(lnav_data.ld_flags & LNF_HEADLESS));
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
textfile_callback cb;
|
2013-09-11 03:13:08 +00:00
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
new_data = tss->rescan_files(cb);
|
|
|
|
force = force || cb.force;
|
2010-12-28 17:39:57 +00:00
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
if (cb.front_file != NULL) {
|
2013-09-14 19:30:57 +00:00
|
|
|
ensure_view(&text_view);
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
if (tss->current_file() != cb.front_file) {
|
|
|
|
tss->to_front(cb.front_file);
|
2013-09-14 19:30:57 +00:00
|
|
|
redo_search(LNV_TEXT);
|
|
|
|
text_view.reload_data();
|
|
|
|
old_bottom = vis_line_t(-1);
|
|
|
|
|
|
|
|
new_data = false;
|
|
|
|
}
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
if (cb.front_top < 0) {
|
|
|
|
cb.front_top += text_view.get_inner_height();
|
2014-03-01 04:35:07 +00:00
|
|
|
}
|
2015-03-28 13:30:30 +00:00
|
|
|
if (cb.front_top < text_view.get_inner_height()) {
|
|
|
|
text_view.set_top(vis_line_t(cb.front_top));
|
2013-09-14 19:30:57 +00:00
|
|
|
scroll_down = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-11 03:13:08 +00:00
|
|
|
if (new_data && lnav_data.ld_search_child[LNV_TEXT].get() != NULL) {
|
|
|
|
lnav_data.ld_search_child[LNV_TEXT]->get_grep_proc()->reset();
|
|
|
|
lnav_data.ld_search_child[LNV_TEXT]->get_grep_proc()->
|
|
|
|
queue_request(grep_line_t(-1));
|
|
|
|
lnav_data.ld_search_child[LNV_TEXT]->get_grep_proc()->start();
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
text_view.reload_data();
|
2010-12-28 17:39:57 +00:00
|
|
|
|
2013-11-06 15:29:20 +00:00
|
|
|
if (scroll_down && text_view.get_top_for_last_row() > text_view.get_top()) {
|
|
|
|
text_view.set_top(text_view.get_top_for_last_row());
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2010-11-22 05:44:45 +00:00
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
old_time = lnav_data.ld_top_time;
|
2013-11-06 15:29:20 +00:00
|
|
|
old_bottom = log_view.get_top_for_last_row();
|
2014-03-13 06:20:18 +00:00
|
|
|
scroll_down = (log_view.get_top() >= old_bottom &&
|
|
|
|
!(lnav_data.ld_flags & LNF_HEADLESS));
|
2009-09-14 01:07:32 +00:00
|
|
|
if (force) {
|
2013-05-28 04:35:00 +00:00
|
|
|
old_count = 0;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2014-10-31 11:49:16 +00:00
|
|
|
|
|
|
|
list<logfile *>::iterator file_iter;
|
|
|
|
for (file_iter = lnav_data.ld_files.begin();
|
|
|
|
file_iter != lnav_data.ld_files.end(); ) {
|
|
|
|
logfile *lf = *file_iter;
|
|
|
|
|
|
|
|
if (!lf->exists() || lf->is_closed()) {
|
2015-04-07 13:09:49 +00:00
|
|
|
log_info("closed log file: %s", lf->get_filename().c_str());
|
2014-10-31 11:49:16 +00:00
|
|
|
lnav_data.ld_file_names.erase(make_pair(lf->get_filename(), lf->get_fd()));
|
2015-03-28 13:30:30 +00:00
|
|
|
lnav_data.ld_text_source.remove(lf);
|
2014-10-31 11:49:16 +00:00
|
|
|
lnav_data.ld_log_source.remove_file(lf);
|
|
|
|
file_iter = lnav_data.ld_files.erase(file_iter);
|
2015-03-22 18:49:37 +00:00
|
|
|
force = true;
|
2014-10-31 11:49:16 +00:00
|
|
|
|
|
|
|
delete lf;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
++file_iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-03 14:07:36 +00:00
|
|
|
if (lss.rebuild_index(force)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
size_t new_count = lss.text_line_count();
|
|
|
|
grep_line_t start_line;
|
|
|
|
int lpc;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
log_view.reload_data();
|
2012-07-13 16:26:47 +00:00
|
|
|
|
2013-11-06 15:29:20 +00:00
|
|
|
if (scroll_down && log_view.get_top_for_last_row() > log_view.get_top()) {
|
|
|
|
log_view.set_top(log_view.get_top_for_last_row());
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
else if (!scroll_down && force) {
|
|
|
|
content_line_t new_top_content = content_line_t(-1);
|
2012-07-13 16:26:47 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (new_count) {
|
|
|
|
new_top_content = lss.at(log_view.get_top());
|
|
|
|
}
|
2012-07-13 16:26:47 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (new_top_content != top_content) {
|
|
|
|
log_view.set_top(lss.find_from_time(old_time));
|
|
|
|
}
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
start_line = force ? grep_line_t(0) : grep_line_t(-1);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (force) {
|
2013-11-06 15:29:20 +00:00
|
|
|
if (lnav_data.ld_search_child[LNV_LOG].get() != NULL) {
|
|
|
|
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->invalidate();
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
log_view.match_reset();
|
|
|
|
}
|
2010-11-22 06:01:57 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
for (lpc = 0; lpc < LG__MAX; lpc++) {
|
|
|
|
if (lnav_data.ld_grep_child[lpc].get() != NULL) {
|
|
|
|
lnav_data.ld_grep_child[lpc]->get_grep_proc()->
|
|
|
|
queue_request(start_line);
|
|
|
|
lnav_data.ld_grep_child[lpc]->get_grep_proc()->start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lnav_data.ld_search_child[LNV_LOG].get() != NULL) {
|
|
|
|
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->reset();
|
|
|
|
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->
|
|
|
|
queue_request(start_line);
|
|
|
|
lnav_data.ld_search_child[LNV_LOG]->get_grep_proc()->start();
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-30 20:23:43 +00:00
|
|
|
if (!lnav_data.ld_view_stack.empty()) {
|
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
|
|
|
lnav_data.ld_bottom_source.update_filtered(tc->get_sub_source());
|
|
|
|
lnav_data.ld_scroll_broadcaster.invoke(tc);
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class plain_text_source
|
|
|
|
: public text_sub_source {
|
|
|
|
public:
|
|
|
|
plain_text_source(string text)
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
size_t start = 0, end;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
while ((end = text.find('\n', start)) != string::npos) {
|
|
|
|
this->tds_lines.push_back(text.substr(start, end - start));
|
|
|
|
start = end + 1;
|
|
|
|
}
|
2014-03-03 00:52:18 +00:00
|
|
|
if (start < text.length()) {
|
|
|
|
this->tds_lines.push_back(text.substr(start));
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2015-03-17 06:10:34 +00:00
|
|
|
plain_text_source(const vector<string> &text_lines) {
|
|
|
|
this->tds_lines = text_lines;
|
2014-03-09 09:29:28 +00:00
|
|
|
};
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
size_t text_line_count()
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
return this->tds_lines.size();
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void text_value_for_line(textview_curses &tc,
|
2013-05-28 04:35:00 +00:00
|
|
|
int row,
|
|
|
|
string &value_out,
|
|
|
|
bool no_scrub)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
value_out = this->tds_lines[row];
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2013-11-06 15:29:20 +00:00
|
|
|
size_t text_size_for_line(textview_curses &tc, int row, bool raw) {
|
|
|
|
return this->tds_lines[row].length();
|
|
|
|
};
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
private:
|
|
|
|
vector<string> tds_lines;
|
|
|
|
};
|
|
|
|
|
|
|
|
class time_label_source
|
|
|
|
: public hist_source::label_source {
|
|
|
|
public:
|
|
|
|
time_label_source() { };
|
|
|
|
|
|
|
|
void hist_label_for_bucket(int bucket_start_value,
|
2013-05-28 04:35:00 +00:00
|
|
|
const hist_source::bucket_t &bucket,
|
|
|
|
string &label_out)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
hist_source::bucket_t::const_iterator iter;
|
|
|
|
int total = 0, errors = 0, warnings = 0;
|
|
|
|
time_t bucket_time = bucket_start_value;
|
|
|
|
struct tm *bucket_tm;
|
|
|
|
char buffer[128];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
bucket_tm = gmtime((time_t *)&bucket_time);
|
|
|
|
if (bucket_tm) {
|
|
|
|
strftime(buffer, sizeof(buffer),
|
|
|
|
" %a %b %d %H:%M ",
|
|
|
|
bucket_tm);
|
|
|
|
}
|
|
|
|
else {
|
2014-03-02 00:35:30 +00:00
|
|
|
log_error("bad time %d", bucket_start_value);
|
2013-05-28 04:35:00 +00:00
|
|
|
buffer[0] = '\0';
|
|
|
|
}
|
|
|
|
for (iter = bucket.begin(); iter != bucket.end(); iter++) {
|
|
|
|
total += (int)iter->second;
|
|
|
|
switch (iter->first) {
|
|
|
|
case logline::LEVEL_FATAL:
|
|
|
|
case logline::LEVEL_ERROR:
|
|
|
|
case logline::LEVEL_CRITICAL:
|
|
|
|
errors += (int)iter->second;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case logline::LEVEL_WARNING:
|
|
|
|
warnings += (int)iter->second;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(buffer);
|
|
|
|
snprintf(&buffer[len], sizeof(buffer) - len,
|
|
|
|
" %8d total %8d errors %8d warnings",
|
|
|
|
total, errors, warnings);
|
|
|
|
|
|
|
|
label_out = string(buffer);
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool append_default_files(lnav_flags_t flag)
|
|
|
|
{
|
|
|
|
bool retval = true;
|
|
|
|
|
|
|
|
if (lnav_data.ld_flags & flag) {
|
2013-05-28 04:35:00 +00:00
|
|
|
pair<multimap<lnav_flags_t, string>::iterator,
|
|
|
|
multimap<lnav_flags_t, string>::iterator> range;
|
|
|
|
for (range = DEFAULT_FILES.equal_range(flag);
|
2013-09-04 09:14:48 +00:00
|
|
|
range.first != range.second;
|
2013-05-28 04:35:00 +00:00
|
|
|
range.first++) {
|
|
|
|
string path = range.first->second;
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (access(path.c_str(), R_OK) == 0) {
|
2013-06-02 21:20:15 +00:00
|
|
|
auto_mem<char> abspath;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-06-02 21:20:15 +00:00
|
|
|
path = get_current_dir() + range.first->second;
|
|
|
|
if ((abspath = realpath(path.c_str(), NULL)) == NULL) {
|
|
|
|
perror("Unable to resolve path");
|
|
|
|
}
|
|
|
|
else {
|
2013-06-16 01:07:50 +00:00
|
|
|
lnav_data.ld_file_names.insert(make_pair(abspath.in(),
|
|
|
|
-1));
|
2013-06-02 21:20:15 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
else if (stat(path.c_str(), &st) == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"error: cannot read -- %s%s\n",
|
|
|
|
get_current_dir().c_str(),
|
|
|
|
path.c_str());
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sigint(int sig)
|
|
|
|
{
|
|
|
|
lnav_data.ld_looping = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sigwinch(int sig)
|
|
|
|
{
|
|
|
|
lnav_data.ld_winched = true;
|
|
|
|
}
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
static void sigchld(int sig)
|
|
|
|
{
|
|
|
|
lnav_data.ld_child_terminated = true;
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
static void back_ten(int ten_minute)
|
|
|
|
{
|
2013-06-20 13:42:11 +00:00
|
|
|
textview_curses * tc = lnav_data.ld_view_stack.top();
|
|
|
|
logfile_sub_source *lss;
|
|
|
|
|
|
|
|
lss = dynamic_cast<logfile_sub_source *>(tc->get_sub_source());
|
|
|
|
|
|
|
|
if (!lss)
|
|
|
|
return;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
time_t hour = rounddown_offset(lnav_data.ld_top_time,
|
2013-05-28 04:35:00 +00:00
|
|
|
60 * 60,
|
|
|
|
ten_minute * 10 * 60);
|
2013-06-20 13:42:11 +00:00
|
|
|
vis_line_t line = lss->find_from_time(hour);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
--line;
|
|
|
|
lnav_data.ld_view_stack.top()->set_top(line);
|
|
|
|
}
|
|
|
|
|
2013-06-14 13:49:00 +00:00
|
|
|
static void update_view_name(void)
|
|
|
|
{
|
|
|
|
status_field &sf = lnav_data.ld_top_source.statusview_value_for_field(
|
|
|
|
top_status_source::TSF_VIEW_NAME);
|
2013-06-16 01:07:50 +00:00
|
|
|
textview_curses * tc = lnav_data.ld_view_stack.top();
|
2013-10-11 13:22:29 +00:00
|
|
|
struct line_range lr(0);
|
2013-06-14 13:49:00 +00:00
|
|
|
|
2014-02-10 15:25:28 +00:00
|
|
|
sf.set_value("% 5s ", tc->get_title().c_str());
|
2014-01-25 17:29:35 +00:00
|
|
|
sf.get_value().get_attrs().push_back(
|
|
|
|
string_attr(lr, &view_curses::VC_STYLE,
|
|
|
|
A_REVERSE | view_colors::ansi_color_pair(COLOR_BLUE, COLOR_WHITE)));
|
2013-06-14 13:49:00 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 06:10:34 +00:00
|
|
|
static void open_schema_view(void)
|
|
|
|
{
|
|
|
|
textview_curses *schema_tc = &lnav_data.ld_views[LNV_SCHEMA];
|
|
|
|
string schema;
|
|
|
|
|
|
|
|
dump_sqlite_schema(lnav_data.ld_db, schema);
|
|
|
|
|
|
|
|
schema += "\n\n-- Virtual Table Definitions --\n\n";
|
|
|
|
schema += ENVIRON_CREATE_STMT;
|
|
|
|
for (log_vtab_manager::iterator vtab_iter =
|
|
|
|
lnav_data.ld_vtab_manager->begin();
|
|
|
|
vtab_iter != lnav_data.ld_vtab_manager->end();
|
|
|
|
++vtab_iter) {
|
2015-04-07 13:09:49 +00:00
|
|
|
schema += "\n" + vtab_iter->second->get_table_statement();
|
2015-03-17 06:10:34 +00:00
|
|
|
}
|
|
|
|
|
2015-03-31 13:34:53 +00:00
|
|
|
delete schema_tc->get_sub_source();
|
2015-03-17 06:10:34 +00:00
|
|
|
|
|
|
|
schema_tc->set_sub_source(new plain_text_source(schema));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void open_pretty_view(void)
|
|
|
|
{
|
|
|
|
textview_curses *log_tc = &lnav_data.ld_views[LNV_LOG];
|
|
|
|
textview_curses *pretty_tc = &lnav_data.ld_views[LNV_PRETTY];
|
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
|
|
|
if (lss.text_line_count() > 0) {
|
2015-03-26 13:13:25 +00:00
|
|
|
ostringstream stream;
|
|
|
|
bool first_line = true;
|
2015-03-17 06:10:34 +00:00
|
|
|
|
2015-03-31 13:34:53 +00:00
|
|
|
delete pretty_tc->get_sub_source();
|
2015-04-05 18:59:14 +00:00
|
|
|
for (vis_line_t vl = log_tc->get_top(); vl <= log_tc->get_bottom(); ++vl) {
|
2015-03-26 13:13:25 +00:00
|
|
|
content_line_t cl = lss.at(vl);
|
|
|
|
logfile *lf = lss.find(cl);
|
|
|
|
logfile::iterator ll = lf->begin() + cl;
|
|
|
|
shared_buffer_ref sbr;
|
|
|
|
|
|
|
|
if (!first_line && ll->is_continued()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ll = lf->message_start(ll);
|
|
|
|
|
|
|
|
lf->read_full_message(ll, sbr);
|
|
|
|
data_scanner ds(sbr);
|
|
|
|
pretty_printer pp(&ds);
|
|
|
|
|
|
|
|
// TODO: dump more details of the line in the output.
|
|
|
|
stream << pp.print() << endl;
|
|
|
|
first_line = false;
|
|
|
|
}
|
|
|
|
pretty_tc->set_sub_source(new plain_text_source(stream.str()));
|
|
|
|
if (lnav_data.ld_last_pretty_print_top != log_tc->get_top()) {
|
|
|
|
pretty_tc->set_top(vis_line_t(0));
|
|
|
|
}
|
|
|
|
lnav_data.ld_last_pretty_print_top = log_tc->get_top();
|
2015-03-17 06:10:34 +00:00
|
|
|
}
|
2015-04-05 18:59:14 +00:00
|
|
|
else {
|
|
|
|
log_warning("no log data to pretty-print");
|
|
|
|
}
|
2015-03-17 06:10:34 +00:00
|
|
|
}
|
|
|
|
|
2013-01-20 06:28:21 +00:00
|
|
|
bool toggle_view(textview_curses *toggle_tc)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2015-03-28 13:30:30 +00:00
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.empty() ? NULL : lnav_data.ld_view_stack.top();
|
2013-05-28 04:35:00 +00:00
|
|
|
bool retval = false;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
require(toggle_tc != NULL);
|
|
|
|
require(toggle_tc >= &lnav_data.ld_views[0]);
|
|
|
|
require(toggle_tc < &lnav_data.ld_views[LNV__MAX]);
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
if (tc == toggle_tc) {
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_view_stack.pop();
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-03-17 06:10:34 +00:00
|
|
|
if (toggle_tc == &lnav_data.ld_views[LNV_SCHEMA]) {
|
|
|
|
open_schema_view();
|
|
|
|
}
|
|
|
|
else if (toggle_tc == &lnav_data.ld_views[LNV_PRETTY]) {
|
|
|
|
open_pretty_view();
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_view_stack.push(toggle_tc);
|
|
|
|
retval = true;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
tc = lnav_data.ld_view_stack.top();
|
|
|
|
tc->set_needs_update();
|
|
|
|
lnav_data.ld_scroll_broadcaster.invoke(tc);
|
|
|
|
|
2013-06-14 13:49:00 +00:00
|
|
|
update_view_name();
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2013-09-14 19:30:57 +00:00
|
|
|
void redo_search(lnav_view_t view_index)
|
2013-01-20 06:28:21 +00:00
|
|
|
{
|
2013-06-26 13:14:09 +00:00
|
|
|
textview_curses *tc = &lnav_data.ld_views[view_index];
|
2013-01-20 06:28:21 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->reload_data();
|
2013-06-26 13:14:09 +00:00
|
|
|
if (lnav_data.ld_search_child[view_index].get() != NULL) {
|
|
|
|
grep_proc *gp = lnav_data.ld_search_child[view_index]->get_grep_proc();
|
2013-01-20 06:28:21 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->match_reset();
|
|
|
|
gp->reset();
|
|
|
|
gp->queue_request(grep_line_t(0));
|
|
|
|
gp->start();
|
|
|
|
}
|
|
|
|
lnav_data.ld_scroll_broadcaster.invoke(tc);
|
2013-01-20 06:28:21 +00:00
|
|
|
}
|
|
|
|
|
2013-04-20 20:21:10 +00:00
|
|
|
/**
|
|
|
|
* Ensure that the view is on the top of the view stack.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-04-20 20:21:10 +00:00
|
|
|
* @param expected_tc The text view that should be on top.
|
2015-03-28 13:30:30 +00:00
|
|
|
* @return True if the view was already on the top of the stack.
|
2013-04-20 20:21:10 +00:00
|
|
|
*/
|
2015-03-28 13:30:30 +00:00
|
|
|
bool ensure_view(textview_curses *expected_tc)
|
2010-02-13 18:23:13 +00:00
|
|
|
{
|
2015-03-28 13:30:30 +00:00
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.empty() ? NULL : lnav_data.ld_view_stack.top();
|
|
|
|
bool retval = true;
|
2010-02-13 18:23:13 +00:00
|
|
|
|
|
|
|
if (tc != expected_tc) {
|
2013-05-28 04:35:00 +00:00
|
|
|
toggle_view(expected_tc);
|
2015-03-28 13:30:30 +00:00
|
|
|
retval = false;
|
2010-02-13 18:23:13 +00:00
|
|
|
}
|
2015-03-28 13:30:30 +00:00
|
|
|
return retval;
|
2010-02-13 18:23:13 +00:00
|
|
|
}
|
|
|
|
|
2014-03-07 13:20:49 +00:00
|
|
|
static vis_line_t next_cluster(
|
|
|
|
vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t),
|
|
|
|
bookmark_type_t *bt,
|
|
|
|
vis_line_t top)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
2013-07-10 03:52:20 +00:00
|
|
|
vis_bookmarks &bm = tc->get_bookmarks();
|
2015-03-29 21:50:34 +00:00
|
|
|
bookmark_vector<vis_line_t> &bv = bm[bt];
|
|
|
|
bool top_is_marked = binary_search(bv.begin(), bv.end(), top);
|
2013-07-10 03:52:20 +00:00
|
|
|
vis_line_t last_top(top);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2015-03-29 21:50:34 +00:00
|
|
|
while ((top = (bv.*f)(top)) != -1) {
|
2013-07-10 03:52:20 +00:00
|
|
|
int diff = top - last_top;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2015-03-29 21:50:34 +00:00
|
|
|
if (!top_is_marked || diff > 1) {
|
2014-03-07 13:20:49 +00:00
|
|
|
return top;
|
2013-06-25 01:08:43 +00:00
|
|
|
}
|
2013-07-10 03:52:20 +00:00
|
|
|
else if (diff < -1) {
|
2013-05-28 04:35:00 +00:00
|
|
|
last_top = top;
|
2015-03-29 21:50:34 +00:00
|
|
|
while ((top = (bv.*f)(top)) != -1) {
|
2013-07-10 03:52:20 +00:00
|
|
|
if (std::abs(last_top - top) > 1)
|
|
|
|
break;
|
|
|
|
last_top = top;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2014-03-07 13:20:49 +00:00
|
|
|
return last_top;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2013-07-10 03:52:20 +00:00
|
|
|
last_top = top;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-07-10 03:52:20 +00:00
|
|
|
|
2014-03-07 13:20:49 +00:00
|
|
|
return vis_line_t(-1);
|
|
|
|
}
|
|
|
|
|
2015-03-29 21:50:34 +00:00
|
|
|
bool moveto_cluster(vis_line_t(bookmark_vector<vis_line_t>::*f) (vis_line_t),
|
|
|
|
bookmark_type_t *bt,
|
|
|
|
vis_line_t top)
|
2014-03-07 13:20:49 +00:00
|
|
|
{
|
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
|
|
|
vis_line_t new_top;
|
|
|
|
|
|
|
|
new_top = next_cluster(f, bt, top);
|
|
|
|
if (new_top != -1) {
|
|
|
|
tc->set_top(new_top);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
alerter::singleton().chime();
|
2013-11-08 15:32:39 +00:00
|
|
|
|
|
|
|
return false;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX For one, this code is kinda crappy. For two, we should probably link
|
|
|
|
* directly with X so we don't need to have xclip installed and it'll work if
|
|
|
|
* we're ssh'd into a box.
|
|
|
|
*/
|
|
|
|
static void copy_to_xclip(void)
|
|
|
|
{
|
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
bookmark_vector<vis_line_t> &bv =
|
|
|
|
tc->get_bookmarks()[&textview_curses::BM_USER];
|
2012-04-04 01:51:15 +00:00
|
|
|
bookmark_vector<vis_line_t>::iterator iter;
|
2014-11-19 14:12:43 +00:00
|
|
|
auto_mem<FILE> pfile(pclose);
|
2013-06-16 01:07:50 +00:00
|
|
|
int line_count = 0;
|
2009-09-14 01:07:32 +00:00
|
|
|
string line;
|
2011-11-09 08:04:30 +00:00
|
|
|
|
2014-11-19 14:12:43 +00:00
|
|
|
pfile = open_clipboard(CT_GENERAL);
|
2011-11-09 08:04:30 +00:00
|
|
|
|
2014-11-19 14:12:43 +00:00
|
|
|
if (!pfile.in()) {
|
2011-11-09 08:04:30 +00:00
|
|
|
flash();
|
2013-06-01 03:45:40 +00:00
|
|
|
lnav_data.ld_rl_view->set_value(
|
|
|
|
"error: Unable to copy to clipboard. "
|
|
|
|
"Make sure xclip or pbcopy is installed.");
|
2011-11-09 08:04:30 +00:00
|
|
|
return;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (iter = bv.begin(); iter != bv.end(); iter++) {
|
2011-11-09 08:04:30 +00:00
|
|
|
tc->grep_value_for_line(*iter, line);
|
|
|
|
fprintf(pfile, "%s\n", line.c_str());
|
2013-06-15 14:11:45 +00:00
|
|
|
line_count += 1;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2013-06-15 14:11:45 +00:00
|
|
|
char buffer[128];
|
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer),
|
|
|
|
"Copied " ANSI_BOLD("%d") " lines to the clipboard",
|
|
|
|
line_count);
|
|
|
|
lnav_data.ld_rl_view->set_value(buffer);
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_paging_key(int ch)
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
textview_curses * tc = lnav_data.ld_view_stack.top();
|
2012-04-04 01:51:15 +00:00
|
|
|
logfile_sub_source *lss = NULL;
|
2013-05-28 04:35:00 +00:00
|
|
|
vis_bookmarks & bm = tc->get_bookmarks();
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
if (tc->handle_key(ch)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
return;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2012-04-04 01:51:15 +00:00
|
|
|
lss = dynamic_cast<logfile_sub_source *>(tc->get_sub_source());
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
/* process the command keystroke */
|
|
|
|
switch (ch) {
|
|
|
|
case 'q':
|
|
|
|
case 'Q':
|
2013-06-16 01:07:50 +00:00
|
|
|
{
|
|
|
|
string msg = "";
|
2013-06-01 03:45:40 +00:00
|
|
|
|
2013-06-16 01:07:50 +00:00
|
|
|
if (tc == &lnav_data.ld_views[LNV_DB]) {
|
|
|
|
msg = HELP_MSG_2(v, V, "to switch to the SQL result view");
|
|
|
|
}
|
|
|
|
else if (tc == &lnav_data.ld_views[LNV_HISTOGRAM]) {
|
|
|
|
msg = HELP_MSG_2(i, I, "to switch to the histogram view");
|
|
|
|
}
|
|
|
|
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
|
|
|
msg = HELP_MSG_1(t, "to switch to the text file view");
|
|
|
|
}
|
|
|
|
else if (tc == &lnav_data.ld_views[LNV_GRAPH]) {
|
|
|
|
msg = HELP_MSG_1(g, "to switch to the graph view");
|
2013-06-01 03:45:40 +00:00
|
|
|
}
|
2013-06-16 01:07:50 +00:00
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(msg);
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_view_stack.pop();
|
|
|
|
if (lnav_data.ld_view_stack.empty() ||
|
|
|
|
(lnav_data.ld_view_stack.size() == 1 &&
|
|
|
|
lnav_data.ld_log_source.text_line_count() == 0)) {
|
|
|
|
lnav_data.ld_looping = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tc = lnav_data.ld_view_stack.top();
|
|
|
|
tc->set_needs_update();
|
2013-04-20 20:21:10 +00:00
|
|
|
lnav_data.ld_scroll_broadcaster.invoke(tc);
|
2013-06-14 13:49:00 +00:00
|
|
|
update_view_name();
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
case KEY_F(2):
|
|
|
|
if (xterm_mouse::is_available()) {
|
|
|
|
lnav_data.ld_mouse.set_enabled(!lnav_data.ld_mouse.is_enabled());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnav_data.ld_rl_view->set_value(
|
|
|
|
"error: mouse support is not available, make sure your TERM is set to "
|
|
|
|
"xterm or xterm-256color");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case 'c':
|
2013-05-28 04:35:00 +00:00
|
|
|
copy_to_xclip();
|
2014-11-06 07:36:07 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
|
|
|
|
C, "to clear marked messages"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2012-04-04 01:51:15 +00:00
|
|
|
case 'C':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lss) {
|
2014-04-18 14:29:29 +00:00
|
|
|
lss->text_clear_marks(&textview_curses::BM_USER);
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2013-08-25 14:12:41 +00:00
|
|
|
|
2015-03-19 04:54:46 +00:00
|
|
|
lnav_data.ld_select_start.erase(tc);
|
|
|
|
lnav_data.ld_last_user_mark.erase(tc);
|
2013-08-25 14:12:41 +00:00
|
|
|
tc->get_bookmarks()[&textview_curses::BM_USER].clear();
|
|
|
|
tc->reload_data();
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_value("Cleared bookmarks");
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2012-04-04 01:51:15 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case 'e':
|
2013-05-28 04:35:00 +00:00
|
|
|
moveto_cluster(&bookmark_vector<vis_line_t>::next,
|
|
|
|
&logfile_sub_source::BM_ERRORS,
|
|
|
|
tc->get_top());
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
w, W,
|
|
|
|
"to move forward/backward through warning messages"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'E':
|
2013-05-28 04:35:00 +00:00
|
|
|
moveto_cluster(&bookmark_vector<vis_line_t>::prev,
|
|
|
|
&logfile_sub_source::BM_ERRORS,
|
|
|
|
tc->get_top());
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
w, W,
|
|
|
|
"to move forward/backward through warning messages"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'w':
|
2013-05-28 04:35:00 +00:00
|
|
|
moveto_cluster(&bookmark_vector<vis_line_t>::next,
|
|
|
|
&logfile_sub_source::BM_WARNINGS,
|
|
|
|
tc->get_top());
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
o, O,
|
|
|
|
"to move forward/backward an hour"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'W':
|
2013-05-28 04:35:00 +00:00
|
|
|
moveto_cluster(&bookmark_vector<vis_line_t>::prev,
|
|
|
|
&logfile_sub_source::BM_WARNINGS,
|
|
|
|
tc->get_top());
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
o, O,
|
|
|
|
"to move forward/backward an hour"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'n':
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->set_top(bm[&textview_curses::BM_SEARCH].next(tc->get_top()));
|
2014-03-04 15:38:33 +00:00
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
2013-06-02 21:20:15 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
2013-06-14 13:49:00 +00:00
|
|
|
"Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<")
|
|
|
|
"' to scroll horizontally to a search result");
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'N':
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->set_top(bm[&textview_curses::BM_SEARCH].prev(tc->get_top()));
|
2014-03-04 15:38:33 +00:00
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
2013-06-02 21:20:15 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
2013-06-14 13:49:00 +00:00
|
|
|
"Press '" ANSI_BOLD(">") "' or '" ANSI_BOLD("<")
|
|
|
|
"' to scroll horizontally to a search result");
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-24 14:55:56 +00:00
|
|
|
case 'y':
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->set_top(bm[&BM_QUERY].next(tc->get_top()));
|
|
|
|
break;
|
2013-05-24 14:55:56 +00:00
|
|
|
|
|
|
|
case 'Y':
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->set_top(bm[&BM_QUERY].prev(tc->get_top()));
|
|
|
|
break;
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2010-02-24 04:35:52 +00:00
|
|
|
case '>':
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
|
|
|
std::pair<int, int> range;
|
|
|
|
|
|
|
|
tc->horiz_shift(tc->get_top(),
|
|
|
|
tc->get_bottom(),
|
|
|
|
tc->get_left(),
|
2013-06-13 14:18:59 +00:00
|
|
|
"$search",
|
2013-05-28 04:35:00 +00:00
|
|
|
range);
|
|
|
|
if (range.second != INT_MAX) {
|
|
|
|
tc->set_left(range.second);
|
2013-06-15 14:11:45 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_1(m, "to bookmark a line"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
flash();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-02-24 04:35:52 +00:00
|
|
|
case '<':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (tc->get_left() == 0) {
|
|
|
|
flash();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::pair<int, int> range;
|
|
|
|
|
|
|
|
tc->horiz_shift(tc->get_top(),
|
|
|
|
tc->get_bottom(),
|
|
|
|
tc->get_left(),
|
2013-06-13 14:18:59 +00:00
|
|
|
"$search",
|
2013-05-28 04:35:00 +00:00
|
|
|
range);
|
|
|
|
if (range.first != -1) {
|
|
|
|
tc->set_left(range.first);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
tc->set_left(0);
|
|
|
|
}
|
2013-06-15 14:11:45 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_1(m, "to bookmark a line"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2010-02-24 04:35:52 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case 'f':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (tc == &lnav_data.ld_views[LNV_LOG]) {
|
|
|
|
tc->set_top(bm[&logfile_sub_source::BM_FILES].next(tc->get_top()));
|
|
|
|
}
|
|
|
|
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
|
|
|
textfile_sub_source &tss = lnav_data.ld_text_source;
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
if (!tss.empty()) {
|
|
|
|
tss.rotate_right();
|
2013-06-26 13:14:09 +00:00
|
|
|
redo_search(LNV_TEXT);
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'F':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (tc == &lnav_data.ld_views[LNV_LOG]) {
|
|
|
|
tc->set_top(bm[&logfile_sub_source::BM_FILES].prev(tc->get_top()));
|
|
|
|
}
|
|
|
|
else if (tc == &lnav_data.ld_views[LNV_TEXT]) {
|
|
|
|
textfile_sub_source &tss = lnav_data.ld_text_source;
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
if (!tss.empty()) {
|
|
|
|
tss.rotate_left();
|
2013-06-26 13:14:09 +00:00
|
|
|
redo_search(LNV_TEXT);
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'z':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (tc == &lnav_data.ld_views[LNV_HISTOGRAM]) {
|
|
|
|
if ((lnav_data.ld_hist_zoom + 1) >= HIST_ZOOM_LEVELS) {
|
|
|
|
flash();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnav_data.ld_hist_zoom += 1;
|
|
|
|
rebuild_hist(0, true);
|
|
|
|
}
|
2013-06-02 21:20:15 +00:00
|
|
|
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
|
2013-06-16 01:07:50 +00:00
|
|
|
I,
|
|
|
|
"to switch to the log view at the top displayed time"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'Z':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (tc == &lnav_data.ld_views[LNV_HISTOGRAM]) {
|
|
|
|
if (lnav_data.ld_hist_zoom == 0) {
|
|
|
|
flash();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnav_data.ld_hist_zoom -= 1;
|
|
|
|
rebuild_hist(0, true);
|
|
|
|
}
|
2013-06-02 21:20:15 +00:00
|
|
|
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
|
2013-06-16 01:07:50 +00:00
|
|
|
I,
|
|
|
|
"to switch to the log view at the top displayed time"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2014-03-07 13:20:49 +00:00
|
|
|
case 'u': {
|
|
|
|
vis_line_t user_top, part_top;
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_1(c, "to copy marked lines to the clipboard; ")
|
|
|
|
HELP_MSG_1(C, "to clear marked lines"));
|
|
|
|
|
|
|
|
user_top = next_cluster(&bookmark_vector<vis_line_t>::next,
|
2013-07-10 03:52:20 +00:00
|
|
|
&textview_curses::BM_USER,
|
|
|
|
tc->get_top());
|
2014-03-07 13:20:49 +00:00
|
|
|
part_top = next_cluster(&bookmark_vector<vis_line_t>::next,
|
|
|
|
&textview_curses::BM_PARTITION,
|
|
|
|
tc->get_top());
|
|
|
|
if (part_top == -1 && user_top == -1) {
|
|
|
|
alerter::singleton().chime();
|
|
|
|
}
|
|
|
|
else if (part_top == -1) {
|
|
|
|
tc->set_top(user_top);
|
|
|
|
}
|
|
|
|
else if (user_top == -1) {
|
|
|
|
tc->set_top(part_top);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tc->set_top(min(user_top, part_top));
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2014-03-07 13:20:49 +00:00
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2014-03-07 13:20:49 +00:00
|
|
|
case 'U': {
|
|
|
|
vis_line_t user_top, part_top;
|
|
|
|
|
|
|
|
user_top = next_cluster(&bookmark_vector<vis_line_t>::prev,
|
2013-07-10 03:52:20 +00:00
|
|
|
&textview_curses::BM_USER,
|
|
|
|
tc->get_top());
|
2014-03-07 13:20:49 +00:00
|
|
|
part_top = next_cluster(&bookmark_vector<vis_line_t>::prev,
|
|
|
|
&textview_curses::BM_PARTITION,
|
|
|
|
tc->get_top());
|
|
|
|
if (part_top == -1 && user_top == -1) {
|
|
|
|
alerter::singleton().chime();
|
|
|
|
}
|
|
|
|
else if (part_top == -1) {
|
|
|
|
tc->set_top(user_top);
|
|
|
|
}
|
|
|
|
else if (user_top == -1) {
|
|
|
|
tc->set_top(part_top);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tc->set_top(max(user_top, part_top));
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2014-03-07 13:20:49 +00:00
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'm':
|
2013-06-20 13:42:11 +00:00
|
|
|
lnav_data.ld_last_user_mark[tc] = tc->get_top();
|
|
|
|
tc->toggle_user_mark(&textview_curses::BM_USER,
|
|
|
|
vis_line_t(lnav_data.ld_last_user_mark[tc]));
|
|
|
|
tc->reload_data();
|
2013-06-01 03:45:40 +00:00
|
|
|
|
2013-06-20 13:42:11 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
|
|
|
u, U,
|
|
|
|
"to move forward/backward through user bookmarks"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2012-11-28 16:39:39 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
case 'J':
|
2013-06-20 13:42:11 +00:00
|
|
|
if (lnav_data.ld_last_user_mark.find(tc) ==
|
|
|
|
lnav_data.ld_last_user_mark.end() ||
|
|
|
|
!tc->is_visible(vis_line_t(lnav_data.ld_last_user_mark[tc]))) {
|
2015-03-19 04:54:46 +00:00
|
|
|
lnav_data.ld_select_start[tc] = tc->get_top();
|
2013-06-20 13:42:11 +00:00
|
|
|
lnav_data.ld_last_user_mark[tc] = tc->get_top();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vis_line_t height;
|
|
|
|
unsigned long width;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-20 13:42:11 +00:00
|
|
|
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));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2013-06-20 13:42:11 +00:00
|
|
|
if (lnav_data.ld_last_user_mark[tc] + 1 >=
|
|
|
|
tc->get_inner_height()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lnav_data.ld_last_user_mark[tc] += 1;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2013-06-20 13:42:11 +00:00
|
|
|
tc->toggle_user_mark(&textview_curses::BM_USER,
|
|
|
|
vis_line_t(lnav_data.ld_last_user_mark[tc]));
|
|
|
|
tc->reload_data();
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
|
|
|
|
c,
|
|
|
|
"to copy marked lines to the clipboard"));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2013-01-20 06:28:21 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
case 'K':
|
2013-06-20 13:42:11 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
int new_mark;
|
|
|
|
|
|
|
|
if (lnav_data.ld_last_user_mark.find(tc) ==
|
|
|
|
lnav_data.ld_last_user_mark.end() ||
|
|
|
|
!tc->is_visible(vis_line_t(lnav_data.ld_last_user_mark[tc]))) {
|
|
|
|
new_mark = tc->get_top();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
new_mark = lnav_data.ld_last_user_mark[tc];
|
2013-01-20 06:28:21 +00:00
|
|
|
}
|
|
|
|
|
2013-06-20 13:42:11 +00:00
|
|
|
tc->toggle_user_mark(&textview_curses::BM_USER,
|
|
|
|
vis_line_t(new_mark));
|
2013-05-28 04:35:00 +00:00
|
|
|
if (new_mark == tc->get_top()) {
|
|
|
|
tc->shift_top(vis_line_t(-1));
|
|
|
|
}
|
|
|
|
if (new_mark > 0) {
|
|
|
|
lnav_data.ld_last_user_mark[tc] = new_mark - 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnav_data.ld_last_user_mark[tc] = new_mark;
|
|
|
|
flash();
|
|
|
|
}
|
2015-03-19 04:54:46 +00:00
|
|
|
lnav_data.ld_select_start[tc] = tc->get_top();
|
2013-01-20 06:28:21 +00:00
|
|
|
tc->reload_data();
|
2013-06-02 21:20:15 +00:00
|
|
|
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(
|
2013-06-16 01:07:50 +00:00
|
|
|
c,
|
|
|
|
"to copy marked lines to the clipboard"));
|
2013-01-20 06:28:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-11-11 16:44:44 +00:00
|
|
|
case 'L': {
|
|
|
|
vis_line_t top = tc->get_top();
|
|
|
|
vis_line_t bottom = tc->get_bottom();
|
2015-04-02 13:49:16 +00:00
|
|
|
char line_break[120];
|
2014-11-11 16:44:44 +00:00
|
|
|
|
|
|
|
nodelay(lnav_data.ld_window, 0);
|
|
|
|
endwin();
|
|
|
|
{
|
|
|
|
guard_termios tguard(STDOUT_FILENO);
|
|
|
|
struct termios new_termios = *tguard.get_termios();
|
2014-11-11 17:41:57 +00:00
|
|
|
new_termios.c_oflag |= ONLCR | OPOST;
|
2014-11-11 16:44:44 +00:00
|
|
|
tcsetattr(STDOUT_FILENO, TCSANOW, &new_termios);
|
|
|
|
snprintf(line_break, sizeof(line_break),
|
2015-04-02 13:49:16 +00:00
|
|
|
"\n---------------- Lines %'d-%'d, "
|
|
|
|
"press any key to exit lo-fi mode "
|
|
|
|
"----------------\n\n",
|
2014-11-11 16:44:44 +00:00
|
|
|
(int) top, (int) bottom);
|
|
|
|
write(STDOUT_FILENO, line_break, strlen(line_break));
|
|
|
|
for (; top <= bottom; ++top) {
|
|
|
|
attr_line_t al;
|
|
|
|
tc->listview_value_for_row(*tc, top, al);
|
|
|
|
write(STDOUT_FILENO, al.get_string().c_str(), al.length());
|
|
|
|
write(STDOUT_FILENO, "\n", 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cbreak();
|
|
|
|
getch();
|
|
|
|
refresh();
|
|
|
|
nodelay(lnav_data.ld_window, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
case 'M':
|
2013-06-20 13:42:11 +00:00
|
|
|
if (lnav_data.ld_last_user_mark.find(tc) ==
|
|
|
|
lnav_data.ld_last_user_mark.end()) {
|
|
|
|
flash();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int start_line = min((int)tc->get_top(),
|
|
|
|
lnav_data.ld_last_user_mark[tc] + 1);
|
|
|
|
int end_line = max((int)tc->get_top(),
|
|
|
|
lnav_data.ld_last_user_mark[tc] - 1);
|
|
|
|
|
|
|
|
tc->toggle_user_mark(&textview_curses::BM_USER,
|
|
|
|
vis_line_t(start_line),
|
|
|
|
vis_line_t(end_line));
|
|
|
|
tc->reload_data();
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-03-16 22:07:08 +00:00
|
|
|
#if 0
|
2013-06-02 21:20:15 +00:00
|
|
|
case 'S':
|
2013-06-20 13:42:11 +00:00
|
|
|
{
|
|
|
|
bookmark_vector<vis_line_t>::iterator iter;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-06-20 13:42:11 +00:00
|
|
|
for (iter = bm[&textview_curses::BM_SEARCH].begin();
|
|
|
|
iter != bm[&textview_curses::BM_SEARCH].end();
|
|
|
|
++iter) {
|
|
|
|
tc->toggle_user_mark(&textview_curses::BM_USER, *iter);
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-06-20 13:42:11 +00:00
|
|
|
lnav_data.ld_last_user_mark[tc] = -1;
|
|
|
|
tc->reload_data();
|
|
|
|
}
|
|
|
|
break;
|
2014-03-16 22:07:08 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
if (lss) {
|
|
|
|
vis_line_t next_top = vis_line_t(tc->get_top() + 2);
|
|
|
|
|
|
|
|
if (!lss->is_time_offset_enabled()) {
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_1(T, "to disable elapsed-time mode"));
|
|
|
|
}
|
|
|
|
lss->set_time_offset(true);
|
|
|
|
while (next_top < tc->get_inner_height()) {
|
|
|
|
if (lss->find_line(lss->at(next_top))->is_continued()) {
|
|
|
|
}
|
|
|
|
else if (lss->get_line_accel_direction(next_top) ==
|
|
|
|
log_accel::A_DECEL) {
|
|
|
|
--next_top;
|
|
|
|
tc->set_top(next_top);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++next_top;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'S':
|
|
|
|
if (lss) {
|
|
|
|
vis_line_t next_top = tc->get_top();
|
|
|
|
|
|
|
|
if (!lss->is_time_offset_enabled()) {
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_1(T, "to disable elapsed-time mode"));
|
|
|
|
}
|
|
|
|
lss->set_time_offset(true);
|
2014-11-12 05:18:55 +00:00
|
|
|
while (0 <= next_top && next_top < tc->get_inner_height()) {
|
2014-03-16 22:07:08 +00:00
|
|
|
if (lss->find_line(lss->at(next_top))->is_continued()) {
|
|
|
|
}
|
|
|
|
else if (lss->get_line_accel_direction(next_top) ==
|
|
|
|
log_accel::A_DECEL) {
|
|
|
|
--next_top;
|
|
|
|
tc->set_top(next_top);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
--next_top;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lss) {
|
|
|
|
int ten_minute = (ch - '0') * 10 * 60;
|
|
|
|
time_t hour = rounddown(lnav_data.ld_top_time +
|
|
|
|
(60 * 60) -
|
|
|
|
ten_minute +
|
|
|
|
1,
|
|
|
|
60 * 60);
|
|
|
|
vis_line_t line = lss->find_from_time(hour + ten_minute);
|
|
|
|
|
|
|
|
tc->set_top(line);
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '!':
|
2013-05-28 04:35:00 +00:00
|
|
|
back_ten(1);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '@':
|
2013-05-28 04:35:00 +00:00
|
|
|
back_ten(2);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '#':
|
2013-05-28 04:35:00 +00:00
|
|
|
back_ten(3);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '$':
|
2013-05-28 04:35:00 +00:00
|
|
|
back_ten(4);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '%':
|
2013-05-28 04:35:00 +00:00
|
|
|
back_ten(5);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '^':
|
2013-05-28 04:35:00 +00:00
|
|
|
back_ten(6);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-14 13:49:00 +00:00
|
|
|
case '9':
|
|
|
|
if (lss) {
|
|
|
|
double tenth = ((double)tc->get_inner_height()) / 10.0;
|
|
|
|
|
|
|
|
tc->shift_top(vis_line_t(tenth));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '(':
|
|
|
|
if (lss) {
|
|
|
|
double tenth = ((double)tc->get_inner_height()) / 10.0;
|
|
|
|
|
|
|
|
tc->shift_top(vis_line_t(-tenth));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case '0':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lss) {
|
|
|
|
time_t first_time = lnav_data.ld_top_time;
|
|
|
|
int step = 24 * 60 * 60;
|
|
|
|
vis_line_t line =
|
2013-06-30 23:43:08 +00:00
|
|
|
lss->find_from_time(roundup_size(first_time, step));
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->set_top(line);
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case ')':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lss) {
|
|
|
|
time_t day = rounddown(lnav_data.ld_top_time, 24 * 60 * 60);
|
|
|
|
vis_line_t line = lss->find_from_time(day);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
--line;
|
|
|
|
tc->set_top(line);
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'D':
|
|
|
|
case 'O':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (tc->get_top() == 0) {
|
|
|
|
flash();
|
|
|
|
}
|
|
|
|
else if (lss) {
|
|
|
|
int step = ch == 'D' ? (24 * 60 * 60) : (60 * 60);
|
|
|
|
time_t top_time = lnav_data.ld_top_time;
|
|
|
|
vis_line_t line = lss->find_from_time(top_time - step);
|
|
|
|
|
|
|
|
if (line != 0) {
|
|
|
|
--line;
|
|
|
|
}
|
|
|
|
tc->set_top(line);
|
2013-06-15 23:42:21 +00:00
|
|
|
|
2013-06-15 14:11:45 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(/, "to search"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'd':
|
|
|
|
case 'o':
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lss) {
|
|
|
|
int step = ch == 'd' ? (24 * 60 * 60) : (60 * 60);
|
|
|
|
vis_line_t line =
|
|
|
|
lss->find_from_time(lnav_data.ld_top_time + step);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
tc->set_top(line);
|
2013-06-15 14:11:45 +00:00
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_1(/, "to search"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case ':':
|
2013-06-06 02:34:48 +00:00
|
|
|
if (lnav_data.ld_views[LNV_LOG].get_inner_height() > 0) {
|
2013-06-16 01:07:50 +00:00
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
|
|
|
textview_curses & log_view = lnav_data.ld_views[LNV_LOG];
|
|
|
|
content_line_t cl = lss.at(log_view.get_top());
|
|
|
|
logfile * lf = lss.find(cl);
|
2013-07-09 04:09:35 +00:00
|
|
|
logfile::iterator ll = lf->begin() + cl;
|
2014-02-01 14:41:11 +00:00
|
|
|
log_data_helper ldh(lss);
|
2013-06-06 02:34:48 +00:00
|
|
|
|
2013-09-14 19:30:57 +00:00
|
|
|
lnav_data.ld_rl_view->clear_possibilities(LNM_COMMAND, "colname");
|
2013-06-06 02:34:48 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
ldh.parse_line(log_view.get_top(), true);
|
2013-06-06 02:34:48 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
for (vector<string>::iterator iter = ldh.ldh_namer->cn_names.begin();
|
|
|
|
iter != ldh.ldh_namer->cn_names.end();
|
|
|
|
++iter) {
|
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_COMMAND, "colname", *iter);
|
2013-06-06 02:34:48 +00:00
|
|
|
}
|
2013-07-09 04:09:35 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
ldh.clear();
|
|
|
|
|
2013-07-09 04:09:35 +00:00
|
|
|
lnav_data.ld_rl_view->clear_possibilities(LNM_COMMAND, "line-time");
|
|
|
|
{
|
|
|
|
struct timeval tv = lf->get_time_offset();
|
|
|
|
char buffer[64];
|
|
|
|
|
|
|
|
sql_strftime(buffer, sizeof(buffer),
|
2014-02-23 18:23:17 +00:00
|
|
|
ll->get_time(), ll->get_millis(), 'T');
|
2013-07-09 04:09:35 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_COMMAND,
|
|
|
|
"line-time",
|
|
|
|
buffer);
|
|
|
|
sql_strftime(buffer, sizeof(buffer),
|
|
|
|
ll->get_time() - tv.tv_sec,
|
2014-02-23 18:23:17 +00:00
|
|
|
ll->get_millis() - (tv.tv_usec / 1000),
|
|
|
|
'T');
|
2013-07-09 04:09:35 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(LNM_COMMAND,
|
|
|
|
"line-time",
|
|
|
|
buffer);
|
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
}
|
2014-10-30 15:37:06 +00:00
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
add_view_text_possibilities(LNM_COMMAND, "filter", tc);
|
|
|
|
lnav_data.ld_rl_view->
|
|
|
|
add_possibility(LNM_COMMAND, "filter",
|
|
|
|
lnav_data.ld_last_search[tc - lnav_data.ld_views]);
|
|
|
|
add_filter_possibilities(tc);
|
2015-03-29 21:50:34 +00:00
|
|
|
add_mark_possibilities();
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_mode = LNM_COMMAND;
|
|
|
|
lnav_data.ld_rl_view->focus(LNM_COMMAND, ":");
|
2013-07-25 13:22:54 +00:00
|
|
|
lnav_data.ld_bottom_source.set_prompt("Enter an lnav command: "
|
2014-03-16 22:07:08 +00:00
|
|
|
"(Press " ANSI_BOLD("CTRL+]") " to abort)");
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '/':
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_mode = LNM_SEARCH;
|
2014-02-10 02:41:32 +00:00
|
|
|
lnav_data.ld_previous_search = lnav_data.ld_last_search[tc - lnav_data.ld_views];
|
|
|
|
lnav_data.ld_search_start_line = tc->get_top();
|
2014-10-30 15:37:06 +00:00
|
|
|
add_view_text_possibilities(LNM_SEARCH, "*", tc);
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_rl_view->focus(LNM_SEARCH, "/");
|
2013-06-08 19:07:13 +00:00
|
|
|
lnav_data.ld_bottom_source.set_prompt(
|
2013-07-25 13:22:54 +00:00
|
|
|
"Enter a regular expression to search for: "
|
2014-03-16 22:07:08 +00:00
|
|
|
"(Press " ANSI_BOLD("CTRL+]") " to abort)");
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case ';':
|
2013-05-24 14:55:56 +00:00
|
|
|
if (tc == &lnav_data.ld_views[LNV_LOG] ||
|
2014-02-24 19:43:50 +00:00
|
|
|
tc == &lnav_data.ld_views[LNV_DB] ||
|
|
|
|
tc == &lnav_data.ld_views[LNV_SCHEMA]) {
|
2013-05-28 04:35:00 +00:00
|
|
|
textview_curses &log_view = lnav_data.ld_views[LNV_LOG];
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_mode = LNM_SQL;
|
2013-06-06 02:34:48 +00:00
|
|
|
setup_logline_table();
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_rl_view->focus(LNM_SQL, ";");
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_bottom_source.update_loading(0, 0);
|
|
|
|
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
field_overlay_source *fos;
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
fos = (field_overlay_source *)log_view.get_overlay_source();
|
|
|
|
fos->fos_active_prev = fos->fos_active;
|
|
|
|
if (!fos->fos_active) {
|
|
|
|
fos->fos_active = true;
|
|
|
|
tc->reload_data();
|
|
|
|
}
|
2014-03-16 22:07:08 +00:00
|
|
|
lnav_data.ld_bottom_source.set_prompt("Enter an SQL query: (Press "
|
|
|
|
ANSI_BOLD("CTRL+]") " to abort)");
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-24 14:55:56 +00:00
|
|
|
case 'p':
|
|
|
|
field_overlay_source *fos;
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
fos =
|
|
|
|
(field_overlay_source *)lnav_data.ld_views[LNV_LOG].
|
|
|
|
get_overlay_source();
|
2013-05-24 14:55:56 +00:00
|
|
|
fos->fos_active = !fos->fos_active;
|
|
|
|
tc->reload_data();
|
|
|
|
break;
|
|
|
|
|
2015-03-17 06:10:34 +00:00
|
|
|
case 'P':
|
|
|
|
if (tc == &lnav_data.ld_views[LNV_PRETTY] ||
|
|
|
|
(lss && lss->text_line_count() > 0)) {
|
|
|
|
toggle_view(&lnav_data.ld_views[LNV_PRETTY]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnav_data.ld_rl_view->set_value("Pretty-printed only works with log messages");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-11-22 05:44:45 +00:00
|
|
|
case 't':
|
2013-06-15 01:12:52 +00:00
|
|
|
if (lnav_data.ld_text_source.current_file() == NULL) {
|
|
|
|
flash();
|
2013-06-15 14:11:45 +00:00
|
|
|
lnav_data.ld_rl_view->set_value("No text files loaded");
|
2013-06-15 01:12:52 +00:00
|
|
|
}
|
|
|
|
else if (toggle_view(&lnav_data.ld_views[LNV_TEXT])) {
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
f, F,
|
|
|
|
"to switch to the next/previous file"));
|
2013-06-01 03:45:40 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2010-11-22 05:44:45 +00:00
|
|
|
|
2012-10-29 23:38:58 +00:00
|
|
|
case 'T':
|
|
|
|
lnav_data.ld_log_source.toggle_time_offset();
|
2015-04-02 06:36:11 +00:00
|
|
|
if (lss && lss->is_time_offset_enabled()) {
|
2014-03-16 22:07:08 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_2(s, S, "to move forward/backward through slow downs"));
|
|
|
|
}
|
2012-10-29 23:38:58 +00:00
|
|
|
tc->reload_data();
|
|
|
|
break;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case 'i':
|
2013-06-01 03:45:40 +00:00
|
|
|
if (toggle_view(&lnav_data.ld_views[LNV_HISTOGRAM])) {
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_2(z, Z, "to zoom in/out"));
|
2013-06-01 03:45:40 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
lnav_data.ld_rl_view->set_alt_value("");
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case 'I':
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
|
|
|
time_t log_top = lnav_data.ld_top_time;
|
|
|
|
|
|
|
|
if (toggle_view(&lnav_data.ld_views[LNV_HISTOGRAM])) {
|
|
|
|
hist_source &hs = lnav_data.ld_hist_source;
|
|
|
|
|
|
|
|
tc = lnav_data.ld_view_stack.top();
|
|
|
|
tc->set_top(hs.row_for_value(log_top));
|
|
|
|
}
|
|
|
|
else {
|
2015-03-23 04:58:12 +00:00
|
|
|
textview_curses &hist_tc = lnav_data.ld_views[LNV_HISTOGRAM];
|
|
|
|
textview_curses &log_tc = lnav_data.ld_views[LNV_LOG];
|
|
|
|
time_t hist_top =
|
|
|
|
lnav_data.ld_hist_source.value_for_row(hist_tc.get_top());
|
2013-05-28 04:35:00 +00:00
|
|
|
lss = &lnav_data.ld_log_source;
|
2015-03-23 04:58:12 +00:00
|
|
|
log_tc.set_top(lss->find_from_time(hist_top));
|
|
|
|
log_tc.set_needs_update();
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-11-24 22:26:10 +00:00
|
|
|
case KEY_CTRL_G:
|
2013-05-28 04:35:00 +00:00
|
|
|
toggle_view(&lnav_data.ld_views[LNV_GRAPH]);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case '?':
|
2013-05-28 04:35:00 +00:00
|
|
|
toggle_view(&lnav_data.ld_views[LNV_HELP]);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2010-03-15 15:43:58 +00:00
|
|
|
case 'v':
|
2013-05-28 04:35:00 +00:00
|
|
|
toggle_view(&lnav_data.ld_views[LNV_DB]);
|
|
|
|
break;
|
|
|
|
|
2010-03-15 15:43:58 +00:00
|
|
|
case 'V':
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
|
|
|
textview_curses *db_tc = &lnav_data.ld_views[LNV_DB];
|
|
|
|
db_label_source &dls = lnav_data.ld_db_rows;
|
|
|
|
hist_source & hs = lnav_data.ld_db_source;
|
|
|
|
|
|
|
|
if (toggle_view(db_tc)) {
|
|
|
|
unsigned int lpc;
|
|
|
|
|
|
|
|
for (lpc = 0; lpc < dls.dls_headers.size(); lpc++) {
|
2013-05-28 14:08:49 +00:00
|
|
|
if (dls.dls_headers[lpc] != "log_line") {
|
2013-05-28 04:35:00 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
char linestr[64];
|
|
|
|
int line_number = (int)tc->get_top();
|
|
|
|
unsigned int row;
|
|
|
|
|
|
|
|
snprintf(linestr, sizeof(linestr), "%d", line_number);
|
|
|
|
for (row = 0; row < dls.dls_rows.size(); row++) {
|
2014-03-11 12:37:13 +00:00
|
|
|
if (strcmp(dls.dls_rows[row][lpc],
|
2013-05-28 04:35:00 +00:00
|
|
|
linestr) == 0) {
|
|
|
|
vis_line_t db_line(hs.row_for_value(row));
|
|
|
|
|
|
|
|
db_tc->set_top(db_line);
|
|
|
|
db_tc->set_needs_update();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int db_row = hs.value_for_row(db_tc->get_top());
|
|
|
|
unsigned int lpc;
|
|
|
|
|
|
|
|
for (lpc = 0; lpc < dls.dls_headers.size(); lpc++) {
|
2013-05-28 14:08:49 +00:00
|
|
|
if (dls.dls_headers[lpc] != "log_line") {
|
2013-05-28 04:35:00 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int line_number;
|
|
|
|
|
|
|
|
tc = &lnav_data.ld_views[LNV_LOG];
|
2014-03-11 12:37:13 +00:00
|
|
|
if (sscanf(dls.dls_rows[db_row][lpc],
|
2013-05-28 04:35:00 +00:00
|
|
|
"%d",
|
|
|
|
&line_number) &&
|
|
|
|
line_number < tc->listview_rows(*tc)) {
|
|
|
|
tc->set_top(vis_line_t(line_number));
|
|
|
|
tc->set_needs_update();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-23 20:43:51 +00:00
|
|
|
case '\t':
|
|
|
|
if (tc == &lnav_data.ld_views[LNV_DB])
|
|
|
|
{
|
|
|
|
hist_source &hs = lnav_data.ld_db_source;
|
|
|
|
db_label_source &dls = lnav_data.ld_db_rows;
|
|
|
|
std::vector<bucket_type_t> &displayed = hs.get_displayed_buckets();
|
2014-02-01 14:41:11 +00:00
|
|
|
std::vector<int>::iterator start_iter, iter;
|
2013-06-23 20:43:51 +00:00
|
|
|
|
|
|
|
start_iter = dls.dls_headers_to_graph.begin();
|
|
|
|
if (!displayed.empty()) {
|
|
|
|
advance(start_iter, (int)displayed[0] + 1);
|
|
|
|
}
|
|
|
|
displayed.clear();
|
|
|
|
iter = find(start_iter,
|
|
|
|
dls.dls_headers_to_graph.end(),
|
|
|
|
true);
|
|
|
|
if (iter != dls.dls_headers_to_graph.end()) {
|
|
|
|
bucket_type_t type;
|
|
|
|
|
|
|
|
type = bucket_type_t(distance(dls.dls_headers_to_graph.begin(), iter));
|
|
|
|
displayed.push_back(type);
|
|
|
|
}
|
2014-03-11 15:18:51 +00:00
|
|
|
if (displayed.empty()) {
|
|
|
|
lnav_data.ld_rl_view->set_value("Graphing all values");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int index = displayed[0];
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_value("Graphing column " ANSI_BOLD_START +
|
|
|
|
dls.dls_headers[index] + ANSI_NORM);
|
|
|
|
}
|
2013-06-23 20:43:51 +00:00
|
|
|
tc->reload_data();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// XXX I'm sure there must be a better way to handle the difference between
|
|
|
|
// iterator and reverse_iterator.
|
|
|
|
case KEY_BTAB:
|
|
|
|
if (tc == &lnav_data.ld_views[LNV_DB])
|
|
|
|
{
|
|
|
|
hist_source &hs = lnav_data.ld_db_source;
|
|
|
|
db_label_source &dls = lnav_data.ld_db_rows;
|
|
|
|
std::vector<bucket_type_t> &displayed = hs.get_displayed_buckets();
|
2014-02-01 14:41:11 +00:00
|
|
|
std::vector<int>::reverse_iterator start_iter, iter;
|
2013-06-23 20:43:51 +00:00
|
|
|
|
|
|
|
start_iter = dls.dls_headers_to_graph.rbegin();
|
|
|
|
if (!displayed.empty()) {
|
|
|
|
advance(start_iter, dls.dls_headers_to_graph.size() - (int)displayed[0]);
|
|
|
|
}
|
|
|
|
displayed.clear();
|
|
|
|
iter = find(start_iter,
|
|
|
|
dls.dls_headers_to_graph.rend(),
|
|
|
|
true);
|
|
|
|
if (iter != dls.dls_headers_to_graph.rend()) {
|
|
|
|
bucket_type_t type;
|
|
|
|
|
|
|
|
type = bucket_type_t(distance(dls.dls_headers_to_graph.begin(), --iter.base()));
|
|
|
|
displayed.push_back(type);
|
|
|
|
}
|
|
|
|
tc->reload_data();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
case 'X':
|
2014-03-13 05:54:35 +00:00
|
|
|
lnav_data.ld_rl_view->set_value(execute_command("close"));
|
2013-10-11 13:22:29 +00:00
|
|
|
break;
|
|
|
|
|
2011-06-11 17:26:52 +00:00
|
|
|
case '\\':
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
|
|
|
vis_bookmarks &bm = tc->get_bookmarks();
|
|
|
|
string ex;
|
|
|
|
|
|
|
|
for (bookmark_vector<vis_line_t>::iterator iter =
|
|
|
|
bm[&BM_EXAMPLE].begin();
|
|
|
|
iter != bm[&BM_EXAMPLE].end();
|
|
|
|
++iter) {
|
|
|
|
string line;
|
|
|
|
|
|
|
|
tc->get_sub_source()->text_value_for_line(*tc, *iter, line);
|
|
|
|
ex += line + "\n";
|
|
|
|
}
|
|
|
|
lnav_data.ld_views[LNV_EXAMPLE].set_sub_source(new plain_text_source(
|
|
|
|
ex));
|
|
|
|
ensure_view(&lnav_data.ld_views[LNV_EXAMPLE]);
|
|
|
|
}
|
|
|
|
break;
|
2011-06-11 17:26:52 +00:00
|
|
|
|
2013-06-02 21:20:15 +00:00
|
|
|
case 'r':
|
2014-11-06 05:29:31 +00:00
|
|
|
if (!lnav_data.ld_session_file_names.empty()) {
|
|
|
|
lnav_data.ld_session_file_index =
|
|
|
|
(lnav_data.ld_session_file_index + 1) %
|
|
|
|
lnav_data.ld_session_file_names.size();
|
|
|
|
reset_session();
|
|
|
|
load_session();
|
|
|
|
rebuild_indexes(true);
|
|
|
|
}
|
2013-06-02 21:20:15 +00:00
|
|
|
break;
|
2013-06-16 01:07:50 +00:00
|
|
|
|
2013-06-02 21:20:15 +00:00
|
|
|
case 'R':
|
2013-06-16 01:07:50 +00:00
|
|
|
if (lnav_data.ld_session_file_index == 0) {
|
|
|
|
lnav_data.ld_session_file_index =
|
|
|
|
lnav_data.ld_session_file_names.size() - 1;
|
|
|
|
}
|
|
|
|
else{
|
2013-06-02 21:20:15 +00:00
|
|
|
lnav_data.ld_session_file_index -= 1;
|
2013-06-16 01:07:50 +00:00
|
|
|
}
|
2013-06-02 21:20:15 +00:00
|
|
|
reset_session();
|
|
|
|
load_session();
|
|
|
|
rebuild_indexes(true);
|
|
|
|
break;
|
2013-06-16 01:07:50 +00:00
|
|
|
|
2013-06-02 21:20:15 +00:00
|
|
|
case KEY_CTRL_R:
|
|
|
|
reset_session();
|
|
|
|
rebuild_indexes(true);
|
2013-06-14 13:49:00 +00:00
|
|
|
lnav_data.ld_rl_view->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
r, R,
|
|
|
|
"to restore the next/previous session"));
|
2013-06-02 21:20:15 +00:00
|
|
|
break;
|
|
|
|
|
2013-11-08 15:32:39 +00:00
|
|
|
case KEY_CTRL_W:
|
|
|
|
execute_command(lnav_data.ld_views[LNV_LOG].get_word_wrap() ?
|
|
|
|
"disable-word-wrap" : "enable-word-wrap");
|
|
|
|
break;
|
|
|
|
|
2015-03-20 03:43:22 +00:00
|
|
|
case KEY_CTRL_L:
|
|
|
|
execute_command("redraw");
|
|
|
|
break;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
default:
|
2014-03-02 00:35:30 +00:00
|
|
|
log_warning("unhandled %d", ch);
|
2013-06-15 14:11:45 +00:00
|
|
|
lnav_data.ld_rl_view->set_value("Unrecognized keystroke, press "
|
|
|
|
ANSI_BOLD("?")
|
|
|
|
" to view help");
|
2013-05-28 04:35:00 +00:00
|
|
|
flash();
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_rl_key(int ch)
|
|
|
|
{
|
|
|
|
switch (ch) {
|
|
|
|
case KEY_PPAGE:
|
|
|
|
case KEY_NPAGE:
|
2013-05-28 04:35:00 +00:00
|
|
|
handle_paging_key(ch);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-07-24 14:42:16 +00:00
|
|
|
case KEY_CTRL_RBRACKET:
|
|
|
|
lnav_data.ld_rl_view->abort();
|
|
|
|
break;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
default:
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_rl_view->handle_key(ch);
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
readline_context::command_map_t lnav_commands;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-02 21:20:15 +00:00
|
|
|
string execute_command(string cmdline)
|
2011-06-11 18:24:23 +00:00
|
|
|
{
|
|
|
|
stringstream ss(cmdline);
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2011-06-11 18:24:23 +00:00
|
|
|
vector<string> args;
|
2013-05-28 04:35:00 +00:00
|
|
|
string buf, msg;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2014-03-02 00:35:30 +00:00
|
|
|
log_info("Executing: %s", cmdline.c_str());
|
|
|
|
|
2011-06-11 18:24:23 +00:00
|
|
|
while (ss >> buf) {
|
2013-05-28 04:35:00 +00:00
|
|
|
args.push_back(buf);
|
2011-06-11 18:24:23 +00:00
|
|
|
}
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2011-06-11 18:24:23 +00:00
|
|
|
if (args.size() > 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
readline_context::command_map_t::iterator iter;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if ((iter = lnav_commands.find(args[0])) ==
|
|
|
|
lnav_commands.end()) {
|
|
|
|
msg = "error: unknown command - " + args[0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
msg = iter->second(cmdline, args);
|
|
|
|
}
|
2011-06-11 18:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
string execute_sql(string sql, string &alt_msg)
|
|
|
|
{
|
|
|
|
db_label_source & dls = lnav_data.ld_db_rows;
|
|
|
|
hist_source & hs = lnav_data.ld_db_source;
|
|
|
|
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
|
|
|
|
string stmt_str = trim(sql);
|
|
|
|
string retval;
|
|
|
|
int retcode;
|
|
|
|
|
2014-03-02 00:35:30 +00:00
|
|
|
log_info("Executing SQL: %s", sql.c_str());
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
if (stmt_str == ".schema") {
|
|
|
|
alt_msg = "";
|
|
|
|
|
2014-03-02 16:55:00 +00:00
|
|
|
ensure_view(&lnav_data.ld_views[LNV_SCHEMA]);
|
2014-03-01 04:35:07 +00:00
|
|
|
|
|
|
|
lnav_data.ld_mode = LNM_PAGING;
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
hs.clear();
|
|
|
|
hs.get_displayed_buckets().clear();
|
|
|
|
dls.clear();
|
|
|
|
dls.dls_stmt_str = stmt_str;
|
|
|
|
retcode = sqlite3_prepare_v2(lnav_data.ld_db.in(),
|
|
|
|
stmt_str.c_str(),
|
|
|
|
-1,
|
|
|
|
stmt.out(),
|
|
|
|
NULL);
|
|
|
|
if (retcode != SQLITE_OK) {
|
|
|
|
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
|
|
|
|
2014-03-03 00:52:18 +00:00
|
|
|
retval = "error: " + string(errmsg);
|
2014-03-01 04:35:07 +00:00
|
|
|
alt_msg = "";
|
|
|
|
}
|
|
|
|
else if (stmt == NULL) {
|
|
|
|
retval = "";
|
|
|
|
alt_msg = "";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bool done = false;
|
2014-03-01 05:27:14 +00:00
|
|
|
int param_count;
|
|
|
|
|
|
|
|
param_count = sqlite3_bind_parameter_count(stmt.in());
|
|
|
|
for (int lpc = 0; lpc < param_count; lpc++) {
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = sqlite3_bind_parameter_name(stmt.in(), lpc + 1);
|
|
|
|
if (name[0] == '$') {
|
|
|
|
const char *env_value;
|
|
|
|
|
|
|
|
if ((env_value = getenv(&name[1])) != NULL) {
|
|
|
|
sqlite3_bind_text(stmt.in(), lpc + 1, env_value, -1, SQLITE_STATIC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-03-01 04:35:07 +00:00
|
|
|
|
2014-03-11 15:18:51 +00:00
|
|
|
if (lnav_data.ld_rl_view != NULL) {
|
|
|
|
lnav_data.ld_rl_view->set_value("Executing query: " + sql + " ...");
|
|
|
|
lnav_data.ld_rl_view->do_update();
|
|
|
|
}
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
lnav_data.ld_log_source.text_clear_marks(&BM_QUERY);
|
|
|
|
while (!done) {
|
|
|
|
retcode = sqlite3_step(stmt.in());
|
|
|
|
|
|
|
|
switch (retcode) {
|
|
|
|
case SQLITE_OK:
|
|
|
|
case SQLITE_DONE:
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SQLITE_ROW:
|
|
|
|
sql_callback(stmt.in());
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: {
|
|
|
|
const char *errmsg;
|
|
|
|
|
2014-03-03 00:52:18 +00:00
|
|
|
log_error("sqlite3_step error code: %d", retcode);
|
2014-03-01 04:35:07 +00:00
|
|
|
errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
2014-03-03 00:52:18 +00:00
|
|
|
retval = "error: " + string(errmsg);
|
2014-03-01 04:35:07 +00:00
|
|
|
done = true;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2014-03-01 04:35:07 +00:00
|
|
|
break;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2014-03-01 04:35:07 +00:00
|
|
|
}
|
|
|
|
}
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
if (retcode == SQLITE_DONE) {
|
|
|
|
lnav_data.ld_views[LNV_LOG].reload_data();
|
|
|
|
lnav_data.ld_views[LNV_DB].reload_data();
|
|
|
|
lnav_data.ld_views[LNV_DB].set_left(0);
|
|
|
|
|
|
|
|
if (dls.dls_rows.size() > 0) {
|
|
|
|
vis_bookmarks &bm =
|
|
|
|
lnav_data.ld_views[LNV_LOG].get_bookmarks();
|
|
|
|
|
2015-04-06 09:48:12 +00:00
|
|
|
if (!(lnav_data.ld_flags & LNF_HEADLESS) &&
|
|
|
|
dls.dls_headers.size() == 1 && !bm[&BM_QUERY].empty()) {
|
2014-03-01 04:35:07 +00:00
|
|
|
retval = "";
|
|
|
|
alt_msg = HELP_MSG_2(
|
|
|
|
y, Y,
|
|
|
|
"to move forward/backward through query results "
|
|
|
|
"in the log view");
|
|
|
|
}
|
2015-04-06 09:48:12 +00:00
|
|
|
else if (!(lnav_data.ld_flags & LNF_HEADLESS) &&
|
|
|
|
dls.dls_rows.size() == 1) {
|
2014-03-01 04:35:07 +00:00
|
|
|
string row;
|
2011-06-11 18:24:23 +00:00
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
hs.text_value_for_line(lnav_data.ld_views[LNV_DB], 1, row, true);
|
|
|
|
retval = "SQL Result: " + row;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char row_count[32];
|
|
|
|
|
|
|
|
ensure_view(&lnav_data.ld_views[LNV_DB]);
|
|
|
|
snprintf(row_count, sizeof(row_count),
|
|
|
|
ANSI_BOLD("%'d") " row(s) matched",
|
|
|
|
(int)dls.dls_rows.size());
|
|
|
|
retval = row_count;
|
|
|
|
alt_msg = HELP_MSG_2(
|
|
|
|
y, Y,
|
|
|
|
"to move forward/backward through query results "
|
|
|
|
"in the log view");
|
|
|
|
}
|
|
|
|
}
|
2014-03-13 03:36:14 +00:00
|
|
|
#ifdef HAVE_SQLITE3_STMT_READONLY
|
2014-03-03 00:52:18 +00:00
|
|
|
else if (sqlite3_stmt_readonly(stmt.in())) {
|
2014-03-01 04:35:07 +00:00
|
|
|
retval = "No rows matched";
|
|
|
|
alt_msg = "";
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2014-03-13 03:36:14 +00:00
|
|
|
#endif
|
2011-06-11 18:24:23 +00:00
|
|
|
}
|
2014-03-01 04:35:07 +00:00
|
|
|
|
|
|
|
if (!(lnav_data.ld_flags & LNF_HEADLESS)) {
|
|
|
|
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 *)lnav_data.ld_views[LNV_LOG].
|
|
|
|
get_overlay_source();
|
|
|
|
fos->fos_active = fos->fos_active_prev;
|
|
|
|
|
|
|
|
redo_search(LNV_DB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lnav_data.ld_views[LNV_LOG].reload_data();
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void execute_file(string path)
|
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
if (path == "-") {
|
|
|
|
file = stdin;
|
|
|
|
}
|
|
|
|
else if ((file = fopen(path.c_str(), "r")) == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int line_number = 0;
|
|
|
|
char *line = NULL;
|
|
|
|
size_t line_max_size;
|
|
|
|
ssize_t line_size;
|
|
|
|
|
|
|
|
while ((line_size = getline(&line, &line_max_size, file)) != -1) {
|
|
|
|
line_number += 1;
|
|
|
|
|
|
|
|
if (trim(line).empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (line[0] == '#') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
string rc, alt_msg;
|
|
|
|
|
|
|
|
if (line[line_size - 1] == '\n') {
|
|
|
|
line[line_size - 1] = '\0';
|
|
|
|
}
|
|
|
|
switch (line[0]) {
|
|
|
|
case ':':
|
|
|
|
rc = execute_command(&line[1]);
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
case ';':
|
|
|
|
setup_logline_table();
|
|
|
|
rc = execute_sql(&line[1], alt_msg);
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
execute_file(&line[1]);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = execute_command(line);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-03-13 06:20:18 +00:00
|
|
|
if (rescan_files()) {
|
|
|
|
rebuild_indexes(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info("%s:%d:execute result -- %s",
|
2014-03-01 04:35:07 +00:00
|
|
|
path.c_str(),
|
|
|
|
line_number,
|
|
|
|
rc.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file != stdin) {
|
|
|
|
fclose(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-03 00:52:18 +00:00
|
|
|
void execute_init_commands(vector<pair<string, string> > &msgs)
|
2014-03-01 04:35:07 +00:00
|
|
|
{
|
|
|
|
if (lnav_data.ld_commands.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::list<string>::iterator iter = lnav_data.ld_commands.begin();
|
|
|
|
iter != lnav_data.ld_commands.end();
|
|
|
|
++iter) {
|
|
|
|
string msg, alt_msg;
|
|
|
|
|
|
|
|
switch (iter->at(0)) {
|
|
|
|
case ':':
|
|
|
|
msg = execute_command(iter->substr(1));
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
case ';':
|
|
|
|
setup_logline_table();
|
|
|
|
msg = execute_sql(iter->substr(1), alt_msg);
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
execute_file(iter->substr(1));
|
|
|
|
break;
|
|
|
|
}
|
2014-03-03 00:52:18 +00:00
|
|
|
|
|
|
|
msgs.push_back(make_pair(msg, alt_msg));
|
2014-03-13 06:20:18 +00:00
|
|
|
|
|
|
|
if (rescan_files()) {
|
|
|
|
rebuild_indexes(true);
|
|
|
|
}
|
2014-03-01 04:35:07 +00:00
|
|
|
}
|
|
|
|
lnav_data.ld_commands.clear();
|
2011-06-11 18:24:23 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 02:34:48 +00:00
|
|
|
int sql_callback(sqlite3_stmt *stmt)
|
2009-10-06 21:14:49 +00:00
|
|
|
{
|
2013-05-24 14:55:56 +00:00
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
2013-05-28 04:35:00 +00:00
|
|
|
db_label_source & dls = lnav_data.ld_db_rows;
|
|
|
|
hist_source & hs = lnav_data.ld_db_source;
|
2013-05-24 14:55:56 +00:00
|
|
|
int ncols = sqlite3_column_count(stmt);
|
2009-10-06 21:14:49 +00:00
|
|
|
int row_number;
|
|
|
|
int lpc, retval = 0;
|
|
|
|
|
|
|
|
row_number = dls.dls_rows.size();
|
|
|
|
dls.dls_rows.resize(row_number + 1);
|
|
|
|
if (dls.dls_headers.empty()) {
|
2013-05-28 04:35:00 +00:00
|
|
|
for (lpc = 0; lpc < ncols; lpc++) {
|
|
|
|
int type = sqlite3_column_type(stmt, lpc);
|
2013-05-24 14:55:56 +00:00
|
|
|
string colname = sqlite3_column_name(stmt, lpc);
|
2013-05-28 04:35:00 +00:00
|
|
|
bool graphable;
|
2013-05-24 14:55:56 +00:00
|
|
|
|
|
|
|
graphable = ((type == SQLITE_INTEGER || type == SQLITE_FLOAT) &&
|
|
|
|
!binary_search(lnav_data.ld_db_key_names.begin(),
|
|
|
|
lnav_data.ld_db_key_names.end(),
|
|
|
|
colname));
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
dls.push_header(colname, type, graphable);
|
2013-05-24 14:55:56 +00:00
|
|
|
if (graphable) {
|
2013-05-28 04:35:00 +00:00
|
|
|
hs.set_role_for_type(bucket_type_t(lpc),
|
|
|
|
view_colors::singleton().
|
|
|
|
next_plain_highlight());
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
2009-10-06 21:14:49 +00:00
|
|
|
}
|
|
|
|
for (lpc = 0; lpc < ncols; lpc++) {
|
2013-05-28 04:35:00 +00:00
|
|
|
const char *value = (const char *)sqlite3_column_text(stmt, lpc);
|
|
|
|
double num_value = 0.0;
|
|
|
|
|
|
|
|
dls.push_column(value);
|
2013-05-28 14:08:49 +00:00
|
|
|
if (dls.dls_headers[lpc] == "log_line") {
|
2013-05-28 04:35:00 +00:00
|
|
|
int line_number = -1;
|
|
|
|
|
|
|
|
if (sscanf(value, "%d", &line_number) == 1) {
|
|
|
|
lss.text_mark(&BM_QUERY, line_number, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dls.dls_headers_to_graph[lpc]) {
|
|
|
|
sscanf(value, "%lf", &num_value);
|
|
|
|
hs.add_value(row_number, bucket_type_t(lpc), num_value);
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-05-28 04:35:00 +00:00
|
|
|
hs.add_empty_value(row_number);
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
2009-10-06 21:14:49 +00:00
|
|
|
}
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2009-10-06 21:14:49 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-03-04 15:38:33 +00:00
|
|
|
void execute_search(lnav_view_t view, const std::string ®ex_orig)
|
2013-06-15 23:42:21 +00:00
|
|
|
{
|
|
|
|
auto_ptr<grep_highlighter> &gc = lnav_data.ld_search_child[view];
|
2013-06-16 01:07:50 +00:00
|
|
|
textview_curses & tc = lnav_data.ld_views[view];
|
2014-03-04 15:38:33 +00:00
|
|
|
std::string regex = regex_orig;
|
2013-06-15 23:42:21 +00:00
|
|
|
|
|
|
|
if ((gc.get() == NULL) || (regex != lnav_data.ld_last_search[view])) {
|
|
|
|
const char *errptr;
|
2014-03-04 15:38:33 +00:00
|
|
|
pcre * code = NULL;
|
2013-06-15 23:42:21 +00:00
|
|
|
int eoff;
|
2014-03-04 15:38:33 +00:00
|
|
|
bool quoted = false;
|
2013-06-15 23:42:21 +00:00
|
|
|
|
2013-06-26 13:14:09 +00:00
|
|
|
tc.match_reset();
|
|
|
|
|
2013-06-15 23:42:21 +00:00
|
|
|
if (regex.empty() && gc.get() != NULL) {
|
|
|
|
tc.grep_begin(*(gc->get_grep_proc()));
|
|
|
|
tc.grep_end(*(gc->get_grep_proc()));
|
|
|
|
}
|
|
|
|
gc.reset();
|
|
|
|
|
2014-03-02 00:35:30 +00:00
|
|
|
log_debug("start search for: '%s'", regex.c_str());
|
2013-06-15 23:42:21 +00:00
|
|
|
|
|
|
|
if (regex.empty()) {
|
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
|
|
|
}
|
|
|
|
else if ((code = pcre_compile(regex.c_str(),
|
|
|
|
PCRE_CASELESS,
|
|
|
|
&errptr,
|
|
|
|
&eoff,
|
|
|
|
NULL)) == NULL) {
|
2014-03-04 15:38:33 +00:00
|
|
|
lnav_data.ld_bottom_source.grep_error(
|
|
|
|
"regexp error: " + string(errptr));
|
|
|
|
|
|
|
|
quoted = true;
|
|
|
|
regex = pcrecpp::RE::QuoteMeta(regex);
|
|
|
|
|
|
|
|
log_info("invalid search regex, using quoted: %s", regex.c_str());
|
|
|
|
if ((code = pcre_compile(regex.c_str(),
|
|
|
|
PCRE_CASELESS,
|
|
|
|
&errptr,
|
|
|
|
&eoff,
|
|
|
|
NULL)) == NULL) {
|
|
|
|
log_error("Unable to compile quoted regex: %s", regex.c_str());
|
|
|
|
}
|
2013-06-15 23:42:21 +00:00
|
|
|
}
|
|
|
|
|
2014-03-04 15:38:33 +00:00
|
|
|
if (code != NULL) {
|
|
|
|
textview_curses::highlighter hl(
|
|
|
|
code, false, view_colors::VCR_SEARCH);
|
|
|
|
|
|
|
|
if (!quoted) {
|
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
|
|
|
}
|
2013-06-15 23:42:21 +00:00
|
|
|
lnav_data.ld_bottom_source.set_prompt("");
|
|
|
|
|
|
|
|
textview_curses::highlight_map_t &hm = tc.get_highlights();
|
|
|
|
hm["$search"] = hl;
|
|
|
|
|
|
|
|
auto_ptr<grep_proc> gp(new grep_proc(code,
|
2014-03-04 15:38:33 +00:00
|
|
|
tc,
|
|
|
|
lnav_data.ld_max_fd,
|
|
|
|
lnav_data.ld_read_fds));
|
2013-06-15 23:42:21 +00:00
|
|
|
|
|
|
|
gp->queue_request(grep_line_t(tc.get_top()));
|
|
|
|
if (tc.get_top() > 0) {
|
2014-03-04 15:38:33 +00:00
|
|
|
gp->queue_request(grep_line_t(0), grep_line_t(tc.get_top()));
|
2013-06-15 23:42:21 +00:00
|
|
|
}
|
|
|
|
gp->start();
|
2013-07-23 12:55:08 +00:00
|
|
|
gp->set_sink(&tc);
|
2013-06-15 23:42:21 +00:00
|
|
|
|
|
|
|
tc.set_follow_search(true);
|
|
|
|
|
2014-03-04 15:38:33 +00:00
|
|
|
auto_ptr<grep_highlighter> gh(
|
|
|
|
new grep_highlighter(gp, "$search", hm));
|
2013-06-15 23:42:21 +00:00
|
|
|
gc = gh;
|
|
|
|
}
|
|
|
|
}
|
2013-06-16 01:07:50 +00:00
|
|
|
|
2013-06-15 23:42:21 +00:00
|
|
|
lnav_data.ld_last_search[view] = regex;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
static void rl_search_internal(void *dummy, readline_curses *rc, bool complete = false)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2013-07-24 14:42:16 +00:00
|
|
|
string term_val;
|
2009-09-14 01:07:32 +00:00
|
|
|
string name;
|
|
|
|
|
|
|
|
switch (lnav_data.ld_mode) {
|
|
|
|
case LNM_SEARCH:
|
2013-06-13 14:18:59 +00:00
|
|
|
name = "$search";
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case LNM_CAPTURE:
|
2014-03-06 14:58:49 +00:00
|
|
|
require(0);
|
2013-06-13 14:18:59 +00:00
|
|
|
name = "$capture";
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case LNM_COMMAND:
|
2013-05-28 04:35:00 +00:00
|
|
|
return;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case LNM_SQL:
|
2014-02-24 19:43:50 +00:00
|
|
|
term_val = trim(rc->get_value() + ";");
|
2013-07-24 14:42:16 +00:00
|
|
|
|
2014-02-24 19:43:50 +00:00
|
|
|
if (term_val.size() > 0 && term_val[0] == '.') {
|
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
|
|
|
}
|
|
|
|
else if (!sqlite3_complete(term_val.c_str())) {
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_bottom_source.
|
|
|
|
grep_error("sql error: incomplete statement");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
|
|
|
|
int retcode;
|
|
|
|
|
|
|
|
retcode = sqlite3_prepare_v2(lnav_data.ld_db,
|
|
|
|
rc->get_value().c_str(),
|
|
|
|
-1,
|
|
|
|
stmt.out(),
|
|
|
|
NULL);
|
|
|
|
if (retcode != SQLITE_OK) {
|
|
|
|
const char *errmsg = sqlite3_errmsg(lnav_data.ld_db);
|
|
|
|
|
|
|
|
lnav_data.ld_bottom_source.
|
|
|
|
grep_error(string("sql error: ") + string(errmsg));
|
|
|
|
}
|
|
|
|
else {
|
2013-06-16 01:07:50 +00:00
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
default:
|
2014-03-06 14:58:49 +00:00
|
|
|
require(0);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 01:07:50 +00:00
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
|
|
|
lnav_view_t index = (lnav_view_t)(tc - lnav_data.ld_views);
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-06-18 04:29:42 +00:00
|
|
|
if (!complete) {
|
2013-09-10 13:20:37 +00:00
|
|
|
tc->set_top(lnav_data.ld_search_start_line);
|
2014-06-18 04:29:42 +00:00
|
|
|
}
|
2013-06-15 23:42:21 +00:00
|
|
|
execute_search(index, rc->get_value());
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
static void rl_search(void *dummy, readline_curses *rc)
|
|
|
|
{
|
|
|
|
rl_search_internal(dummy, rc);
|
|
|
|
}
|
|
|
|
|
2013-07-24 14:42:16 +00:00
|
|
|
static void rl_abort(void *dummy, readline_curses *rc)
|
|
|
|
{
|
|
|
|
textview_curses *tc = lnav_data.ld_view_stack.top();
|
|
|
|
lnav_view_t index = (lnav_view_t)(tc - lnav_data.ld_views);
|
|
|
|
|
|
|
|
lnav_data.ld_bottom_source.set_prompt("");
|
|
|
|
|
|
|
|
lnav_data.ld_bottom_source.grep_error("");
|
|
|
|
switch (lnav_data.ld_mode) {
|
|
|
|
case LNM_SEARCH:
|
|
|
|
tc->set_top(lnav_data.ld_search_start_line);
|
|
|
|
execute_search(index, lnav_data.ld_previous_search);
|
|
|
|
break;
|
|
|
|
case LNM_SQL:
|
|
|
|
{
|
|
|
|
field_overlay_source *fos;
|
|
|
|
|
|
|
|
fos =
|
|
|
|
(field_overlay_source *)lnav_data.ld_views[LNV_LOG].
|
|
|
|
get_overlay_source();
|
|
|
|
fos->fos_active = fos->fos_active_prev;
|
|
|
|
tc->reload_data();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lnav_data.ld_mode = LNM_PAGING;
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
static void rl_callback(void *dummy, readline_curses *rc)
|
|
|
|
{
|
2014-03-01 04:35:07 +00:00
|
|
|
string alt_msg;
|
2013-06-16 01:07:50 +00:00
|
|
|
|
2014-10-30 15:37:06 +00:00
|
|
|
lnav_data.ld_bottom_source.set_prompt("");
|
2009-09-14 01:07:32 +00:00
|
|
|
switch (lnav_data.ld_mode) {
|
2009-10-14 19:42:58 +00:00
|
|
|
case LNM_PAGING:
|
2014-03-06 14:58:49 +00:00
|
|
|
require(0);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
case LNM_COMMAND:
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_mode = LNM_PAGING;
|
2013-06-01 03:45:40 +00:00
|
|
|
rc->set_alt_value("");
|
2014-02-24 23:50:42 +00:00
|
|
|
rc->set_value(execute_command(rc->get_value()));
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case LNM_SEARCH:
|
|
|
|
case LNM_CAPTURE:
|
2013-09-10 13:20:37 +00:00
|
|
|
rl_search_internal(dummy, rc, true);
|
2013-05-28 04:35:00 +00:00
|
|
|
if (rc->get_value().size() > 0) {
|
2014-11-19 14:12:43 +00:00
|
|
|
auto_mem<FILE> pfile(pclose);
|
|
|
|
|
|
|
|
pfile = open_clipboard(CT_FIND);
|
|
|
|
if (pfile.in() != NULL) {
|
|
|
|
fprintf(pfile, "%s", rc->get_value().c_str());
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_view_stack.top()->set_follow_search(false);
|
|
|
|
rc->set_value("search: " + rc->get_value());
|
2013-06-14 13:49:00 +00:00
|
|
|
rc->set_alt_value(HELP_MSG_2(
|
2013-06-16 01:07:50 +00:00
|
|
|
n, N,
|
|
|
|
"to move forward/backward through search results"));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
lnav_data.ld_mode = LNM_PAGING;
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
case LNM_SQL:
|
2014-03-01 04:35:07 +00:00
|
|
|
rc->set_value(execute_sql(rc->get_value(), alt_msg));
|
|
|
|
rc->set_alt_value(alt_msg);
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_mode = LNM_PAGING;
|
|
|
|
break;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-09 09:29:28 +00:00
|
|
|
static void rl_display_matches(void *dummy, readline_curses *rc)
|
|
|
|
{
|
|
|
|
const std::vector<std::string> &matches = rc->get_matches();
|
|
|
|
textview_curses &tc = lnav_data.ld_match_view;
|
|
|
|
unsigned long width, height;
|
|
|
|
int max_len, cols, rows, match_height, bottom_height;
|
|
|
|
|
|
|
|
getmaxyx(lnav_data.ld_window, height, width);
|
|
|
|
|
|
|
|
max_len = rc->get_max_match_length() + 2;
|
2014-03-09 19:55:02 +00:00
|
|
|
cols = max(1UL, width / max_len);
|
2014-03-09 09:29:28 +00:00
|
|
|
rows = (matches.size() + cols - 1) / cols;
|
|
|
|
|
|
|
|
match_height = min((unsigned long)rows, (height - 4) / 2);
|
|
|
|
bottom_height = match_height + 1 + rc->get_height();
|
|
|
|
|
|
|
|
for (int lpc = 0; lpc < LNV__MAX; lpc++) {
|
|
|
|
lnav_data.ld_views[lpc].set_height(vis_line_t(-bottom_height));
|
|
|
|
}
|
|
|
|
lnav_data.ld_status[LNS_BOTTOM].set_top(-bottom_height);
|
|
|
|
|
2015-03-31 13:34:53 +00:00
|
|
|
delete tc.get_sub_source();
|
2014-03-09 09:29:28 +00:00
|
|
|
|
|
|
|
if (cols == 1) {
|
|
|
|
tc.set_sub_source(new plain_text_source(rc->get_matches()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
std::vector<std::string> horiz_matches;
|
|
|
|
|
|
|
|
horiz_matches.resize(rows);
|
2015-04-02 08:48:21 +00:00
|
|
|
for (size_t lpc = 0; lpc < matches.size(); lpc++) {
|
2014-03-09 09:29:28 +00:00
|
|
|
int curr_row = lpc % rows;
|
|
|
|
|
|
|
|
horiz_matches[curr_row].append(matches[lpc]);
|
|
|
|
horiz_matches[curr_row].append(
|
|
|
|
max_len - matches[lpc].length(), ' ');
|
|
|
|
}
|
|
|
|
tc.set_sub_source(new plain_text_source(horiz_matches));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match_height > 0) {
|
|
|
|
tc.set_window(lnav_data.ld_window);
|
|
|
|
tc.set_y(height - bottom_height + 1);
|
|
|
|
tc.set_height(vis_line_t(match_height));
|
|
|
|
tc.reload_data();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tc.set_window(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rl_display_next(void *dummy, readline_curses *rc)
|
|
|
|
{
|
|
|
|
textview_curses &tc = lnav_data.ld_match_view;
|
|
|
|
|
|
|
|
if (tc.get_top() >= (tc.get_top_for_last_row() - 1)) {
|
|
|
|
tc.set_top(vis_line_t(0));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tc.shift_top(tc.get_height());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
static void usage(void)
|
|
|
|
{
|
|
|
|
const char *usage_msg =
|
2014-11-19 14:12:43 +00:00
|
|
|
"usage: %s [options] [logfile1 logfile2 ...]\n"
|
2013-05-28 04:35:00 +00:00
|
|
|
"\n"
|
|
|
|
"A curses-based log file viewer that indexes log messages by type\n"
|
|
|
|
"and time to make it easier to navigate through files quickly.\n"
|
|
|
|
"\n"
|
|
|
|
"Key bindings:\n"
|
|
|
|
" ? View/leave the online help text.\n"
|
|
|
|
" q Quit the program.\n"
|
|
|
|
"\n"
|
|
|
|
"Options:\n"
|
|
|
|
" -h Print this message, then exit.\n"
|
2014-02-10 15:53:56 +00:00
|
|
|
" -H Display the internal help text.\n"
|
2014-03-03 06:26:41 +00:00
|
|
|
" -I path An additional configuration directory.\n"
|
2014-11-05 17:01:09 +00:00
|
|
|
" -i Install the given format files and exit.\n"
|
2013-06-29 13:22:24 +00:00
|
|
|
" -C Check configuration and then exit.\n"
|
2013-04-20 20:21:10 +00:00
|
|
|
" -d file Write debug messages to the given file.\n"
|
2013-05-28 04:35:00 +00:00
|
|
|
" -V Print version information.\n"
|
2014-03-01 04:35:07 +00:00
|
|
|
"\n"
|
2013-05-28 04:35:00 +00:00
|
|
|
" -a Load all of the most recent log file types.\n"
|
|
|
|
" -r Load older rotated log files as well.\n"
|
2013-05-01 04:48:16 +00:00
|
|
|
" -t Prepend timestamps to the lines of data being read in\n"
|
|
|
|
" on the standard input.\n"
|
|
|
|
" -w file Write the contents of the standard input to this file.\n"
|
2013-05-28 04:35:00 +00:00
|
|
|
"\n"
|
2014-03-07 14:29:20 +00:00
|
|
|
" -c cmd Execute a command after the files have been loaded.\n"
|
|
|
|
" -f path Execute the commands in the given file.\n"
|
|
|
|
" -n Run without the curses UI. (headless mode)\n"
|
|
|
|
" -q Do not print the log messages after executing all\n"
|
|
|
|
" of the commands.\n"
|
|
|
|
"\n"
|
2013-05-28 04:35:00 +00:00
|
|
|
"Optional arguments:\n"
|
|
|
|
" logfile1 The log files or directories to view. If a\n"
|
|
|
|
" directory is given, all of the files in the\n"
|
|
|
|
" directory will be loaded.\n"
|
|
|
|
"\n"
|
|
|
|
"Examples:\n"
|
|
|
|
" To load and follow the syslog file:\n"
|
2014-11-19 14:12:43 +00:00
|
|
|
" $ lnav\n"
|
2013-05-28 04:35:00 +00:00
|
|
|
"\n"
|
|
|
|
" To load all of the files in /var/log:\n"
|
|
|
|
" $ lnav /var/log\n"
|
|
|
|
"\n"
|
|
|
|
" To watch the output of make with timestamps prepended:\n"
|
|
|
|
" $ make 2>&1 | lnav -t\n"
|
|
|
|
"\n"
|
2015-04-07 04:33:34 +00:00
|
|
|
"Version: " VCS_PACKAGE_STRING "\n";
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
fprintf(stderr, usage_msg, lnav_data.ld_program_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static pcre *xpcre_compile(const char *pattern, int options = 0)
|
|
|
|
{
|
|
|
|
const char *errptr;
|
2013-05-28 04:35:00 +00:00
|
|
|
pcre * retval;
|
|
|
|
int eoff;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
if ((retval = pcre_compile(pattern,
|
2013-05-28 04:35:00 +00:00
|
|
|
options,
|
|
|
|
&errptr,
|
|
|
|
&eoff,
|
|
|
|
NULL)) == NULL) {
|
|
|
|
fprintf(stderr, "internal error: failed to compile -- %s\n", pattern);
|
|
|
|
fprintf(stderr, "internal error: %s\n", errptr);
|
|
|
|
|
|
|
|
exit(1);
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2012-11-28 16:39:39 +00:00
|
|
|
/**
|
|
|
|
* Callback used to keep track of the timestamps for the top and bottom lines
|
|
|
|
* in the log view. This function is intended to be used as the callback
|
|
|
|
* function in a view_action.
|
|
|
|
*
|
2013-05-28 04:35:00 +00:00
|
|
|
* @param lv The listview object that contains the log
|
2012-11-28 16:39:39 +00:00
|
|
|
*/
|
2009-09-14 01:07:32 +00:00
|
|
|
static void update_times(void *, listview_curses *lv)
|
|
|
|
{
|
|
|
|
if (lv == &lnav_data.ld_views[LNV_LOG] && lv->get_inner_height() > 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
logfile_sub_source &lss = lnav_data.ld_log_source;
|
2013-06-22 14:55:49 +00:00
|
|
|
logline *ll;
|
|
|
|
|
|
|
|
ll = lss.find_line(lss.at(lv->get_top()));
|
|
|
|
lnav_data.ld_top_time = ll->get_time();
|
|
|
|
lnav_data.ld_top_time_millis = ll->get_millis();
|
|
|
|
ll = lss.find_line(lss.at(lv->get_bottom()));
|
|
|
|
lnav_data.ld_bottom_time = ll->get_time();
|
|
|
|
lnav_data.ld_bottom_time_millis = ll->get_millis();
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
if (lv == &lnav_data.ld_views[LNV_HISTOGRAM] &&
|
2013-05-28 04:35:00 +00:00
|
|
|
lv->get_inner_height() > 0) {
|
|
|
|
hist_source &hs = lnav_data.ld_hist_source;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_top_time = hs.value_for_row(lv->get_top());
|
2013-06-22 14:55:49 +00:00
|
|
|
lnav_data.ld_top_time_millis = 0;
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_bottom_time = hs.value_for_row(lv->get_bottom());
|
2013-06-22 14:55:49 +00:00
|
|
|
lnav_data.ld_bottom_time_millis = 0;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2015-03-19 04:54:46 +00:00
|
|
|
static void clear_last_user_mark(void *, listview_curses *lv)
|
|
|
|
{
|
|
|
|
textview_curses *tc = (textview_curses *) lv;
|
|
|
|
if (lnav_data.ld_select_start.find(tc) != lnav_data.ld_select_start.end() &&
|
|
|
|
lnav_data.ld_select_start[tc] != tc->get_top()) {
|
|
|
|
lnav_data.ld_select_start.erase(tc);
|
|
|
|
lnav_data.ld_last_user_mark.erase(tc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-29 23:38:58 +00:00
|
|
|
/**
|
|
|
|
* Functor used to compare files based on their device and inode number.
|
|
|
|
*/
|
2011-08-06 16:33:55 +00:00
|
|
|
struct same_file {
|
|
|
|
same_file(const struct stat &stat) : sf_stat(stat) { };
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2012-10-29 23:38:58 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2013-05-28 04:35:00 +00:00
|
|
|
bool operator()(const logfile *lf) const
|
|
|
|
{
|
|
|
|
return this->sf_stat.st_dev == lf->get_stat().st_dev &&
|
|
|
|
this->sf_stat.st_ino == lf->get_stat().st_ino;
|
2011-08-06 16:33:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const struct stat &sf_stat;
|
|
|
|
};
|
|
|
|
|
2012-10-29 23:38:58 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2012-10-29 23:38:58 +00:00
|
|
|
* @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.
|
|
|
|
*/
|
2011-08-06 16:33:55 +00:00
|
|
|
static void watch_logfile(string filename, int fd, bool required)
|
|
|
|
{
|
2014-11-03 14:07:36 +00:00
|
|
|
static loading_observer obs;
|
2012-07-13 16:26:47 +00:00
|
|
|
list<logfile *>::iterator file_iter;
|
2011-08-06 16:33:55 +00:00
|
|
|
struct stat st;
|
2013-05-28 04:35:00 +00:00
|
|
|
int rc;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2014-04-20 21:58:19 +00:00
|
|
|
if (lnav_data.ld_closed_files.count(filename)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-06 16:33:55 +00:00
|
|
|
if (fd != -1) {
|
2013-05-28 04:35:00 +00:00
|
|
|
rc = fstat(fd, &st);
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-05-28 04:35:00 +00:00
|
|
|
rc = stat(filename.c_str(), &st);
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
2012-04-24 21:30:07 +00:00
|
|
|
|
|
|
|
if (rc == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
if (!S_ISREG(st.st_mode)) {
|
|
|
|
if (required) {
|
|
|
|
rc = -1;
|
|
|
|
errno = EINVAL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-04-24 21:30:07 +00:00
|
|
|
}
|
2011-08-06 16:33:55 +00:00
|
|
|
if (rc == -1) {
|
2013-05-28 04:35:00 +00:00
|
|
|
if (required) {
|
|
|
|
throw logfile::error(filename, errno);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
return;
|
|
|
|
}
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
file_iter = find_if(lnav_data.ld_files.begin(),
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_files.end(),
|
|
|
|
same_file(st));
|
2012-07-13 16:26:47 +00:00
|
|
|
|
|
|
|
if (file_iter == lnav_data.ld_files.end()) {
|
2013-05-28 04:35:00 +00:00
|
|
|
if (find(lnav_data.ld_other_files.begin(),
|
|
|
|
lnav_data.ld_other_files.end(),
|
|
|
|
filename) == lnav_data.ld_other_files.end()) {
|
|
|
|
file_format_t ff = detect_file_format(filename);
|
|
|
|
|
|
|
|
switch (ff) {
|
|
|
|
case FF_SQLITE_DB:
|
|
|
|
lnav_data.ld_other_files.push_back(filename);
|
2013-06-06 14:01:32 +00:00
|
|
|
attach_sqlite_db(lnav_data.ld_db.in(), filename);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* It's a new file, load it in. */
|
|
|
|
logfile *lf = new logfile(filename, fd);
|
|
|
|
|
2014-04-18 12:17:24 +00:00
|
|
|
log_info("loading new file: %s", filename.c_str());
|
2014-11-03 14:07:36 +00:00
|
|
|
lf->set_logfile_observer(&obs);
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_files.push_back(lf);
|
2015-03-28 13:30:30 +00:00
|
|
|
lnav_data.ld_text_source.push_back(lf);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
2012-07-13 16:26:47 +00:00
|
|
|
else {
|
2013-05-28 04:35:00 +00:00
|
|
|
/* The file is already loaded, but has been found under a different
|
2012-10-29 23:38:58 +00:00
|
|
|
* name. We just need to update the stored file name.
|
|
|
|
*/
|
2013-05-28 04:35:00 +00:00
|
|
|
(*file_iter)->set_filename(filename);
|
2012-07-13 16:26:47 +00:00
|
|
|
}
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
|
|
|
|
2012-10-29 23:38:58 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2012-04-24 21:30:07 +00:00
|
|
|
static void expand_filename(string path, bool required)
|
|
|
|
{
|
2013-05-31 00:46:41 +00:00
|
|
|
static_root_mem<glob_t, globfree> gl;
|
2012-04-24 21:30:07 +00:00
|
|
|
|
2013-05-31 00:46:41 +00:00
|
|
|
if (glob(path.c_str(), GLOB_NOCHECK, NULL, gl.inout()) == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
int lpc;
|
|
|
|
|
2013-05-31 00:46:41 +00:00
|
|
|
if (gl->gl_pathc == 1 /*&& gl.gl_matchc == 0*/) {
|
2013-05-28 04:35:00 +00:00
|
|
|
/* It's a pattern that doesn't match any files
|
|
|
|
* yet, allow it through since we'll load it in
|
|
|
|
* dynamically.
|
|
|
|
*/
|
|
|
|
required = false;
|
|
|
|
}
|
2013-05-31 00:46:41 +00:00
|
|
|
if (gl->gl_pathc > 1 ||
|
|
|
|
strcmp(path.c_str(), gl->gl_pathv[0]) != 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
required = false;
|
|
|
|
}
|
2013-05-31 00:46:41 +00:00
|
|
|
for (lpc = 0; lpc < (int)gl->gl_pathc; lpc++) {
|
2013-09-14 19:30:57 +00:00
|
|
|
auto_mem<char> abspath;
|
|
|
|
|
|
|
|
if ((abspath = realpath(gl->gl_pathv[lpc], NULL)) == NULL) {
|
2014-03-03 14:31:53 +00:00
|
|
|
if (required) {
|
|
|
|
fprintf(stderr, "Cannot find file: %s -- %s",
|
|
|
|
gl->gl_pathv[lpc], strerror(errno));
|
|
|
|
}
|
2013-09-14 19:30:57 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
watch_logfile(abspath.in(), -1, required);
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2012-04-24 21:30:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-13 06:20:18 +00:00
|
|
|
static bool rescan_files(bool required)
|
2011-08-06 16:33:55 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
set<pair<string, int> >::iterator iter;
|
|
|
|
list<logfile *>::iterator file_iter;
|
2012-10-29 23:38:58 +00:00
|
|
|
bool retval = false;
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2011-08-06 16:33:55 +00:00
|
|
|
for (iter = lnav_data.ld_file_names.begin();
|
2013-05-28 04:35:00 +00:00
|
|
|
iter != lnav_data.ld_file_names.end();
|
|
|
|
iter++) {
|
|
|
|
if (iter->second == -1) {
|
|
|
|
expand_filename(iter->first, required);
|
|
|
|
if (lnav_data.ld_flags & LNF_ROTATED) {
|
|
|
|
string path = iter->first + ".*";
|
|
|
|
|
|
|
|
expand_filename(path, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
watch_logfile(iter->first, iter->second, required);
|
|
|
|
}
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
2012-10-29 23:38:58 +00:00
|
|
|
|
|
|
|
for (file_iter = lnav_data.ld_files.begin();
|
2013-05-28 04:35:00 +00:00
|
|
|
file_iter != lnav_data.ld_files.end(); ) {
|
2013-09-14 19:30:57 +00:00
|
|
|
logfile *lf = *file_iter;
|
|
|
|
|
|
|
|
if (!lf->exists() || lf->is_closed()) {
|
2014-10-31 12:16:07 +00:00
|
|
|
return true;
|
2012-10-29 23:38:58 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
++file_iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
2011-08-06 16:33:55 +00:00
|
|
|
}
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
static string execute_action(log_data_helper &ldh,
|
|
|
|
int value_index,
|
|
|
|
const string &action_name)
|
|
|
|
{
|
|
|
|
std::map<string, log_format::action_def>::const_iterator iter;
|
|
|
|
logline_value &lv = ldh.ldh_line_values[value_index];
|
|
|
|
logfile *lf = ldh.ldh_file;
|
|
|
|
const log_format *format = lf->get_format();
|
|
|
|
pid_t child_pid;
|
|
|
|
string retval;
|
|
|
|
|
|
|
|
iter = format->lf_action_defs.find(action_name);
|
|
|
|
|
|
|
|
const log_format::action_def &action = iter->second;
|
|
|
|
|
|
|
|
auto_pipe in_pipe(STDIN_FILENO);
|
|
|
|
auto_pipe out_pipe(STDOUT_FILENO);
|
|
|
|
auto_pipe err_pipe(STDERR_FILENO);
|
|
|
|
|
|
|
|
in_pipe.open();
|
|
|
|
if (action.ad_capture_output)
|
|
|
|
out_pipe.open();
|
|
|
|
err_pipe.open();
|
|
|
|
|
|
|
|
child_pid = fork();
|
|
|
|
|
|
|
|
in_pipe.after_fork(child_pid);
|
|
|
|
out_pipe.after_fork(child_pid);
|
|
|
|
err_pipe.after_fork(child_pid);
|
|
|
|
|
|
|
|
switch (child_pid) {
|
|
|
|
case -1:
|
|
|
|
retval = "error: unable to fork child process -- " + string(strerror(errno));
|
|
|
|
break;
|
|
|
|
case 0: {
|
|
|
|
const char *args[action.ad_cmdline.size() + 1];
|
|
|
|
set<std::string> path_set(format->get_source_path());
|
|
|
|
char env_buffer[64];
|
|
|
|
int value_line;
|
|
|
|
string path;
|
|
|
|
|
|
|
|
setenv("LNAV_ACTION_FILE", lf->get_filename().c_str(), 1);
|
|
|
|
snprintf(env_buffer, sizeof(env_buffer),
|
|
|
|
"%ld",
|
|
|
|
(ldh.ldh_line - lf->begin()) + 1);
|
|
|
|
setenv("LNAV_ACTION_FILE_LINE", env_buffer, 1);
|
|
|
|
snprintf(env_buffer, sizeof(env_buffer), "%d", ldh.ldh_y_offset + 1);
|
|
|
|
setenv("LNAV_ACTION_MSG_LINE", env_buffer, 1);
|
2014-10-28 14:02:27 +00:00
|
|
|
setenv("LNAV_ACTION_VALUE_NAME", lv.lv_name.get(), 1);
|
2013-10-11 13:22:29 +00:00
|
|
|
value_line = ldh.ldh_y_offset - ldh.get_value_line(lv) + 1;
|
|
|
|
snprintf(env_buffer, sizeof(env_buffer), "%d", value_line);
|
|
|
|
setenv("LNAV_ACTION_VALUE_LINE", env_buffer, 1);
|
|
|
|
|
|
|
|
for (set<string>::iterator path_iter = path_set.begin();
|
|
|
|
path_iter != path_set.end();
|
|
|
|
++path_iter) {
|
|
|
|
if (!path.empty()) {
|
|
|
|
path += ":";
|
|
|
|
}
|
|
|
|
path += *path_iter;
|
|
|
|
}
|
|
|
|
path += ":" + string(getenv("PATH"));
|
|
|
|
setenv("PATH", path.c_str(), 1);
|
|
|
|
for (size_t lpc = 0; lpc < action.ad_cmdline.size(); lpc++) {
|
|
|
|
args[lpc] = action.ad_cmdline[lpc].c_str();
|
|
|
|
}
|
|
|
|
args[action.ad_cmdline.size()] = NULL;
|
|
|
|
execvp(args[0], (char *const *) args);
|
|
|
|
fprintf(stderr,
|
|
|
|
"error: could not exec process -- %s:%s\n",
|
|
|
|
args[0],
|
|
|
|
strerror(errno));
|
2014-03-02 00:35:30 +00:00
|
|
|
_exit(0);
|
2013-10-11 13:22:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default: {
|
|
|
|
static int exec_count = 0;
|
|
|
|
|
|
|
|
string value = lv.to_string();
|
|
|
|
line_buffer lb;
|
|
|
|
off_t off = 0;
|
2014-03-15 11:40:58 +00:00
|
|
|
line_value lv;
|
2013-10-11 13:22:29 +00:00
|
|
|
|
|
|
|
lnav_data.ld_children.push_back(child_pid);
|
|
|
|
|
|
|
|
if (write(in_pipe.write_end(), value.c_str(), value.size()) == -1) {
|
|
|
|
perror("execute_action write");
|
|
|
|
}
|
|
|
|
in_pipe.close();
|
|
|
|
|
|
|
|
lb.set_fd(err_pipe.read_end());
|
|
|
|
|
2014-03-15 11:40:58 +00:00
|
|
|
lb.read_line(off, lv);
|
2013-10-11 13:22:29 +00:00
|
|
|
|
|
|
|
if (out_pipe.read_end() != -1) {
|
|
|
|
piper_proc *pp = new piper_proc(out_pipe.read_end(), false);
|
|
|
|
char desc[128];
|
|
|
|
|
|
|
|
lnav_data.ld_pipers.push_back(pp);
|
|
|
|
snprintf(desc,
|
|
|
|
sizeof(desc), "[%d] Output of %s",
|
|
|
|
exec_count++,
|
|
|
|
action.ad_cmdline[0].c_str());
|
|
|
|
lnav_data.ld_file_names.insert(make_pair(
|
|
|
|
desc,
|
|
|
|
pp->get_fd()));
|
|
|
|
lnav_data.ld_files_to_front.push_back(make_pair(desc, 0));
|
|
|
|
}
|
|
|
|
|
2014-03-15 11:40:58 +00:00
|
|
|
retval = string(lv.lv_start, lv.lv_len);
|
2013-10-11 13:22:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
class action_delegate : public text_delegate {
|
|
|
|
public:
|
|
|
|
action_delegate(logfile_sub_source &lss) : ad_log_helper(lss), ad_press_line(-1) { };
|
|
|
|
|
|
|
|
virtual bool text_handle_mouse(textview_curses &tc, mouse_event &me) {
|
|
|
|
bool retval = false;
|
|
|
|
|
|
|
|
if (me.me_button != BUTTON_LEFT) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
vis_line_t mouse_line = vis_line_t(tc.get_top() + me.me_y);
|
|
|
|
int mouse_left = tc.get_left() + me.me_x;
|
|
|
|
|
|
|
|
switch (me.me_state) {
|
|
|
|
case BUTTON_STATE_PRESSED:
|
|
|
|
if (mouse_line >= vis_line_t(0) && mouse_line <= tc.get_bottom()) {
|
|
|
|
size_t line_end_index = 0;
|
|
|
|
int x_offset;
|
|
|
|
|
|
|
|
this->ad_press_line = mouse_line;
|
|
|
|
this->ad_log_helper.parse_line(mouse_line, true);
|
|
|
|
|
|
|
|
this->ad_log_helper.get_line_bounds(this->ad_line_index, line_end_index);
|
|
|
|
|
|
|
|
struct line_range lr(this->ad_line_index, line_end_index);
|
|
|
|
|
|
|
|
this->ad_press_value = -1;
|
|
|
|
|
|
|
|
x_offset = this->ad_line_index + mouse_left;
|
|
|
|
if (lr.contains(x_offset)) {
|
|
|
|
for (size_t lpc = 0;
|
|
|
|
lpc < this->ad_log_helper.ldh_line_values.size();
|
|
|
|
lpc++) {
|
|
|
|
logline_value &lv = this->ad_log_helper.ldh_line_values[lpc];
|
|
|
|
|
|
|
|
if (lv.lv_origin.contains(x_offset)) {
|
|
|
|
this->ad_press_value = lpc;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BUTTON_STATE_DRAGGED:
|
2014-03-04 05:02:59 +00:00
|
|
|
if (mouse_line != this->ad_press_line) {
|
|
|
|
this->ad_press_value = -1;
|
|
|
|
}
|
2013-10-11 13:22:29 +00:00
|
|
|
if (this->ad_press_value != -1) {
|
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BUTTON_STATE_RELEASED:
|
|
|
|
if (this->ad_press_value != -1 && this->ad_press_line == mouse_line) {
|
|
|
|
logline_value &lv = this->ad_log_helper.ldh_line_values[this->ad_press_value];
|
|
|
|
int x_offset = this->ad_line_index + mouse_left;
|
|
|
|
|
|
|
|
if (lv.lv_origin.contains(x_offset)) {
|
|
|
|
logfile *lf = this->ad_log_helper.ldh_file;
|
|
|
|
const vector<string> *actions;
|
|
|
|
|
|
|
|
actions = lf->get_format()->get_actions(lv);
|
|
|
|
if (actions != NULL && !actions->empty()) {
|
|
|
|
string rc = execute_action(
|
|
|
|
this->ad_log_helper, this->ad_press_value, actions->at(0));
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_value(rc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
|
|
|
log_data_helper ad_log_helper;
|
|
|
|
vis_line_t ad_press_line;
|
|
|
|
int ad_press_value;
|
|
|
|
size_t ad_line_index;
|
|
|
|
};
|
|
|
|
|
2012-04-24 21:31:35 +00:00
|
|
|
class lnav_behavior : public mouse_behavior {
|
|
|
|
public:
|
2013-05-28 04:35:00 +00:00
|
|
|
enum lb_mode_t {
|
|
|
|
LB_MODE_NONE,
|
|
|
|
LB_MODE_DOWN,
|
|
|
|
LB_MODE_UP,
|
|
|
|
LB_MODE_DRAG
|
|
|
|
};
|
|
|
|
|
2013-10-23 14:01:32 +00:00
|
|
|
lnav_behavior() {};
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
int scroll_polarity(int button)
|
|
|
|
{
|
|
|
|
return button == xterm_mouse::XT_SCROLL_UP ? -1 : 1;
|
|
|
|
};
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
void mouse_event(int button, bool release, int x, int y)
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
|
|
|
textview_curses * tc = lnav_data.ld_view_stack.top();
|
2013-10-11 13:22:29 +00:00
|
|
|
struct mouse_event me;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
switch (button & xterm_mouse::XT_BUTTON__MASK) {
|
2013-05-28 04:35:00 +00:00
|
|
|
case xterm_mouse::XT_BUTTON1:
|
2013-10-11 13:22:29 +00:00
|
|
|
me.me_button = BUTTON_LEFT;
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2013-10-11 13:22:29 +00:00
|
|
|
case xterm_mouse::XT_BUTTON2:
|
|
|
|
me.me_button = BUTTON_MIDDLE;
|
|
|
|
break;
|
|
|
|
case xterm_mouse::XT_BUTTON3:
|
|
|
|
me.me_button = BUTTON_RIGHT;
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
case xterm_mouse::XT_SCROLL_UP:
|
2013-10-11 13:22:29 +00:00
|
|
|
me.me_button = BUTTON_SCROLL_UP;
|
|
|
|
break;
|
2013-05-28 04:35:00 +00:00
|
|
|
case xterm_mouse::XT_SCROLL_DOWN:
|
2013-10-11 13:22:29 +00:00
|
|
|
me.me_button = BUTTON_SCROLL_DOWN;
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-10-11 13:22:29 +00:00
|
|
|
|
|
|
|
if (button & xterm_mouse::XT_DRAG_FLAG) {
|
|
|
|
me.me_state = BUTTON_STATE_DRAGGED;
|
|
|
|
}
|
|
|
|
else if (release) {
|
|
|
|
me.me_state = BUTTON_STATE_RELEASED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
me.me_state = BUTTON_STATE_PRESSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
gettimeofday(&me.me_time, NULL);
|
|
|
|
me.me_x = x - 1;
|
|
|
|
me.me_y = y - tc->get_y() - 1;
|
|
|
|
|
|
|
|
tc->handle_mouse(me);
|
2013-05-28 04:35:00 +00:00
|
|
|
};
|
2012-04-24 21:31:35 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
2013-10-29 12:33:39 +00:00
|
|
|
static void handle_key(int ch)
|
|
|
|
{
|
2015-04-02 13:49:16 +00:00
|
|
|
lnav_data.ld_input_state.push_back(ch);
|
|
|
|
|
2013-10-29 12:33:39 +00:00
|
|
|
switch (ch) {
|
|
|
|
case CEOF:
|
|
|
|
case KEY_RESIZE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
switch (lnav_data.ld_mode) {
|
|
|
|
case LNM_PAGING:
|
|
|
|
handle_paging_key(ch);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LNM_COMMAND:
|
|
|
|
case LNM_SEARCH:
|
|
|
|
case LNM_CAPTURE:
|
|
|
|
case LNM_SQL:
|
|
|
|
handle_rl_key(ch);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-03-06 14:58:49 +00:00
|
|
|
require(0);
|
2013-10-29 12:33:39 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-27 03:24:34 +00:00
|
|
|
void update_hits(void *dummy, textview_curses *tc)
|
|
|
|
{
|
2014-03-10 06:38:30 +00:00
|
|
|
if (!lnav_data.ld_view_stack.empty() &&
|
|
|
|
tc == lnav_data.ld_view_stack.top()) {
|
2014-02-27 03:24:34 +00:00
|
|
|
lnav_data.ld_bottom_source.update_hits(tc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 16:16:49 +00:00
|
|
|
static void gather_pipers(void)
|
|
|
|
{
|
|
|
|
for (std::list<piper_proc *>::iterator iter = lnav_data.ld_pipers.begin();
|
|
|
|
iter != lnav_data.ld_pipers.end(); ) {
|
2015-04-06 04:40:04 +00:00
|
|
|
piper_proc *pp = *iter;
|
2015-04-07 13:09:49 +00:00
|
|
|
pid_t child_pid = pp->get_child_pid();
|
2015-04-06 04:40:04 +00:00
|
|
|
if (pp->has_exited()) {
|
2015-04-07 13:09:49 +00:00
|
|
|
log_info("child piper has exited -- %d", child_pid);
|
2015-04-06 04:40:04 +00:00
|
|
|
delete pp;
|
2015-03-16 16:16:49 +00:00
|
|
|
iter = lnav_data.ld_pipers.erase(iter);
|
|
|
|
} else {
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-06 09:48:12 +00:00
|
|
|
static void wait_for_pipers(void)
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
gather_pipers();
|
|
|
|
if (lnav_data.ld_pipers.empty()) {
|
|
|
|
log_debug("all pipers finished");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
usleep(10000);
|
|
|
|
rebuild_indexes(false);
|
|
|
|
}
|
|
|
|
log_debug("%d pipers still active",
|
|
|
|
lnav_data.ld_pipers.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
static void looper(void)
|
|
|
|
{
|
|
|
|
try {
|
2013-05-28 04:35:00 +00:00
|
|
|
readline_context command_context("cmd", &lnav_commands);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
readline_context search_context("search");
|
|
|
|
readline_context index_context("capture");
|
|
|
|
readline_context sql_context("sql", NULL, false);
|
|
|
|
readline_curses rlc;
|
|
|
|
int lpc;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2014-10-30 15:37:06 +00:00
|
|
|
command_context.set_highlighter(readline_command_highlighter);
|
2014-03-04 15:38:33 +00:00
|
|
|
search_context
|
|
|
|
.set_append_character(0)
|
|
|
|
.set_highlighter(readline_regex_highlighter);
|
|
|
|
sql_context.set_highlighter(readline_sqlite_highlighter);
|
2014-02-10 02:41:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
listview_curses::action::broadcaster &sb =
|
|
|
|
lnav_data.ld_scroll_broadcaster;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
rlc.add_context(LNM_COMMAND, command_context);
|
|
|
|
rlc.add_context(LNM_SEARCH, search_context);
|
|
|
|
rlc.add_context(LNM_CAPTURE, index_context);
|
|
|
|
rlc.add_context(LNM_SQL, sql_context);
|
|
|
|
rlc.start();
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_rl_view = &rlc;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2014-03-02 16:55:00 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(
|
|
|
|
LNM_COMMAND, "graph", "\\d+(?:\\.\\d+)?");
|
|
|
|
lnav_data.ld_rl_view->add_possibility(
|
|
|
|
LNM_COMMAND, "graph", "([:= \\t]\\d+(?:\\.\\d+)?)");
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->add_possibility(
|
|
|
|
LNM_COMMAND, "viewname", lnav_view_strings);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2015-04-04 20:36:53 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(
|
|
|
|
LNM_COMMAND, "zoomlevel", lnav_zoom_strings);
|
|
|
|
|
2015-03-28 13:30:30 +00:00
|
|
|
lnav_data.ld_rl_view->add_possibility(
|
|
|
|
LNM_COMMAND, "levelname", logline::level_names);
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
(void)signal(SIGINT, sigint);
|
|
|
|
(void)signal(SIGTERM, sigint);
|
|
|
|
(void)signal(SIGWINCH, sigwinch);
|
2013-10-11 13:22:29 +00:00
|
|
|
(void)signal(SIGCHLD, sigchld);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2012-09-28 18:01:36 +00:00
|
|
|
screen_curses sc;
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_behavior lb;
|
|
|
|
|
2014-01-25 20:13:41 +00:00
|
|
|
ui_periodic_timer::singleton();
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
lnav_data.ld_mouse.set_behavior(&lb);
|
|
|
|
lnav_data.ld_mouse.set_enabled(check_experimental("mouse"));
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
lnav_data.ld_window = sc.get_window();
|
|
|
|
keypad(stdscr, TRUE);
|
|
|
|
(void)nonl();
|
|
|
|
(void)cbreak();
|
|
|
|
(void)noecho();
|
|
|
|
(void)nodelay(lnav_data.ld_window, 1);
|
|
|
|
|
|
|
|
define_key("\033Od", KEY_BEG);
|
|
|
|
define_key("\033Oc", KEY_END);
|
|
|
|
|
|
|
|
view_colors::singleton().init();
|
|
|
|
|
|
|
|
rlc.set_window(lnav_data.ld_window);
|
|
|
|
rlc.set_y(-1);
|
|
|
|
rlc.set_perform_action(readline_curses::action(rl_callback));
|
|
|
|
rlc.set_timeout_action(readline_curses::action(rl_search));
|
2013-07-24 14:42:16 +00:00
|
|
|
rlc.set_abort_action(readline_curses::action(rl_abort));
|
2014-03-09 09:29:28 +00:00
|
|
|
rlc.set_display_match_action(
|
|
|
|
readline_curses::action(rl_display_matches));
|
|
|
|
rlc.set_display_next_action(
|
|
|
|
readline_curses::action(rl_display_next));
|
2013-06-14 13:49:00 +00:00
|
|
|
rlc.set_alt_value(HELP_MSG_2(
|
2014-03-09 09:29:28 +00:00
|
|
|
e, E, "to move forward/backward through error messages"));
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
(void)curs_set(0);
|
|
|
|
|
|
|
|
lnav_data.ld_view_stack.push(&lnav_data.ld_views[LNV_LOG]);
|
2013-06-14 13:49:00 +00:00
|
|
|
update_view_name();
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
for (lpc = 0; lpc < LNV__MAX; lpc++) {
|
|
|
|
lnav_data.ld_views[lpc].set_window(lnav_data.ld_window);
|
|
|
|
lnav_data.ld_views[lpc].set_y(1);
|
|
|
|
lnav_data.ld_views[lpc].
|
2014-03-09 09:29:28 +00:00
|
|
|
set_height(vis_line_t(-(rlc.get_height() + 1)));
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_views[lpc].
|
|
|
|
set_scroll_action(sb.get_functor());
|
2014-02-27 03:24:34 +00:00
|
|
|
lnav_data.ld_views[lpc].set_search_action(
|
|
|
|
textview_curses::action(update_hits));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lnav_data.ld_status[LNS_TOP].set_top(0);
|
2014-03-09 09:29:28 +00:00
|
|
|
lnav_data.ld_status[LNS_BOTTOM].set_top(-(rlc.get_height() + 1));
|
2013-05-28 04:35:00 +00:00
|
|
|
for (lpc = 0; lpc < LNS__MAX; lpc++) {
|
|
|
|
lnav_data.ld_status[lpc].set_window(lnav_data.ld_window);
|
|
|
|
}
|
2014-03-09 09:29:28 +00:00
|
|
|
lnav_data.ld_status[LNS_TOP].set_data_source(
|
|
|
|
&lnav_data.ld_top_source);
|
|
|
|
lnav_data.ld_status[LNS_BOTTOM].set_data_source(
|
|
|
|
&lnav_data.ld_bottom_source);
|
|
|
|
|
|
|
|
lnav_data.ld_match_view.set_show_bottom_border(true);
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
sb.push_back(view_action<listview_curses>(update_times));
|
2015-03-19 04:54:46 +00:00
|
|
|
sb.push_back(view_action<listview_curses>(clear_last_user_mark));
|
2013-05-28 04:35:00 +00:00
|
|
|
sb.push_back(&lnav_data.ld_top_source.filename_wire);
|
|
|
|
sb.push_back(&lnav_data.ld_bottom_source.line_number_wire);
|
|
|
|
sb.push_back(&lnav_data.ld_bottom_source.percent_wire);
|
|
|
|
sb.push_back(&lnav_data.ld_bottom_source.marks_wire);
|
2014-02-10 15:25:28 +00:00
|
|
|
sb.push_back(&lnav_data.ld_term_extra.filename_wire);
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
FD_ZERO(&lnav_data.ld_read_fds);
|
|
|
|
FD_SET(STDIN_FILENO, &lnav_data.ld_read_fds);
|
|
|
|
lnav_data.ld_max_fd =
|
|
|
|
max(STDIN_FILENO, rlc.update_fd_set(lnav_data.ld_read_fds));
|
|
|
|
|
|
|
|
lnav_data.ld_status[0].window_change();
|
|
|
|
lnav_data.ld_status[1].window_change();
|
|
|
|
|
|
|
|
execute_file(dotlnav_path("session"));
|
|
|
|
|
2013-06-15 01:12:52 +00:00
|
|
|
lnav_data.ld_scroll_broadcaster.invoke(lnav_data.ld_view_stack.top());
|
|
|
|
|
2013-05-31 15:01:31 +00:00
|
|
|
bool session_loaded = false;
|
2015-03-23 06:10:52 +00:00
|
|
|
ui_periodic_timer &timer = ui_periodic_timer::singleton();
|
|
|
|
static sig_atomic_t index_counter;
|
2013-05-31 15:01:31 +00:00
|
|
|
|
2015-03-23 06:10:52 +00:00
|
|
|
timer.start_fade(index_counter, 1);
|
2013-05-28 04:35:00 +00:00
|
|
|
while (lnav_data.ld_looping) {
|
|
|
|
fd_set ready_rfds = lnav_data.ld_read_fds;
|
2015-03-23 06:10:52 +00:00
|
|
|
struct timeval to = { 0, 333000 };
|
2013-05-28 04:35:00 +00:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
lnav_data.ld_top_source.update_time();
|
|
|
|
|
|
|
|
if (rescan_files()) {
|
2012-10-29 23:38:58 +00:00
|
|
|
rebuild_indexes(true);
|
|
|
|
}
|
2011-08-06 16:33:55 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_status[LNS_TOP].do_update();
|
2014-03-09 09:29:28 +00:00
|
|
|
lnav_data.ld_view_stack.top()->do_update();
|
|
|
|
lnav_data.ld_match_view.do_update();
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
|
|
|
rlc.do_update();
|
|
|
|
refresh();
|
|
|
|
|
|
|
|
rc = select(lnav_data.ld_max_fd + 1,
|
|
|
|
&ready_rfds, NULL, NULL,
|
|
|
|
&to);
|
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
switch (errno) {
|
2013-06-21 03:36:19 +00:00
|
|
|
case EBADF:
|
|
|
|
{
|
2015-04-08 02:39:27 +00:00
|
|
|
size_t lpc;
|
|
|
|
int fd_flags;
|
2013-06-21 03:36:19 +00:00
|
|
|
|
2014-03-02 00:35:30 +00:00
|
|
|
log_error("bad file descriptor");
|
2013-06-21 03:36:19 +00:00
|
|
|
for (lpc = 0; lpc < FD_SETSIZE; lpc++) {
|
|
|
|
if (fcntl(lpc, F_GETFD, &fd_flags) == -1 &&
|
|
|
|
FD_ISSET(lpc, &lnav_data.ld_read_fds)) {
|
2014-03-02 00:35:30 +00:00
|
|
|
log_error("bad fd %d", lpc);
|
2013-06-21 03:36:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
lnav_data.ld_looping = false;
|
|
|
|
}
|
|
|
|
break;
|
2015-03-23 06:10:52 +00:00
|
|
|
case 0:
|
|
|
|
case EINTR:
|
|
|
|
break;
|
2013-06-21 03:36:19 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
default:
|
2014-03-02 00:35:30 +00:00
|
|
|
log_error("select %s", strerror(errno));
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_looping = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (FD_ISSET(STDIN_FILENO, &ready_rfds)) {
|
2013-10-11 13:22:29 +00:00
|
|
|
static size_t escape_index = 0;
|
|
|
|
static char escape_buffer[32];
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
int ch;
|
|
|
|
|
|
|
|
while ((ch = getch()) != ERR) {
|
2013-07-27 19:07:05 +00:00
|
|
|
alerter::singleton().new_input(ch);
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
if (escape_index > sizeof(escape_buffer) - 1) {
|
|
|
|
escape_index = 0;
|
|
|
|
}
|
|
|
|
else if (escape_index > 0) {
|
|
|
|
escape_buffer[escape_index++] = ch;
|
|
|
|
escape_buffer[escape_index] = '\0';
|
|
|
|
|
2014-03-03 08:55:01 +00:00
|
|
|
if (strcmp("\x1b[", escape_buffer) == 0) {
|
2013-10-11 13:22:29 +00:00
|
|
|
lnav_data.ld_mouse.handle_mouse(ch);
|
|
|
|
}
|
2013-10-29 12:33:39 +00:00
|
|
|
else {
|
2014-01-14 06:29:14 +00:00
|
|
|
for (size_t lpc = 0; lpc < escape_index; lpc++) {
|
2013-10-29 12:33:39 +00:00
|
|
|
handle_key(escape_buffer[lpc]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
escape_index = 0;
|
2013-10-11 13:22:29 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
switch (ch) {
|
|
|
|
case CEOF:
|
|
|
|
case KEY_RESIZE:
|
|
|
|
break;
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
case '\x1b':
|
|
|
|
escape_index = 0;
|
|
|
|
escape_buffer[escape_index++] = ch;
|
|
|
|
escape_buffer[escape_index] = '\0';
|
|
|
|
break;
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
case KEY_MOUSE:
|
2013-10-11 13:22:29 +00:00
|
|
|
lnav_data.ld_mouse.handle_mouse(ch);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2013-10-29 12:33:39 +00:00
|
|
|
handle_key(ch);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-03-23 06:10:52 +00:00
|
|
|
|
|
|
|
if (!lnav_data.ld_looping) {
|
|
|
|
// No reason to keep processing input after the
|
|
|
|
// user has quit. The view stack will also be
|
|
|
|
// empty, which will cause issues.
|
|
|
|
break;
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for (lpc = 0; lpc < LG__MAX; lpc++) {
|
|
|
|
auto_ptr<grep_highlighter> &gc =
|
|
|
|
lnav_data.ld_grep_child[lpc];
|
|
|
|
|
|
|
|
if (gc.get() != NULL) {
|
|
|
|
gc->get_grep_proc()->check_fd_set(ready_rfds);
|
|
|
|
if (lpc == LG_GRAPH) {
|
|
|
|
lnav_data.ld_views[LNV_GRAPH].reload_data();
|
|
|
|
/* XXX */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (lpc = 0; lpc < LNV__MAX; lpc++) {
|
|
|
|
auto_ptr<grep_highlighter> &gc =
|
|
|
|
lnav_data.ld_search_child[lpc];
|
|
|
|
|
|
|
|
if (gc.get() != NULL) {
|
|
|
|
gc->get_grep_proc()->check_fd_set(ready_rfds);
|
|
|
|
|
|
|
|
if (!lnav_data.ld_view_stack.empty()) {
|
|
|
|
lnav_data.ld_bottom_source.
|
|
|
|
update_hits(lnav_data.ld_view_stack.top());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rlc.check_fd_set(ready_rfds);
|
|
|
|
}
|
|
|
|
|
2015-03-23 06:10:52 +00:00
|
|
|
if (timer.fade_diff(index_counter) == 0) {
|
|
|
|
static bool initial_build = false;
|
|
|
|
|
|
|
|
if (lnav_data.ld_mode == LNM_PAGING) {
|
|
|
|
timer.start_fade(index_counter, 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
timer.start_fade(index_counter, 3);
|
|
|
|
}
|
|
|
|
rebuild_indexes(false);
|
|
|
|
if (!initial_build &&
|
|
|
|
lnav_data.ld_log_source.text_line_count() == 0 &&
|
|
|
|
lnav_data.ld_text_source.text_line_count() > 0) {
|
|
|
|
toggle_view(&lnav_data.ld_views[LNV_TEXT]);
|
|
|
|
lnav_data.ld_views[LNV_TEXT].set_top(vis_line_t(0));
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(
|
|
|
|
HELP_MSG_2(f, F,
|
|
|
|
"to switch to the next/previous file"));
|
|
|
|
}
|
|
|
|
if (!initial_build &&
|
|
|
|
lnav_data.ld_log_source.text_line_count() == 0 &&
|
|
|
|
!lnav_data.ld_other_files.empty()) {
|
|
|
|
ensure_view(&lnav_data.ld_views[LNV_SCHEMA]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!initial_build && lnav_data.ld_flags & LNF_HELP) {
|
|
|
|
toggle_view(&lnav_data.ld_views[LNV_HELP]);
|
|
|
|
initial_build = true;
|
|
|
|
}
|
|
|
|
if (lnav_data.ld_log_source.text_line_count() > 0 ||
|
|
|
|
lnav_data.ld_text_source.text_line_count() > 0 ||
|
|
|
|
!lnav_data.ld_other_files.empty()) {
|
|
|
|
initial_build = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!session_loaded) {
|
|
|
|
load_session();
|
|
|
|
if (!lnav_data.ld_session_file_names.empty()) {
|
|
|
|
std::string ago;
|
|
|
|
|
|
|
|
ago = time_ago(lnav_data.ld_session_save_time);
|
|
|
|
lnav_data.ld_rl_view->set_value(
|
|
|
|
("restored session from " ANSI_BOLD_START) +
|
|
|
|
ago +
|
|
|
|
(ANSI_NORM "; press Ctrl-R to reset session"));
|
|
|
|
}
|
|
|
|
rebuild_indexes(true);
|
|
|
|
session_loaded = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
vector<pair<string, string> > msgs;
|
|
|
|
|
|
|
|
execute_init_commands(msgs);
|
|
|
|
|
|
|
|
if (!msgs.empty()) {
|
|
|
|
pair<string, string> last_msg = msgs.back();
|
|
|
|
|
|
|
|
lnav_data.ld_rl_view->set_value(last_msg.first);
|
|
|
|
lnav_data.ld_rl_view->set_alt_value(last_msg.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lnav_data.ld_winched) {
|
|
|
|
struct winsize size;
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
lnav_data.ld_winched = false;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
if (ioctl(fileno(stdout), TIOCGWINSZ, &size) == 0) {
|
|
|
|
resizeterm(size.ws_row, size.ws_col);
|
|
|
|
}
|
|
|
|
rlc.window_change();
|
|
|
|
lnav_data.ld_status[0].window_change();
|
|
|
|
lnav_data.ld_status[1].window_change();
|
|
|
|
lnav_data.ld_view_stack.top()->set_needs_update();
|
2013-10-11 13:22:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lnav_data.ld_child_terminated) {
|
|
|
|
lnav_data.ld_child_terminated = false;
|
|
|
|
|
|
|
|
for (std::list<pid_t>::iterator iter = lnav_data.ld_children.begin();
|
|
|
|
iter != lnav_data.ld_children.end();
|
|
|
|
++iter) {
|
|
|
|
int rc, child_stat;
|
|
|
|
|
|
|
|
rc = waitpid(*iter, &child_stat, WNOHANG);
|
|
|
|
if (rc == -1 || rc == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
iter = lnav_data.ld_children.erase(iter);
|
|
|
|
}
|
|
|
|
|
2015-03-16 16:16:49 +00:00
|
|
|
gather_pipers();
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
catch (readline_curses::error & e) {
|
2014-03-02 00:35:30 +00:00
|
|
|
log_error("error: %s", strerror(e.e_err));
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-20 22:38:37 +00:00
|
|
|
static void setup_highlights(textview_curses::highlight_map_t &hm)
|
|
|
|
{
|
2013-07-13 14:36:48 +00:00
|
|
|
hm["$kw"] = textview_curses::highlighter(xpcre_compile(
|
|
|
|
"(?:"
|
|
|
|
"\\balter |"
|
|
|
|
"\\band\\b|"
|
|
|
|
"\\bas |"
|
|
|
|
"\\bbetween\\b|"
|
|
|
|
"\\bbool\\b|"
|
|
|
|
"\\bboolean\\b|"
|
|
|
|
"\\bbreak\\b|"
|
|
|
|
"\\bcase\\b|"
|
|
|
|
"\\bcatch\\b|"
|
|
|
|
"\\bchar\\b|"
|
|
|
|
"\\bclass\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\bcollate\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\bconst\\b|"
|
|
|
|
"\\bcontinue\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\bcreate\\s+(?:virtual)?|"
|
|
|
|
"\\bdatetime\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\bdef |"
|
|
|
|
"\\bdefault[:\\s]|"
|
|
|
|
"\\bdo\\b|"
|
|
|
|
"\\bdone\\b|"
|
|
|
|
"\\bdouble\\b|"
|
|
|
|
"\\bdrop\\b|"
|
|
|
|
"\\belif |"
|
|
|
|
"\\belse\\b|"
|
|
|
|
"\\benum\\b|"
|
|
|
|
"\\bendif\\b|"
|
|
|
|
"\\besac\\b|"
|
|
|
|
"\\bexcept[\\s:]|"
|
|
|
|
"\\bexists\\b|"
|
|
|
|
"\\bexport\\b|"
|
|
|
|
"\\bextends\\b|"
|
|
|
|
"\\bextern\\b|"
|
|
|
|
"\\bfalse\\b|"
|
|
|
|
"\\bfi\\b|"
|
|
|
|
"\\bfloat\\b|"
|
|
|
|
"\\bfor\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\bforeign\\s+key\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\bfrom |"
|
|
|
|
"\\bgoto\\b|"
|
|
|
|
"\\bgroup by |"
|
|
|
|
"\\bif\\b|"
|
|
|
|
"\\bimport |"
|
|
|
|
"\\bimplements\\b|"
|
|
|
|
"\\bin\\b|"
|
|
|
|
"\\binline\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\binner\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\binsert |"
|
|
|
|
"\\bint\\b|"
|
|
|
|
"\\binto\\b|"
|
|
|
|
"\\binterface\\b|"
|
|
|
|
"\\bjoin\\b|"
|
2013-07-31 04:21:28 +00:00
|
|
|
"\\blambda\\b|"
|
2013-07-26 03:41:42 +00:00
|
|
|
"\\blet\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\blong\\b|"
|
|
|
|
"\\bnamespace\\b|"
|
2013-07-31 04:21:28 +00:00
|
|
|
"\\bnew\\b|"
|
|
|
|
"\\bnot\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\bnull\\b|"
|
|
|
|
"\\boperator\\b|"
|
|
|
|
"\\bor\\b|"
|
|
|
|
"\\border by |"
|
|
|
|
"\\bpackage\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\bprimary\\s+key\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\bprivate\\b|"
|
|
|
|
"\\bprotected\\b|"
|
|
|
|
"\\bpublic\\b|"
|
|
|
|
"\\braise\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\breferences\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\b(?<!@)return\\b|"
|
|
|
|
"\\bselect |"
|
|
|
|
"\\bself\\b|"
|
|
|
|
"\\bshift\\b|"
|
|
|
|
"\\bshort\\b|"
|
|
|
|
"\\bsizeof\\b|"
|
|
|
|
"\\bstatic\\b|"
|
|
|
|
"\\bstruct\\b|"
|
|
|
|
"\\bswitch\\b|"
|
|
|
|
"\\btable\\b|"
|
|
|
|
"\\btemplate\\b|"
|
|
|
|
"\\bthen\\b|"
|
|
|
|
"\\bthis\\b|"
|
|
|
|
"\\b(?<!@)throws?\\b|"
|
|
|
|
"\\btrue\\b|"
|
|
|
|
"\\btry\\b|"
|
|
|
|
"\\btypedef |"
|
|
|
|
"\\btypename |"
|
|
|
|
"\\bunion\\b|"
|
|
|
|
"\\bunsigned |"
|
|
|
|
"\\bupdate |"
|
|
|
|
"\\busing |"
|
|
|
|
"\\bvar\\b|"
|
2014-03-09 09:29:28 +00:00
|
|
|
"\\bview\\b|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"\\bvoid\\b|"
|
|
|
|
"\\bvolatile\\b|"
|
|
|
|
"\\bwhere |"
|
|
|
|
"\\bwhile\\b|"
|
|
|
|
"\\b[a-zA-Z][\\w]+_t\\b"
|
|
|
|
")", PCRE_CASELESS),
|
|
|
|
false, view_colors::VCR_KEYWORD);
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$srcfile"] = textview_curses::
|
2013-05-28 04:35:00 +00:00
|
|
|
highlighter(xpcre_compile(
|
|
|
|
"[\\w\\-_]+\\."
|
|
|
|
"(?:java|a|o|so|c|cc|cpp|cxx|h|hh|hpp|hxx|py|pyc|rb):"
|
|
|
|
"\\d+"));
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$xml"] = textview_curses::
|
2013-07-13 14:36:48 +00:00
|
|
|
highlighter(xpcre_compile("<(/?[^ >=]+)[^>]*>"));
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$stringd"] = textview_curses::
|
2013-07-13 14:36:48 +00:00
|
|
|
highlighter(xpcre_compile("\"(?:\\\\.|[^\"])*\""),
|
|
|
|
false, view_colors::VCR_STRING);
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$strings"] = textview_curses::
|
2013-05-28 04:35:00 +00:00
|
|
|
highlighter(xpcre_compile(
|
2013-07-13 14:36:48 +00:00
|
|
|
"(?<![A-WY-Za-qstv-z])\'(?:\\\\.|[^'])*\'"),
|
|
|
|
false, view_colors::VCR_STRING);
|
|
|
|
hm["$stringb"] = textview_curses::
|
|
|
|
highlighter(xpcre_compile("`(?:\\\\.|[^`])*`"),
|
|
|
|
false, view_colors::VCR_STRING);
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$diffp"] = textview_curses::
|
2013-05-28 04:35:00 +00:00
|
|
|
highlighter(xpcre_compile(
|
|
|
|
"^\\+.*"), false,
|
|
|
|
view_colors::VCR_DIFF_ADD);
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$diffm"] = textview_curses::
|
2013-05-28 04:35:00 +00:00
|
|
|
highlighter(xpcre_compile(
|
2013-07-31 04:21:28 +00:00
|
|
|
"^(?:--- .*|-$|-[^-].*)"), false,
|
2013-05-28 04:35:00 +00:00
|
|
|
view_colors::VCR_DIFF_DELETE);
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$diffs"] = textview_curses::
|
2013-05-28 04:35:00 +00:00
|
|
|
highlighter(xpcre_compile(
|
|
|
|
"^\\@@ .*"), false,
|
|
|
|
view_colors::VCR_DIFF_SECTION);
|
2013-06-02 21:20:15 +00:00
|
|
|
hm["$ip"] = textview_curses::
|
2013-05-28 04:35:00 +00:00
|
|
|
highlighter(xpcre_compile("\\d+\\.\\d+\\.\\d+\\.\\d+"));
|
2013-07-13 14:36:48 +00:00
|
|
|
hm["$comment"] = textview_curses::highlighter(xpcre_compile(
|
2014-01-14 05:58:04 +00:00
|
|
|
"(?<=[\\s;])//.*|/\\*.*\\*/|\\(\\*.*\\*\\)|^#.*|\\s+#.*|dnl.*"), false, view_colors::VCR_COMMENT);
|
2013-07-13 14:36:48 +00:00
|
|
|
hm["$javadoc"] = textview_curses::highlighter(xpcre_compile(
|
2013-07-31 04:21:28 +00:00
|
|
|
"@(?:author|deprecated|exception|file|param|return|see|since|throws|todo|version)"));
|
2013-07-13 14:36:48 +00:00
|
|
|
hm["$var"] = textview_curses::highlighter(xpcre_compile(
|
|
|
|
"(?:"
|
2013-07-23 12:55:08 +00:00
|
|
|
"(?:var\\s+)?([\\-\\w]+)\\s*=|"
|
2013-07-13 14:36:48 +00:00
|
|
|
"(?<!\\$)\\$(\\w+)|"
|
|
|
|
"(?<!\\$)\\$\\((\\w+)\\)|"
|
|
|
|
"(?<!\\$)\\$\\{(\\w+)\\}"
|
|
|
|
")"),
|
|
|
|
false, view_colors::VCR_VARIABLE);
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sql_progress(const struct log_cursor &lc)
|
|
|
|
{
|
2014-01-25 20:13:41 +00:00
|
|
|
static sig_atomic_t sql_counter = 0;
|
2013-09-14 13:36:31 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
size_t total = lnav_data.ld_log_source.text_line_count();
|
|
|
|
off_t off = lc.lc_curr_line;
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (lnav_data.ld_window == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (!lnav_data.ld_looping) {
|
|
|
|
return 1;
|
|
|
|
}
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2014-01-25 20:13:41 +00:00
|
|
|
if (ui_periodic_timer::singleton().time_to_update(sql_counter)) {
|
2013-09-14 13:36:31 +00:00
|
|
|
lnav_data.ld_bottom_source.update_loading(off, total);
|
|
|
|
lnav_data.ld_top_source.update_time();
|
|
|
|
lnav_data.ld_status[LNS_TOP].do_update();
|
|
|
|
lnav_data.ld_status[LNS_BOTTOM].do_update();
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
return 0;
|
2011-10-20 22:38:37 +00:00
|
|
|
}
|
|
|
|
|
2014-11-05 17:01:09 +00:00
|
|
|
static void print_errors(vector<string> error_list)
|
|
|
|
{
|
|
|
|
for (std::vector<std::string>::iterator iter = error_list.begin();
|
|
|
|
iter != error_list.end();
|
|
|
|
++iter) {
|
|
|
|
fprintf(stderr, "%s%s", iter->c_str(),
|
|
|
|
(*iter)[iter->size() - 1] == '\n' ? "" : "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2013-06-29 18:00:34 +00:00
|
|
|
std::vector<std::string> loader_errors;
|
2009-09-14 01:07:32 +00:00
|
|
|
int lpc, c, retval = EXIT_SUCCESS;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
auto_ptr<piper_proc> stdin_reader;
|
2013-05-28 04:35:00 +00:00
|
|
|
const char * stdin_out = NULL;
|
2015-03-14 14:08:48 +00:00
|
|
|
int stdin_out_fd = -1;
|
2009-10-06 21:14:49 +00:00
|
|
|
|
2015-04-06 04:40:04 +00:00
|
|
|
(void)signal(SIGPIPE, SIG_IGN);
|
2013-05-24 14:55:56 +00:00
|
|
|
setlocale(LC_NUMERIC, "");
|
|
|
|
|
2014-04-01 20:07:58 +00:00
|
|
|
lnav_data.ld_program_name = argv[0];
|
|
|
|
|
2014-03-09 15:54:55 +00:00
|
|
|
rl_readline_name = "lnav";
|
|
|
|
|
2013-08-29 04:22:04 +00:00
|
|
|
ensure_dotlnav();
|
|
|
|
|
2014-03-02 00:35:30 +00:00
|
|
|
log_install_handlers();
|
2014-04-19 02:16:29 +00:00
|
|
|
sql_install_logger();
|
2014-03-02 00:35:30 +00:00
|
|
|
|
2014-03-03 06:26:41 +00:00
|
|
|
lnav_data.ld_debug_log_name = "/dev/null";
|
2014-11-05 17:01:09 +00:00
|
|
|
while ((c = getopt(argc, argv, "hHarsCc:I:if:d:nqtw:VW")) != -1) {
|
2014-03-03 06:26:41 +00:00
|
|
|
switch (c) {
|
|
|
|
case 'h':
|
|
|
|
usage();
|
|
|
|
exit(retval);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'H':
|
|
|
|
lnav_data.ld_flags |= LNF_HELP;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
lnav_data.ld_flags |= LNF_CHECK_CONFIG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
switch (optarg[0]) {
|
|
|
|
case ':':
|
|
|
|
case '/':
|
|
|
|
case ';':
|
|
|
|
case '|':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "error: command arguments should start with a "
|
|
|
|
"colon, semi-colon, or pipe-symbol to denote:\n");
|
|
|
|
fprintf(stderr, "error: a built-in command, SQL query, "
|
|
|
|
"or a file path that contains commands to execute\n");
|
|
|
|
usage();
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lnav_data.ld_commands.push_back(optarg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
if (access(optarg, R_OK) != 0) {
|
|
|
|
perror("invalid command file");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
lnav_data.ld_commands.push_back("|" + string(optarg));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'I':
|
|
|
|
if (access(optarg, X_OK) != 0) {
|
|
|
|
perror("invalid config path");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
lnav_data.ld_config_paths.push_back(optarg);
|
|
|
|
break;
|
|
|
|
|
2014-11-05 17:01:09 +00:00
|
|
|
case 'i':
|
|
|
|
lnav_data.ld_flags |= LNF_INSTALL;
|
|
|
|
break;
|
|
|
|
|
2014-03-03 06:26:41 +00:00
|
|
|
case 'd':
|
|
|
|
lnav_data.ld_debug_log_name = optarg;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'a':
|
|
|
|
lnav_data.ld_flags |= LNF__ALL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
lnav_data.ld_flags |= LNF_HEADLESS;
|
|
|
|
break;
|
|
|
|
|
2014-03-07 13:20:49 +00:00
|
|
|
case 'q':
|
|
|
|
lnav_data.ld_flags |= LNF_QUIET;
|
|
|
|
break;
|
|
|
|
|
2014-03-03 06:26:41 +00:00
|
|
|
case 'r':
|
|
|
|
lnav_data.ld_flags |= LNF_ROTATED;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 's':
|
|
|
|
lnav_data.ld_flags |= LNF_SYSLOG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 't':
|
|
|
|
lnav_data.ld_flags |= LNF_TIMESTAMP;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'w':
|
|
|
|
stdin_out = optarg;
|
|
|
|
break;
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
case 'W':
|
|
|
|
{
|
|
|
|
char b;
|
|
|
|
read(STDIN_FILENO, &b, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-03-03 06:26:41 +00:00
|
|
|
case 'V':
|
2015-04-07 04:33:34 +00:00
|
|
|
printf("%s\n", VCS_PACKAGE_STRING);
|
2014-03-03 06:26:41 +00:00
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
retval = EXIT_FAILURE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
|
|
|
lnav_log_file = fopen(lnav_data.ld_debug_log_name, "a");
|
2015-04-07 13:09:49 +00:00
|
|
|
log_info("lnav started");
|
2014-03-03 06:26:41 +00:00
|
|
|
|
2014-11-05 17:01:09 +00:00
|
|
|
if (lnav_data.ld_flags & LNF_INSTALL) {
|
|
|
|
string installed_path = dotlnav_path("formats/installed/");
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
fprintf(stderr, "error: expecting file format paths\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (lpc = 0; lpc < argc; lpc++) {
|
|
|
|
vector<string> format_list = load_format_file(argv[lpc], loader_errors);
|
|
|
|
|
|
|
|
if (!loader_errors.empty()) {
|
|
|
|
print_errors(loader_errors);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
if (format_list.empty()) {
|
|
|
|
fprintf(stderr, "error: format file is empty: %s\n", argv[lpc]);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
string dst_name = format_list[0] + ".json";
|
|
|
|
string dst_path = installed_path + dst_name;
|
|
|
|
auto_fd in_fd, out_fd;
|
|
|
|
|
|
|
|
if ((in_fd = open(argv[lpc], O_RDONLY)) == -1) {
|
|
|
|
perror("unable to open file to install");
|
|
|
|
}
|
|
|
|
else if ((out_fd = open(dst_path.c_str(),
|
|
|
|
O_WRONLY | O_CREAT, 0644)) == -1) {
|
|
|
|
fprintf(stderr, "error: unable to open destination: %s -- %s\n",
|
|
|
|
dst_path.c_str(), strerror(errno));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
char buffer[2048];
|
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
while ((rc = read(in_fd, buffer, sizeof(buffer))) > 0) {
|
|
|
|
write(out_fd, buffer, rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "info: installed: %s\n", dst_path.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-03-03 06:26:41 +00:00
|
|
|
load_formats(lnav_data.ld_config_paths, loader_errors);
|
2013-06-29 18:00:34 +00:00
|
|
|
if (!loader_errors.empty()) {
|
2014-11-05 17:01:09 +00:00
|
|
|
print_errors(loader_errors);
|
2013-06-29 18:00:34 +00:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2014-03-03 06:26:41 +00:00
|
|
|
if (lnav_data.ld_flags & LNF_CHECK_CONFIG) {
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2011-07-18 13:34:41 +00:00
|
|
|
/* If we statically linked against an ncurses library that had a non-
|
|
|
|
* standard path to the terminfo database, we need to set this variable
|
|
|
|
* so that it will try the default path.
|
|
|
|
*/
|
2013-08-30 02:15:45 +00:00
|
|
|
setenv("TERMINFO_DIRS",
|
|
|
|
"/usr/share/terminfo:/lib/terminfo:/usr/share/lib/terminfo",
|
|
|
|
0);
|
2011-07-18 13:34:41 +00:00
|
|
|
|
2009-10-06 21:14:49 +00:00
|
|
|
if (sqlite3_open(":memory:", lnav_data.ld_db.out()) != SQLITE_OK) {
|
2013-05-29 14:28:57 +00:00
|
|
|
fprintf(stderr, "error: unable to create sqlite memory database\n");
|
2013-05-28 04:35:00 +00:00
|
|
|
exit(EXIT_FAILURE);
|
2009-10-06 21:14:49 +00:00
|
|
|
}
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2013-05-24 14:55:56 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
int register_collation_functions(sqlite3 * db);
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2013-06-06 14:01:32 +00:00
|
|
|
register_sqlite_funcs(lnav_data.ld_db.in(), sqlite_registration_funcs);
|
2013-05-28 04:35:00 +00:00
|
|
|
register_collation_functions(lnav_data.ld_db.in());
|
2013-05-24 14:55:56 +00:00
|
|
|
}
|
|
|
|
|
2014-05-07 04:26:05 +00:00
|
|
|
register_environ_vtab(lnav_data.ld_db.in());
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
lnav_data.ld_vtab_manager =
|
2013-05-28 04:35:00 +00:00
|
|
|
new log_vtab_manager(lnav_data.ld_db,
|
2013-06-26 03:43:27 +00:00
|
|
|
lnav_data.ld_views[LNV_LOG],
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_log_source,
|
|
|
|
sql_progress);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-12 04:10:59 +00:00
|
|
|
{
|
|
|
|
auto_mem<char, sqlite3_free> errmsg;
|
|
|
|
|
|
|
|
if (sqlite3_exec(lnav_data.ld_db.in(),
|
|
|
|
init_sql,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
errmsg.out()) != SQLITE_OK) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"error: unable to execute DB init -- %s\n",
|
|
|
|
errmsg.in());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-12 13:59:48 +00:00
|
|
|
lnav_data.ld_vtab_manager->register_vtab(new log_vtab_impl("generic_log"));
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
for (std::vector<log_format *>::iterator iter = log_format::get_root_formats().begin();
|
|
|
|
iter != log_format::get_root_formats().end();
|
|
|
|
++iter) {
|
|
|
|
log_vtab_impl *lvi = (*iter)->get_vtab_impl();
|
|
|
|
|
|
|
|
if (lvi != NULL) {
|
|
|
|
lnav_data.ld_vtab_manager->register_vtab(lvi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
DEFAULT_FILES.insert(make_pair(LNF_SYSLOG, string("var/log/messages")));
|
2011-06-20 05:30:10 +00:00
|
|
|
DEFAULT_FILES.insert(make_pair(LNF_SYSLOG, string("var/log/system.log")));
|
|
|
|
DEFAULT_FILES.insert(make_pair(LNF_SYSLOG, string("var/log/syslog")));
|
2012-11-28 16:39:39 +00:00
|
|
|
DEFAULT_FILES.insert(make_pair(LNF_SYSLOG, string("var/log/syslog.log")));
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2012-07-13 16:26:47 +00:00
|
|
|
init_lnav_commands(lnav_commands);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
lnav_data.ld_views[LNV_HELP].
|
2011-07-17 16:41:41 +00:00
|
|
|
set_sub_source(new plain_text_source(help_txt));
|
2014-03-15 17:08:50 +00:00
|
|
|
lnav_data.ld_views[LNV_HELP].set_word_wrap(true);
|
2009-09-14 01:07:32 +00:00
|
|
|
lnav_data.ld_views[LNV_LOG].
|
|
|
|
set_sub_source(&lnav_data.ld_log_source);
|
2013-10-11 13:22:29 +00:00
|
|
|
lnav_data.ld_views[LNV_LOG].
|
|
|
|
set_delegate(new action_delegate(lnav_data.ld_log_source));
|
2010-11-22 05:44:45 +00:00
|
|
|
lnav_data.ld_views[LNV_TEXT].
|
|
|
|
set_sub_source(&lnav_data.ld_text_source);
|
2009-09-14 01:07:32 +00:00
|
|
|
lnav_data.ld_views[LNV_HISTOGRAM].
|
|
|
|
set_sub_source(&lnav_data.ld_hist_source);
|
|
|
|
lnav_data.ld_views[LNV_GRAPH].
|
|
|
|
set_sub_source(&lnav_data.ld_graph_source);
|
|
|
|
lnav_data.ld_views[LNV_DB].
|
|
|
|
set_sub_source(&lnav_data.ld_db_source);
|
2013-05-24 14:55:56 +00:00
|
|
|
lnav_data.ld_db_overlay.dos_labels = &lnav_data.ld_db_rows;
|
|
|
|
lnav_data.ld_views[LNV_DB].
|
|
|
|
set_overlay_source(&lnav_data.ld_db_overlay);
|
|
|
|
lnav_data.ld_views[LNV_LOG].
|
2013-10-11 13:22:29 +00:00
|
|
|
set_overlay_source(new field_overlay_source(lnav_data.ld_log_source));
|
2013-05-24 14:55:56 +00:00
|
|
|
lnav_data.ld_db_overlay.dos_hist_source = &lnav_data.ld_db_source;
|
2014-03-09 09:29:28 +00:00
|
|
|
lnav_data.ld_match_view.set_left(0);
|
|
|
|
|
2014-02-24 23:50:42 +00:00
|
|
|
for (int lpc = 0; lpc < LNV__MAX; lpc++) {
|
|
|
|
lnav_data.ld_views[lpc].set_gutter_source(new log_gutter_source());
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
setup_highlights(lnav_data.ld_views[LNV_LOG].get_highlights());
|
2011-10-20 22:38:37 +00:00
|
|
|
setup_highlights(lnav_data.ld_views[LNV_TEXT].get_highlights());
|
2014-03-09 09:29:28 +00:00
|
|
|
setup_highlights(lnav_data.ld_views[LNV_SCHEMA].get_highlights());
|
2015-03-17 06:10:34 +00:00
|
|
|
setup_highlights(lnav_data.ld_views[LNV_PRETTY].get_highlights());
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
{
|
|
|
|
hist_source &hs = lnav_data.ld_hist_source;
|
|
|
|
|
|
|
|
lnav_data.ld_hist_zoom = 2;
|
|
|
|
hs.set_role_for_type(bucket_type_t(logline::LEVEL_FATAL),
|
|
|
|
view_colors::VCR_ERROR);
|
|
|
|
hs.set_role_for_type(bucket_type_t(logline::LEVEL_CRITICAL),
|
|
|
|
view_colors::VCR_ERROR);
|
|
|
|
hs.set_role_for_type(bucket_type_t(logline::LEVEL_ERROR),
|
|
|
|
view_colors::VCR_ERROR);
|
|
|
|
hs.set_role_for_type(bucket_type_t(logline::LEVEL_WARNING),
|
|
|
|
view_colors::VCR_WARNING);
|
|
|
|
hs.set_label_source(new time_label_source());
|
2015-04-04 20:36:53 +00:00
|
|
|
|
|
|
|
lnav_data.ld_log_source.set_index_delegate(
|
|
|
|
new hist_index_delegate(lnav_data.ld_hist_source,
|
|
|
|
lnav_data.ld_views[LNV_HISTOGRAM]));
|
|
|
|
|
|
|
|
int zoom_level = lnav_data.ld_hist_zoom;
|
|
|
|
|
|
|
|
hs.set_bucket_size(HIST_ZOOM_VALUES[zoom_level].hl_bucket_size);
|
|
|
|
hs.set_group_size(HIST_ZOOM_VALUES[zoom_level].hl_group_size);
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
hist_source &hs = lnav_data.ld_graph_source;
|
|
|
|
|
|
|
|
hs.set_bucket_size(1);
|
|
|
|
hs.set_group_size(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
hist_source &hs = lnav_data.ld_db_source;
|
|
|
|
|
|
|
|
hs.set_bucket_size(1);
|
|
|
|
hs.set_group_size(10);
|
|
|
|
hs.set_label_source(&lnav_data.ld_db_rows);
|
|
|
|
}
|
|
|
|
|
2014-02-10 15:25:28 +00:00
|
|
|
for (int lpc = 0; lpc < LNV__MAX; lpc++) {
|
|
|
|
lnav_data.ld_views[lpc].set_title(view_titles[lpc]);
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
lnav_data.ld_looping = true;
|
|
|
|
lnav_data.ld_mode = LNM_PAGING;
|
2014-03-02 00:35:30 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (isatty(STDIN_FILENO) && argc == 0 &&
|
|
|
|
!(lnav_data.ld_flags & LNF__ALL)) {
|
|
|
|
lnav_data.ld_flags |= LNF_SYSLOG;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lnav_data.ld_flags != 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
char start_dir[FILENAME_MAX];
|
|
|
|
|
|
|
|
if (getcwd(start_dir, sizeof(start_dir)) == NULL) {
|
|
|
|
perror("getcwd");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
do {
|
|
|
|
for (lpc = 0; lpc < LNB__MAX; lpc++) {
|
|
|
|
if (!append_default_files((lnav_flags_t)(1L << lpc))) {
|
|
|
|
retval = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (lnav_data.ld_file_names.empty() &&
|
|
|
|
change_to_parent_dir());
|
|
|
|
|
|
|
|
if (chdir(start_dir) == -1) {
|
|
|
|
perror("chdir(start_dir)");
|
|
|
|
}
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (lpc = 0; lpc < argc; lpc++) {
|
2013-05-31 00:46:41 +00:00
|
|
|
auto_mem<char> abspath;
|
2013-06-16 01:07:50 +00:00
|
|
|
struct stat st;
|
2012-04-24 21:30:07 +00:00
|
|
|
|
2013-09-14 19:30:57 +00:00
|
|
|
if (is_glob(argv[lpc])) {
|
|
|
|
lnav_data.ld_file_names.insert(make_pair(argv[lpc], -1));
|
|
|
|
}
|
|
|
|
else if (stat(argv[lpc], &st) == -1) {
|
2013-05-31 00:46:41 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"Cannot stat file: %s -- %s\n",
|
|
|
|
argv[lpc],
|
|
|
|
strerror(errno));
|
|
|
|
retval = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
else if ((abspath = realpath(argv[lpc], NULL)) == NULL) {
|
|
|
|
perror("Cannot find file");
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
else if (S_ISDIR(st.st_mode)) {
|
2013-05-31 00:46:41 +00:00
|
|
|
string dir_wild(abspath.in());
|
2012-04-24 21:30:07 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
if (dir_wild[dir_wild.size() - 1] == '/') {
|
|
|
|
dir_wild.resize(dir_wild.size() - 1);
|
|
|
|
}
|
|
|
|
lnav_data.ld_file_names.insert(make_pair(dir_wild + "/*", -1));
|
|
|
|
}
|
|
|
|
else {
|
2013-05-31 00:46:41 +00:00
|
|
|
lnav_data.ld_file_names.insert(make_pair(abspath.in(), -1));
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
if (!(lnav_data.ld_flags & LNF_HEADLESS) && !isatty(STDOUT_FILENO)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
fprintf(stderr, "error: stdout is not a tty.\n");
|
|
|
|
retval = EXIT_FAILURE;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isatty(STDIN_FILENO)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
stdin_reader =
|
|
|
|
auto_ptr<piper_proc>(new piper_proc(STDIN_FILENO,
|
|
|
|
lnav_data.ld_flags &
|
|
|
|
LNF_TIMESTAMP, stdin_out));
|
2015-03-14 14:08:48 +00:00
|
|
|
stdin_out_fd = stdin_reader->get_fd();
|
|
|
|
lnav_data.ld_file_names.insert(make_pair("stdin", stdin_out_fd));
|
2013-05-28 04:35:00 +00:00
|
|
|
if (dup2(STDOUT_FILENO, STDIN_FILENO) == -1) {
|
|
|
|
perror("cannot dup stdout to stdin");
|
|
|
|
}
|
2015-04-02 13:49:16 +00:00
|
|
|
lnav_data.ld_pipers.push_back(stdin_reader.release());
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2012-09-28 18:01:36 +00:00
|
|
|
|
2014-09-29 05:36:07 +00:00
|
|
|
if (lnav_data.ld_file_names.empty() && !(lnav_data.ld_flags & LNF_HELP)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
fprintf(stderr, "error: no log files given/found.\n");
|
|
|
|
retval = EXIT_FAILURE;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (retval != EXIT_SUCCESS) {
|
2013-05-28 04:35:00 +00:00
|
|
|
usage();
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-05-28 04:35:00 +00:00
|
|
|
try {
|
|
|
|
rescan_files(true);
|
2014-03-06 14:58:49 +00:00
|
|
|
|
2015-04-07 04:33:34 +00:00
|
|
|
log_info("startup: %s", VCS_PACKAGE_STRING);
|
2014-03-02 00:35:30 +00:00
|
|
|
log_host_info();
|
2014-11-04 04:02:22 +00:00
|
|
|
log_info("Libraries:");
|
|
|
|
#ifdef HAVE_BZLIB_H
|
|
|
|
log_info(" bzip=%s", BZ2_bzlibVersion());
|
|
|
|
#endif
|
|
|
|
log_info(" ncurses=%s", NCURSES_VERSION);
|
|
|
|
log_info(" pcre=%s", pcre_version());
|
|
|
|
log_info(" readline=%s", rl_library_version);
|
|
|
|
log_info(" sqlite=%s", sqlite3_version);
|
|
|
|
log_info(" zlib=%s", zlibVersion());
|
2014-03-02 19:56:58 +00:00
|
|
|
log_info("lnav_data:");
|
|
|
|
log_info(" flags=%x", lnav_data.ld_flags);
|
|
|
|
log_info(" commands:");
|
|
|
|
for (std::list<string>::iterator cmd_iter =
|
|
|
|
lnav_data.ld_commands.begin();
|
|
|
|
cmd_iter != lnav_data.ld_commands.end();
|
|
|
|
++cmd_iter) {
|
|
|
|
log_info(" %s", cmd_iter->c_str());
|
|
|
|
}
|
|
|
|
log_info(" files:");
|
|
|
|
for (std::set<pair<string, int> >::iterator file_iter =
|
|
|
|
lnav_data.ld_file_names.begin();
|
|
|
|
file_iter != lnav_data.ld_file_names.end();
|
|
|
|
++file_iter) {
|
|
|
|
log_info(" %s", file_iter->first.c_str());
|
|
|
|
}
|
2014-03-01 04:35:07 +00:00
|
|
|
|
|
|
|
if (lnav_data.ld_flags & LNF_HEADLESS) {
|
2014-03-03 00:52:18 +00:00
|
|
|
std::vector<pair<string, string> > msgs;
|
|
|
|
std::vector<pair<string, string> >::iterator msg_iter;
|
2014-03-01 04:35:07 +00:00
|
|
|
textview_curses *tc;
|
|
|
|
attr_line_t al;
|
|
|
|
const std::string &line = al.get_string();
|
2014-03-03 00:52:18 +00:00
|
|
|
bool found_error = false;
|
2014-03-01 04:35:07 +00:00
|
|
|
|
|
|
|
alerter::singleton().enabled(false);
|
|
|
|
|
2014-03-02 19:01:33 +00:00
|
|
|
lnav_data.ld_view_stack.push(&lnav_data.ld_views[LNV_LOG]);
|
2015-04-06 09:48:12 +00:00
|
|
|
// Read all of stdin
|
|
|
|
wait_for_pipers();
|
2014-03-01 04:35:07 +00:00
|
|
|
rebuild_indexes(true);
|
|
|
|
|
|
|
|
lnav_data.ld_views[LNV_LOG].set_top(vis_line_t(0));
|
2013-05-31 15:01:31 +00:00
|
|
|
|
2015-04-06 09:48:12 +00:00
|
|
|
log_info("Executing initial commands");
|
2014-03-03 00:52:18 +00:00
|
|
|
execute_init_commands(msgs);
|
2015-04-06 09:48:12 +00:00
|
|
|
wait_for_pipers();
|
2014-03-13 06:20:18 +00:00
|
|
|
rebuild_indexes(false);
|
2014-03-03 00:52:18 +00:00
|
|
|
|
|
|
|
for (msg_iter = msgs.begin();
|
|
|
|
msg_iter != msgs.end();
|
|
|
|
++msg_iter) {
|
|
|
|
if (strncmp("error:", msg_iter->first.c_str(), 6) != 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s\n", msg_iter->first.c_str());
|
|
|
|
found_error = true;
|
|
|
|
}
|
2013-05-31 15:01:31 +00:00
|
|
|
|
2014-03-03 00:52:18 +00:00
|
|
|
if (!found_error &&
|
2014-03-07 13:20:49 +00:00
|
|
|
!(lnav_data.ld_flags & LNF_QUIET) &&
|
2014-03-03 00:52:18 +00:00
|
|
|
!lnav_data.ld_view_stack.empty() &&
|
2014-03-01 04:35:07 +00:00
|
|
|
!lnav_data.ld_stdout_used) {
|
|
|
|
bool suppress_empty_lines = false;
|
|
|
|
list_overlay_source *los;
|
2015-04-06 09:48:12 +00:00
|
|
|
unsigned long view_index;
|
2014-03-01 04:35:07 +00:00
|
|
|
vis_line_t y;
|
2013-05-31 15:01:31 +00:00
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
tc = lnav_data.ld_view_stack.top();
|
2015-04-06 09:48:12 +00:00
|
|
|
view_index = tc - lnav_data.ld_views;
|
|
|
|
switch (view_index) {
|
|
|
|
case LNV_DB:
|
|
|
|
case LNV_HISTOGRAM:
|
|
|
|
suppress_empty_lines = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2014-03-01 04:35:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
los = tc->get_overlay_source();
|
|
|
|
|
|
|
|
for (vis_line_t vl = tc->get_top();
|
|
|
|
vl < tc->get_inner_height();
|
|
|
|
++vl, ++y) {
|
2014-03-02 16:55:00 +00:00
|
|
|
while (los != NULL &&
|
|
|
|
los->list_value_for_overlay(*tc, y, al)) {
|
2014-03-01 04:35:07 +00:00
|
|
|
printf("%s\n", line.c_str());
|
|
|
|
++y;
|
|
|
|
}
|
|
|
|
|
|
|
|
tc->listview_value_for_row(*tc, vl, al);
|
|
|
|
if (suppress_empty_lines && line.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("%s\n", line.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
init_session();
|
|
|
|
|
2014-03-02 19:56:58 +00:00
|
|
|
log_info(" session_id=%s", lnav_data.ld_session_id.c_str());
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
scan_sessions();
|
|
|
|
|
|
|
|
guard_termios gt(STDIN_FILENO);
|
2014-03-02 00:35:30 +00:00
|
|
|
|
|
|
|
lnav_log_orig_termios = gt.get_termios();
|
|
|
|
|
2014-03-01 04:35:07 +00:00
|
|
|
looper();
|
|
|
|
|
|
|
|
save_session();
|
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
catch (line_buffer::error & e) {
|
|
|
|
fprintf(stderr, "error: %s\n", strerror(e.e_err));
|
|
|
|
}
|
|
|
|
catch (logfile::error & e) {
|
|
|
|
if (e.e_err != EINTR) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"error: %s -- '%s'\n",
|
|
|
|
strerror(e.e_err),
|
|
|
|
e.e_filename.c_str());
|
|
|
|
}
|
|
|
|
}
|
2013-07-10 05:27:48 +00:00
|
|
|
|
|
|
|
// When reading from stdin, dump out the last couple hundred lines so
|
|
|
|
// the user can have the text in their terminal history.
|
2015-04-04 09:15:19 +00:00
|
|
|
if (stdin_out_fd != -1 && !(lnav_data.ld_flags & LNF_HEADLESS)) {
|
2013-07-10 05:27:48 +00:00
|
|
|
list<logfile *>::iterator file_iter;
|
|
|
|
struct stat st;
|
|
|
|
|
2015-03-14 14:08:48 +00:00
|
|
|
fstat(stdin_out_fd, &st);
|
2013-07-10 05:27:48 +00:00
|
|
|
file_iter = find_if(lnav_data.ld_files.begin(),
|
|
|
|
lnav_data.ld_files.end(),
|
|
|
|
same_file(st));
|
|
|
|
if (file_iter != lnav_data.ld_files.end()) {
|
|
|
|
logfile::iterator line_iter;
|
|
|
|
logfile *lf = *file_iter;
|
|
|
|
string str;
|
|
|
|
|
|
|
|
for (line_iter = lf->begin();
|
|
|
|
line_iter != lf->end();
|
|
|
|
++line_iter) {
|
|
|
|
lf->read_line(line_iter, str);
|
|
|
|
|
|
|
|
write(STDOUT_FILENO, str.c_str(), str.size());
|
|
|
|
write(STDOUT_FILENO, "\n", 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|