Blame plugins/findinfiles/matcher.vala

Packit 6978fb
/*
Packit 6978fb
* Copyright (C) 2015 The Lemon Man
Packit 6978fb
*
Packit 6978fb
* This program is free software; you can redistribute it and/or modify
Packit 6978fb
* it under the terms of the GNU General Public License as published by
Packit 6978fb
* the Free Software Foundation; either version 2, or (at your option)
Packit 6978fb
* any later version.
Packit 6978fb
*
Packit 6978fb
* This program is distributed in the hope that it will be useful,
Packit 6978fb
* but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6978fb
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6978fb
* GNU General Public License for more details.
Packit 6978fb
*
Packit 6978fb
* You should have received a copy of the GNU General Public License
Packit 6978fb
* along with this program; if not, write to the Free Software
Packit 6978fb
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 6978fb
*/
Packit 6978fb
Packit 6978fb
namespace Gedit {
Packit 6978fb
namespace FindInFilesPlugin {
Packit 6978fb
Packit 6978fb
class RegexFind : Object, IMatcher {
Packit 6978fb
    private Regex re;
Packit 6978fb
Packit 6978fb
    public RegexFind (string pattern, bool ignore_case) throws Error {
Packit 6978fb
        var flags = RegexCompileFlags.OPTIMIZE;
Packit 6978fb
Packit 6978fb
        if (ignore_case)
Packit 6978fb
            flags |= RegexCompileFlags.CASELESS;
Packit 6978fb
Packit 6978fb
        re = new Regex (pattern, flags);
Packit 6978fb
    }
Packit 6978fb
Packit 6978fb
    public bool has_match (uint8 *text, size_t text_length, size_t pos, ref Range match) {
Packit 6978fb
        MatchInfo info;
Packit 6978fb
        int casted_pos;
Packit 6978fb
Packit 6978fb
        // Prevent an integer overflow when downcasting from size_t to int
Packit 6978fb
        if (pos > int.MAX) {
Packit 6978fb
            casted_pos = 0;
Packit 6978fb
            text += pos;
Packit 6978fb
        } else {
Packit 6978fb
            casted_pos = (int)pos;
Packit 6978fb
        }
Packit 6978fb
Packit 6978fb
        // Avoid strdup-ing the whole buffer
Packit 6978fb
        unowned string str = (string)text;
Packit 6978fb
Packit 6978fb
        // Pass the text length as str isn't null terminated
Packit 6978fb
        try {
Packit 6978fb
            if (!re.match_full (str, (ssize_t)text_length, casted_pos, 0, out info))
Packit 6978fb
                return false;
Packit 6978fb
        }
Packit 6978fb
        catch (RegexError err) {
Packit 6978fb
            warning (err.message);
Packit 6978fb
            return false;
Packit 6978fb
        }
Packit 6978fb
Packit 6978fb
        info.fetch_pos (0, out match.from, out match.to);
Packit 6978fb
Packit 6978fb
        return true;
Packit 6978fb
    }
Packit 6978fb
}
Packit 6978fb
Packit 6978fb
class BoyerMooreHorspool : Object, IMatcher {
Packit 6978fb
    private string pattern;
Packit 6978fb
    private int bad_char_shift[256];
Packit 6978fb
Packit 6978fb
    private bool ignore_case;
Packit 6978fb
Packit 6978fb
    public BoyerMooreHorspool (string pattern_, bool ignore_case_) {
Packit 6978fb
        pattern = pattern_;
Packit 6978fb
        ignore_case = ignore_case_;
Packit 6978fb
Packit 6978fb
        for (int i = 0; i < 256; i++) {
Packit 6978fb
            bad_char_shift[i] = pattern.length;
Packit 6978fb
        }
Packit 6978fb
Packit 6978fb
        for (int i = 0; i < pattern.length - 1; i++) {
Packit 6978fb
            if (ignore_case) {
Packit 6978fb
                bad_char_shift[Posix.toupper(pattern[i])] = pattern.length - 1 - i;
Packit 6978fb
                bad_char_shift[Posix.tolower(pattern[i])] = pattern.length - 1 - i;
Packit 6978fb
            } else {
Packit 6978fb
                bad_char_shift[pattern[i]] = pattern.length - 1 - i;
Packit 6978fb
            }
Packit 6978fb
        }
Packit 6978fb
    }
Packit 6978fb
Packit 6978fb
    public bool has_match (uint8 *text, size_t text_length, size_t pos, ref Range match) {
Packit 6978fb
        uint i = 0;
Packit 6978fb
Packit 6978fb
        text += pos;
Packit 6978fb
        text_length -= pos;
Packit 6978fb
Packit 6978fb
        if (text_length < pattern.length)
Packit 6978fb
            return false;
Packit 6978fb
Packit 6978fb
        while (i <= text_length - pattern.length) {
Packit 6978fb
            for (int j = pattern.length - 1; j >= 0; j--) {
Packit 6978fb
                // Check for a match backwards
Packit 6978fb
                if (ignore_case) {
Packit 6978fb
                    if (Posix.tolower(text[i + j]) != Posix.tolower(pattern[j]))
Packit 6978fb
                        break;
Packit 6978fb
                } else {
Packit 6978fb
                    if (text[i + j] != pattern[j])
Packit 6978fb
                        break;
Packit 6978fb
                }
Packit 6978fb
Packit 6978fb
                // The whole needle has been matched!
Packit 6978fb
                if (j == 0) {
Packit 6978fb
                    match.from = pos + i;
Packit 6978fb
                    match.to = match.from + pattern.length;
Packit 6978fb
                    return true;
Packit 6978fb
                }
Packit 6978fb
            }
Packit 6978fb
Packit 6978fb
            // Jump ahead in the buffer
Packit 6978fb
            i += bad_char_shift[text[i + pattern.length - 1]];
Packit 6978fb
        }
Packit 6978fb
Packit 6978fb
        return false;
Packit 6978fb
    }
Packit 6978fb
}
Packit 6978fb
Packit 6978fb
} // namespace FindInFilesPlugin
Packit 6978fb
} // namespace Gedit