[ci] Fix clang-santisers job for GHA change
[xapian.git] / xapian-bindings / php / php.i
blob299b78b1b72fc0b1e4ac5e1e44ffed3ab0cfa366
1 %module(directors="1") xapian
2 %{
3 /* php.i: SWIG interface file for the PHP bindings
5 * Copyright (C) 2004-2022 Olly Betts
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
23 #include "../xapian-version.h"
26 // This works around a build failure on Illuminos:
27 // https://trac.xapian.org/ticket/793
28 %begin %{
29 #include <string>
33 extern "C" {
34 // Needed for php_array_merge().
35 #include <ext/standard/php_array.h>
39 // Use SWIG directors for PHP wrappers.
40 #define XAPIAN_SWIG_DIRECTORS
42 %include ../xapian-head.i
44 /* Add a section to the output from phpinfo(). */
45 %pragma(php) phpinfo="\
46 php_info_print_table_start();\n\
47 php_info_print_table_row(2, \"Xapian Support\", \"enabled\");\n\
48 php_info_print_table_row(2, \"Xapian Compiled Version\",\n\
49 XAPIAN_BINDINGS_VERSION);\n\
50 php_info_print_table_row(2, \"Xapian Linked Version\",\n\
51 Xapian::version_string());\n\
52 php_info_print_table_end();\
55 %pragma(php) version=PACKAGE_VERSION
57 %rename("is_empty") empty() const;
58 %rename("clone_object") clone() const;
60 /* Handle op as an int rather than an enum. */
61 %apply int { Xapian::Query::op };
63 /* STRING has a lower precedence that numbers, but the SWIG PHP check for
64 * number (in 1.3.28 at least) includes IS_STRING which means that for a
65 * method taking either int or string, the int version will always be used.
66 * Simplest workaround is to set the precedence here higher that the numeric
67 * precedences - i.e. SWIG_TYPECHECK_VOIDPTR instead of SWIG_TYPECHECK_STRING.
69 %typemap(typecheck, precedence=SWIG_TYPECHECK_VOIDPTR) const std::string & {
70 $1 = (Z_TYPE($input) == IS_STRING);
73 /* The SWIG overloading doesn't handle this correctly by default. */
74 %typemap(typecheck, precedence=SWIG_TYPECHECK_BOOL) bool {
75 $1 = (Z_TYPE($input) == IS_TRUE || Z_TYPE($input) == IS_FALSE || Z_TYPE($input) == IS_LONG);
78 #define XAPIAN_MIXED_SUBQUERIES_BY_ITERATOR_TYPEMAP
80 %typemap(typecheck, precedence=500) (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
81 $1 = (Z_TYPE($input) == IS_ARRAY);
82 /* FIXME: if we add more array typemaps, we'll need to check the elements
83 * of the array here to disambiguate. */
87 /** Merge _ps properties.
89 * We use these to keep references to XapianPostingSource objects used in
90 * XapianQuery objects.
92 static void merge_ps_references(zval* target_this, zval& input) {
93 zval* zvq = zend_read_property(Z_OBJCE(input), Z_OBJ(input), "_ps", strlen("_ps"), false, NULL);
94 if (zend_hash_num_elements(Z_ARR_P(zvq)) > 0) {
95 zval* zv = zend_read_property(Z_OBJCE_P(target_this), Z_OBJ_P(target_this), "_ps", strlen("_ps"), false, NULL);
96 if (zend_hash_num_elements(Z_ARR_P(zv)) == 0) {
97 ZVAL_COPY(zv, zvq);
98 } else {
99 SEPARATE_ARRAY(zv);
100 php_array_merge(Z_ARR_P(zv), Z_ARR_P(zvq));
105 class XapianSWIGQueryItor {
106 #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2
107 Bucket* p;
108 #else
109 zval* p;
110 size_t elt_size;
111 #endif
113 zval* target_this;
115 public:
116 typedef std::random_access_iterator_tag iterator_category;
117 typedef Xapian::Query value_type;
118 typedef Xapian::termcount_diff difference_type;
119 typedef Xapian::Query * pointer;
120 typedef Xapian::Query & reference;
122 XapianSWIGQueryItor()
123 : p(NULL) { }
125 void begin(zval* input, zval* target_this_) {
126 HashTable *ht = Z_ARRVAL_P(input);
127 #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2
128 p = ht->arData;
129 #else
130 elt_size = ZEND_HASH_ELEMENT_SIZE(ht);
131 p = ZEND_HASH_ELEMENT(ht, 0);
132 #endif
133 target_this = target_this_;
136 void end(zval * input) {
137 HashTable *ht = Z_ARRVAL_P(input);
138 #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2
139 p = ht->arData + ht->nNumUsed;
140 #else
141 elt_size = ZEND_HASH_ELEMENT_SIZE(ht);
142 p = ZEND_HASH_ELEMENT(ht, ht->nNumUsed);
143 #endif
146 XapianSWIGQueryItor & operator++() {
147 #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2
148 ++p;
149 #else
150 p = ZEND_HASH_NEXT_ELEMENT(p, elt_size);
151 #endif
152 return *this;
155 Xapian::Query operator*() const {
156 #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2
157 zval *item = &p->val;
158 #else
159 zval *item = p;
160 #endif
162 if (Z_TYPE_P(item) == IS_STRING) {
163 size_t len = Z_STRLEN_P(item);
164 const char *str = Z_STRVAL_P(item);
165 return Xapian::Query(string(str, len));
168 Xapian::Query *subq = 0;
169 if (SWIG_ConvertPtr(item, (void **)&subq,
170 SWIGTYPE_p_Xapian__Query, 0) < 0) {
171 subq = 0;
173 if (!subq) {
174 SWIG_PHP_Error(E_ERROR, "Expected XapianQuery object or string");
175 fail: // Label which SWIG_PHP_Error needs.
176 return Xapian::Query();
178 merge_ps_references(target_this, *item);
179 return *subq;
182 bool operator==(const XapianSWIGQueryItor & o) {
183 return p == o.p;
186 bool operator!=(const XapianSWIGQueryItor & o) {
187 return !(*this == o);
190 difference_type operator-(const XapianSWIGQueryItor &o) const {
191 #if PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 2
192 return p - o.p;
193 #else
194 auto d = reinterpret_cast<const char*>(p) -
195 reinterpret_cast<const char*>(o.p);
196 return d / elt_size;
197 #endif
203 %typemap(in, phptype="array") (XapianSWIGQueryItor qbegin, XapianSWIGQueryItor qend) {
204 // $1 and $2 are default initialised where SWIG declares them.
205 if (Z_TYPE($input) == IS_ARRAY) {
206 // The typecheck typemap should have ensured this is an array.
207 $1.begin(&$input, ZEND_THIS);
208 $2.end(&$input);
212 #define XAPIAN_TERMITERATOR_PAIR_OUTPUT_TYPEMAP
213 %typemap(out, phptype="array") std::pair<Xapian::TermIterator, Xapian::TermIterator> {
214 array_init($result);
216 for (Xapian::TermIterator i = $1.first; i != $1.second; ++i) {
217 const string& term = *i;
218 add_next_index_stringl($result, term.data(), term.length());
222 %typemap(directorin) (size_t num_tags, const std::string tags[]) {
223 array_init_size($input, num_tags);
225 for (size_t i = 0; i != num_tags; ++i) {
226 const string& term = tags[i];
227 add_next_index_stringl($input, term.data(), term.length());
232 #include <xapian/iterator.h>
235 %define PHP_ITERATOR(NS, CLASS, RET_TYPE, REWIND_ACTION)
236 %typemap("phpinterfaces") NS::CLASS "Iterator";
237 %extend NS::CLASS {
238 const NS::CLASS & key() { return *self; }
239 RET_TYPE current() { return **self; }
240 bool valid() { return Xapian::iterator_valid(*self); }
241 void rewind() { REWIND_ACTION }
243 %enddef
245 PHP_ITERATOR(Xapian, ESetIterator, std::string, Xapian::iterator_rewind(*self);)
246 PHP_ITERATOR(Xapian, MSetIterator, Xapian::docid, Xapian::iterator_rewind(*self);)
247 PHP_ITERATOR(Xapian, TermIterator, std::string, )
248 PHP_ITERATOR(Xapian, PositionIterator, Xapian::termpos, )
249 PHP_ITERATOR(Xapian, PostingIterator, Xapian::docid, )
250 PHP_ITERATOR(Xapian, ValueIterator, std::string, )
252 %include except.i
254 %define XAPIAN_FUNCTOR(CLASS, PARAM, CODE...)
255 %typemap(in, phptype="SWIGTYPE") (CLASS PARAM) %{
256 $typemap(in, CLASS)
257 { CODE }
259 %enddef
261 XAPIAN_FUNCTOR(Xapian::FieldProcessor*, proc,
262 zval* zv = zend_read_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_procs", strlen("_procs"), false, NULL);
263 SEPARATE_ARRAY(zv);
264 Z_ADDREF($input);
265 add_next_index_zval(zv, &$input);
268 XAPIAN_FUNCTOR(Xapian::RangeProcessor*, range_proc,
269 zval* zv = zend_read_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_procs", strlen("_procs"), false, NULL);
270 SEPARATE_ARRAY(zv);
271 Z_ADDREF($input);
272 add_next_index_zval(zv, &$input);
275 XAPIAN_FUNCTOR(Xapian::Stopper*, stop,
276 zend_update_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_stopper", strlen("_stopper"), &$input);
279 XAPIAN_FUNCTOR(Xapian::KeyMaker*, sorter,
280 zend_update_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_sorter", strlen("_sorter"), &$input);
283 // Unset _sorter on any set_sort_by_...() which sets sorting by a slot.
284 %typemap(in, phptype="int") (Xapian::valueno sort_key) %{
285 $typemap(in, Xapian::valueno)
286 zend_update_property_null(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_sorter", strlen("_sorter"));
289 %typemap(out, phptype="void") (void Xapian::Enquire::set_sort_by_relevance) %{
290 zend_update_property_null(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_sorter", strlen("_sorter"));
293 %typemap(out, phptype="void") (void Xapian::Enquire::clear_matchspies) %{
294 { zval z; ZVAL_EMPTY_ARRAY(&z); zend_update_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_spies", strlen("_spies"), &z); }
297 XAPIAN_FUNCTOR(Xapian::MatchSpy*, spy,
298 zval* zv = zend_read_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_spies", strlen("_spies"), false, NULL);
299 SEPARATE_ARRAY(zv);
300 Z_ADDREF($input);
301 add_next_index_zval(zv, &$input);
304 XAPIAN_FUNCTOR(Xapian::PostingSource*, source,
305 zval* zv = zend_read_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_ps", strlen("_ps"), false, NULL);
306 SEPARATE_ARRAY(zv);
307 Z_ADDREF($input);
308 add_next_index_zval(zv, &$input);
311 XAPIAN_FUNCTOR(const Xapian::Query&, a, merge_ps_references(ZEND_THIS, $input);)
313 XAPIAN_FUNCTOR(const Xapian::Query&, b, merge_ps_references(ZEND_THIS, $input);)
315 XAPIAN_FUNCTOR(const Xapian::Query&, subquery, merge_ps_references(ZEND_THIS, $input);)
317 // Enquire::set_query() stores the PHP query object, which means we hold on to any
318 // references to PHP XapianPostingSource objects it contains.
319 XAPIAN_FUNCTOR(const Xapian::Query&, query,
320 zend_update_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_query", strlen("_query"), &$input);
323 // Then Enquire::get_query() returns the PHP query object if one is set, otherwise
324 // it returns the result C++ gave us (which will be an empty XapianQuery object.
325 // We could avoid calling C++ at all here, but I don't see an easy way to do so.
326 // This isn't a widely used method, and the C++ call should be pretty cheap anyway.
327 %typemap(out, phptype="SWIGTYPE") (const Xapian::Query& Xapian::Enquire::get_query) %{
329 zval* zv = zend_read_property(Z_OBJCE_P(ZEND_THIS), Z_OBJ_P(ZEND_THIS), "_query", strlen("_query"), false, NULL);
330 if (Z_TYPE_P(zv) == IS_OBJECT) {
331 RETVAL_OBJ_COPY(Z_OBJ_P(zv));
332 } else {
333 $typemap(out, const Query&)
338 %include ../xapian-headers.i
340 // Compatibility wrapping for Xapian::BAD_VALUENO (wrapped as a constant since
341 // xapian-bindings 1.4.10).
342 %inline %{
343 namespace Xapian {
344 static Xapian::valueno BAD_VALUENO_get() { return Xapian::BAD_VALUENO; }
347 // Can't throw an exception.
348 %exception Xapian::BAD_VALUENO_get "$action"