aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cfile.h1
-rw-r--r--docbook/release-notes.asciidoc1
-rw-r--r--file.c103
-rw-r--r--ui/gtk/find_dlg.c1
-rw-r--r--ui/qt/search_frame.cpp68
-rw-r--r--ui/qt/search_frame.h4
-rw-r--r--ui/qt/search_frame.ui7
7 files changed, 146 insertions, 39 deletions
diff --git a/cfile.h b/cfile.h
index 5d40dd8ce1..7c270608f8 100644
--- a/cfile.h
+++ b/cfile.h
@@ -103,6 +103,7 @@ typedef struct _capture_file {
gboolean packet_data; /* TRUE if "String" search in "Packet data" was last selected */
guint32 search_pos; /* Byte position of last byte found in a hex search */
gboolean case_type; /* TRUE if case-insensitive text search */
+ GRegex *regex; /* Set if regular expression search */
search_charset_t scs_type; /* Character set for text search */
search_direction dir; /* Direction in which to do searches */
gboolean search_in_progress; /* TRUE if user just clicked OK in the Find dialog or hit <control>N/B */
diff --git a/docbook/release-notes.asciidoc b/docbook/release-notes.asciidoc
index 3243c621c3..179809fe3a 100644
--- a/docbook/release-notes.asciidoc
+++ b/docbook/release-notes.asciidoc
@@ -28,6 +28,7 @@ since version 2.0.0:
** You can now switch between between Capture and File Format dissection of
the current capture file via the View menu in the Qt GUI.
** You can now show selected packet bytes as ASCII, HTML, Image, ISO 8859-1, Raw or UTF-8.
+** You can now use regular expressions in Find Packet.
//=== Removed Dissectors
diff --git a/file.c b/file.c
index f576cb8d25..10290dd2c8 100644
--- a/file.c
+++ b/file.c
@@ -118,6 +118,8 @@ static match_result match_wide(capture_file *cf, frame_data *fdata,
void *criterion);
static match_result match_binary(capture_file *cf, frame_data *fdata,
void *criterion);
+static match_result match_regex(capture_file *cf, frame_data *fdata,
+ void *criterion);
static match_result match_dfilter(capture_file *cf, frame_data *fdata,
void *criterion);
static match_result match_marked(capture_file *cf, frame_data *fdata,
@@ -2896,22 +2898,30 @@ match_subtree_text(proto_node *node, gpointer data)
proto_item_fill_label(fi, label_str);
}
- /* Does that label match? */
- label_len = strlen(label_ptr);
- for (i = 0; i < label_len; i++) {
- c_char = label_ptr[i];
- if (cf->case_type)
- c_char = g_ascii_toupper(c_char);
- if (c_char == string[c_match]) {
- c_match++;
- if (c_match == string_len) {
- /* No need to look further; we have a match */
- mdata->frame_matched = TRUE;
- mdata->finfo = fi;
- return;
- }
- } else
- c_match = 0;
+ if (cf->regex) {
+ if (g_regex_match(cf->regex, label_ptr, (GRegexMatchFlags) 0, NULL)) {
+ mdata->frame_matched = TRUE;
+ mdata->finfo = fi;
+ return;
+ }
+ } else {
+ /* Does that label match? */
+ label_len = strlen(label_ptr);
+ for (i = 0; i < label_len; i++) {
+ c_char = label_ptr[i];
+ if (cf->case_type)
+ c_char = g_ascii_toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ /* No need to look further; we have a match */
+ mdata->frame_matched = TRUE;
+ mdata->finfo = fi;
+ return;
+ }
+ } else
+ c_match = 0;
+ }
}
/* Recurse into the subtree, if it exists */
@@ -2963,18 +2973,25 @@ match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
/* Found it. See if we match. */
info_column = edt.pi.cinfo->columns[colx].col_data;
info_column_len = strlen(info_column);
- for (i = 0; i < info_column_len; i++) {
- c_char = info_column[i];
- if (cf->case_type)
- c_char = g_ascii_toupper(c_char);
- if (c_char == string[c_match]) {
- c_match++;
- if (c_match == string_len) {
- result = MR_MATCHED;
- break;
- }
- } else
- c_match = 0;
+ if (cf->regex) {
+ if (g_regex_match(cf->regex, info_column, (GRegexMatchFlags) 0, NULL)) {
+ result = MR_MATCHED;
+ break;
+ }
+ } else {
+ for (i = 0; i < info_column_len; i++) {
+ c_char = info_column[i];
+ if (cf->case_type)
+ c_char = g_ascii_toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ result = MR_MATCHED;
+ break;
+ }
+ } else
+ c_match = 0;
+ }
}
break;
}
@@ -3008,8 +3025,11 @@ cf_find_packet_data(capture_file *cf, const guint8 *string, size_t string_size,
info.data = string;
info.data_len = string_size;
- /* String or hex search? */
- if (cf->string) {
+ /* Regex, String or hex search? */
+ if (cf->regex) {
+ /* Regular Expression search */
+ return find_packet(cf, match_regex, NULL, dir);
+ } else if (cf->string) {
/* String search - what type of string? */
switch (cf->scs_type) {
@@ -3214,6 +3234,29 @@ match_binary(capture_file *cf, frame_data *fdata, void *criterion)
return result;
}
+static match_result
+match_regex(capture_file *cf, frame_data *fdata, void *criterion _U_)
+{
+ match_result result = MR_NOTMATCHED;
+ GMatchInfo *match_info = NULL;
+
+ /* Load the frame's data. */
+ if (!cf_read_record(cf, fdata)) {
+ /* Attempt to get the packet failed. */
+ return MR_ERROR;
+ }
+
+ if (g_regex_match_full(cf->regex, ws_buffer_start_ptr(&cf->buf), fdata->cap_len,
+ 0, (GRegexMatchFlags) 0, &match_info, NULL))
+ {
+ gint start_pos = 0, end_pos = 0;
+ g_match_info_fetch_pos (match_info, 0, &start_pos, &end_pos);
+ cf->search_pos = end_pos; /* TODO: use start_pos to show correct length for regex */
+ result = MR_MATCHED;
+ }
+ return result;
+}
+
gboolean
cf_find_packet_dfilter(capture_file *cf, dfilter_t *sfcode,
search_direction dir)
diff --git a/ui/gtk/find_dlg.c b/ui/gtk/find_dlg.c
index 1d3c7b59a5..7b85f07f7e 100644
--- a/ui/gtk/find_dlg.c
+++ b/ui/gtk/find_dlg.c
@@ -653,6 +653,7 @@ find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
cfile.string = string_search;
cfile.scs_type = scs_type;
cfile.case_type = case_type;
+ cfile.regex = NULL;
cfile.packet_data = packet_data;
cfile.decode_data = decode_data;
cfile.summary_data = summary_data;
diff --git a/ui/qt/search_frame.cpp b/ui/qt/search_frame.cpp
index 6fe3f2de03..c0c7f13c64 100644
--- a/ui/qt/search_frame.cpp
+++ b/ui/qt/search_frame.cpp
@@ -40,7 +40,8 @@ enum {
enum {
df_search_,
hex_search_,
- string_search_
+ string_search_,
+ regex_search_
};
enum {
@@ -52,7 +53,8 @@ enum {
SearchFrame::SearchFrame(QWidget *parent) :
AccordionFrame(parent),
sf_ui_(new Ui::SearchFrame),
- cap_file_(NULL)
+ cap_file_(NULL),
+ regex_(NULL)
{
sf_ui_->setupUi(this);
@@ -67,6 +69,9 @@ SearchFrame::SearchFrame(QWidget *parent) :
SearchFrame::~SearchFrame()
{
+ if (regex_) {
+ g_regex_unref(regex_);
+ }
delete sf_ui_;
}
@@ -138,6 +143,33 @@ void SearchFrame::keyPressEvent(QKeyEvent *event)
}
}
+bool SearchFrame::regexCompile()
+{
+ int flags = (G_REGEX_OPTIMIZE);
+ if (!sf_ui_->caseCheckBox->isChecked()) {
+ flags |= G_REGEX_CASELESS;
+ }
+
+ if (regex_) {
+ g_regex_unref(regex_);
+ }
+
+ if (sf_ui_->searchLineEdit->text().isEmpty()) {
+ regex_ = NULL;
+ return false;
+ }
+
+ GError *g_error = NULL;
+ regex_ = g_regex_new(sf_ui_->searchLineEdit->text().toUtf8().constData(),
+ (GRegexCompileFlags)flags, (GRegexMatchFlags) 0, &g_error);
+ if (g_error) {
+ regex_error_ = g_error->message;
+ g_error_free(g_error);
+ }
+
+ return regex_ ? true : false;
+}
+
void SearchFrame::updateWidgets()
{
if (cap_file_) {
@@ -147,12 +179,12 @@ void SearchFrame::updateWidgets()
return;
}
- bool enable = sf_ui_->searchTypeComboBox->currentIndex() == string_search_;
- sf_ui_->searchInComboBox->setEnabled(enable);
- sf_ui_->caseCheckBox->setEnabled(enable);
- sf_ui_->charEncodingComboBox->setEnabled(enable);
+ int search_type = sf_ui_->searchTypeComboBox->currentIndex();
+ sf_ui_->searchInComboBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
+ sf_ui_->caseCheckBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
+ sf_ui_->charEncodingComboBox->setEnabled(search_type == string_search_);
- switch (sf_ui_->searchTypeComboBox->currentIndex()) {
+ switch (search_type) {
case df_search_:
sf_ui_->searchLineEdit->checkDisplayFilter(sf_ui_->searchLineEdit->text());
break;
@@ -178,6 +210,13 @@ void SearchFrame::updateWidgets()
sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
}
break;
+ case regex_search_:
+ if (regexCompile()) {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
+ } else {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
+ }
+ break;
default:
// currentIndex is probably -1. Nothing is selected or list is empty.
return;
@@ -190,6 +229,11 @@ void SearchFrame::updateWidgets()
}
}
+void SearchFrame::on_caseCheckBox_toggled(bool)
+{
+ regexCompile();
+}
+
void SearchFrame::on_searchTypeComboBox_currentIndexChanged(int)
{
updateWidgets();
@@ -216,12 +260,14 @@ void SearchFrame::on_findButton_clicked()
cap_file_->hex = FALSE;
cap_file_->string = FALSE;
cap_file_->case_type = FALSE;
+ cap_file_->regex = NULL;
cap_file_->packet_data = FALSE;
cap_file_->decode_data = FALSE;
cap_file_->summary_data = FALSE;
cap_file_->scs_type = SCS_NARROW_AND_WIDE;
- switch (sf_ui_->searchTypeComboBox->currentIndex()) {
+ int search_type = sf_ui_->searchTypeComboBox->currentIndex();
+ switch (search_type) {
case df_search_:
if (!dfilter_compile(sf_ui_->searchLineEdit->text().toUtf8().constData(), &dfp, NULL)) {
err_string = tr("Invalid filter.");
@@ -245,6 +291,7 @@ void SearchFrame::on_findButton_clicked()
cap_file_->hex = TRUE;
break;
case string_search_:
+ case regex_search_:
if (sf_ui_->searchLineEdit->text().isEmpty()) {
err_string = tr("You didn't specify any text for which to search.");
emit pushFilterSyntaxStatus(err_string);
@@ -252,6 +299,7 @@ void SearchFrame::on_findButton_clicked()
}
cap_file_->string = TRUE;
cap_file_->case_type = sf_ui_->caseCheckBox->isChecked() ? FALSE : TRUE;
+ cap_file_->regex = (search_type == regex_search_ ? regex_ : NULL);
switch (sf_ui_->charEncodingComboBox->currentIndex()) {
case narrow_and_wide_chars_:
cap_file_->scs_type = SCS_NARROW_AND_WIDE;
@@ -305,6 +353,10 @@ void SearchFrame::on_findButton_clicked()
return;
}
} else if (cap_file_->string) {
+ if (search_type == regex_search_ && !cap_file_->regex) {
+ emit pushFilterSyntaxStatus(regex_error_);
+ return;
+ }
if (cap_file_->summary_data) {
/* String in the Info column of the summary line */
found_packet = cf_find_packet_summary_line(cap_file_, string, cap_file_->dir);
diff --git a/ui/qt/search_frame.h b/ui/qt/search_frame.h
index 9ba8c62c1c..ee895e0366 100644
--- a/ui/qt/search_frame.h
+++ b/ui/qt/search_frame.h
@@ -55,12 +55,16 @@ protected:
virtual void keyPressEvent(QKeyEvent *event);
private:
+ bool regexCompile();
void updateWidgets();
Ui::SearchFrame *sf_ui_;
capture_file *cap_file_;
+ GRegex *regex_;
+ QString regex_error_;
private slots:
+ void on_caseCheckBox_toggled(bool);
void on_searchTypeComboBox_currentIndexChanged(int);
void on_searchLineEdit_textChanged(const QString &);
void on_findButton_clicked();
diff --git a/ui/qt/search_frame.ui b/ui/qt/search_frame.ui
index e05a4ff06b..d2b9056118 100644
--- a/ui/qt/search_frame.ui
+++ b/ui/qt/search_frame.ui
@@ -106,7 +106,7 @@
<item>
<widget class="QComboBox" name="searchTypeComboBox">
<property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Search for data using display filter syntax (e.g. ip.addr==10.1.1.1), a hexadecimal string (e.g. fffffda5) or a plain string (e.g. My String).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Search for data using display filter syntax (e.g. ip.addr==10.1.1.1), a hexadecimal string (e.g. fffffda5), a plain string (e.g. My String) or a regular expression (e.g. colou?r).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
@@ -123,6 +123,11 @@
<string>String</string>
</property>
</item>
+ <item>
+ <property name="text">
+ <string>Regular Expression</string>
+ </property>
+ </item>
</widget>
</item>
<item>