mirror of https://github.com/tstack/lnav
Some more sequence matching stuff.
parent
e3d2d41aba
commit
44e8abc593
@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef __byte_array_hh
|
||||
#define __byte_array_hh
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
template<size_t BYTE_COUNT>
|
||||
struct byte_array {
|
||||
byte_array() { };
|
||||
|
||||
byte_array(const byte_array &other) {
|
||||
memcpy(this->ba_data, other.ba_data, BYTE_COUNT);
|
||||
};
|
||||
|
||||
bool operator<(const byte_array &other) const {
|
||||
return memcmp(this->ba_data, other.ba_data, BYTE_COUNT) < 0;
|
||||
};
|
||||
|
||||
unsigned char ba_data[BYTE_COUNT];
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,52 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "sequence_matcher.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
sequence_matcher::sequence_matcher(field_col_t &example)
|
||||
{
|
||||
for (field_col_t::iterator col_iter = example.begin();
|
||||
col_iter != example.end();
|
||||
++col_iter) {
|
||||
std::string first_value;
|
||||
field sf;
|
||||
|
||||
sf.sf_value = *col_iter;
|
||||
for (field_row_t::iterator row_iter = (*col_iter).begin();
|
||||
row_iter != (*col_iter).end();
|
||||
++row_iter) {
|
||||
if (row_iter == (*col_iter).begin()) {
|
||||
first_value = *row_iter;
|
||||
}
|
||||
else if (first_value != *row_iter) {
|
||||
sf.sf_type = FT_CONSTANT;
|
||||
}
|
||||
}
|
||||
if (sf.sf_type == FT_VARIABLE)
|
||||
sf.sf_value.clear();
|
||||
this->sm_fields.push_back(sf);
|
||||
}
|
||||
this->sm_count = example.front().size();
|
||||
}
|
||||
|
||||
void sequence_matcher::identity(const std::vector<string> &values, id_t &id_out)
|
||||
{
|
||||
SHA_CTX context;
|
||||
int lpc = 0;
|
||||
|
||||
SHA_Init(&context);
|
||||
for (std::list<field>::iterator iter = sm_fields.begin();
|
||||
iter != sm_fields.end();
|
||||
++iter, lpc++) {
|
||||
if (iter->sf_type == FT_VARIABLE) {
|
||||
SHA_Update(&context,
|
||||
values[lpc].c_str(),
|
||||
values[lpc].length() + 1);
|
||||
}
|
||||
}
|
||||
SHA_Final(id_out.ba_data, &context);
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
|
||||
#ifndef __sequence_matcher_hh
|
||||
#define __sequence_matcher_hh
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "byte_array.hh"
|
||||
|
||||
class sequence_matcher {
|
||||
public:
|
||||
typedef std::vector<std::string> field_row_t;
|
||||
typedef std::list<field_row_t> field_col_t;
|
||||
|
||||
typedef byte_array<20> id_t;
|
||||
|
||||
enum field_type_t {
|
||||
FT_VARIABLE,
|
||||
FT_CONSTANT,
|
||||
};
|
||||
|
||||
struct field {
|
||||
|
||||
public:
|
||||
field() : sf_type(FT_VARIABLE) { };
|
||||
|
||||
field_type_t sf_type;
|
||||
field_row_t sf_value;
|
||||
};
|
||||
|
||||
sequence_matcher(field_col_t &example);
|
||||
|
||||
void identity(const std::vector<std::string> &values, id_t &id_out);
|
||||
|
||||
template<typename T>
|
||||
bool match(const std::vector<std::string> &values,
|
||||
std::vector<T> &state,
|
||||
T index) {
|
||||
bool index_match = true;
|
||||
int lpc = 0;
|
||||
|
||||
retry:
|
||||
for (std::list<field>::iterator iter = this->sm_fields.begin();
|
||||
iter != this->sm_fields.end();
|
||||
++iter, lpc++) {
|
||||
if (iter->sf_type != sequence_matcher::FT_CONSTANT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter->sf_value[state.size()] != values[lpc]) {
|
||||
if (state.size() > 0) {
|
||||
state.clear();
|
||||
lpc = 0;
|
||||
goto retry;
|
||||
}
|
||||
else {
|
||||
index_match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index_match) {
|
||||
state.push_back(index);
|
||||
}
|
||||
|
||||
return (this->sm_count == state.size());
|
||||
};
|
||||
|
||||
private:
|
||||
int sm_count;
|
||||
std::list<field> sm_fields;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,63 @@
|
||||
|
||||
#ifndef __sequence_sink_hh
|
||||
#define __sequence_sink_hh
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "bookmarks.hh"
|
||||
#include "grep_proc.hh"
|
||||
#include "sequence_matcher.hh"
|
||||
|
||||
class sequence_sink : public grep_proc_sink {
|
||||
public:
|
||||
sequence_sink(sequence_matcher &sm, bookmark_vector &bv) :
|
||||
ss_matcher(sm),
|
||||
ss_bookmarks(bv) {
|
||||
};
|
||||
|
||||
void grep_match(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
int start,
|
||||
int end) {
|
||||
this->ss_line_values.clear();
|
||||
};
|
||||
|
||||
void grep_capture(grep_proc &gp,
|
||||
grep_line_t line,
|
||||
int start,
|
||||
int end,
|
||||
char *capture) {
|
||||
if (start == -1)
|
||||
this->ss_line_values.push_back("");
|
||||
else
|
||||
this->ss_line_values.push_back(std::string(capture));
|
||||
};
|
||||
|
||||
void grep_match_end(grep_proc &gp, grep_line_t line) {
|
||||
sequence_matcher::id_t line_id;
|
||||
|
||||
this->ss_matcher.identity(this->ss_line_values, line_id);
|
||||
|
||||
std::vector<grep_line_t> &line_state = this->ss_state[line_id];
|
||||
if (this->ss_matcher.match(this->ss_line_values,
|
||||
line_state,
|
||||
line)) {
|
||||
std::vector<grep_line_t>::iterator iter;
|
||||
|
||||
for (iter = line_state.begin();
|
||||
iter != line_state.end();
|
||||
++iter) {
|
||||
this->ss_bookmarks.insert_once(vis_line_t(*iter));
|
||||
}
|
||||
line_state.clear();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
sequence_matcher &ss_matcher;
|
||||
bookmark_vector &ss_bookmarks;
|
||||
std::vector<std::string> ss_line_values;
|
||||
std::map< sequence_matcher::id_t, std::vector<grep_line_t> > ss_state;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
Nov 3 09:23:38 veridian foo[7998]: eth0 is up
|
||||
Nov 3 09:23:38 veridian foo[16442]: eth1 is up
|
||||
Nov 3 09:23:38 veridian foo[7999]: eth0 is down
|
Loading…
Reference in New Issue