1 %{
2 /* python/util.i: custom Python typemaps for xapian-bindings
3  *
4  * Copyright (C) 1999,2000,2001 BrightStation PLC
5  * Copyright (C) 2002 Ananova Ltd
6  * Copyright (C) 2002,2003 James Aylett
7  * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2013,2017 Olly Betts
8  * Copyright (C) 2007 Lemur Consulting Ltd
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of the
13  * License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
23  * USA
24  */
25 %}
26 
27 %include typemaps.i
28 %include stl.i
29 
30 /* Wrap get_description() methods as str(). */
31 %rename(__str__) get_description;
32 
33 /* Hide "unsafe" C++ iterator methods. */
34 %rename(_allterms_begin) Xapian::Database::allterms_begin;
35 %rename(_allterms_end) Xapian::Database::allterms_end;
36 %rename(_metadata_keys_begin) Xapian::Database::metadata_keys_begin;
37 %rename(_metadata_keys_end) Xapian::Database::metadata_keys_end;
38 %rename(_synonym_keys_begin) Xapian::Database::synonym_keys_begin;
39 %rename(_synonym_keys_end) Xapian::Database::synonym_keys_end;
40 %rename(_synonyms_begin) Xapian::Database::synonyms_begin;
41 %rename(_synonyms_end) Xapian::Database::synonyms_end;
42 %rename(_spellings_begin) Xapian::Database::spellings_begin;
43 %rename(_spellings_end) Xapian::Database::spellings_end;
44 %rename(_positionlist_begin) Xapian::Database::positionlist_begin;
45 %rename(_positionlist_end) Xapian::Database::positionlist_end;
46 %rename(_postlist_begin) Xapian::Database::postlist_begin;
47 %rename(_postlist_end) Xapian::Database::postlist_end;
48 %rename(_termlist_begin) Xapian::Database::termlist_begin;
49 %rename(_termlist_end) Xapian::Database::termlist_end;
50 %rename(_termlist_begin) Xapian::Document::termlist_begin;
51 %rename(_termlist_end) Xapian::Document::termlist_end;
52 %rename(_values_begin) Xapian::Document::values_begin;
53 %rename(_values_end) Xapian::Document::values_end;
54 %rename(_get_matching_terms_begin) Xapian::Enquire::get_matching_terms_begin;
55 %rename(_get_matching_terms_end) Xapian::Enquire::get_matching_terms_end;
56 %rename(_begin) Xapian::ESet::begin;
57 %rename(_end) Xapian::ESet::end;
58 %rename(_begin) Xapian::MSet::begin;
59 %rename(_end) Xapian::MSet::end;
60 %rename(_positionlist_begin) Xapian::PostingIterator::positionlist_begin;
61 %rename(_positionlist_end) Xapian::PostingIterator::positionlist_end;
62 %rename(_get_terms_begin) Xapian::Query::get_terms_begin;
63 %rename(_get_terms_end) Xapian::Query::get_terms_end;
64 %rename(_stoplist_begin) Xapian::QueryParser::stoplist_begin;
65 %rename(_stoplist_end) Xapian::QueryParser::stoplist_end;
66 %rename(_unstem_begin) Xapian::QueryParser::unstem_begin;
67 %rename(_unstem_end) Xapian::QueryParser::unstem_end;
68 %rename(_positionlist_begin) Xapian::TermIterator::positionlist_begin;
69 %rename(_positionlist_end) Xapian::TermIterator::positionlist_end;
70 
71 /* We replace the get_hit() method with one which returns an MSetitem. */
72 %rename(_get_hit_internal) Xapian::MSet::get_hit;
73 
74 %{
75 namespace Xapian {
get_py_query(PyObject * obj)76     Query *get_py_query(PyObject *obj) {
77 	PyObject * mythis = PyObject_GetAttrString(obj, "this");
78 	if (!mythis)
79 	    return 0;
80 
81 	Query * retval = 0;
82 	int res = SWIG_ConvertPtr(mythis, (void **)&retval,
83 				  SWIGTYPE_p_Xapian__Query, 0);
84 	if (!SWIG_IsOK(res)) {
85 	    retval = 0;
86 	}
87 	Py_DECREF(mythis);
88 	return retval;
89     }
90 }
91 %}
92 
93 %typedef PyObject *LangSpecificListType;
94 
95 %inline %{
96 #define MSET_DID 0
97 #define MSET_WT 1
98 #define MSET_RANK 2
99 #define MSET_PERCENT 3
100 #define MSET_DOCUMENT 4
101 
102 #define ESET_TNAME 0
103 #define ESET_WT 1
104 %}
105 
106 %feature("nothread") Xapian::MSet::items;
107 %{
108 /* The GIL must be held when this is called. */
Xapian_MSet_items_get(Xapian::MSet * mset)109 PyObject *Xapian_MSet_items_get(Xapian::MSet *mset)
110 {
111     PyObject *retval = PyList_New(mset->size());
112     if (retval == 0) {
113 	return NULL;
114     }
115 
116     Py_ssize_t idx = 0;
117     for (Xapian::MSetIterator i = mset->begin(); i != mset->end(); ++i) {
118 	PyObject *t = PyTuple_New(4);
119 	if (!t) {
120 	    Py_DECREF(retval);
121 	    return NULL;
122 	}
123 
124 	PyList_SET_ITEM(retval, idx++, t);
125 
126 	PyTuple_SET_ITEM(t, MSET_DID, PyInt_FromLong(*i));
127 	PyTuple_SET_ITEM(t, MSET_WT, PyFloat_FromDouble(i.get_weight()));
128 	PyTuple_SET_ITEM(t, MSET_RANK, PyInt_FromLong(i.get_rank()));
129 	PyTuple_SET_ITEM(t, MSET_PERCENT, PyInt_FromLong(i.get_percent()));
130     }
131     return retval;
132 }
133 %}
134 
135 %feature("nothread") Xapian::ESet::items;
136 %{
137 /* The GIL must be held when this is called. */
Xapian_ESet_items_get(Xapian::ESet * eset)138 PyObject *Xapian_ESet_items_get(Xapian::ESet *eset)
139 {
140     PyObject *retval = PyList_New(eset->size());
141     if (retval == 0) {
142 	return NULL;
143     }
144 
145     Py_ssize_t idx = 0;
146     for (Xapian::ESetIterator i = eset->begin(); i != eset->end(); ++i) {
147 	PyObject *t = PyTuple_New(2);
148 	if (!t) {
149 	    Py_DECREF(retval);
150 	    return NULL;
151 	}
152 
153 	PyList_SET_ITEM(retval, idx++, t);
154 
155 	PyObject * str = PyString_FromStringAndSize((*i).data(), (*i).size());
156 	if (str == 0) {
157 	    Py_DECREF(retval);
158 	    return NULL;
159 	}
160 
161 	PyTuple_SET_ITEM(t, ESET_TNAME, str);
162 	PyTuple_SET_ITEM(t, ESET_WT, PyFloat_FromDouble(i.get_weight()));
163     }
164     return retval;
165 }
166 %}
167 
168 namespace Xapian {
169     %extend TermIterator {
__eq__(const TermIterator & other)170 	bool __eq__(const TermIterator &other) {
171 	    return (*self)==other;
172 	}
__ne__(const TermIterator & other)173 	bool __ne__(const TermIterator &other) {
174 	    return (*self)!=other;
175 	}
176     }
177     %rename(_TermIterator) TermIterator;
178 
179     %extend PositionIterator {
__eq__(const PositionIterator & other)180 	bool __eq__(const PositionIterator &other) {
181 	    return (*self)==other;
182 	}
__ne__(const PositionIterator & other)183 	bool __ne__(const PositionIterator &other) {
184 	    return (*self)!=other;
185 	}
186     }
187     %rename(_PositionIterator) PositionIterator;
188 
189     %extend PostingIterator {
__eq__(const PostingIterator & other)190 	bool __eq__(const PostingIterator &other) {
191 	    return (*self)==other;
192 	}
__ne__(const PostingIterator & other)193 	bool __ne__(const PostingIterator &other) {
194 	    return (*self)!=other;
195 	}
196     }
197     %rename(_PostingIterator) PostingIterator;
198 
199     %extend ValueIterator {
__eq__(const ValueIterator & other)200 	bool __eq__(const ValueIterator &other) {
201 	    return (*self)==other;
202 	}
__ne__(const ValueIterator & other)203 	bool __ne__(const ValueIterator &other) {
204 	    return (*self)!=other;
205 	}
206     }
207     %rename(_ValueIterator) ValueIterator;
208 
209     %extend MSetIterator {
__eq__(const MSetIterator & other)210 	bool __eq__(const MSetIterator &other) {
211 	    return (*self)==other;
212 	}
__ne__(const MSetIterator & other)213 	bool __ne__(const MSetIterator &other) {
214 	    return (*self)!=other;
215 	}
216     }
217     %rename(_MSetIterator) MSetIterator;
218 
219     %extend ESetIterator {
__eq__(const ESetIterator & other)220 	bool __eq__(const ESetIterator &other) {
221 	    return (*self)==other;
222 	}
__ne__(const ESetIterator & other)223 	bool __ne__(const ESetIterator &other) {
224 	    return (*self)!=other;
225 	}
226     }
227     %rename(_ESetIterator) ESetIterator;
228 
229     %extend MSet {
230 	%immutable;
231 	// access to the items array
232 	PyObject *items;
233 	%mutable;
234 
235 	// for comparison
__cmp__(const MSet & other)236 	int __cmp__(const MSet &other) {
237 	    if (self->get_max_possible() != other.get_max_possible()) {
238 		return (self->get_max_possible() < other.get_max_possible())? -1 : 1;
239 	    }
240 	    if (self->size() != other.size()) {
241 		return (self->size() < other.size())? -1 : 1;
242 	    }
243 
244 	    for (size_t i=0; i<self->size(); ++i) {
245 		if (*(*self)[i] != *other[i]) {
246 		    return (*(*self)[i] < *other[i])? -1 : 1;
247 		}
248 		if ((*self)[i].get_weight() != other[i].get_weight()) {
249 		    return ((*self)[i].get_weight() < other[i].get_weight())? -1 : 1;
250 		}
251 	    }
252 	    return 0;
253 	}
254     }
255 
256     //%apply LangSpecificListType items { PyObject *items }
257 
258     %extend ESet {
259 	%immutable;
260 	PyObject *items;
261 	%mutable;
262     }
263 }
264 
265 %fragment("XapianSWIG_anystring_as_ptr", "header", fragment="SWIG_AsPtr_std_string") {
266 /* Utility function which works like SWIG_AsPtr_std_string, but
267  * converts unicode strings to UTF-8 simple strings first. */
268 static int
XapianSWIG_anystring_as_ptr(PyObject * obj,std::string ** val)269 XapianSWIG_anystring_as_ptr(PyObject * obj, std::string **val)
270 {
271     if (PyUnicode_Check(obj)) {
272 	PyObject * strobj = PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(obj), PyUnicode_GET_SIZE(obj), "ignore");
273 	if (strobj == NULL) return SWIG_ERROR;
274 	int res = SWIG_AsPtr_std_string(strobj, val);
275 	Py_DECREF(strobj);
276 	return res;
277     } else {
278 	return SWIG_AsPtr_std_string(obj, val);
279     }
280 }
281 }
282 
283 /* These typemaps depends somewhat heavily on the internals of SWIG, so
284  * might break with future versions of SWIG.
285  */
286 %typemap(in, fragment="XapianSWIG_anystring_as_ptr") const std::string &(int res = SWIG_OLDOBJ) {
287     std::string *ptr = (std::string *)0;
288     res = XapianSWIG_anystring_as_ptr($input, &ptr);
289     if (!SWIG_IsOK(res)) {
290 	%argument_fail(res, "$type", $symname, $argnum);
291     }
292     if (!ptr) {
293 	%argument_nullref("$type", $symname, $argnum);
294     }
295     $1 = ptr;
296 }
297 %typemap(in, fragment="XapianSWIG_anystring_as_ptr") std::string {
298     std::string *ptr = (std::string *)0;
299     int res = XapianSWIG_anystring_as_ptr($input, &ptr);
300     if (!SWIG_IsOK(res) || !ptr) {
301 	%argument_fail((ptr ? res : SWIG_TypeError), "$type", $symname, $argnum);
302     }
303     $1 = *ptr;
304     if (SWIG_IsNewObj(res)) delete ptr;
305 }
306 %typemap(freearg, noblock=1, match="in") const std::string & {
307     if (SWIG_IsNewObj(res$argnum)) %delete($1);
308 }
309 %typemap(typecheck, noblock=1, precedence=900, fragment="XapianSWIG_anystring_as_ptr") const std::string & {
310     int res = XapianSWIG_anystring_as_ptr($input, (std::string**)(0));
311     $1 = SWIG_CheckState(res);
312 }
313 
314 %typemap(in, fragment="XapianSWIG_anystring_as_ptr") const std::string *(int res = SWIG_OLDOBJ) {
315     std::string *ptr = (std::string *)0;
316     if ($input != Py_None) {
317 	res = XapianSWIG_anystring_as_ptr($input, &ptr);
318 	if (!SWIG_IsOK(res)) {
319 	    %argument_fail(res, "$type", $symname, $argnum);
320 	}
321     }
322     $1 = ptr;
323 }
324 %typemap(freearg, noblock=1, match="in") const std::string * {
325     if (SWIG_IsNewObj(res$argnum)) %delete($1);
326 }
327 %typemap(typecheck, noblock=1, precedence=900, fragment="XapianSWIG_anystring_as_ptr") const std::string * {
328     if ($input == Py_None) {
329 	$1 = 1;
330     } else {
331 	int res = XapianSWIG_anystring_as_ptr($input, (std::string**)(0));
332 	$1 = SWIG_CheckState(res);
333     }
334 }
335 
336 /* This typemap is only currently needed for returning a value from the
337  * get_description() method of a Stopper subclass to a C++ caller, but might be
338  * more generally useful in future.
339  */
340 %typemap(directorout, noblock=1, fragment="XapianSWIG_anystring_as_ptr") std::string {
341     std::string *swig_optr = 0;
342     int swig_ores;
343     {
344 	PyObject * tmp = $input;
345 	Py_INCREF(tmp);
346 	swig_ores = XapianSWIG_anystring_as_ptr(tmp, &swig_optr);
347 	Py_DECREF(tmp);
348     }
349     if (!SWIG_IsOK(swig_ores) || !swig_optr) {
350 	%dirout_fail((swig_optr ? swig_ores : SWIG_TypeError), "$type");
351     }
352     $result = *swig_optr;
353     if (SWIG_IsNewObj(swig_ores)) %delete(swig_optr);
354 }
355 
356 /** This pair of typemaps implements conversion of the return value of
357  *  ValueRangeProcessor subclasses implemented in Python from a tuple of
358  *  (valueno, begin, end) to a return value of valueno, and assigning the new
359  *  values of begin and end to the parameters.
360  */
361 %typemap(directorin,noblock=1) std::string & {
362     $input = SWIG_From_std_string(static_cast< std::string >($1_name));
363 }
364 %typemap(directorout,noblock=1) Xapian::valueno {
365     if (!PyTuple_Check($input)) {
366         %dirout_fail(SWIG_TypeError, "($type, std::string, std::string)");
367     }
368     if (PyTuple_Size($input) != 3) {
369         %dirout_fail(SWIG_IndexError, "($type, std::string, std::string)");
370     }
371 
372     // Set the return value from the first item of the tuple.
373     unsigned int swig_val;
374     int swig_res = SWIG_AsVal_unsigned_SS_int(PyTuple_GET_ITEM((PyObject *)$input, 0), &swig_val);
375     if (!SWIG_IsOK(swig_res)) {
376         %dirout_fail(swig_res, "($type, std::string, std::string)");
377     }
378     c_result = static_cast< Xapian::valueno >(swig_val);
379 
380     // Set "begin" from the second item of the tuple.
381     std::string *ptr = (std::string *)0;
382     swig_res = SWIG_AsPtr_std_string(PyTuple_GET_ITEM((PyObject *)$input, 1), &ptr);
383     if (!SWIG_IsOK(swig_res) || !ptr) {
384         delete ptr;
385         ptr = (std::string *)0;
386 	%dirout_fail((ptr ? swig_res : SWIG_TypeError), "($type, std::string, std::string)");
387     }
388     begin = *ptr;
389     delete ptr;
390     ptr = (std::string *)0;
391 
392     // Set "end" from the third item of the tuple.
393     swig_res = SWIG_AsPtr_std_string(PyTuple_GET_ITEM((PyObject *)$input, 2), &ptr);
394     if (!SWIG_IsOK(swig_res) || !ptr) {
395         delete ptr;
396         ptr = (std::string *)0;
397 	%dirout_fail((ptr ? swig_res : SWIG_TypeError), "($type, std::string, std::string)");
398     }
399     end = *ptr;
400     delete ptr;
401     ptr = (std::string *)0;
402 }
403 
404 /* These typemaps handle ValueRangeProcessors, which take non-const references
405  * to std::string and modify the strings.
406  */
407 %typemap(in) std::string &begin (std::string temp),
408              std::string &end (std::string temp) {
409     std::string *ptr = (std::string *)0;
410     int res = SWIG_AsPtr_std_string($input, &ptr);
411     if (!SWIG_IsOK(res) || !ptr) {
412 	%argument_fail((ptr ? res : SWIG_TypeError), "$type", $symname, $argnum);
413     }
414     temp = *ptr;
415     $1 = &temp;
416     if (SWIG_IsNewObj(res)) delete ptr;
417 }
418 %typemap(argout) (std::string &begin, std::string &end) {
419     PyObject * str;
420     PyObject * newresult;
421 
422     // Put the existing result into the first item of a new 3-tuple.
423     newresult = PyTuple_New(3);
424     if (newresult == 0) {
425         Py_DECREF($result);
426         $result = NULL;
427         SWIG_fail;
428     }
429     PyTuple_SET_ITEM(newresult, 0, $result);
430     $result = newresult;
431 
432     str = PyString_FromStringAndSize($1->data(), $1->size());
433     if (str == 0) {
434         Py_DECREF($result);
435         $result = NULL;
436         SWIG_fail;
437     }
438     PyTuple_SET_ITEM($result, 1, str);
439 
440     str = PyString_FromStringAndSize($2->data(), $2->size());
441     if (str == 0) {
442         Py_DECREF($result);
443         $result = NULL;
444         SWIG_fail;
445     }
446 
447     PyTuple_SET_ITEM($result, 2, str);
448 }
449 
450 %typemap(directorin) (size_t num_tags, const std::string tags[]) {
451     PyObject * result = PyList_New(num_tags);
452     if (result == 0) {
453 	return NULL;
454     }
455 
456     for (size_t i = 0; i != num_tags; ++i) {
457 	PyObject * str = PyString_FromStringAndSize(tags[i].data(), tags[i].size());
458 	if (str == 0) {
459 	    Py_DECREF(result);
460 	    return NULL;
461 	}
462 
463 	PyList_SET_ITEM(result, i, str);
464     }
465     $input = result;
466 }
467 
468 /* vim:set syntax=cpp:set noexpandtab: */
469