diff --git a/src/k_merge_tree.h b/src/k_merge_tree.h index 4ad57b37..80c817de 100644 --- a/src/k_merge_tree.h +++ b/src/k_merge_tree.h @@ -147,12 +147,27 @@ private: }; +inline long kmerge_tree_brute_log2(long value) +{ + + long square = 2; + long count = 1; + while ( square < value ) + { + square *= 2; + ++count; + } + + return count; + +} // kmerge_tree_brute_log2 + //~~~~~~~~~~class kmerge_tree_c template kmerge_tree_c::kmerge_tree_c(long bucket_qty) : bucket_qty_mbr(bucket_qty), - number_of_levels_mbr(bucket_qty ? ::log2(bucket_qty_mbr) : 0), // don't add one - build_levels is zero based + number_of_levels_mbr(bucket_qty ? ::kmerge_tree_brute_log2(bucket_qty_mbr) : 0), // don't add one - build_levels is zero based top_node_ptr_mbr(NULL), first_leaf_ptr(NULL), last_leaf_ptr(NULL) diff --git a/src/lnav.cc b/src/lnav.cc index dc95406f..393f9c77 100644 --- a/src/lnav.cc +++ b/src/lnav.cc @@ -896,6 +896,11 @@ static void moveto_cluster(vis_line_t(bookmark_vector::*f) ( time_t last_time; logline * ll; + if (lss.empty()) { + flash(); + return; + } + ll = lss.find_line(lss.at(top)); last_time = ll->get_time(); last_level = ll->get_level(); diff --git a/src/logfile_sub_source.cc b/src/logfile_sub_source.cc index 6c0562e7..f6e35b72 100644 --- a/src/logfile_sub_source.cc +++ b/src/logfile_sub_source.cc @@ -368,7 +368,7 @@ bool logfile_sub_source::rebuild_index(observer *obs, bool force) } if (retval || force) { - size_t index_size; + size_t index_size = 0; if (force) { this->lss_index.clear(); diff --git a/src/logfile_sub_source.hh b/src/logfile_sub_source.hh index c9006cc6..a75bb55d 100644 --- a/src/logfile_sub_source.hh +++ b/src/logfile_sub_source.hh @@ -118,6 +118,9 @@ public: { return this->lss_index.size(); }; + + bool empty() const { return this->lss_index.empty(); }; + void text_value_for_line(textview_curses &tc, int row, std::string &value_out, diff --git a/src/pcrepp.cc b/src/pcrepp.cc index b21415a9..8ab51416 100644 --- a/src/pcrepp.cc +++ b/src/pcrepp.cc @@ -36,6 +36,19 @@ const int JIT_STACK_MIN_SIZE = 32 * 1024; const int JIT_STACK_MAX_SIZE = 512 * 1024; +pcre_context::capture_t *pcre_context::operator[](const char *name) const +{ + capture_t *retval = NULL; + int index; + + index = this->pc_pcre->name_index(name); + if (index != PCRE_ERROR_NOSUBSTRING) { + retval = &this->pc_captures[index + 1]; + } + + return retval; +} + #ifdef PCRE_STUDY_JIT_COMPILE pcre_jit_stack *pcrepp::jit_stack(void) { diff --git a/src/pcrepp.hh b/src/pcrepp.hh index 4bf7a648..f7f81af5 100644 --- a/src/pcrepp.hh +++ b/src/pcrepp.hh @@ -57,6 +57,8 @@ #include +class pcrepp; + /** * Context that tracks captures found during a match operation. This class is a * base that defines iterator methods and fields, but does not allocate space @@ -95,6 +97,8 @@ public: return this->pc_count; }; + void set_pcrepp(const pcrepp *src) { this->pc_pcre = src; }; + /** * @return a capture_t that covers all of the text that was matched. */ @@ -105,10 +109,17 @@ public: /** @return An iterator that refers to the end of the capture array. */ iterator end() { return pc_captures + pc_count; }; + capture_t *operator[](int offset) { + return &this->pc_captures[offset + 1]; + }; + + capture_t *operator[](const char *name) const; + protected: pcre_context(capture_t *captures, int max_count) : pc_captures(captures), pc_max_count(max_count), pc_count(0) { }; + const pcrepp *pc_pcre; capture_t *pc_captures; int pc_max_count; int pc_count; @@ -216,6 +227,50 @@ private: const char *pi_string; }; +struct pcre_named_capture { + class iterator { + public: + iterator(pcre_named_capture *pnc, size_t name_len) + : i_named_capture(pnc), i_name_len(name_len) + { + }; + + iterator() : i_named_capture(NULL), i_name_len(0) { }; + + const pcre_named_capture &operator*(void) const { + return *this->i_named_capture; + }; + + const pcre_named_capture *operator->(void) const { + return this->i_named_capture; + }; + + bool operator!=(const iterator &rhs) const { + return this->i_named_capture != rhs.i_named_capture; + }; + + iterator &operator++() { + char *ptr = (char *)this->i_named_capture; + + ptr += this->i_name_len; + this->i_named_capture = (pcre_named_capture *)ptr; + return *this; + }; + + private: + pcre_named_capture *i_named_capture; + size_t i_name_len; + }; + + int index() const { + return (this->pnc_index_msb << 8 | this->pnc_index_lsb); + }; + + char pnc_index_msb; + char pnc_index_lsb; + char pnc_name[]; +}; + class pcrepp { public: class error : public std::exception { @@ -272,6 +327,28 @@ public: } }; + pcre_named_capture::iterator named_begin() const { + return pcre_named_capture::iterator(this->p_named_entries, + this->p_name_len); + }; + + pcre_named_capture::iterator named_end() const { + char *ptr = (char *)this->p_named_entries; + + ptr += this->p_named_count * this->p_name_len; + return pcre_named_capture::iterator((pcre_named_capture *)ptr, + this->p_name_len); + }; + + int name_index(const char *name) const { + int retval = pcre_get_stringnumber(this->p_code, name); + + if (retval == PCRE_ERROR_NOSUBSTRING) + return retval; + + return retval - 1; + }; + bool match(pcre_context &pc, pcre_input &pi, int options = 0) const { int length, startoffset, filtered_options = options; @@ -279,6 +356,7 @@ public: const char *str; int rc; + pc.set_pcrepp(this); pi.pi_offset = pi.pi_next_offset; str = pi.get_string(); @@ -369,9 +447,24 @@ private: pcre_assign_jit_stack(extra, NULL, jit_stack()); #endif } + pcre_fullinfo(this->p_code, + this->p_code_extra, + PCRE_INFO_NAMECOUNT, + &this->p_named_count); + pcre_fullinfo(this->p_code, + this->p_code_extra, + PCRE_INFO_NAMEENTRYSIZE, + &this->p_name_len); + pcre_fullinfo(this->p_code, + this->p_code_extra, + PCRE_INFO_NAMETABLE, + &this->p_named_entries); }; pcre *p_code; auto_mem p_code_extra; + int p_named_count; + int p_name_len; + pcre_named_capture *p_named_entries; }; #endif diff --git a/test/test_pcrepp.cc b/test/test_pcrepp.cc index 5cb1becf..8dd072e3 100644 --- a/test/test_pcrepp.cc +++ b/test/test_pcrepp.cc @@ -42,36 +42,60 @@ int main(int argc, char *argv[]) int retval = EXIT_SUCCESS; { - pcrepp nomatch("nothing-to-match"); - pcre_input pi("dummy"); - - assert(!nomatch.match(context, pi)); + pcrepp nomatch("nothing-to-match"); + pcre_input pi("dummy"); + + assert(!nomatch.match(context, pi)); } { - pcrepp match1("(\\w*)=(\\d+)"); - pcre_input pi("a=1 b=2"); - pcre_context::capture_t *cap; - - assert(match1.match(context, pi)); - - cap = context.all(); - assert(cap->c_begin == 0); - assert(cap->c_end == 3); + pcrepp match1("(\\w*)=(\\d+)"); + pcre_input pi("a=1 b=2"); + pcre_context::capture_t *cap; - assert((context.end() - context.begin()) == 2); - assert(pi.get_substr(context.begin()) == "a"); - assert(pi.get_substr(context.begin() + 1) == "1"); + assert(match1.match(context, pi)); - assert(match1.match(context, pi)); - assert((context.end() - context.begin()) == 2); - assert(pi.get_substr(context.begin()) == "b"); - assert(pi.get_substr(context.begin() + 1) == "2"); + cap = context.all(); + assert(cap->c_begin == 0); + assert(cap->c_end == 3); + + assert((context.end() - context.begin()) == 2); + assert(pi.get_substr(context.begin()) == "a"); + assert(pi.get_substr(context.begin() + 1) == "1"); + assert(pi.get_substr(context[1]) == "1"); + + assert(match1.match(context, pi)); + assert((context.end() - context.begin()) == 2); + assert(pi.get_substr(context.begin()) == "b"); + assert(pi.get_substr(context.begin() + 1) == "2"); } { - pcrepp match2(""); + pcrepp match2(""); } - + + { + pcrepp match3("(?\\d+)(?\\w+)"); + pcre_named_capture::iterator iter; + const char *expected_names[] = { + "var1", + "var2", + }; + int index = 0; + + for (iter = match3.named_begin(); + iter != match3.named_end(); + ++iter, index++) { + assert(strcmp(iter->pnc_name, expected_names[index]) == 0); + } + + assert(match3.name_index("var2") == 1); + + pcre_input pi("123foo"); + + match3.match(context, pi); + assert(pi.get_substr(context["var1"]) == "123"); + } + return retval; }