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,2016,2017,2019 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 /* So iterator objects match the Python3 iterator API. */
34 %rename(__next__) next;
35 
36 /* Hide "unsafe" C++ iterator methods. */
37 %rename(_allterms_begin) Xapian::Database::allterms_begin;
38 %rename(_allterms_end) Xapian::Database::allterms_end;
39 %rename(_metadata_keys_begin) Xapian::Database::metadata_keys_begin;
40 %rename(_metadata_keys_end) Xapian::Database::metadata_keys_end;
41 %rename(_synonym_keys_begin) Xapian::Database::synonym_keys_begin;
42 %rename(_synonym_keys_end) Xapian::Database::synonym_keys_end;
43 %rename(_synonyms_begin) Xapian::Database::synonyms_begin;
44 %rename(_synonyms_end) Xapian::Database::synonyms_end;
45 %rename(_spellings_begin) Xapian::Database::spellings_begin;
46 %rename(_spellings_end) Xapian::Database::spellings_end;
47 %rename(_positionlist_begin) Xapian::Database::positionlist_begin;
48 %rename(_positionlist_end) Xapian::Database::positionlist_end;
49 %rename(_postlist_begin) Xapian::Database::postlist_begin;
50 %rename(_postlist_end) Xapian::Database::postlist_end;
51 %rename(_termlist_begin) Xapian::Database::termlist_begin;
52 %rename(_termlist_end) Xapian::Database::termlist_end;
53 %rename(_termlist_begin) Xapian::Document::termlist_begin;
54 %rename(_termlist_end) Xapian::Document::termlist_end;
55 %rename(_values_begin) Xapian::Document::values_begin;
56 %rename(_values_end) Xapian::Document::values_end;
57 %rename(_get_matching_terms_begin) Xapian::Enquire::get_matching_terms_begin;
58 %rename(_get_matching_terms_end) Xapian::Enquire::get_matching_terms_end;
59 %rename(_begin) Xapian::ESet::begin;
60 %rename(_end) Xapian::ESet::end;
61 %rename(_begin) Xapian::MSet::begin;
62 %rename(_end) Xapian::MSet::end;
63 %rename(_positionlist_begin) Xapian::PostingIterator::positionlist_begin;
64 %rename(_positionlist_end) Xapian::PostingIterator::positionlist_end;
65 %rename(_get_terms_begin) Xapian::Query::get_terms_begin;
66 %rename(_get_terms_end) Xapian::Query::get_terms_end;
67 %rename(_stoplist_begin) Xapian::QueryParser::stoplist_begin;
68 %rename(_stoplist_end) Xapian::QueryParser::stoplist_end;
69 %rename(_unstem_begin) Xapian::QueryParser::unstem_begin;
70 %rename(_unstem_end) Xapian::QueryParser::unstem_end;
71 %rename(_positionlist_begin) Xapian::TermIterator::positionlist_begin;
72 %rename(_positionlist_end) Xapian::TermIterator::positionlist_end;
73 
74 /* We replace the get_hit() method with one which returns an MSetitem. */
75 %rename(_get_hit_internal) Xapian::MSet::get_hit;
76 
77 %{
78 namespace Xapian {
get_py_query(PyObject * obj)79     Query *get_py_query(PyObject *obj) {
80 	PyObject * mythis = PyObject_GetAttrString(obj, "this");
81 	if (!mythis)
82 	    return 0;
83 
84 	Query * retval = 0;
85 	int res = SWIG_ConvertPtr(mythis, (void **)&retval,
86 				  SWIGTYPE_p_Xapian__Query, 0);
87 	if (!SWIG_IsOK(res)) {
88 	    retval = 0;
89 	}
90 	Py_DECREF(mythis);
91 	return retval;
92     }
93 }
94 %}
95 
96 namespace Xapian {
97     %extend TermIterator {
__eq__(const TermIterator & other)98 	bool __eq__(const TermIterator &other) {
99 	    return (*self)==other;
100 	}
__ne__(const TermIterator & other)101 	bool __ne__(const TermIterator &other) {
102 	    return (*self)!=other;
103 	}
104     }
105     %rename(_TermIterator) TermIterator;
106 
107     %extend PositionIterator {
__eq__(const PositionIterator & other)108 	bool __eq__(const PositionIterator &other) {
109 	    return (*self)==other;
110 	}
__ne__(const PositionIterator & other)111 	bool __ne__(const PositionIterator &other) {
112 	    return (*self)!=other;
113 	}
114     }
115     %rename(_PositionIterator) PositionIterator;
116 
117     %extend PostingIterator {
__eq__(const PostingIterator & other)118 	bool __eq__(const PostingIterator &other) {
119 	    return (*self)==other;
120 	}
__ne__(const PostingIterator & other)121 	bool __ne__(const PostingIterator &other) {
122 	    return (*self)!=other;
123 	}
124     }
125     %rename(_PostingIterator) PostingIterator;
126 
127     %extend ValueIterator {
__eq__(const ValueIterator & other)128 	bool __eq__(const ValueIterator &other) {
129 	    return (*self)==other;
130 	}
__ne__(const ValueIterator & other)131 	bool __ne__(const ValueIterator &other) {
132 	    return (*self)!=other;
133 	}
134     }
135     %rename(_ValueIterator) ValueIterator;
136 
137     %extend MSetIterator {
__eq__(const MSetIterator & other)138 	bool __eq__(const MSetIterator &other) {
139 	    return (*self)==other;
140 	}
__ne__(const MSetIterator & other)141 	bool __ne__(const MSetIterator &other) {
142 	    return (*self)!=other;
143 	}
144     }
145     %rename(_MSetIterator) MSetIterator;
146 
147     %extend ESetIterator {
__eq__(const ESetIterator & other)148 	bool __eq__(const ESetIterator &other) {
149 	    return (*self)==other;
150 	}
__ne__(const ESetIterator & other)151 	bool __ne__(const ESetIterator &other) {
152 	    return (*self)!=other;
153 	}
154     }
155     %rename(_ESetIterator) ESetIterator;
156 }
157 
158 %fragment("XapianSWIG_anystring_as_ptr", "header", fragment="SWIG_AsPtr_std_string") {
159 /* Utility function which works like SWIG_AsPtr_std_string, but
160  * converts unicode strings to UTF-8 simple strings first. */
161 static int
XapianSWIG_anystring_as_ptr(PyObject * obj,std::string ** val)162 XapianSWIG_anystring_as_ptr(PyObject * obj, std::string **val)
163 {
164     if (PyUnicode_Check(obj)) {
165 	PyObject* strobj = PyUnicode_AsUTF8String(obj);
166 	if (strobj == NULL) return INT_MIN;
167 	char *p;
168 	Py_ssize_t len;
169 	PyBytes_AsStringAndSize(strobj, &p, &len);
170 	if (val) *val = new std::string(p, len);
171 	Py_DECREF(strobj);
172 	return SWIG_NEWOBJ;
173     } else if (PyBytes_Check(obj)) {
174 	char *p;
175 	Py_ssize_t len;
176 	PyBytes_AsStringAndSize(obj, &p, &len);
177 	if (val) *val = new std::string(p, len);
178 	return SWIG_NEWOBJ;
179     } else {
180 	return SWIG_AsPtr_std_string(obj, val);
181     }
182 }
183 }
184 
185 /* These typemaps depends somewhat heavily on the internals of SWIG, so
186  * might break with future versions of SWIG.
187  */
188 %typemap(in, fragment="XapianSWIG_anystring_as_ptr") const std::string &(int res = SWIG_OLDOBJ) {
189     std::string *ptr = (std::string *)0;
190     res = XapianSWIG_anystring_as_ptr($input, &ptr);
191     if (!SWIG_IsOK(res)) {
192 	if (res == INT_MIN) SWIG_fail;
193 	%argument_fail(res, "$type", $symname, $argnum);
194     }
195     if (!ptr) {
196 	%argument_nullref("$type", $symname, $argnum);
197     }
198     $1 = ptr;
199 }
200 %typemap(in, fragment="XapianSWIG_anystring_as_ptr") std::string {
201     std::string *ptr = (std::string *)0;
202     int res = XapianSWIG_anystring_as_ptr($input, &ptr);
203     if (!SWIG_IsOK(res) || !ptr) {
204 	if (res == INT_MIN) SWIG_fail;
205 	%argument_fail((ptr ? res : SWIG_TypeError), "$type", $symname, $argnum);
206     }
207     $1 = *ptr;
208     if (SWIG_IsNewObj(res)) delete ptr;
209 }
210 %typemap(freearg, noblock=1, match="in") const std::string & {
211     if (SWIG_IsNewObj(res$argnum)) %delete($1);
212 }
213 %typemap(typecheck, noblock=1, precedence=900) const std::string & {
214     if (PyUnicode_Check($input)) {
215 	$1 = 1;
216     } else if (PyBytes_Check($input)) {
217 	$1 = 1;
218     } else {
219 	int res = SWIG_AsPtr_std_string($input, (std::string**)(0));
220 	$1 = SWIG_CheckState(res);
221     }
222 }
223 
224 %typemap(in, fragment="XapianSWIG_anystring_as_ptr") const std::string *(int res = SWIG_OLDOBJ) {
225     std::string *ptr = (std::string *)0;
226     if ($input != Py_None) {
227 	res = XapianSWIG_anystring_as_ptr($input, &ptr);
228 	if (!SWIG_IsOK(res)) {
229 	    if (res == INT_MIN) SWIG_fail;
230 	    %argument_fail(res, "$type", $symname, $argnum);
231 	}
232     }
233     $1 = ptr;
234 }
235 %typemap(freearg, noblock=1, match="in") const std::string * {
236     if (SWIG_IsNewObj(res$argnum)) %delete($1);
237 }
238 %typemap(typecheck, noblock=1, precedence=900) const std::string * {
239     if ($input == Py_None) {
240 	$1 = 1;
241     } else if (PyUnicode_Check($input)) {
242 	$1 = 1;
243     } else if (PyBytes_Check($input)) {
244 	$1 = 1;
245     } else {
246 	int res = SWIG_AsPtr_std_string($input, (std::string**)(0));
247 	$1 = SWIG_CheckState(res);
248     }
249 }
250 
251 /* This typemap is only currently needed for returning a value from the
252  * get_description() method of a Stopper subclass to a C++ caller, but might be
253  * more generally useful in future.
254  */
255 %typemap(directorout, noblock=1, fragment="XapianSWIG_anystring_as_ptr") std::string {
256     std::string *swig_optr = 0;
257     int swig_ores;
258     {
259 	PyObject * tmp = $input;
260 	Py_INCREF(tmp);
261 	swig_ores = XapianSWIG_anystring_as_ptr(tmp, &swig_optr);
262 	Py_DECREF(tmp);
263     }
264     if (!SWIG_IsOK(swig_ores) || !swig_optr) {
265 	%dirout_fail((swig_optr ? swig_ores : SWIG_TypeError), "$type");
266     }
267     $result = *swig_optr;
268     if (SWIG_IsNewObj(swig_ores)) %delete(swig_optr);
269 }
270 
271 /** This pair of typemaps implements conversion of the return value of
272  *  ValueRangeProcessor subclasses implemented in Python from a tuple of
273  *  (valueno, begin, end) to a return value of valueno, and assigning the new
274  *  values of begin and end to the parameters.
275  */
276 %typemap(directorin,noblock=1) std::string & {
277     $input = SWIG_From_std_string(static_cast< std::string >($1_name));
278 }
279 %typemap(directorout,noblock=1) Xapian::valueno {
280     if (!PyTuple_Check($input)) {
281         %dirout_fail(SWIG_TypeError, "($type, std::string, std::string)");
282     }
283     if (PyTuple_Size($input) != 3) {
284         %dirout_fail(SWIG_IndexError, "($type, std::string, std::string)");
285     }
286 
287     // Set the return value from the first item of the tuple.
288     unsigned int swig_val;
289     int swig_res = SWIG_AsVal_unsigned_SS_int(PyTuple_GET_ITEM((PyObject *)$input, 0), &swig_val);
290     if (!SWIG_IsOK(swig_res)) {
291         %dirout_fail(swig_res, "($type, std::string, std::string)");
292     }
293     c_result = static_cast< Xapian::valueno >(swig_val);
294 
295     // Set "begin" from the second item of the tuple.
296     std::string *ptr = (std::string *)0;
297     swig_res = SWIG_AsPtr_std_string(PyTuple_GET_ITEM((PyObject *)$input, 1), &ptr);
298     if (!SWIG_IsOK(swig_res) || !ptr) {
299         delete ptr;
300         ptr = (std::string *)0;
301 	%dirout_fail((ptr ? swig_res : SWIG_TypeError), "($type, std::string, std::string)");
302     }
303     begin = *ptr;
304     delete ptr;
305     ptr = (std::string *)0;
306 
307     // Set "end" from the third item of the tuple.
308     swig_res = SWIG_AsPtr_std_string(PyTuple_GET_ITEM((PyObject *)$input, 2), &ptr);
309     if (!SWIG_IsOK(swig_res) || !ptr) {
310         delete ptr;
311         ptr = (std::string *)0;
312 	%dirout_fail((ptr ? swig_res : SWIG_TypeError), "($type, std::string, std::string)");
313     }
314     end = *ptr;
315     delete ptr;
316     ptr = (std::string *)0;
317 }
318 
319 /* These typemaps handle ValueRangeProcessors, which take non-const references
320  * to std::string and modify the strings.
321  */
322 %typemap(in) std::string &begin (std::string temp),
323              std::string &end (std::string temp) {
324     std::string *ptr = (std::string *)0;
325     int res = XapianSWIG_anystring_as_ptr($input, &ptr);
326     if (!SWIG_IsOK(res) || !ptr) {
327 	%argument_fail((ptr ? res : SWIG_TypeError), "$type", $symname, $argnum);
328     }
329     temp = *ptr;
330     $1 = &temp;
331     if (SWIG_IsNewObj(res)) delete ptr;
332 }
333 %typemap(argout) (std::string &begin, std::string &end) {
334     PyObject * str;
335     PyObject * newresult;
336 
337     // Put the existing result into the first item of a new 3-tuple.
338     newresult = PyTuple_New(3);
339     if (newresult == 0) {
340         Py_DECREF($result);
341         $result = NULL;
342         SWIG_fail;
343     }
344     PyTuple_SET_ITEM(newresult, 0, $result);
345     $result = newresult;
346 
347     str = PyBytes_FromStringAndSize($1->data(), $1->size());
348     if (str == 0) {
349         Py_DECREF($result);
350         $result = NULL;
351         SWIG_fail;
352     }
353     PyTuple_SET_ITEM($result, 1, str);
354 
355     str = PyBytes_FromStringAndSize($2->data(), $2->size());
356     if (str == 0) {
357         Py_DECREF($result);
358         $result = NULL;
359         SWIG_fail;
360     }
361 
362     PyTuple_SET_ITEM($result, 2, str);
363 }
364 
365 %typemap(directorin) (size_t num_tags, const std::string tags[]) {
366     PyObject * result = PyList_New(num_tags);
367     if (result == 0) {
368 	return NULL;
369     }
370 
371     for (size_t i = 0; i != num_tags; ++i) {
372 	PyObject * str = PyBytes_FromStringAndSize(tags[i].data(), tags[i].size());
373 	if (str == 0) {
374 	    Py_DECREF(result);
375 	    return NULL;
376 	}
377 
378 	PyList_SET_ITEM(result, i, str);
379     }
380     $input = result;
381 }
382 
383 /* vim:set syntax=cpp:set noexpandtab: */
384