1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | This source file is subject to version 3.01 of the PHP license, |
6 : | that is bundled with this package in the file LICENSE, and is |
7 : | available through the world-wide-web at the following url: |
8 : | http://www.php.net/license/3_01.txt |
9 : | If you did not receive a copy of the PHP license and are unable to |
10 : | obtain it through the world-wide-web, please send a note to |
11 : | license@php.net so we can mail you a copy immediately. |
12 : +----------------------------------------------------------------------+
13 : | Authors: Derick Rethans <derick@php.net> |
14 : +----------------------------------------------------------------------+
15 : */
16 :
17 : /* $Id: collator.c 266584 2008-09-20 22:06:18Z felipe $ */
18 :
19 : #include "php.h"
20 : #include "ext/standard/php_array.h"
21 : #include "zend_interfaces.h"
22 : #include "zend_exceptions.h"
23 : #include "php_unicode.h"
24 : #include <unicode/ucol.h>
25 :
26 :
27 : const zend_function_entry collator_funcs_collator[] = {
28 : ZEND_ME(collator, __construct, NULL, ZEND_ACC_PUBLIC)
29 : ZEND_FENTRY(getDefault, ZEND_FN(collator_get_default), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
30 : ZEND_FENTRY(setDefault, ZEND_FN(collator_set_default), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
31 : ZEND_NAMED_FE(compare, ZEND_FN(collator_compare), NULL)
32 : ZEND_NAMED_FE(setStrength, ZEND_FN(collator_set_strength), NULL)
33 : ZEND_NAMED_FE(setAttribute, ZEND_FN(collator_set_attribute), NULL)
34 : ZEND_NAMED_FE(getStrength, ZEND_FN(collator_get_strength), NULL)
35 : ZEND_NAMED_FE(getAttribute, ZEND_FN(collator_get_attribute), NULL)
36 : ZEND_NAMED_FE(sort, ZEND_FN(collator_sort), NULL)
37 : {NULL, NULL, NULL}
38 : };
39 :
40 : zend_class_entry *unicode_collator_ce;
41 :
42 : static zend_object_handlers unicode_object_handlers_collator;
43 :
44 : typedef struct _php_collator_obj php_collator_obj;
45 :
46 : struct _php_collator_obj {
47 : zend_object std;
48 : zend_collator *zcoll;
49 : };
50 :
51 : #define COLLATOR_SET_CONTEXT \
52 : zval *object; \
53 : object = getThis(); \
54 :
55 : #define COLLATOR_FETCH_OBJECT \
56 : php_collator_obj *obj; \
57 : COLLATOR_SET_CONTEXT; \
58 : if (object) { \
59 : if (zend_parse_parameters_none() == FAILURE) { \
60 : return; \
61 : } \
62 : } else { \
63 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, NULL, "O", &object, unicode_ce_collator) == FAILURE) { \
64 : RETURN_FALSE; \
65 : } \
66 : } \
67 : obj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
68 :
69 : static zend_object_value collator_object_create(zend_class_entry *class_type TSRMLS_DC);
70 : static void collator_object_free_storage(void *object TSRMLS_DC);
71 :
72 : static void collator_register_class(TSRMLS_D)
73 17007 : {
74 : zend_class_entry ce_collator;
75 :
76 17007 : INIT_CLASS_ENTRY(ce_collator, "Collator", collator_funcs_collator);
77 17007 : ce_collator.create_object = collator_object_create;
78 17007 : unicode_collator_ce = zend_register_internal_class_ex(&ce_collator, NULL, NULL TSRMLS_CC);
79 17007 : memcpy(&unicode_object_handlers_collator, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
80 17007 : unicode_object_handlers_collator.clone_obj = NULL;
81 :
82 : #define REGISTER_COLLATOR_CLASS_CONST_STRING(const_name, value) \
83 : zend_declare_class_constant_stringl(unicode_collator_ce, const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
84 : #define REGISTER_COLLATOR_CLASS_CONST_LONG(const_name, value) \
85 : zend_declare_class_constant_long(unicode_collator_ce, const_name, sizeof(const_name)-1, value TSRMLS_CC);
86 :
87 : /* Attributes */
88 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("FRENCH_COLLATION", UCOL_FRENCH_COLLATION);
89 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("ALTERNATE_HANDLING", UCOL_ALTERNATE_HANDLING);
90 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("CASE_FIRST", UCOL_CASE_FIRST);
91 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("CASE_LEVEL", UCOL_CASE_LEVEL);
92 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("NORMALIZATION_MODE", UCOL_NORMALIZATION_MODE);
93 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("STRENGTH", UCOL_STRENGTH);
94 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("HIRAGANA_QUARTERNARY_MODE", UCOL_HIRAGANA_QUATERNARY_MODE);
95 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("NUMERIC_COLLATION", UCOL_NUMERIC_COLLATION);
96 :
97 :
98 : /* Attribute value constants */
99 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("DEFAULT_VALUE", UCOL_DEFAULT);
100 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("PRIMARY", UCOL_PRIMARY);
101 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("SECONDARY", UCOL_SECONDARY);
102 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("TERTIARY", UCOL_TERTIARY);
103 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("DEFAULT_STRENGHT", UCOL_DEFAULT_STRENGTH);
104 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("QUARTERNARY", UCOL_QUATERNARY);
105 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("IDENTICAL", UCOL_IDENTICAL);
106 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("ON", UCOL_ON);
107 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("OFF", UCOL_OFF);
108 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("SHIFTED", UCOL_SHIFTED);
109 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("NON_IGNORABLE", UCOL_NON_IGNORABLE);
110 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("LOWER_FIRST", UCOL_LOWER_FIRST);
111 17007 : REGISTER_COLLATOR_CLASS_CONST_LONG("UPPER_FIRST", UCOL_UPPER_FIRST);
112 17007 : }
113 :
114 :
115 : void php_init_collation(TSRMLS_D)
116 17007 : {
117 17007 : collator_register_class(TSRMLS_C);
118 17007 : }
119 :
120 :
121 : static zend_object_value collator_object_create(zend_class_entry *ce TSRMLS_DC)
122 0 : {
123 : php_collator_obj *intern;
124 : zend_object_value retval;
125 : zval *tmp;
126 :
127 0 : intern = emalloc(sizeof(php_collator_obj));
128 0 : memset(intern, 0, sizeof(php_collator_obj));
129 :
130 0 : zend_object_std_init(&intern->std, ce TSRMLS_CC);
131 0 : zend_hash_copy(intern->std.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
132 :
133 0 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) collator_object_free_storage, NULL TSRMLS_CC);
134 0 : retval.handlers = &unicode_object_handlers_collator;
135 :
136 0 : return retval;
137 : }
138 :
139 : static void collator_object_free_storage(void *object TSRMLS_DC)
140 0 : {
141 0 : php_collator_obj *intern = (php_collator_obj *)object;
142 :
143 0 : if (intern->zcoll) {
144 0 : zend_collator_destroy(intern->zcoll);
145 : }
146 :
147 0 : zend_object_std_dtor(&intern->std TSRMLS_CC);
148 :
149 0 : efree(object);
150 0 : }
151 :
152 : static zval* collator_set_wrapper(zval *object, zend_collator *zcoll TSRMLS_DC)
153 0 : {
154 : php_collator_obj *coll_obj;
155 :
156 0 : if (Z_TYPE_P(object) != IS_OBJECT) {
157 0 : object_init_ex(object, unicode_collator_ce);
158 : }
159 :
160 0 : coll_obj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
161 0 : coll_obj->zcoll = zcoll;
162 :
163 0 : return object;
164 : }
165 :
166 : /* {{{ proto Collator::__construct(string locale) U
167 : Create a new Collator object */
168 : PHP_METHOD(collator, __construct)
169 0 : {
170 0 : zif_collator_create(INTERNAL_FUNCTION_PARAM_PASSTHRU);
171 0 : }
172 : /* }}} */
173 :
174 : /* {{{ proto Collator collator_create(string locale) U
175 : Create a new Collator object */
176 : PHP_FUNCTION(collator_create)
177 0 : {
178 0 : UErrorCode status = U_ZERO_ERROR;
179 : char *collator_name;
180 : int collator_name_len;
181 : zval *object;
182 : UCollator *ucoll;
183 : zend_error_handling error_handling;
184 :
185 0 : zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
186 :
187 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &collator_name, &collator_name_len) == FAILURE) {
188 0 : RETURN_FALSE;
189 : }
190 0 : zend_restore_error_handling(&error_handling TSRMLS_CC);
191 :
192 0 : if ((object = getThis()) == NULL) {
193 0 : object = return_value;
194 : }
195 0 : ucoll = ucol_open(collator_name, &status);
196 0 : if (U_FAILURE(status)) {
197 : /* UTODO handle error case properly */
198 0 : zend_error(E_ERROR, "Could not open collator for locale %s", collator_name);
199 0 : return;
200 : }
201 0 : collator_set_wrapper(object, zend_collator_create(ucoll) TSRMLS_CC);
202 : }
203 : /* }}} */
204 :
205 : /* {{{ proto int Collator::compare(string str1, string str2) U
206 : Compare two strings using collation }}} */
207 : /* {{{ proto int collator_compare(Collator coll, string str1, string str2) U
208 : Compare two strings using collation */
209 : PHP_FUNCTION(collator_compare)
210 0 : {
211 : zval *object;
212 : php_collator_obj *collatorobj;
213 : UChar *string1, *string2;
214 : int string1_len, string2_len;
215 :
216 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ouu", &object, unicode_collator_ce, &string1, &string1_len, &string2, &string2_len) == FAILURE) {
217 0 : RETURN_FALSE;
218 : }
219 0 : collatorobj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
220 0 : RETURN_LONG(ucol_strcoll(collatorobj->zcoll->coll, string1, string1_len, string2, string2_len));
221 : }
222 : /* }}} */
223 :
224 : /* {{{ proto array Collator::sort(array input) U
225 : Sort an array using collation }}} */
226 : /* {{{ proto array collator_sort(Collator coll, array input) U
227 : Sort an array using collation */
228 : PHP_FUNCTION(collator_sort)
229 0 : {
230 : zval *object;
231 : php_collator_obj *collatorobj;
232 : zval *array;
233 : HashTable *target_hash;
234 : zend_collator *orig_collator;
235 :
236 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa/", &object, unicode_collator_ce, &array) == FAILURE) {
237 0 : RETURN_FALSE;
238 : }
239 0 : collatorobj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
240 :
241 0 : target_hash = HASH_OF(array);
242 0 : php_set_compare_func(PHP_SORT_LOCALE_STRING TSRMLS_CC);
243 0 : orig_collator = UG(default_collator);
244 0 : UG(default_collator) = collatorobj->zcoll;
245 0 : if (zend_hash_sort(target_hash, zend_qsort, php_array_data_compare, 1 TSRMLS_CC) == FAILURE) {
246 0 : RETVAL_FALSE;
247 : } else {
248 0 : RETVAL_ZVAL(array, 1, 0);
249 : }
250 0 : UG(default_collator) = orig_collator;
251 : }
252 : /* }}} */
253 :
254 : /* {{{ proto void Collator::setStrength(int strength) U
255 : Set the collation strength }}} */
256 : /* {{{ proto void collator_set_strength(Collator coll, int strength) U
257 : Set the collation strength */
258 : PHP_FUNCTION(collator_set_strength)
259 0 : {
260 : zval *object;
261 : php_collator_obj *collatorobj;
262 : long strength;
263 :
264 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, unicode_collator_ce, &strength) == FAILURE) {
265 0 : RETURN_FALSE;
266 : }
267 0 : collatorobj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
268 0 : ucol_setStrength(collatorobj->zcoll->coll, strength);
269 : }
270 : /* }}} */
271 :
272 : /* {{{ proto int Collator::getStrength() U
273 : Returns the current collation strength }}} */
274 : /* {{{ proto int collator_get_strength(Collator coll) U
275 : Returns the current collation strength */
276 : PHP_FUNCTION(collator_get_strength)
277 0 : {
278 : zval *object;
279 : php_collator_obj *collatorobj;
280 :
281 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, unicode_collator_ce) == FAILURE) {
282 0 : RETURN_FALSE;
283 : }
284 0 : collatorobj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
285 0 : RETURN_LONG(ucol_getStrength(collatorobj->zcoll->coll));
286 : }
287 : /* }}} */
288 :
289 : /* {{{ proto bool Collator::setAttribute(int attribute, int value) U
290 : Set a collation attribute }}} */
291 : /* {{{ proto bool collator_set_attribute(Collator coll, int attribute, int value) U
292 : Set a collation attribute */
293 : PHP_FUNCTION(collator_set_attribute)
294 0 : {
295 : zval *object;
296 : php_collator_obj *collatorobj;
297 : long attribute, value;
298 : UErrorCode error;
299 :
300 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll", &object, unicode_collator_ce, &attribute, &value) == FAILURE) {
301 0 : RETURN_FALSE;
302 : }
303 0 : collatorobj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
304 0 : error = U_ZERO_ERROR;
305 0 : ucol_setAttribute(collatorobj->zcoll->coll, attribute, value, &error);
306 0 : RETURN_BOOL(error == U_ZERO_ERROR ? 1 : 0);
307 : }
308 : /* }}} */
309 :
310 :
311 : /* {{{ proto int Collator::getAttribute(int attribute) U
312 : Returns a collation attribute }}} */
313 : /* {{{ proto int collator_get_attribute(Collator coll, int attribute) U
314 : Returns a collation attribute */
315 : PHP_FUNCTION(collator_get_attribute)
316 0 : {
317 : zval *object;
318 : php_collator_obj *collatorobj;
319 : long attribute, value;
320 : UErrorCode error;
321 :
322 0 : if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &object, unicode_collator_ce, &attribute) == FAILURE) {
323 0 : RETURN_FALSE;
324 : }
325 0 : collatorobj = (php_collator_obj *) zend_object_store_get_object(object TSRMLS_CC);
326 0 : error = U_ZERO_ERROR;
327 0 : value = ucol_getAttribute(collatorobj->zcoll->coll, attribute, &error);
328 0 : if (error != U_ZERO_ERROR) {
329 0 : RETURN_FALSE;
330 : }
331 0 : RETURN_LONG(value);
332 : }
333 : /* }}} */
334 :
335 : /* {{{ proto Collator collator_get_default(void) U
336 : Returns default collator */
337 : PHP_FUNCTION(collator_get_default)
338 0 : {
339 0 : if (zend_parse_parameters_none() == FAILURE) {
340 0 : RETURN_FALSE;
341 : }
342 :
343 0 : UG(default_collator)->refcount++;
344 0 : collator_set_wrapper(return_value, UG(default_collator) TSRMLS_CC);
345 : }
346 : /* }}} */
347 :
348 : /* {{{ proto void collator_set_default(Collator coll) U
349 : Sets default collator */
350 : PHP_FUNCTION(collator_set_default)
351 0 : {
352 : zval *coll;
353 : php_collator_obj *coll_obj;
354 :
355 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &coll, unicode_collator_ce) == FAILURE) {
356 0 : RETURN_FALSE;
357 : }
358 :
359 0 : coll_obj = (php_collator_obj *) zend_object_store_get_object(coll TSRMLS_CC);
360 0 : zend_collator_destroy(UG(default_collator));
361 0 : coll_obj->zcoll->refcount++;
362 0 : UG(default_collator) = coll_obj->zcoll;
363 :
364 0 : RETURN_TRUE;
365 : }
366 : /* }}} */
367 :
368 : /*
369 : * Local variables:
370 : * tab-width: 4
371 : * c-basic-offset: 4
372 : * End:
373 : * vim600: noet sw=4 ts=4 fdm=marker
374 : * vim<600: noet sw=4 ts=4
375 : */
|