1 /*
2 +----------------------------------------------------------------------+
3 | This source file is subject to version 3.01 of the PHP license, |
4 | that is bundled with this package in the file LICENSE, and is |
5 | available through the world-wide-web at the following url: |
6 | http://www.php.net/license/3_01.txt |
7 | If you did not receive a copy of the PHP license and are unable to |
8 | obtain it through the world-wide-web, please send a note to |
9 | license@php.net so we can mail you a copy immediately. |
10 +----------------------------------------------------------------------+
11 | Authors: Gustavo Lopes <cataphract@php.net> |
12 +----------------------------------------------------------------------+
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #include <unicode/brkiter.h>
20 #include "codepointiterator_internal.h"
21
22 #include "breakiterator_iterators.h"
23
24 extern "C" {
25 #include "../php_intl.h"
26 #define USE_BREAKITERATOR_POINTER 1
27 #include "breakiterator_class.h"
28 #include "../locale/locale.h"
29 #include <zend_exceptions.h>
30 #include <zend_interfaces.h>
31 }
32
33 using PHP::CodePointBreakIterator;
34 using icu::BreakIterator;
35 using icu::Locale;
36
PHP_METHOD(IntlBreakIterator,__construct)37 U_CFUNC PHP_METHOD(IntlBreakIterator, __construct)
38 {
39 zend_throw_exception( NULL,
40 "An object of this type cannot be created with the new operator",
41 0 );
42 }
43
_breakiter_factory(const char * func_name,BreakIterator * (* func)(const Locale &,UErrorCode &),INTERNAL_FUNCTION_PARAMETERS)44 static void _breakiter_factory(const char *func_name,
45 BreakIterator *(*func)(const Locale&, UErrorCode&),
46 INTERNAL_FUNCTION_PARAMETERS)
47 {
48 BreakIterator *biter;
49 const char *locale_str = NULL;
50 size_t dummy;
51 char *msg;
52 UErrorCode status = UErrorCode();
53 intl_error_reset(NULL);
54
55 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s!",
56 &locale_str, &dummy) == FAILURE) {
57 RETURN_THROWS();
58 }
59
60 if (locale_str == NULL) {
61 locale_str = intl_locale_get_default();
62 }
63
64 biter = func(Locale::createFromName(locale_str), status);
65 intl_error_set_code(NULL, status);
66 // Todo check if this can happen?
67 if (U_FAILURE(status)) {
68 spprintf(&msg, 0, "%s: error creating BreakIterator",
69 func_name);
70 intl_error_set_custom_msg(NULL, msg, 1);
71 efree(msg);
72 RETURN_NULL();
73 }
74
75 breakiterator_object_create(return_value, biter, 1);
76 }
77
PHP_METHOD(IntlBreakIterator,createWordInstance)78 U_CFUNC PHP_METHOD(IntlBreakIterator, createWordInstance)
79 {
80 _breakiter_factory("breakiter_create_word_instance",
81 &BreakIterator::createWordInstance,
82 INTERNAL_FUNCTION_PARAM_PASSTHRU);
83 }
84
PHP_METHOD(IntlBreakIterator,createLineInstance)85 U_CFUNC PHP_METHOD(IntlBreakIterator, createLineInstance)
86 {
87 _breakiter_factory("breakiter_create_line_instance",
88 &BreakIterator::createLineInstance,
89 INTERNAL_FUNCTION_PARAM_PASSTHRU);
90 }
91
PHP_METHOD(IntlBreakIterator,createCharacterInstance)92 U_CFUNC PHP_METHOD(IntlBreakIterator, createCharacterInstance)
93 {
94 _breakiter_factory("breakiter_create_character_instance",
95 &BreakIterator::createCharacterInstance,
96 INTERNAL_FUNCTION_PARAM_PASSTHRU);
97 }
98
PHP_METHOD(IntlBreakIterator,createSentenceInstance)99 U_CFUNC PHP_METHOD(IntlBreakIterator, createSentenceInstance)
100 {
101 _breakiter_factory("breakiter_create_sentence_instance",
102 &BreakIterator::createSentenceInstance,
103 INTERNAL_FUNCTION_PARAM_PASSTHRU);
104 }
105
PHP_METHOD(IntlBreakIterator,createTitleInstance)106 U_CFUNC PHP_METHOD(IntlBreakIterator, createTitleInstance)
107 {
108 _breakiter_factory("breakiter_create_title_instance",
109 &BreakIterator::createTitleInstance,
110 INTERNAL_FUNCTION_PARAM_PASSTHRU);
111 }
112
PHP_METHOD(IntlBreakIterator,createCodePointInstance)113 U_CFUNC PHP_METHOD(IntlBreakIterator, createCodePointInstance)
114 {
115 intl_error_reset(NULL);
116
117 if (zend_parse_parameters_none() == FAILURE) {
118 RETURN_THROWS();
119 }
120
121 CodePointBreakIterator *cpbi = new CodePointBreakIterator();
122 breakiterator_object_create(return_value, cpbi, 1);
123 }
124
PHP_METHOD(IntlBreakIterator,getText)125 U_CFUNC PHP_METHOD(IntlBreakIterator, getText)
126 {
127 BREAKITER_METHOD_INIT_VARS;
128 object = ZEND_THIS;
129
130 if (zend_parse_parameters_none() == FAILURE) {
131 RETURN_THROWS();
132 }
133
134 BREAKITER_METHOD_FETCH_OBJECT;
135
136 if (Z_ISUNDEF(bio->text)) {
137 RETURN_NULL();
138 } else {
139 ZVAL_COPY(return_value, &bio->text);
140 }
141 }
142
PHP_METHOD(IntlBreakIterator,setText)143 U_CFUNC PHP_METHOD(IntlBreakIterator, setText)
144 {
145 UText *ut = NULL;
146 zend_string *text;
147 BREAKITER_METHOD_INIT_VARS;
148 object = ZEND_THIS;
149
150 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
151 RETURN_THROWS();
152 }
153
154 BREAKITER_METHOD_FETCH_OBJECT;
155
156 ut = utext_openUTF8(ut, ZSTR_VAL(text), ZSTR_LEN(text), BREAKITER_ERROR_CODE_P(bio));
157 INTL_METHOD_CHECK_STATUS_OR_NULL(bio, "breakiter_set_text: error opening UText");
158
159 bio->biter->setText(ut, BREAKITER_ERROR_CODE(bio));
160 utext_close(ut); /* ICU shallow clones the UText */
161 INTL_METHOD_CHECK_STATUS_OR_NULL(bio, "breakiter_set_text: error calling "
162 "BreakIterator::setText()");
163
164 /* When ICU clones the UText, it does not copy the buffer, so we have to
165 * keep the string buffer around by holding a reference to its zval. This
166 * also allows a faste implementation of getText() */
167 zval_ptr_dtor(&bio->text);
168 ZVAL_STR_COPY(&bio->text, text);
169
170 RETURN_TRUE;
171 }
172
_breakiter_no_args_ret_int32(int32_t (BreakIterator::* func)(),INTERNAL_FUNCTION_PARAMETERS)173 static void _breakiter_no_args_ret_int32(
174 int32_t (BreakIterator::*func)(),
175 INTERNAL_FUNCTION_PARAMETERS)
176 {
177 char *msg;
178 BREAKITER_METHOD_INIT_VARS;
179 object = ZEND_THIS;
180
181 if (zend_parse_parameters_none() == FAILURE) {
182 RETURN_THROWS();
183 }
184
185 BREAKITER_METHOD_FETCH_OBJECT;
186
187 int32_t res = (bio->biter->*func)();
188
189 RETURN_LONG((zend_long)res);
190 }
191
_breakiter_int32_ret_int32(int32_t (BreakIterator::* func)(int32_t),INTERNAL_FUNCTION_PARAMETERS)192 static void _breakiter_int32_ret_int32(
193 int32_t (BreakIterator::*func)(int32_t),
194 INTERNAL_FUNCTION_PARAMETERS)
195 {
196 zend_long arg;
197 BREAKITER_METHOD_INIT_VARS;
198 object = ZEND_THIS;
199
200 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &arg) == FAILURE) {
201 RETURN_THROWS();
202 }
203
204 BREAKITER_METHOD_FETCH_OBJECT;
205
206 if (arg < INT32_MIN || arg > INT32_MAX) {
207 zend_argument_value_error(1, "must be between %d and %d", INT32_MIN, INT32_MAX);
208 RETURN_THROWS();
209 }
210
211 int32_t res = (bio->biter->*func)((int32_t)arg);
212
213 RETURN_LONG((zend_long)res);
214 }
215
PHP_METHOD(IntlBreakIterator,first)216 U_CFUNC PHP_METHOD(IntlBreakIterator, first)
217 {
218 _breakiter_no_args_ret_int32(&BreakIterator::first,
219 INTERNAL_FUNCTION_PARAM_PASSTHRU);
220 }
221
PHP_METHOD(IntlBreakIterator,last)222 U_CFUNC PHP_METHOD(IntlBreakIterator, last)
223 {
224 _breakiter_no_args_ret_int32(&BreakIterator::last,
225 INTERNAL_FUNCTION_PARAM_PASSTHRU);
226 }
227
PHP_METHOD(IntlBreakIterator,previous)228 U_CFUNC PHP_METHOD(IntlBreakIterator, previous)
229 {
230 _breakiter_no_args_ret_int32(&BreakIterator::previous,
231 INTERNAL_FUNCTION_PARAM_PASSTHRU);
232 }
233
PHP_METHOD(IntlBreakIterator,next)234 U_CFUNC PHP_METHOD(IntlBreakIterator, next)
235 {
236 zval *arg = NULL;
237
238 if (ZEND_NUM_ARGS() == 0) {
239 goto no_arg_version;
240 }
241 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z!", &arg) == FAILURE) {
242 RETURN_THROWS();
243 }
244
245 if (arg == NULL) {
246 ZEND_NUM_ARGS() = 0; /* pretend we don't have any argument */
247 no_arg_version:
248 _breakiter_no_args_ret_int32(&BreakIterator::next,
249 INTERNAL_FUNCTION_PARAM_PASSTHRU);
250 } else {
251 _breakiter_int32_ret_int32(&BreakIterator::next,
252 INTERNAL_FUNCTION_PARAM_PASSTHRU);
253 }
254 }
255
PHP_METHOD(IntlBreakIterator,current)256 U_CFUNC PHP_METHOD(IntlBreakIterator, current)
257 {
258 BREAKITER_METHOD_INIT_VARS;
259 object = ZEND_THIS;
260
261 if (zend_parse_parameters_none() == FAILURE) {
262 RETURN_THROWS();
263 }
264
265 BREAKITER_METHOD_FETCH_OBJECT;
266
267 int32_t res = bio->biter->current();
268
269 RETURN_LONG((zend_long)res);
270 }
271
PHP_METHOD(IntlBreakIterator,following)272 U_CFUNC PHP_METHOD(IntlBreakIterator, following)
273 {
274 _breakiter_int32_ret_int32(
275 &BreakIterator::following,
276 INTERNAL_FUNCTION_PARAM_PASSTHRU);
277 }
278
PHP_METHOD(IntlBreakIterator,preceding)279 U_CFUNC PHP_METHOD(IntlBreakIterator, preceding)
280 {
281 _breakiter_int32_ret_int32(
282 &BreakIterator::preceding,
283 INTERNAL_FUNCTION_PARAM_PASSTHRU);
284 }
285
PHP_METHOD(IntlBreakIterator,isBoundary)286 U_CFUNC PHP_METHOD(IntlBreakIterator, isBoundary)
287 {
288 zend_long offset;
289 BREAKITER_METHOD_INIT_VARS;
290 object = ZEND_THIS;
291
292 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l",
293 &offset) == FAILURE) {
294 RETURN_THROWS();
295 }
296
297 if (offset < INT32_MIN || offset > INT32_MAX) {
298 zend_argument_value_error(1, "must be between %d and %d", INT32_MIN, INT32_MAX);
299 RETURN_THROWS();
300 }
301
302 BREAKITER_METHOD_FETCH_OBJECT;
303
304 UBool res = bio->biter->isBoundary((int32_t)offset);
305
306 RETURN_BOOL((zend_long)res);
307 }
308
PHP_METHOD(IntlBreakIterator,getLocale)309 U_CFUNC PHP_METHOD(IntlBreakIterator, getLocale)
310 {
311 zend_long locale_type;
312 BREAKITER_METHOD_INIT_VARS;
313 object = ZEND_THIS;
314
315 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &locale_type) == FAILURE) {
316 RETURN_THROWS();
317 }
318
319 /* Change to ValueError? */
320 if (locale_type != ULOC_ACTUAL_LOCALE && locale_type != ULOC_VALID_LOCALE) {
321 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
322 "breakiter_get_locale: invalid locale type", 0);
323 RETURN_FALSE;
324 }
325
326 BREAKITER_METHOD_FETCH_OBJECT;
327
328 Locale locale = bio->biter->getLocale((ULocDataLocaleType)locale_type,
329 BREAKITER_ERROR_CODE(bio));
330 INTL_METHOD_CHECK_STATUS(bio,
331 "breakiter_get_locale: Call to ICU method has failed");
332
333 RETURN_STRING(locale.getName());
334 }
335
PHP_METHOD(IntlBreakIterator,getPartsIterator)336 U_CFUNC PHP_METHOD(IntlBreakIterator, getPartsIterator)
337 {
338 zend_long key_type = 0;
339 BREAKITER_METHOD_INIT_VARS;
340 object = ZEND_THIS;
341
342 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &key_type) == FAILURE) {
343 RETURN_THROWS();
344 }
345
346 if (key_type != PARTS_ITERATOR_KEY_SEQUENTIAL
347 && key_type != PARTS_ITERATOR_KEY_LEFT
348 && key_type != PARTS_ITERATOR_KEY_RIGHT) {
349 zend_argument_value_error(1, "must be one of IntlPartsIterator::KEY_SEQUENTIAL, "
350 "IntlPartsIterator::KEY_LEFT, or IntlPartsIterator::KEY_RIGHT");
351 RETURN_THROWS();
352 }
353
354 BREAKITER_METHOD_FETCH_OBJECT;
355
356 IntlIterator_from_BreakIterator_parts(
357 object, return_value, (parts_iter_key_type)key_type);
358 }
359
PHP_METHOD(IntlBreakIterator,getErrorCode)360 U_CFUNC PHP_METHOD(IntlBreakIterator, getErrorCode)
361 {
362 BREAKITER_METHOD_INIT_VARS;
363 object = ZEND_THIS;
364
365 if (zend_parse_parameters_none() == FAILURE) {
366 RETURN_THROWS();
367 }
368
369 /* Fetch the object (without resetting its last error code ). */
370 bio = Z_INTL_BREAKITERATOR_P(object);
371 RETURN_LONG((zend_long)BREAKITER_ERROR_CODE(bio));
372 }
373
PHP_METHOD(IntlBreakIterator,getErrorMessage)374 U_CFUNC PHP_METHOD(IntlBreakIterator, getErrorMessage)
375 {
376 zend_string* message = NULL;
377 BREAKITER_METHOD_INIT_VARS;
378 object = ZEND_THIS;
379
380 if (zend_parse_parameters_none() == FAILURE) {
381 RETURN_THROWS();
382 }
383
384
385 /* Fetch the object (without resetting its last error code ). */
386 bio = Z_INTL_BREAKITERATOR_P(object);
387
388 /* Return last error message. */
389 message = intl_error_get_message(BREAKITER_ERROR_P(bio));
390 RETURN_STR(message);
391 }
392
PHP_METHOD(IntlBreakIterator,getIterator)393 U_CFUNC PHP_METHOD(IntlBreakIterator, getIterator)
394 {
395 if (zend_parse_parameters_none() == FAILURE) {
396 return;
397 }
398
399 zend_create_internal_iterator_zval(return_value, ZEND_THIS);
400 }
401