/* * Sary::Searcher - a searcher class for Sary * * $Id: searcher.c,v 1.4 2005/02/04 04:33:45 knok Exp $ * * Copyright (C) 2000 TAKAOKA Kazuma * Copyright (C) 2002 Hiroyuki Komatsu * All right reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ #include #include #include "sary.h" #include "ruby.h" #include "version.h" #define GET_Searcher(obj, dat) Data_Get_Struct(obj, SarySearcher, dat) static VALUE SearcherClass; /* For Searcher class. */ static VALUE rsearcher_s_new(int argc, VALUE *argv, VALUE klass); static void rsearcher_destroy(SarySearcher *searcher); static VALUE rsearcher_search(VALUE klass, VALUE pattern); static VALUE rsearcher_multi_search(VALUE klass, VALUE pattern_array); static VALUE rsearcher_isearch(VALUE klass, VALUE pattern, VALUE len); static VALUE rsearcher_isearch_reset(VALUE klass); static VALUE rsearcher_icase_search(VALUE klass, VALUE pattern); static VALUE rsearcher_get_next_context_lines(int argc, VALUE *argv, VALUE klass); static VALUE rsearcher_get_next_tagged_region(VALUE klass, VALUE start_tag, VALUE end_tag); static VALUE rsearcher_each_context_lines(int argc, VALUE *argv, VALUE klass); static VALUE rsearcher_each_tagged_region(VALUE klass, VALUE start_tag, VALUE end_tag); static VALUE rsearcher_count_occurrences(VALUE klass); static VALUE rsearcher_get_offsets(VALUE klass); static VALUE rsearcher_get_line_by_offset(VALUE klass, VALUE offset); static VALUE rsearcher_get_ranges(VALUE klass); static VALUE rsearcher_get_line_by_range(VALUE klass, VALUE range); /* static VALUE rsearcher_sort_occurence(VALUE klass); */ static VALUE rsearcher_enable_cache(VALUE klass); /* * Initilize Searcher class instance. */ static VALUE rsearcher_s_new(int argc, VALUE *argv, VALUE klass) { NEWOBJ(data, struct RData); OBJSETUP(data, klass, T_DATA); rb_obj_call_init((VALUE)data, argc, argv); return (VALUE)data; } static VALUE rsearcher_initialize(int argc, VALUE *argv, VALUE klass) { SarySearcher *searcher; char *file_name_ptr; char *array_name_ptr; VALUE file_name, array_name; rb_scan_args(argc, argv, "11", &file_name, &array_name); Check_SafeStr(file_name); #if RUBY_VERSION_CODE >= 180 file_name_ptr = StringValuePtr(file_name); #else file_name_ptr = STR2CSTR(file_name); #endif if (array_name == Qnil) searcher = sary_searcher_new(file_name_ptr); else { Check_SafeStr(array_name); #if RUBY_VERSION_CODE >= 180 array_name_ptr = StringValuePtr(array_name); #else array_name_ptr = STR2CSTR(array_name); #endif searcher = sary_searcher_new2(file_name_ptr, array_name_ptr); } if (searcher == NULL) rb_raise(rb_eIOError, g_strerror(errno)); Check_Type(klass, T_DATA); RDATA(klass)->dfree = (RUBY_DATA_FUNC)rsearcher_destroy; RDATA(klass)->dmark = (RUBY_DATA_FUNC)0; DATA_PTR(klass) = searcher; return klass; } /* * Destroy instance. */ static void rsearcher_destroy(SarySearcher *searcher) { sary_searcher_destroy(searcher); } /* * Instance methods. */ static VALUE rsearcher_search(VALUE klass, VALUE pattern) { SarySearcher *searcher; char *pat; /* int count, len; */ int len; GET_Searcher(klass, searcher); Check_SafeStr(pattern); #if RUBY_VERSION_CODE >= 180 pat = StringValuePtr(pattern); len = RSTRING(pattern)->len; #else pat = str2cstr(pattern, &len); #endif if (sary_searcher_search2(searcher, pat, len)) return Qtrue; else return Qfalse; } static VALUE rsearcher_multi_search(VALUE klass, VALUE pattern_array) { SarySearcher *searcher; char **pat; /* int count, len, i; */ int len, i; VALUE pattern; GET_Searcher(klass, searcher); len = RARRAY(pattern_array)->len; if (len == 0) { return Qfalse; } pat = ALLOCA_N(char*, len); for (i = 0; i < len; i++) { pattern = rb_ary_entry(pattern_array, (long)i); Check_SafeStr(pattern); #if RUBY_VERSION_CODE >= 180 pat[i] = StringValuePtr(pattern); #else pat[i] = STR2CSTR(pattern); #endif } if (sary_searcher_multi_search(searcher, pat, len)) return Qtrue; else return Qfalse; } static VALUE rsearcher_isearch(VALUE klass, VALUE pattern, VALUE len) { SarySearcher *searcher; char *pat; /* int count; */ GET_Searcher(klass, searcher); Check_SafeStr(pattern); #if RUBY_VERSION_CODE >= 180 pat = StringValuePtr(pattern); #else pat = STR2CSTR(pattern); #endif if (sary_searcher_isearch(searcher, pat, NUM2INT(len))) return Qtrue; else return Qfalse; } static VALUE rsearcher_isearch_reset(VALUE klass) { SarySearcher *searcher; GET_Searcher(klass, searcher); sary_searcher_isearch_reset(searcher); return klass; } static VALUE rsearcher_icase_search(VALUE klass, VALUE pattern) { SarySearcher *searcher; char *pat; /* int count, len; */ int len; GET_Searcher(klass, searcher); Check_SafeStr(pattern); #if RUBY_VERSION_CODE >= 180 pat = StringValuePtr(pattern); len = RSTRING(pattern)->len; #else pat = str2cstr(pattern, &len); #endif if (sary_searcher_icase_search2(searcher, pat, len)) return Qtrue; else return Qfalse; } static VALUE rsearcher_get_next_context_lines(int argc, VALUE *argv, VALUE klass) { SarySearcher *searcher; VALUE bkwrd, frwrd; int bk, fr, len; char *region; GET_Searcher(klass, searcher); if (sary_searcher_count_occurrences(searcher) == 0) return Qnil; rb_scan_args(argc, argv, "02", &bkwrd, &frwrd); bk = (bkwrd == Qnil) ? 0 : NUM2INT(bkwrd); fr = (frwrd == Qnil) ? 0 : NUM2INT(frwrd); region = sary_searcher_get_next_context_lines2(searcher, bk, fr, &len); if (region == NULL) return Qnil; else return rb_str_new(region, len); } static VALUE rsearcher_get_next_tagged_region(VALUE klass, VALUE start_tag, VALUE end_tag) { SarySearcher *searcher; char* stag, *etag, *region; int slen, elen, rlen; GET_Searcher(klass, searcher); if (sary_searcher_count_occurrences(searcher) == 0) return Qnil; Check_SafeStr(start_tag); Check_SafeStr(end_tag); #if RUBY_VERSION_CODE >= 180 stag = StringValuePtr(start_tag); etag = StringValuePtr(end_tag); slen = RSTRING(stag)->len; elen = RSTRING(etag)->len; #else stag = rb_str2cstr(start_tag, &slen); etag = rb_str2cstr(end_tag, &elen); #endif region = sary_searcher_get_next_tagged_region2(searcher, stag, slen, etag, elen, &rlen); if (region == NULL) return Qnil; else return rb_str_new(region, rlen); } static VALUE rsearcher_each_context_lines(int argc, VALUE *argv, VALUE klass) { VALUE str; while (!NIL_P(str = rsearcher_get_next_context_lines(argc, argv, klass))) rb_yield(str); return klass; } static VALUE rsearcher_each_tagged_region(VALUE klass, VALUE start_tag, VALUE end_tag) { VALUE str; while (!NIL_P(str = rsearcher_get_next_tagged_region(klass, start_tag, end_tag))) rb_yield(str); return klass; } static VALUE rsearcher_count_occurrences(VALUE klass) { SarySearcher *searcher; GET_Searcher(klass, searcher); return INT2NUM(sary_searcher_count_occurrences(searcher)); } static VALUE rsearcher_get_offsets(VALUE klass) { SarySearcher *searcher; SaryText *text; long len, l; int tmp; gchar *bof, *cur; VALUE ary; GET_Searcher(klass, searcher); len = sary_searcher_count_occurrences(searcher); if (len == 0) return Qnil; ary = rb_ary_new2(len); text = sary_searcher_get_text(searcher); bof = text->bof; for (l = 0; l < len; l ++) { cur = sary_searcher_get_next_context_lines2(searcher, 0, 0, &tmp); rb_ary_store(ary, l, INT2NUM(cur - bof)); } return ary; } static VALUE rsearcher_get_line_by_offset(VALUE klass, VALUE offset) { SarySearcher *searcher; SaryText *text; int o, l; gchar *c; o = NUM2INT(offset); GET_Searcher(klass, searcher); text = sary_searcher_get_text(searcher); c = text->bof + o; sary_text_set_cursor(text, c); l = sary_text_get_linelen(text); return rb_str_new(c, l); } static VALUE rsearcher_get_ranges(VALUE klass) { SarySearcher *searcher; SaryText *text; long len, l; int tmp; gchar *bof, *cur; VALUE ary; GET_Searcher(klass, searcher); len = sary_searcher_count_occurrences(searcher); if (len == 0) return Qnil; ary = rb_ary_new2(len); text = sary_searcher_get_text(searcher); bof = text->bof; for (l = 0; l < len; l ++) { VALUE range; cur = sary_searcher_get_next_context_lines2(searcher, 0, 0, &tmp); range = rb_range_new(INT2NUM(cur - bof), INT2NUM(cur - bof + tmp + 1), 1); rb_ary_store(ary, l, range); } return ary; } static VALUE rsearcher_get_line_by_range(VALUE klass, VALUE range) { SarySearcher *searcher; SaryText *text; int o, l; gchar *c; ID first, last; first = rb_intern("first"); last = rb_intern("last"); o = NUM2INT(rb_funcall(range, first, 0, 0)); l = NUM2INT(rb_funcall(range, last, 0, 0)) - NUM2INT(rb_funcall(range, first, 0, 0)); if (rb_funcall(range, rb_intern("exclude_end?"), 0, 0)) l--; GET_Searcher(klass, searcher); text = sary_searcher_get_text(searcher); c = text->bof + o; sary_text_set_cursor(text, c); return rb_str_new(c, l); } static VALUE rsearcher_enable_cache(VALUE klass) { SarySearcher *searcher; GET_Searcher(klass, searcher); sary_searcher_enable_cache(searcher); return klass; } static VALUE rsearcher_sort_occurrences(VALUE klass) { SarySearcher *searcher; GET_Searcher(klass, searcher); if (sary_searcher_count_occurrences(searcher) != 0) sary_searcher_sort_occurrences(searcher); return klass; } /* * Initialize class */ void Init_sarysearcher(VALUE module) { SearcherClass = rb_define_class_under(module, "Searcher", rb_cObject); rb_define_singleton_method(SearcherClass, "new", rsearcher_s_new, -1); rb_define_method(SearcherClass, "initialize", rsearcher_initialize, -1); rb_define_method(SearcherClass, "search", rsearcher_search, 1); rb_define_method(SearcherClass, "multi_search", rsearcher_multi_search, 1); rb_define_method(SearcherClass, "isearch", rsearcher_isearch, 2); rb_define_method(SearcherClass, "isearch_reset", rsearcher_isearch_reset, 0); rb_define_method(SearcherClass, "icase_search", rsearcher_icase_search, 1); rb_define_method(SearcherClass, "get_next_context_lines", rsearcher_get_next_context_lines, -1); rb_define_method(SearcherClass, "get_next_context_line", rsearcher_get_next_context_lines, -1); rb_define_method(SearcherClass, "get_next_tagged_region", rsearcher_get_next_tagged_region, 2); rb_define_method(SearcherClass, "each_context_lines", rsearcher_each_context_lines, -1); rb_define_method(SearcherClass, "each_context_line", rsearcher_each_context_lines, -1); rb_define_method(SearcherClass, "each_tagged_region", rsearcher_each_tagged_region, 2); rb_define_method(SearcherClass, "count_occurrences", rsearcher_count_occurrences, 0); rb_define_method(SearcherClass, "sort_occurrences", rsearcher_sort_occurrences, 0); rb_define_method(SearcherClass, "get_offsets", rsearcher_get_offsets, 0); rb_define_method(SearcherClass, "get_line_by_offset", rsearcher_get_line_by_offset, 1); rb_define_method(SearcherClass, "get_ranges", rsearcher_get_ranges, 0); rb_define_method(SearcherClass, "get_line_by_range", rsearcher_get_line_by_range, 1); rb_define_method(SearcherClass, "enable_cache", rsearcher_enable_cache, 0); }