Commit 6996b0ef authored by Fabien Parent's avatar Fabien Parent
Browse files

Remove the dependency to libpcre.

parent c69ed423
......@@ -52,8 +52,6 @@ src_regexxer_SOURCES = \
src/mainwindow.cc \
src/mainwindow.h \
src/miscutils.h \
src/pcreshell.cc \
src/pcreshell.h \
src/prefdialog.cc \
src/prefdialog.h \
src/sharedptr.h \
......
......@@ -38,8 +38,8 @@ AM_GLIB_GNU_GETTEXT
# gmodule-export-2.0 adds -Wl,--export-dynamic to the linker flags
# so that libglade can get at the custom widget creation functions.
PKG_CHECK_MODULES([REGEXXER_MODULES],
[gtk+-2.0 >= 2.16.0 gtkmm-2.4 >= 2.12.0 gconfmm-2.6 >= 2.6.1
libpcre >= 5.0 gtksourceviewmm-2.0 >= 2.9.0])
[gtk+-2.0 >= 2.16.0 gtkmm-2.4 >= 2.12.0 glibmm-2.4 >= 2.27.4.1
gconfmm-2.6 >= 2.6.1 gtksourceviewmm-2.0 >= 2.9.0])
DK_PKG_PATH_PROG([GDK_PIXBUF_CSOURCE], [gdk-pixbuf-2.0], [gdk-pixbuf-csource])
DK_PKG_PATH_PROG([GTK_UPDATE_ICON_CACHE], [gtk+-2.0], [gtk-update-icon-cache])
......
......@@ -22,7 +22,6 @@
#include "filebufferundo.h"
#include "globalstrings.h"
#include "miscutils.h"
#include "pcreshell.h"
#include "stringutils.h"
#include "translation.h"
......@@ -254,7 +253,7 @@ bool FileBuffer::in_user_action() const
* If multiple is false then every line is matched only once, otherwise
* multiple matches per line will be found (like modifier /g in Perl).
*/
int FileBuffer::find_matches(Pcre::Pattern& pattern, bool multiple,
int FileBuffer::find_matches(const Glib::RefPtr<Glib::Regex>& pattern, bool multiple,
const sigc::slot<void, int, const Glib::ustring&>& feedback)
{
ScopedLock lock (*this);
......@@ -292,10 +291,12 @@ int FileBuffer::find_matches(Pcre::Pattern& pattern, bool multiple,
return match_count_;
}
const int capture_count =
pattern.match(subject, offset, (last_was_empty) ? Pcre::ANCHORED | Pcre::NOT_EMPTY
: Pcre::MatchOptions(0));
if (capture_count <= 0)
Glib::MatchInfo match_info;
bool is_matched =
pattern->match(subject, offset, match_info,
(last_was_empty) ? Glib::REGEX_MATCH_ANCHORED | Glib::REGEX_MATCH_NOTEMPTY
: static_cast<Glib::RegexMatchFlags>(0));
if (!is_matched)
{
if (last_was_empty && unsigned(offset) < subject.bytes())
{
......@@ -312,7 +313,8 @@ int FileBuffer::find_matches(Pcre::Pattern& pattern, bool multiple,
++match_count_;
++original_match_count_;
const std::pair<int, int> bounds = pattern.get_substring_bounds(0);
std::pair<int, int> bounds;
match_info.fetch_pos(0, bounds.first, bounds.second);
iterator start = line;
iterator stop = line;
......@@ -321,7 +323,7 @@ int FileBuffer::find_matches(Pcre::Pattern& pattern, bool multiple,
stop .set_line_index(bounds.second);
const MatchDataPtr match (new MatchData(
original_match_count_, subject, pattern, capture_count));
original_match_count_, subject, match_info));
match_set_.insert(match_set_.end(), match);
match->install_mark(start);
......
......@@ -50,7 +50,7 @@ public:
bool is_freeable() const;
bool in_user_action() const;
int find_matches(Pcre::Pattern& pattern, bool multiple,
int find_matches(const Glib::RefPtr<Glib::Regex>& pattern, bool multiple,
const sigc::slot<void, int, const Glib::ustring&>& feedback);
int get_match_count() const;
......
......@@ -19,7 +19,6 @@
*/
#include "fileshared.h"
#include "pcreshell.h"
#include <glib.h>
#include <algorithm>
......@@ -59,15 +58,20 @@ namespace Regexxer
/**** Regexxer::MatchData **************************************************/
MatchData::MatchData(int match_index, const Glib::ustring& line,
const Pcre::Pattern& pattern, int capture_count)
Glib::MatchInfo& match_info)
:
index (match_index),
subject (line)
{
int capture_count = match_info.get_match_count();
captures.reserve(capture_count);
for (int i = 0; i < capture_count; ++i)
captures.push_back(pattern.get_substring_bounds(i));
{
std::pair<int, int> bounds;
match_info.fetch_pos(i, bounds.first, bounds.second);
captures.push_back(bounds);
}
length = calculate_match_length(subject, captures.front());
}
......
......@@ -28,8 +28,6 @@
#include <utility>
#include <vector>
namespace Pcre { class Pattern; }
namespace Regexxer
{
......@@ -79,7 +77,7 @@ struct MatchData : public Util::SharedObject
Glib::RefPtr<Gtk::TextMark> mark;
MatchData(int match_index, const Glib::ustring& line,
const Pcre::Pattern& pattern, int capture_count);
Glib::MatchInfo& match_info);
~MatchData();
void install_mark(const Gtk::TextBuffer::iterator& pos);
......
......@@ -21,7 +21,6 @@
#include "filetree.h"
#include "filetreeprivate.h"
#include "globalstrings.h"
#include "pcreshell.h"
#include "stringutils.h"
#include "translation.h"
......@@ -106,7 +105,7 @@ FileTree::FileTree()
FileTree::~FileTree()
{}
void FileTree::find_files(const std::string& dirname, Pcre::Pattern& pattern,
void FileTree::find_files(const std::string& dirname, const Glib::RefPtr<Glib::Regex>& pattern,
bool recursive, bool hidden)
{
FindData find_data (pattern, recursive, hidden);
......@@ -224,7 +223,7 @@ BoundState FileTree::get_bound_state()
return bound;
}
void FileTree::find_matches(Pcre::Pattern& pattern, bool multiple)
void FileTree::find_matches(const Glib::RefPtr<Glib::Regex>& pattern, bool multiple)
{
{
Util::ScopedBlock block_conn (conn_match_count_);
......@@ -391,7 +390,7 @@ void FileTree::find_recursively(const std::string& dirname, FindData& find_data)
{
const ustring basename = Glib::filename_display_basename(fullname);
if (find_data.pattern.match(basename) > 0)
if (find_data.pattern->match(basename))
{
find_add_file(basename, fullname, find_data);
++file_count;
......
......@@ -33,7 +33,7 @@
#include <list>
namespace Gtk { class TreeStore; }
namespace Pcre { class Pattern; }
namespace Glib { class Regex; }
namespace Gnome { namespace Conf { class Value; } }
namespace Regexxer
......@@ -47,7 +47,7 @@ public:
FileTree();
virtual ~FileTree();
void find_files(const std::string& dirname, Pcre::Pattern& pattern,
void find_files(const std::string& dirname, const Glib::RefPtr<Glib::Regex>& pattern,
bool recursive, bool hidden);
int get_file_count() const;
......@@ -60,7 +60,7 @@ public:
BoundState get_bound_state();
void find_matches(Pcre::Pattern& pattern, bool multiple);
void find_matches(const Glib::RefPtr<Glib::Regex>& pattern, bool multiple);
long get_match_count() const;
void replace_all_matches(const Glib::ustring& substitution);
......
......@@ -192,7 +192,8 @@ const std::list<Glib::ustring>& FileTree::Error::get_error_list() const
/**** Regexxer::FileTree::FindData *****************************************/
FileTree::FindData::FindData(Pcre::Pattern& pattern_, bool recursive_, bool hidden_)
FileTree::FindData::FindData(const Glib::RefPtr<Glib::Regex>& pattern_,
bool recursive_, bool hidden_)
:
pattern (pattern_),
recursive (recursive_),
......@@ -205,7 +206,8 @@ FileTree::FindData::~FindData()
/**** Regexxer::FileTree::FindMatchesData **********************************/
FileTree::FindMatchesData::FindMatchesData(Pcre::Pattern& pattern_, bool multiple_)
FileTree::FindMatchesData::FindMatchesData(const Glib::RefPtr<Glib::Regex>& pattern_,
bool multiple_)
:
pattern (pattern_),
multiple (multiple_),
......
......@@ -117,10 +117,10 @@ private:
struct FileTree::FindData
{
FindData(Pcre::Pattern& pattern_, bool recursive_, bool hidden_);
FindData(const Glib::RefPtr<Glib::Regex>& pattern_, bool recursive_, bool hidden_);
~FindData();
Pcre::Pattern& pattern;
const Glib::RefPtr<Glib::Regex>& pattern;
const bool recursive;
const bool hidden;
FileTreePrivate::DirStack dirstack;
......@@ -133,11 +133,11 @@ private:
struct FileTree::FindMatchesData
{
FindMatchesData(Pcre::Pattern& pattern_, bool multiple_);
FindMatchesData(const Glib::RefPtr<Glib::Regex>& pattern_, bool multiple_);
Pcre::Pattern& pattern;
const bool multiple;
bool path_match_first_set;
const Glib::RefPtr<Glib::Regex>& pattern;
const bool multiple;
bool path_match_first_set;
private:
FindMatchesData(const FileTree::FindMatchesData&);
......
......@@ -21,7 +21,6 @@
#include "mainwindow.h"
#include "filetree.h"
#include "globalstrings.h"
#include "pcreshell.h"
#include "prefdialog.h"
#include "statusline.h"
#include "stringutils.h"
......@@ -545,13 +544,15 @@ void MainWindow::on_find_files()
try
{
Pcre::Pattern pattern (Util::shell_pattern_to_regex(combo_entry_pattern_->get_entry()->get_text()), Pcre::DOTALL);
Glib::RefPtr<Glib::Regex> pattern = Glib::Regex::create(
Util::shell_pattern_to_regex(combo_entry_pattern_->get_entry()->get_text()),
Glib::REGEX_DOTALL);
filetree_->find_files(folder, pattern,
button_recursive_->get_active(),
button_hidden_->get_active());
}
catch (const Pcre::Error&)
catch (const Glib::RegexError&)
{
Gtk::MessageDialog dialog (*window_, _("The file search pattern is invalid."),
false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
......@@ -580,24 +581,18 @@ void MainWindow::on_exec_search()
try
{
Pcre::Pattern pattern (regex, (caseless) ? Pcre::CASELESS : Pcre::CompileOptions(0));
Glib::RefPtr<Glib::Regex> pattern =
Glib::Regex::create(regex, (caseless) ? Glib::REGEX_CASELESS
: static_cast<Glib::RegexCompileFlags>(0));
filetree_->find_matches(pattern, multiple);
}
catch (const Pcre::Error& error)
catch (const Glib::RegexError& error)
{
Gtk::MessageDialog dialog (*window_, error.what(), false,
Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
dialog.run();
const int offset = error.offset();
if (offset >= 0 && offset < entry_regex_->get_text_length())
{
entry_regex_->grab_focus();
entry_regex_->select_region(offset, offset + 1);
}
return;
}
......
/*
* Copyright (c) 2002-2007 Daniel Elstner <daniel.kitta@gmail.com>
*
* This file is part of regexxer.
*
* regexxer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* regexxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with regexxer; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "pcreshell.h"
#include "miscutils.h"
#include "stringutils.h"
#include "translation.h"
#include <pcre.h>
#include <glib.h>
#include <glibmm.h>
#include <algorithm>
namespace
{
static
int byte_to_char_offset(Glib::ustring::const_iterator start, int byte_offset)
{
return std::distance(start, Glib::ustring::const_iterator(start.base() + byte_offset));
}
/*
* Explicitely forbid any usage of the \C escape to match a single byte.
* Having Pcre::Pattern::match() return matches on partial UTF-8 characters
* would make regexxer crash faster than you can say "illegal sequence!"
*/
static
void check_for_single_byte_escape(const Glib::ustring& regex)
{
using std::string;
string::size_type index = 0;
while ((index = regex.raw().find("\\C", index, 2)) != string::npos)
{
// Find the first of a sequence of backslashes preceding 'C'.
string::size_type rewind = regex.raw().find_last_not_of('\\', index);
rewind = (rewind != string::npos) ? rewind + 1 : 0;
// The \C we found is a real \C escape only if preceded by an even number
// of backslashes. If this holds true, let's stage a right little tantrum.
if ((index - rewind) % 2 == 0)
{
throw Pcre::Error(_("Using the \\C escape sequence to match a single byte is not supported."),
byte_to_char_offset(regex.begin(), index + 1));
}
index += 2;
}
}
static
void throw_regex_error(const Glib::ustring&, int, const char*) G_GNUC_NORETURN;
static
void throw_regex_error(const Glib::ustring& regex, int byte_offset, const char* message)
{
using Glib::ustring;
const ustring what = (message) ? Glib::locale_to_utf8(message) : Glib::ustring();
if (byte_offset >= 0 && unsigned(byte_offset) < regex.raw().size())
{
const int offset = byte_to_char_offset(regex.begin(), byte_offset);
const gunichar error_char = *ustring::const_iterator(regex.raw().begin() + byte_offset);
throw Pcre::Error(Util::compose(
_("Error in regular expression at \342\200\234%1\342\200\235 (index %2):\n%3"),
ustring(1, error_char), Util::int_to_string(offset + 1), what), offset);
}
else
{
throw Pcre::Error(Util::compose(_("Error in regular expression:\n%1"), what));
}
}
} // anonymous namespace
namespace Pcre
{
/**** Pcre::Error **********************************************************/
Error::Error(const Glib::ustring& message, int offset)
:
message_ (message),
offset_ (offset)
{}
Error::~Error()
{}
Error::Error(const Error& other)
:
message_ (other.message_),
offset_ (other.offset_)
{}
Error& Error::operator=(const Error& other)
{
// Note that this is exception safe because only the first assignment below
// could throw. If that changes the copy-and-swap technique should be used
// instead.
message_ = other.message_;
offset_ = other.offset_;
return *this;
}
/**** Pcre::Pattern ********************************************************/
Pattern::Pattern(const Glib::ustring& regex, CompileOptions options)
:
pcre_ (0),
ovector_ (0),
ovecsize_ (0)
{
check_for_single_byte_escape(regex);
const char* error_message = 0;
int error_offset = -1;
pcre_ = pcre_compile(regex.c_str(), options | PCRE_UTF8, &error_message, &error_offset, 0);
if (!pcre_)
throw_regex_error(regex, error_offset, error_message);
int capture_count = 0;
const int result G_GNUC_UNUSED = pcre_fullinfo(static_cast<pcre*>(pcre_), 0,
PCRE_INFO_CAPTURECOUNT, &capture_count);
g_assert(result == 0);
g_assert(capture_count >= 0);
ovecsize_ = 3 * (capture_count + 1);
ovector_ = g_new0(int, ovecsize_);
}
Pattern::~Pattern()
{
g_free(ovector_);
(*pcre_free)(pcre_);
}
int Pattern::match(const Glib::ustring& subject, int offset, MatchOptions options)
{
const int captures = pcre_exec(static_cast<pcre*>(pcre_), 0, subject.raw().data(),
subject.raw().size(), offset, options, ovector_, ovecsize_);
if (captures >= 0 || captures == PCRE_ERROR_NOMATCH)
return captures;
// Of all possible error conditions pcre_exec() might return, hitting
// the match limit is the only one that could be triggered by user input.
if (captures == PCRE_ERROR_MATCHLIMIT)
throw Error(_("Reached the recursion and backtracking limit of the regular expression engine."));
g_return_val_if_reached(captures);
}
std::pair<int, int> Pattern::get_substring_bounds(int index) const
{
g_return_val_if_fail(index >= 0 && 3 * index < ovecsize_, std::make_pair(-1, -1));
return std::make_pair(ovector_[2 * index], ovector_[2 * index + 1]);
}
Glib::ustring Pattern::get_substring(const Glib::ustring& subject, int index) const
{
const std::pair<int, int> bounds = get_substring_bounds(index);
if (bounds.first >= 0 && bounds.first < bounds.second)
{
const char *const data = subject.data();
return Glib::ustring(data + bounds.first, data + bounds.second);
}
return Glib::ustring();
}
} // namespace Pcre
/*
* Copyright (c) 2002-2007 Daniel Elstner <daniel.kitta@gmail.com>
*
* This file is part of regexxer.
*
* regexxer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* regexxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with regexxer; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef REGEXXER_PCRESHELL_H_INCLUDED
#define REGEXXER_PCRESHELL_H_INCLUDED
#include <glibmm/ustring.h>
#include <utility>
namespace Pcre
{
/*
* The numeric values are copied from pcre.h. This is quite safe
* because they cannot be changed without breaking ABI.
*/
enum CompileOptions
{
CASELESS = 0x0001,
MULTILINE = 0x0002,
DOTALL = 0x0004,
EXTENDED = 0x0008,
DOLLAR_ENDONLY = 0x0020,
EXTRA = 0x0040,
UNGREEDY = 0x0200
};
inline CompileOptions operator|(CompileOptions lhs, CompileOptions rhs)
{ return static_cast<CompileOptions>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)); }
inline CompileOptions operator&(CompileOptions lhs, CompileOptions rhs)
{ return static_cast<CompileOptions>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)); }
inline CompileOptions operator^(CompileOptions lhs, CompileOptions rhs)
{ return static_cast<CompileOptions>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)); }
inline CompileOptions operator~(CompileOptions flags)
{ return static_cast<CompileOptions>(~static_cast<unsigned>(flags)); }
inline CompileOptions& operator|=(CompileOptions& lhs, CompileOptions rhs)
{ return (lhs = static_cast<CompileOptions>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs))); }
inline CompileOptions& operator&=(CompileOptions& lhs, CompileOptions rhs)
{ return (lhs = static_cast<CompileOptions>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs))); }
inline CompileOptions& operator^=(CompileOptions& lhs, CompileOptions rhs)
{ return (lhs = static_cast<CompileOptions>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs))); }
/*
* The numeric values are copied from pcre.h. This is quite safe
* because they cannot be changed without breaking ABI.
*/
enum MatchOptions
{
ANCHORED = 0x0010,
NOT_BOL = 0x0080,
NOT_EOL = 0x0100,
NOT_EMPTY = 0x0400
};
inline MatchOptions operator|(MatchOptions lhs, MatchOptions rhs)
{ return static_cast<MatchOptions>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs)); }
inline MatchOptions operator&(MatchOptions lhs, MatchOptions rhs)
{ return static_cast<MatchOptions>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs)); }
inline MatchOptions operator^(MatchOptions lhs, MatchOptions rhs)
{ return static_cast<MatchOptions>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs)); }
inline MatchOptions operator~(MatchOptions flags)
{ return static_cast<MatchOptions>(~static_cast<unsigned>(flags)); }
inline MatchOptions& operator|=(MatchOptions& lhs, MatchOptions rhs)
{ return (lhs = static_cast<MatchOptions>(static_cast<unsigned>(lhs) | static_cast<unsigned>(rhs))); }
inline MatchOptions& operator&=(MatchOptions& lhs, MatchOptions rhs)
{ return (lhs = static_cast<MatchOptions>(static_cast<unsigned>(lhs) & static_cast<unsigned>(rhs))); }
inline MatchOptions& operator^=(MatchOptions& lhs, MatchOptions rhs)
{ return (lhs = static_cast<MatchOptions>(static_cast<unsigned>(lhs) ^ static_cast<unsigned>(rhs))); }
class Error
{
public:
explicit Error(const Glib::ustring& message, int offset = -1);
virtual ~Error();
Error(const Error& other);
Error& operator=(const Error& other);
Glib::ustring what() const { return message_; }
int offset() const { return offset_; } // in characters
private:
Glib::ustring message_;
int offset_;
};
/*
* Pcre::Pattern represents a compiled regular expression.
* Note that all offset values are in bytes, not characters. <