1 %module xapian
2 %{
3 /* perl.i: SWIG interface file for the Perl bindings
4 *
5 * Copyright (C) 2009 Kosei Moriyama
6 * Copyright (C) 2011,2012,2013,2015,2016,2019,2020 Olly Betts
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23 %}
24
25 %begin %{
26 // Older Perl headers contain things which cause warnings with more recent
27 // C++ compilers. There's nothing we can really do about them, so just
28 // suppress them.
29 #ifdef __clang__
30 # pragma clang diagnostic push
31 # pragma clang diagnostic ignored "-Wreserved-user-defined-literal"
32 #elif defined __GNUC__
33 // Warning added in GCC 4.8 and we don't support anything older.
34 # pragma GCC diagnostic push
35 # pragma GCC diagnostic ignored "-Wliteral-suffix"
36 #endif
37
38 extern "C" {
39 #include "EXTERN.h"
40 #include "perl.h"
41 #include "XSUB.h"
42 }
43
44 #ifdef __clang__
45 # pragma clang diagnostic pop
46 #elif defined __GNUC__
47 # pragma GCC diagnostic pop
48 #endif
49 %}
50
51 /* The XS Xapian never wrapped these, and they're now deprecated. */
52 #define XAPIAN_BINDINGS_SKIP_DEPRECATED_DB_FACTORIES
53
54 %include ../xapian-head.i
55
56 /* "next" is a keyword in Perl. */
57 %rename(increment_weight) *::next(double min_wt);
58
59 /* Wrapping constant values. */
60 %constant int OP_AND = Xapian::Query::OP_AND;
61 %constant int OP_OR = Xapian::Query::OP_OR;
62 %constant int OP_AND_NOT = Xapian::Query::OP_AND_NOT;
63 %constant int OP_XOR = Xapian::Query::OP_XOR;
64 %constant int OP_AND_MAYBE = Xapian::Query::OP_AND_MAYBE;
65 %constant int OP_FILTER = Xapian::Query::OP_FILTER;
66 %constant int OP_NEAR = Xapian::Query::OP_NEAR;
67 %constant int OP_PHRASE = Xapian::Query::OP_PHRASE;
68 %constant int OP_VALUE_RANGE = Xapian::Query::OP_VALUE_RANGE;
69 %constant int OP_SCALE_WEIGHT = Xapian::Query::OP_SCALE_WEIGHT;
70 %constant int OP_ELITE_SET = Xapian::Query::OP_ELITE_SET;
71 %constant int OP_VALUE_GE = Xapian::Query::OP_VALUE_GE;
72 %constant int OP_SYNONYM = Xapian::Query::OP_SYNONYM;
73 %constant int OP_MAX = Xapian::Query::OP_MAX;
74 %constant int OP_WILDCARD = Xapian::Query::OP_WILDCARD;
75 %constant int OP_VALUE_LE = Xapian::Query::OP_VALUE_LE;
76 %constant int OP_INVALID = Xapian::Query::OP_INVALID;
77 %constant int ENQ_ASCENDING = Xapian::Enquire::ASCENDING;
78 %constant int ENQ_DESCENDING = Xapian::Enquire::DESCENDING;
79 %constant int ENQ_DONT_CARE = Xapian::Enquire::DONT_CARE;
80 %constant int FLAG_BOOLEAN = Xapian::QueryParser::FLAG_BOOLEAN;
81 %constant int FLAG_PHRASE = Xapian::QueryParser::FLAG_PHRASE;
82 %constant int FLAG_LOVEHATE = Xapian::QueryParser::FLAG_LOVEHATE;
83 %constant int FLAG_BOOLEAN_ANY_CASE = Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE;
84 %constant int FLAG_WILDCARD = Xapian::QueryParser::FLAG_WILDCARD;
85 %constant int FLAG_PURE_NOT = Xapian::QueryParser::FLAG_PURE_NOT;
86 %constant int FLAG_PARTIAL = Xapian::QueryParser::FLAG_PARTIAL;
87 %constant int FLAG_SPELLING_CORRECTION = Xapian::QueryParser::FLAG_SPELLING_CORRECTION;
88 %constant int FLAG_SYNONYM = Xapian::QueryParser::FLAG_SYNONYM;
89 %constant int FLAG_AUTO_SYNONYMS = Xapian::QueryParser::FLAG_AUTO_SYNONYMS;
90 %constant int FLAG_AUTO_MULTIWORD_SYNONYMS = Xapian::QueryParser::FLAG_AUTO_MULTIWORD_SYNONYMS;
91 %constant int FLAG_CJK_NGRAM = Xapian::QueryParser::FLAG_CJK_NGRAM;
92 %constant int FLAG_DEFAULT = Xapian::QueryParser::FLAG_DEFAULT;
93 %constant int STEM_NONE = Xapian::QueryParser::STEM_NONE;
94 %constant int STEM_SOME = Xapian::QueryParser::STEM_SOME;
95 %constant int STEM_SOME_FULL_POS = Xapian::QueryParser::STEM_SOME_FULL_POS;
96 %constant int STEM_ALL = Xapian::QueryParser::STEM_ALL;
97 %constant int STEM_ALL_Z = Xapian::QueryParser::STEM_ALL_Z;
98 %constant int FLAG_SPELLING = Xapian::TermGenerator::FLAG_SPELLING;
99 // FLAG_CJK_NGRAM already set above from QueryParser (values match).
100 %constant int WILDCARD_LIMIT_ERROR = Xapian::Query::WILDCARD_LIMIT_ERROR;
101 %constant int WILDCARD_LIMIT_FIRST = Xapian::Query::WILDCARD_LIMIT_FIRST;
102 %constant int WILDCARD_LIMIT_MOST_FREQUENT = Xapian::Query::WILDCARD_LIMIT_MOST_FREQUENT;
103
104 /* Xapian::Enquire */
105 %feature("shadow") Xapian::Enquire::get_mset
106 %{
107 sub get_mset {
108 my $self = $_[0];
109 my $nargs = scalar(@_);
110 if( $nargs == 4 ) {
111 my $type = ref( $_[2] );
112 if ( $type eq 'Xapian::RSet' ) {
113 # get_mset(first, max, rset)
114 splice @_, 2, 0, (0); # insert checkatleast
115 }
116 }
117 return Xapianc::Enquire_get_mset( @_ );
118 }
119 %}
120
121 %feature("shadow") Xapian::Enquire::set_query
122 %{
123 sub set_query {
124 if (ref($_[1]) ne 'Xapian::Query') {
125 push @_, Xapian::Query->new(splice @_, 1);
126 }
127 Xapianc::Enquire_set_query(@_);
128 }
129 %}
130
131 %feature("shadow") Xapian::Enquire::set_sort_by_key
132 %{
133 sub set_sort_by_key {
134 my $self = $_[0];
135 my $sorter = $_[1];
136 $self{_sorter} = $sorter;
137 Xapianc::Enquire_set_sort_by_key( @_ );
138 }
139 %}
140
141 %feature("shadow") Xapian::Enquire::set_sort_by_key_then_relevance
142 %{
143 sub set_sort_by_key_then_relevance {
144 my $self = $_[0];
145 my $sorter = $_[1];
146 $self{_sorter} = $sorter;
147 Xapianc::Enquire_set_sort_by_key_then_relevance( @_ );
148 }
149 %}
150
151 %feature("shadow") Xapian::Enquire::set_sort_by_relevance_then_key
152 %{
153 sub set_sort_by_relevance_then_key {
154 my $self = $_[0];
155 my $sorter = $_[1];
156 $self{_sorter} = $sorter;
157 Xapianc::Enquire_set_sort_by_relevance_then_key( @_ );
158 }
159 %}
160
161 /* Xapian::Enquire */
162 %extend Xapian::Enquire {
163 // For compatibility with Search::Xapian.
get_mset(Xapian::doccount first,Xapian::doccount maxitems,const Xapian::MatchDecider * mdecider)164 Xapian::MSet get_mset(Xapian::doccount first,
165 Xapian::doccount maxitems,
166 const Xapian::MatchDecider* mdecider) {
167 return $self->get_mset(first, maxitems, 0, NULL, mdecider);
168 }
169 }
170
171 /* Xapian::ESet */
172 %extend Xapian::ESet {
FETCH(int index)173 Xapian::ESetIterator FETCH(int index) {
174 return ((*self)[index]);
175 }
176 }
177
178 /* Xapian::ESetIterator */
179 %extend Xapian::ESetIterator {
get_termname()180 std::string get_termname() {
181 return self->operator*();
182 }
183 }
184
185 /* Xapian::MSet */
186 %extend Xapian::MSet {
FETCH(int index)187 Xapian::MSetIterator FETCH(int index) {
188 return ((*self)[index]);
189 }
190 }
191
192 /* Xapian::Query */
193 %feature("shadow") Xapian::Query::Query
194 %{
195 sub new {
196 my $class = shift;
197 my $query;
198
199 if( @_ <= 1 ) {
200 $query = Xapianc::new_Query(@_);
201 } else {
202 use Carp;
203 my $op = $_[0];
204 if( $op !~ /^\d+$/ ) {
205 Carp::croak( "USAGE: $class->new('term') or $class->new(OP, <args>)" );
206 }
207 if( $op == 8 ) { # FIXME: 8 is OP_VALUE_RANGE; eliminate hardcoded literal
208 if( @_ != 4 ) {
209 Carp::croak( "USAGE: $class->new(OP_VALUE_RANGE, VALNO, START, END)" );
210 }
211 $query = Xapianc::new_Query( @_ );
212 } elsif( $op == 9 ) { # FIXME: OP_SCALE_WEIGHT
213 if( @_ != 3 ) {
214 Carp::croak( "USAGE: $class->new(OP_SCALE_WEIGHT, QUERY, FACTOR)" );
215 }
216 $query = Xapianc::new_Query( @_ );
217 } elsif( $op == 11 || $op == 12 ) { # FIXME: OP_VALUE_GE, OP_VALUE_LE; eliminate hardcoded literals
218 if( @_ != 3 ) {
219 Carp::croak( "USAGE: $class->new(OP_VALUE_[GL]E, VALNO, LIMIT)" );
220 }
221 $query = Xapianc::new_Query( @_ );
222 } else {
223 shift @_;
224 $query = Xapian::newN( $op, \@_ );
225 }
226 }
227 return $query;
228 }
229 %}
230
231 %typemap(in) SV ** {
232 AV *tempav;
233 I32 len;
234 int i;
235 SV **tv;
236 if (!SvROK($input))
237 croak("Argument $argnum is not a reference.");
238 if (SvTYPE(SvRV($input)) != SVt_PVAV)
239 croak("Argument $argnum is not an array.");
240 tempav = (AV*)SvRV($input);
241 len = av_len(tempav);
242 $1 = (SV **) malloc((len+2)*sizeof(SV *));
243 for (i = 0; i <= len; i++) {
244 tv = av_fetch(tempav, i, 0);
245 $1[i] = *tv;
246 }
247 $1[i] = NULL;
248 };
249
250 %typemap(freearg) SV ** {
251 free($1);
252 }
253
254 %{
255 class XapianSWIGQueryItor {
256 AV * array;
257
258 int i;
259
260 public:
XapianSWIGQueryItor()261 XapianSWIGQueryItor() { }
262
begin(AV * array_)263 void begin(AV * array_) {
264 array = array_;
265 i = 0;
266 }
267
end(int n)268 void end(int n) {
269 i = n;
270 }
271
272 XapianSWIGQueryItor & operator++() {
273 ++i;
274 return *this;
275 }
276
277 Xapian::Query operator*() const {
278 SV **svp = av_fetch(array, i, 0);
279 if( svp == NULL )
280 croak("Unexpected NULL returned by av_fetch()");
281 SV *sv = *svp;
282
283 if (!SvOK(sv)) {
284 croak("USAGE: Xapian::Query->new(OP, @TERMS_OR_QUERY_OBJECTS)");
285 }
286
287 Xapian::Query *q;
288 if (SWIG_ConvertPtr(sv, (void**)&q,
289 SWIGTYPE_p_Xapian__Query, 0) == SWIG_OK) {
290 return *q;
291 }
292
293 STRLEN len;
294 const char * ptr = SvPV(sv, len);
295 return Xapian::Query(string(ptr, len));
296 }
297
298 bool operator==(const XapianSWIGQueryItor & o) {
299 return i == o.i;
300 }
301
302 bool operator!=(const XapianSWIGQueryItor & o) {
303 return !(*this == o);
304 }
305
306 typedef std::input_iterator_tag iterator_category;
307 typedef Xapian::Query value_type;
308 typedef Xapian::termcount_diff difference_type;
309 typedef Xapian::Query * pointer;
310 typedef Xapian::Query & reference;
311 };
312
313 %}
314
315 %inline %{
newN(int op_,SV * q_)316 Xapian::Query * newN(int op_, SV *q_) {
317 Xapian::Query::op op = (Xapian::Query::op)op_;
318 XapianSWIGQueryItor b, e;
319
320 AV *q = (AV *) SvRV(q_);
321
322 b.begin(q);
323 e.end(av_len(q) + 1);
324
325 try {
326 return new Xapian::Query(op, b, e);
327 } catch (const Xapian::Error &error) {
328 croak( "Exception: %s", error.get_msg().c_str() );
329 }
330 }
331 %}
332
333 /* Xapian::QueryParser */
334 %feature("shadow") Xapian::QueryParser::QueryParser
335 %{
336 sub new {
337 my $class = shift;
338 my $qp = Xapianc::new_QueryParser();
339
340 bless $qp, $class;
341 $qp->set_database(@_) if scalar(@_) == 1;
342
343 return $qp;
344 }
345 %}
346
347 %feature("shadow") Xapian::QueryParser::set_stopper
348 %{
349 sub set_stopper {
350 my ($self, $stopper) = @_;
351 $self{_stopper} = $stopper;
352 Xapianc::QueryParser_set_stopper( @_ );
353 }
354 %}
355
356 %feature("shadow") Xapian::QueryParser::add_rangeprocessor
357 %{
358 sub add_rangeprocessor {
359 my ($self, $rproc) = @_;
360 push @{$self{_rproc}}, $rproc;
361 Xapianc::QueryParser_add_rangeprocessor( @_ );
362 }
363 %}
364
365 %feature("shadow") Xapian::QueryParser::add_valuerangeprocessor
366 %{
367 sub add_valuerangeprocessor {
368 my ($self, $vrproc) = @_;
369 push @{$self{_vrproc}}, $vrproc;
370 Xapianc::QueryParser_add_valuerangeprocessor( @_ );
371 }
372 %}
373
374 /* Xapian::SimpleStopper */
375 %feature("shadow") Xapian::SimpleStopper::SimpleStopper
376 %{
377 sub new {
378 my $class = shift;
379 my $stopper = Xapianc::new_SimpleStopper();
380
381 bless $stopper, $class;
382 foreach (@_) {
383 $stopper->add($_);
384 }
385
386 return $stopper;
387 }
388 %}
389
390 %extend Xapian::SimpleStopper {
stop_word(std::string term)391 bool stop_word(std::string term) {
392 return (*self)(term);
393 }
394 }
395
396 /* Xapian::Stem */
397 %extend Xapian::Stem {
stem_word(std::string word)398 std::string stem_word(std::string word) {
399 return (*self)(word);
400 }
401 }
402
403 /* Xapian::TermIterator */
404 %rename(get_termname) Xapian::TermIterator::get_term;
405
406 /* Xapian::WritableDatabase */
407 %rename(replace_document_by_term) \
408 Xapian::WritableDatabase::replace_document(const std::string &,
409 const Xapian::Document &);
410 %rename(delete_document_by_term) \
411 Xapian::WritableDatabase::delete_document(const std::string &);
412
413 %feature("shadow") Xapian::WritableDatabase::WritableDatabase
414 %{
415 sub new {
416 my $pkg = shift;
417 my $self;
418 if( scalar(@_) == 0 ) {
419 # For compatibility with Search::Xapian
420 @_ = ('', $Xapianc::DB_BACKEND_INMEMORY);
421 }
422 $self = Xapianc::new_WritableDatabase(@_);
423 bless $self, $pkg if defined($self);
424 }
425 %}
426
427 %define SUB_CLASS(NS, CLASS)
428 %{
429 class perl##CLASS : public NS::CLASS {
430 SV* callback;
431
432 public:
CLASS(SV * func)433 perl##CLASS(SV* func) {
434 callback = newSVsv(func);
435 }
436
CLASS()437 ~perl##CLASS() {
438 SvREFCNT_dec(callback);
439 }
440
operator()441 bool operator()(const std::string &term) const {
442 dSP;
443
444 ENTER;
445 SAVETMPS;
446
447 PUSHMARK(SP);
448
449 SV* arg = sv_newmortal();
450 sv_setpvn(arg, term.data(), term.size());
451 XPUSHs(arg);
452 PUTBACK;
453
454 int count = call_sv(callback, G_SCALAR);
455
456 SPAGAIN;
457 if (count != 1)
458 croak("callback function should return 1 value, got %d", count);
459
460 bool result = POPi;
461
462 PUTBACK;
463
464 FREETMPS;
465 LEAVE;
466
467 return result;
468 }
469 };
470 %}
471
472 %enddef
473
474 SUB_CLASS(Xapian, ExpandDecider)
475 SUB_CLASS(Xapian, Stopper)
476
477 %{
478 class perlMatchDecider : public Xapian::MatchDecider {
479 SV* callback;
480
481 public:
perlMatchDecider(SV * func)482 perlMatchDecider(SV* func) {
483 callback = newSVsv(func);
484 }
485
~perlMatchDecider()486 ~perlMatchDecider() {
487 SvREFCNT_dec(callback);
488 }
489
operator()490 bool operator()(const Xapian::Document &doc) const {
491 dSP;
492
493 ENTER;
494 SAVETMPS;
495
496 PUSHMARK(SP);
497
498 XPUSHs(SWIG_NewPointerObj(const_cast<Xapian::Document*>(&doc),
499 SWIGTYPE_p_Xapian__Document, 0));
500 PUTBACK;
501
502 int count = call_sv(callback, G_SCALAR);
503
504 SPAGAIN;
505 if (count != 1)
506 croak("callback function should return 1 value, got %d", count);
507
508 bool result = POPi;
509
510 PUTBACK;
511
512 FREETMPS;
513 LEAVE;
514
515 return result;
516 }
517 };
518 %}
519
520 %{
521 class perlStemImplementation : public Xapian::StemImplementation {
522 SV* callback;
523
524 public:
perlStemImplementation(SV * func)525 perlStemImplementation(SV* func) {
526 callback = newSVsv(func);
527 }
528
~perlStemImplementation()529 ~perlStemImplementation() {
530 SvREFCNT_dec(callback);
531 }
532
operator()533 std::string operator()(const std::string& word) {
534 dSP;
535
536 ENTER;
537 SAVETMPS;
538
539 PUSHMARK(SP);
540
541 SV* arg = sv_newmortal();
542 sv_setpvn(arg, word.data(), word.size());
543 XPUSHs(arg);
544 PUTBACK;
545
546 int count = call_sv(callback, G_SCALAR);
547
548 SPAGAIN;
549 if (count != 1)
550 croak("callback function should return 1 value, got %d", count);
551
552 SV* sv = POPs;
553 STRLEN len;
554 const char* ptr = SvPV(sv, len);
555 std::string result(ptr, len);
556
557 PUTBACK;
558
559 FREETMPS;
560 LEAVE;
561
562 return result;
563 }
564
get_description()565 std::string get_description() const {
566 return "perlStemImplementation()";
567 }
568 };
569 %}
570
571 %{
572 class perlKeyMaker : public Xapian::KeyMaker {
573 SV* callback;
574
575 public:
perlKeyMaker(SV * func)576 perlKeyMaker(SV* func) {
577 callback = newSVsv(func);
578 }
579
~perlKeyMaker()580 ~perlKeyMaker() {
581 SvREFCNT_dec(callback);
582 }
583
operator()584 std::string operator()(const Xapian::Document &doc) const {
585 dSP;
586
587 ENTER;
588 SAVETMPS;
589
590 PUSHMARK(SP);
591
592 XPUSHs(SWIG_NewPointerObj(const_cast<Xapian::Document*>(&doc),
593 SWIGTYPE_p_Xapian__Document, 0));
594 PUTBACK;
595
596 int count = call_sv(callback, G_SCALAR);
597
598 SPAGAIN;
599 if (count != 1)
600 croak("callback function should return 1 value, got %d", count);
601
602 SV* sv = POPs;
603 STRLEN len;
604 const char* ptr = SvPV(sv, len);
605 std::string result(ptr, len);
606
607 PUTBACK;
608
609 FREETMPS;
610 LEAVE;
611
612 return result;
613 }
614 };
615 %}
616
617 %{
618 class perlRangeProcessor : public Xapian::RangeProcessor {
619 SV* callback;
620
621 public:
perlRangeProcessor(SV * func)622 perlRangeProcessor(SV* func) {
623 callback = newSVsv(func);
624 }
625
~perlRangeProcessor()626 ~perlRangeProcessor() {
627 SvREFCNT_dec(callback);
628 }
629
operator()630 Xapian::Query operator()(const std::string& begin, const std::string& end) {
631 dSP;
632
633 ENTER;
634 SAVETMPS;
635
636 PUSHMARK(SP);
637 EXTEND(SP, 2);
638 SV* arg = sv_newmortal();
639 sv_setpvn(arg, begin.data(), begin.size());
640 PUSHs(arg);
641 arg = sv_newmortal();
642 sv_setpvn(arg, end.data(), end.size());
643 PUSHs(arg);
644 PUTBACK;
645
646 int count = call_sv(callback, G_SCALAR);
647
648 SPAGAIN;
649 if (count != 1)
650 croak("callback function should return 1 value, got %d", count);
651
652 // Allow the function to return a string or Query object.
653 SV* sv = POPs;
654 if (!SvOK(sv))
655 croak("function must return a string or Query object");
656
657 Xapian::Query result;
658 Xapian::Query* q;
659 if (SWIG_ConvertPtr(sv, (void**)&q,
660 SWIGTYPE_p_Xapian__Query, 0) == SWIG_OK) {
661 result = *q;
662 } else {
663 STRLEN len;
664 const char* ptr = SvPV(sv, len);
665 result = Xapian::Query(string(ptr, len));
666 }
667
668 PUTBACK;
669
670 FREETMPS;
671 LEAVE;
672
673 return result;
674 }
675 };
676 %}
677
678 %{
679 class perlFieldProcessor : public Xapian::FieldProcessor {
680 SV* callback;
681
682 public:
perlFieldProcessor(SV * func)683 perlFieldProcessor(SV* func) {
684 callback = newSVsv(func);
685 }
686
~perlFieldProcessor()687 ~perlFieldProcessor() {
688 SvREFCNT_dec(callback);
689 }
690
operator()691 Xapian::Query operator()(const std::string &str) {
692 dSP;
693
694 ENTER;
695 SAVETMPS;
696
697 PUSHMARK(SP);
698
699 SV* arg = sv_newmortal();
700 sv_setpvn(arg, str.data(), str.size());
701 XPUSHs(arg);
702 PUTBACK;
703
704 int count = call_sv(callback, G_SCALAR);
705
706 SPAGAIN;
707 if (count != 1)
708 croak("callback function should return 1 value, got %d", count);
709
710 // Allow the function to return a string or Query object.
711 SV* sv = POPs;
712 if (!SvOK(sv))
713 croak("function must return a string or Query object");
714
715 Xapian::Query result;
716 Xapian::Query* q;
717 if (SWIG_ConvertPtr(sv, (void**)&q,
718 SWIGTYPE_p_Xapian__Query, 0) == SWIG_OK) {
719 result = *q;
720 } else {
721 STRLEN len;
722 const char* ptr = SvPV(sv, len);
723 result = Xapian::Query(string(ptr, len));
724 }
725
726 PUTBACK;
727
728 FREETMPS;
729 LEAVE;
730
731 return result;
732 }
733 };
734 %}
735
736 %{
737 class perlMatchSpy : public Xapian::MatchSpy {
738 SV* callback;
739
740 public:
perlMatchSpy(SV * func)741 perlMatchSpy(SV* func) {
742 callback = newSVsv(func);
743 }
744
~perlMatchSpy()745 ~perlMatchSpy() {
746 SvREFCNT_dec(callback);
747 }
748
operator()749 void operator()(const Xapian::Document &doc, double wt) {
750 dSP;
751
752 ENTER;
753 SAVETMPS;
754
755 PUSHMARK(SP);
756 EXTEND(SP, 2);
757 PUSHs(SWIG_NewPointerObj(const_cast<Xapian::Document*>(&doc),
758 SWIGTYPE_p_Xapian__Document, 0));
759 mPUSHn(wt);
760 PUTBACK;
761
762 (void)call_sv(callback, G_VOID);
763
764 SPAGAIN;
765 PUTBACK;
766
767 FREETMPS;
768 LEAVE;
769 }
770 };
771 %}
772
773 %define SUB_CLASS_TYPEMAPS(NS, CLASS)
774
775 %typemap(typecheck, precedence=100) NS::CLASS * {
776 SV* sv = $input;
777 void* ptr;
778 if (SWIG_ConvertPtr(sv, &ptr, $descriptor(NS::CLASS *), 0) == SWIG_OK) {
779 (void)ptr;
780 $1 = 1;
781 } else {
782 /* The docs in perlapi for call_sv say:
783 *
784 * [T]he SV may be any of a CV, a GV, a reference to a CV, a
785 * reference to a GV or "SvPV(sv)" will be used as the name of the
786 * sub to call.
787 *
788 * To make overloading work helpfully, we don't allow passing the name
789 * of a sub. Search::Xapian did in some cases, but it seems unlikely
790 * anyone relied on this.
791 */
792 svtype t = SvTYPE(sv);
793 if (t == SVt_RV) {
794 t = SvTYPE(SvRV(sv));
795 }
796 $1 = (t == SVt_PVCV || t == SVt_PVGV);
797 }
798 }
799 %typemap(in) NS::CLASS * {
800 SV* sv = $input;
801 if (SWIG_ConvertPtr(sv, (void**)&$1,
802 $descriptor(NS::CLASS *), 0) != SWIG_OK) {
803 $1 = new perl##CLASS(sv);
804 }
805 }
806
807 %enddef
808 SUB_CLASS_TYPEMAPS(Xapian, MatchDecider)
809 SUB_CLASS_TYPEMAPS(Xapian, ExpandDecider)
810 SUB_CLASS_TYPEMAPS(Xapian, Stopper)
811 SUB_CLASS_TYPEMAPS(Xapian, StemImplementation)
812 SUB_CLASS_TYPEMAPS(Xapian, KeyMaker)
813 SUB_CLASS_TYPEMAPS(Xapian, RangeProcessor)
814 SUB_CLASS_TYPEMAPS(Xapian, FieldProcessor)
815 SUB_CLASS_TYPEMAPS(Xapian, MatchSpy)
816
817 %include except.i
818 %include ../xapian-headers.i
819 %include extra.i
820