summaryrefslogtreecommitdiff
path: root/ext/intl/collator
diff options
context:
space:
mode:
Diffstat (limited to 'ext/intl/collator')
-rw-r--r--ext/intl/collator/collator.c96
-rw-r--r--ext/intl/collator/collator.h29
-rw-r--r--ext/intl/collator/collator_attr.c157
-rw-r--r--ext/intl/collator/collator_attr.h28
-rw-r--r--ext/intl/collator/collator_class.c202
-rw-r--r--ext/intl/collator/collator_class.h69
-rw-r--r--ext/intl/collator/collator_compare.c133
-rw-r--r--ext/intl/collator/collator_compare.h25
-rw-r--r--ext/intl/collator/collator_convert.c485
-rw-r--r--ext/intl/collator/collator_convert.h38
-rw-r--r--ext/intl/collator/collator_create.c87
-rw-r--r--ext/intl/collator/collator_create.h27
-rw-r--r--ext/intl/collator/collator_error.c94
-rw-r--r--ext/intl/collator/collator_error.h26
-rw-r--r--ext/intl/collator/collator_is_numeric.c305
-rw-r--r--ext/intl/collator/collator_is_numeric.h26
-rw-r--r--ext/intl/collator/collator_locale.c80
-rw-r--r--ext/intl/collator/collator_locale.h25
-rw-r--r--ext/intl/collator/collator_sort.c621
-rw-r--r--ext/intl/collator/collator_sort.h30
20 files changed, 2583 insertions, 0 deletions
diff --git a/ext/intl/collator/collator.c b/ext/intl/collator/collator.c
new file mode 100644
index 0000000..047a738
--- /dev/null
+++ b/ext/intl/collator/collator.c
@@ -0,0 +1,96 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "collator_class.h"
+#include "collator.h"
+
+#include <unicode/utypes.h>
+#include <unicode/ucol.h>
+#include <unicode/ustring.h>
+
+/* {{{ collator_register_constants
+ * Register constants common for the both (OO and procedural)
+ * APIs.
+ */
+void collator_register_constants( INIT_FUNC_ARGS )
+{
+ if( !Collator_ce_ptr )
+ {
+ zend_error( E_ERROR, "Collator class not defined" );
+ return;
+ }
+
+ #define COLLATOR_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS)
+ #define COLLATOR_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( Collator_ce_ptr, ZEND_STRS( #x ) - 1, UCOL_##x TSRMLS_CC );
+ #define COLLATOR_EXPOSE_CUSTOM_CLASS_CONST(name, value) zend_declare_class_constant_long( Collator_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );
+
+ /* UColAttributeValue constants */
+ COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "DEFAULT_VALUE", UCOL_DEFAULT );
+
+ COLLATOR_EXPOSE_CLASS_CONST( PRIMARY );
+ COLLATOR_EXPOSE_CLASS_CONST( SECONDARY );
+ COLLATOR_EXPOSE_CLASS_CONST( TERTIARY );
+ COLLATOR_EXPOSE_CLASS_CONST( DEFAULT_STRENGTH );
+ COLLATOR_EXPOSE_CLASS_CONST( QUATERNARY );
+ COLLATOR_EXPOSE_CLASS_CONST( IDENTICAL );
+
+ COLLATOR_EXPOSE_CLASS_CONST( OFF );
+ COLLATOR_EXPOSE_CLASS_CONST( ON );
+
+ COLLATOR_EXPOSE_CLASS_CONST( SHIFTED );
+ COLLATOR_EXPOSE_CLASS_CONST( NON_IGNORABLE );
+
+ COLLATOR_EXPOSE_CLASS_CONST( LOWER_FIRST );
+ COLLATOR_EXPOSE_CLASS_CONST( UPPER_FIRST );
+
+ /* UColAttribute constants */
+ COLLATOR_EXPOSE_CLASS_CONST( FRENCH_COLLATION );
+ COLLATOR_EXPOSE_CLASS_CONST( ALTERNATE_HANDLING );
+ COLLATOR_EXPOSE_CLASS_CONST( CASE_FIRST );
+ COLLATOR_EXPOSE_CLASS_CONST( CASE_LEVEL );
+ COLLATOR_EXPOSE_CLASS_CONST( NORMALIZATION_MODE );
+ COLLATOR_EXPOSE_CLASS_CONST( STRENGTH );
+ COLLATOR_EXPOSE_CLASS_CONST( HIRAGANA_QUATERNARY_MODE );
+ COLLATOR_EXPOSE_CLASS_CONST( NUMERIC_COLLATION );
+
+ /* ULocDataLocaleType constants */
+ COLLATOR_EXPOSE_CONST( ULOC_ACTUAL_LOCALE );
+ COLLATOR_EXPOSE_CONST( ULOC_VALID_LOCALE );
+
+ /* sort flags */
+ COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "SORT_REGULAR", COLLATOR_SORT_REGULAR );
+ COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "SORT_STRING", COLLATOR_SORT_STRING );
+ COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "SORT_NUMERIC", COLLATOR_SORT_NUMERIC );
+
+ #undef COLLATOR_EXPOSE_CUSTOM_CLASS_CONST
+ #undef COLLATOR_EXPOSE_CLASS_CONST
+ #undef COLLATOR_EXPOSE_CONST
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator.h b/ext/intl/collator/collator.h
new file mode 100644
index 0000000..96e7aa0
--- /dev/null
+++ b/ext/intl/collator/collator.h
@@ -0,0 +1,29 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_COLLATOR_H
+#define CCOLLATOR_COLLATOR_H
+
+#include <php.h>
+
+#define COLLATOR_SORT_REGULAR 0
+#define COLLATOR_SORT_STRING 1
+#define COLLATOR_SORT_NUMERIC 2
+
+void collator_register_constants( INIT_FUNC_ARGS );
+
+#endif // COLLATOR_COLLATOR_H
diff --git a/ext/intl/collator/collator_attr.c b/ext/intl/collator/collator_attr.c
new file mode 100644
index 0000000..684e72c
--- /dev/null
+++ b/ext/intl/collator/collator_attr.c
@@ -0,0 +1,157 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator_class.h"
+#include "collator_convert.h"
+#include "collator_attr.h"
+
+#include <unicode/ustring.h>
+
+/* {{{ proto int Collator::getAttribute( int $attr )
+ * Get collation attribute value. }}} */
+/* {{{ proto int collator_get_attribute( Collator $coll, int $attr )
+ * Get collation attribute value.
+ */
+PHP_FUNCTION( collator_get_attribute )
+{
+ long attribute, value;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
+ &object, Collator_ce_ptr, &attribute ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_get_attribute: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ value = ucol_getAttribute( co->ucoll, attribute, COLLATOR_ERROR_CODE_P( co ) );
+ COLLATOR_CHECK_STATUS( co, "Error getting attribute value" );
+
+ RETURN_LONG( value );
+}
+/* }}} */
+
+/* {{{ proto bool Collator::getAttribute( int $attr )
+ * Get collation attribute value. }}} */
+/* {{{ proto bool collator_set_attribute( Collator $coll, int $attr, int $val )
+ * Set collation attribute.
+ */
+PHP_FUNCTION( collator_set_attribute )
+{
+ long attribute, value;
+ COLLATOR_METHOD_INIT_VARS
+
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll",
+ &object, Collator_ce_ptr, &attribute, &value ) == FAILURE)
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_set_attribute: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ /* Set new value for the given attribute. */
+ ucol_setAttribute( co->ucoll, attribute, value, COLLATOR_ERROR_CODE_P( co ) );
+ COLLATOR_CHECK_STATUS( co, "Error setting attribute value" );
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int Collator::getStrength()
+ * Returns the current collation strength. }}} */
+/* {{{ proto int collator_get_strength(Collator coll)
+ * Returns the current collation strength.
+ */
+PHP_FUNCTION( collator_get_strength )
+{
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Collator_ce_ptr ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_get_strength: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ /* Get current strength and return it. */
+ RETURN_LONG( ucol_getStrength( co->ucoll ) );
+}
+/* }}} */
+
+/* {{{ proto bool Collator::setStrength(int strength)
+ * Set the collation strength. }}} */
+/* {{{ proto bool collator_set_strength(Collator coll, int strength)
+ * Set the collation strength.
+ */
+PHP_FUNCTION( collator_set_strength )
+{
+ long strength;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
+ &object, Collator_ce_ptr, &strength ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_set_strength: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ /* Set given strength. */
+ ucol_setStrength( co->ucoll, strength );
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_attr.h b/ext/intl/collator/collator_attr.h
new file mode 100644
index 0000000..85636cc
--- /dev/null
+++ b/ext/intl/collator/collator_attr.h
@@ -0,0 +1,28 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_ATTR_H
+#define CCOLLATOR_ATTR_H
+
+#include <php.h>
+
+PHP_FUNCTION( collator_get_attribute );
+PHP_FUNCTION( collator_set_attribute );
+PHP_FUNCTION( collator_get_strength );
+PHP_FUNCTION( collator_set_strength );
+
+#endif // COLLATOR_ATTR_H
diff --git a/ext/intl/collator/collator_class.c b/ext/intl/collator/collator_class.c
new file mode 100644
index 0000000..d1fa10e
--- /dev/null
+++ b/ext/intl/collator/collator_class.c
@@ -0,0 +1,202 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "collator_class.h"
+#include "php_intl.h"
+#include "collator_attr.h"
+#include "collator_compare.h"
+#include "collator_sort.h"
+#include "collator_convert.h"
+#include "collator_locale.h"
+#include "collator_create.h"
+#include "collator_error.h"
+#include "intl_error.h"
+
+#include <unicode/ucol.h>
+
+zend_class_entry *Collator_ce_ptr = NULL;
+static zend_object_handlers Collator_handlers;
+
+/*
+ * Auxiliary functions needed by objects of 'Collator' class
+ */
+
+/* {{{ Collator_objects_dtor */
+static void Collator_objects_dtor(
+ void *object,
+ zend_object_handle handle TSRMLS_DC )
+{
+ zend_objects_destroy_object( object, handle TSRMLS_CC );
+}
+/* }}} */
+
+/* {{{ Collator_objects_free */
+void Collator_objects_free( zend_object *object TSRMLS_DC )
+{
+ Collator_object* co = (Collator_object*)object;
+
+ zend_object_std_dtor( &co->zo TSRMLS_CC );
+
+ collator_object_destroy( co TSRMLS_CC );
+
+ efree( co );
+}
+/* }}} */
+
+/* {{{ Collator_object_create */
+zend_object_value Collator_object_create(
+ zend_class_entry *ce TSRMLS_DC )
+{
+ zend_object_value retval;
+ Collator_object* intern;
+
+ intern = ecalloc( 1, sizeof(Collator_object) );
+ intl_error_init( COLLATOR_ERROR_P( intern ) TSRMLS_CC );
+ zend_object_std_init( &intern->zo, ce TSRMLS_CC );
+ object_properties_init(&intern->zo, ce);
+
+ retval.handle = zend_objects_store_put(
+ intern,
+ Collator_objects_dtor,
+ (zend_objects_free_object_storage_t)Collator_objects_free,
+ NULL TSRMLS_CC );
+
+ retval.handlers = &Collator_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/*
+ * 'Collator' class registration structures & functions
+ */
+
+/* {{{ Collator methods arguments info */
+/* NOTE: modifying 'collator_XX_args' do not forget to
+ modify approptiate 'collator_XX_args' for
+ the procedural API.
+*/
+ZEND_BEGIN_ARG_INFO_EX( collator_0_args, 0, 0, 0 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( collator_1_arg, 0, 0, 1 )
+ ZEND_ARG_INFO( 0, arg1 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( collator_2_args, 0, 0, 2 )
+ ZEND_ARG_INFO( 0, arg1 )
+ ZEND_ARG_INFO( 0, arg2 )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( collator_sort_args, 0, 0, 1 )
+ ZEND_ARG_ARRAY_INFO( 1, arr, 0 )
+ ZEND_ARG_INFO( 0, flags )
+ZEND_END_ARG_INFO()
+
+/* }}} */
+
+/* {{{ Collator_class_functions
+ * Every 'Collator' class method has an entry in this table
+ */
+
+zend_function_entry Collator_class_functions[] = {
+ PHP_ME( Collator, __construct, collator_1_arg, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
+ ZEND_FENTRY( create, ZEND_FN( collator_create ), collator_1_arg, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
+ PHP_NAMED_FE( compare, ZEND_FN( collator_compare ), collator_2_args )
+ PHP_NAMED_FE( sort, ZEND_FN( collator_sort ), collator_sort_args )
+ PHP_NAMED_FE( sortWithSortKeys, ZEND_FN( collator_sort_with_sort_keys ), collator_sort_args )
+ PHP_NAMED_FE( asort, ZEND_FN( collator_asort ), collator_sort_args )
+ PHP_NAMED_FE( getAttribute, ZEND_FN( collator_get_attribute ), collator_1_arg )
+ PHP_NAMED_FE( setAttribute, ZEND_FN( collator_set_attribute ), collator_2_args )
+ PHP_NAMED_FE( getStrength, ZEND_FN( collator_get_strength ), collator_0_args )
+ PHP_NAMED_FE( setStrength, ZEND_FN( collator_set_strength ), collator_1_arg )
+ PHP_NAMED_FE( getLocale, ZEND_FN( collator_get_locale ), collator_1_arg )
+ PHP_NAMED_FE( getErrorCode, ZEND_FN( collator_get_error_code ), collator_0_args )
+ PHP_NAMED_FE( getErrorMessage, ZEND_FN( collator_get_error_message ), collator_0_args )
+ PHP_NAMED_FE( getSortKey, ZEND_FN( collator_get_sort_key ), collator_2_args )
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ collator_register_Collator_class
+ * Initialize 'Collator' class
+ */
+void collator_register_Collator_class( TSRMLS_D )
+{
+ zend_class_entry ce;
+
+ /* Create and register 'Collator' class. */
+ INIT_CLASS_ENTRY( ce, "Collator", Collator_class_functions );
+ ce.create_object = Collator_object_create;
+ Collator_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
+
+ memcpy(&Collator_handlers, zend_get_std_object_handlers(),
+ sizeof Collator_handlers);
+ /* Collator has no usable clone semantics - ucol_cloneBinary/ucol_openBinary require binary buffer
+ for which we don't have the place to keep */
+ Collator_handlers.clone_obj = NULL;
+
+ /* Declare 'Collator' class properties. */
+ if( !Collator_ce_ptr )
+ {
+ zend_error( E_ERROR,
+ "Collator: attempt to create properties "
+ "on a non-registered class." );
+ return;
+ }
+}
+/* }}} */
+
+/* {{{ void collator_object_init( Collator_object* co )
+ * Initialize internals of Collator_object.
+ * Must be called before any other call to 'collator_object_...' functions.
+ */
+void collator_object_init( Collator_object* co TSRMLS_DC )
+{
+ if( !co )
+ return;
+
+ intl_error_init( COLLATOR_ERROR_P( co ) TSRMLS_CC );
+}
+/* }}} */
+
+/* {{{ void collator_object_destroy( Collator_object* co )
+ * Clean up mem allocted by internals of Collator_object
+ */
+void collator_object_destroy( Collator_object* co TSRMLS_DC )
+{
+ if( !co )
+ return;
+
+ if( co->ucoll )
+ {
+ ucol_close( co->ucoll );
+ co->ucoll = NULL;
+ }
+
+ intl_error_reset( COLLATOR_ERROR_P( co ) TSRMLS_CC );
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_class.h b/ext/intl/collator/collator_class.h
new file mode 100644
index 0000000..7a56dfc
--- /dev/null
+++ b/ext/intl/collator/collator_class.h
@@ -0,0 +1,69 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_CLASS_H
+#define COLLATOR_CLASS_H
+
+#include <php.h>
+
+#include "../intl_common.h"
+#include "../intl_error.h"
+#include "../intl_data.h"
+
+#include <unicode/ucol.h>
+
+typedef struct {
+ zend_object zo;
+
+ // error handling
+ intl_error err;
+
+ // ICU collator
+ UCollator* ucoll;
+} Collator_object;
+
+#define COLLATOR_ERROR(co) (co)->err
+#define COLLATOR_ERROR_P(co) &(COLLATOR_ERROR(co))
+
+#define COLLATOR_ERROR_CODE(co) INTL_ERROR_CODE(COLLATOR_ERROR(co))
+#define COLLATOR_ERROR_CODE_P(co) &(INTL_ERROR_CODE(COLLATOR_ERROR(co)))
+
+void collator_register_Collator_class( TSRMLS_D );
+void collator_object_init( Collator_object* co TSRMLS_DC );
+void collator_object_destroy( Collator_object* co TSRMLS_DC );
+
+extern zend_class_entry *Collator_ce_ptr;
+
+/* Auxiliary macros */
+
+#define COLLATOR_METHOD_INIT_VARS \
+ zval* object = NULL; \
+ Collator_object* co = NULL; \
+ intl_error_reset( NULL TSRMLS_CC ); \
+
+#define COLLATOR_METHOD_FETCH_OBJECT INTL_METHOD_FETCH_OBJECT(Collator, co)
+
+// Macro to check return value of a ucol_* function call.
+#define COLLATOR_CHECK_STATUS( co, msg ) \
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC ); \
+ if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) ) \
+ { \
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), msg, 0 TSRMLS_CC ); \
+ RETURN_FALSE; \
+ } \
+
+#endif // #ifndef COLLATOR_CLASS_H
diff --git a/ext/intl/collator/collator_compare.c b/ext/intl/collator/collator_compare.c
new file mode 100644
index 0000000..4384558
--- /dev/null
+++ b/ext/intl/collator/collator_compare.c
@@ -0,0 +1,133 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator_class.h"
+#include "collator_compare.h"
+#include "intl_convert.h"
+
+/* {{{ proto int Collator::compare( string $str1, string $str2 )
+ * Compare two strings. }}} */
+/* {{{ proto int collator_compare( Collator $coll, string $str1, string $str2 )
+ * Compare two strings.
+ */
+PHP_FUNCTION( collator_compare )
+{
+ char* str1 = NULL;
+ char* str2 = NULL;
+ int str1_len = 0;
+ int str2_len = 0;
+
+ UChar* ustr1 = NULL;
+ UChar* ustr2 = NULL;
+ int ustr1_len = 0;
+ int ustr2_len = 0;
+
+ UCollationResult result;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss",
+ &object, Collator_ce_ptr, &str1, &str1_len, &str2, &str2_len ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_compare: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ if (!co || !co->ucoll) {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Object not initialized", 0 TSRMLS_CC );
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
+
+ RETURN_FALSE;
+ }
+
+ /*
+ * Compare given strings (converting them to UTF-16 first).
+ */
+
+ /* First convert the strings to UTF-16. */
+ intl_convert_utf8_to_utf16(
+ &ustr1, &ustr1_len, str1, str1_len, COLLATOR_ERROR_CODE_P( co ) );
+ if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
+ {
+ /* Set global error code. */
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+
+ /* Set error messages. */
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Error converting first argument to UTF-16", 0 TSRMLS_CC );
+ if (ustr1) {
+ efree( ustr1 );
+ }
+ RETURN_FALSE;
+ }
+
+ intl_convert_utf8_to_utf16(
+ &ustr2, &ustr2_len, str2, str2_len, COLLATOR_ERROR_CODE_P( co ) );
+ if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
+ {
+ /* Set global error code. */
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+
+ /* Set error messages. */
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Error converting second argument to UTF-16", 0 TSRMLS_CC );
+ if (ustr1) {
+ efree( ustr1 );
+ }
+ if (ustr2) {
+ efree( ustr2 );
+ }
+ RETURN_FALSE;
+ }
+
+ /* Then compare them. */
+ result = ucol_strcoll(
+ co->ucoll,
+ ustr1, ustr1_len,
+ ustr2, ustr2_len );
+
+ if( ustr1 )
+ efree( ustr1 );
+ if( ustr2 )
+ efree( ustr2 );
+
+ /* Return result of the comparison. */
+ RETURN_LONG( result );
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_compare.h b/ext/intl/collator/collator_compare.h
new file mode 100644
index 0000000..4e38b79
--- /dev/null
+++ b/ext/intl/collator/collator_compare.h
@@ -0,0 +1,25 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_COMPARE_H
+#define COLLATOR_COMPARE_H
+
+#include <php.h>
+
+PHP_FUNCTION( collator_compare );
+
+#endif // COLLATOR_COMPARE_H
diff --git a/ext/intl/collator/collator_convert.c b/ext/intl/collator/collator_convert.c
new file mode 100644
index 0000000..e989d4c
--- /dev/null
+++ b/ext/intl/collator/collator_convert.c
@@ -0,0 +1,485 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator_class.h"
+#include "collator_is_numeric.h"
+#include "collator_convert.h"
+#include "intl_convert.h"
+
+#include <unicode/ustring.h>
+#include <php.h>
+
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1)
+#define CAST_OBJECT_SHOULD_FREE ,0
+#else
+#define CAST_OBJECT_SHOULD_FREE
+#endif
+
+#define COLLATOR_CONVERT_RETURN_FAILED(retval) { \
+ zval_add_ref( &retval ); \
+ return retval; \
+ }
+
+/* {{{ collator_convert_hash_item_from_utf8_to_utf16 */
+static void collator_convert_hash_item_from_utf8_to_utf16(
+ HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex,
+ UErrorCode* status )
+{
+ const char* old_val;
+ int old_val_len;
+ UChar* new_val = NULL;
+ int new_val_len = 0;
+ zval** hashData = NULL;
+ zval* znew_val = NULL;
+
+ /* Get current hash item. */
+ zend_hash_get_current_data( hash, (void**) &hashData );
+
+ /* Process string values only. */
+ if( Z_TYPE_P( *hashData ) != IS_STRING )
+ return;
+
+ old_val = Z_STRVAL_P( *hashData );
+ old_val_len = Z_STRLEN_P( *hashData );
+
+ /* Convert it from UTF-8 to UTF-16LE and save the result to new_val[_len]. */
+ intl_convert_utf8_to_utf16( &new_val, &new_val_len, old_val, old_val_len, status );
+ if( U_FAILURE( *status ) )
+ return;
+
+ /* Update current hash item with the converted value. */
+ MAKE_STD_ZVAL( znew_val );
+ ZVAL_STRINGL( znew_val, (char*)new_val, UBYTES(new_val_len), FALSE );
+
+ if( hashKeyType == HASH_KEY_IS_STRING )
+ {
+ zend_hash_update( hash, hashKey, strlen( hashKey ) + 1,
+ (void*) &znew_val, sizeof(zval*), NULL );
+ }
+ else /* hashKeyType == HASH_KEY_IS_LONG */
+ {
+ zend_hash_index_update( hash, hashIndex,
+ (void*) &znew_val, sizeof(zval*), NULL );
+ }
+}
+/* }}} */
+
+/* {{{ collator_convert_hash_item_from_utf16_to_utf8 */
+static void collator_convert_hash_item_from_utf16_to_utf8(
+ HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex,
+ UErrorCode* status )
+{
+ const char* old_val;
+ int old_val_len;
+ char* new_val = NULL;
+ int new_val_len = 0;
+ zval** hashData = NULL;
+ zval* znew_val = NULL;
+
+ /* Get current hash item. */
+ zend_hash_get_current_data( hash, (void**) &hashData );
+
+ /* Process string values only. */
+ if( Z_TYPE_P( *hashData ) != IS_STRING )
+ return;
+
+ old_val = Z_STRVAL_P( *hashData );
+ old_val_len = Z_STRLEN_P( *hashData );
+
+ /* Convert it from UTF-16LE to UTF-8 and save the result to new_val[_len]. */
+ intl_convert_utf16_to_utf8( &new_val, &new_val_len,
+ (UChar*)old_val, UCHARS(old_val_len), status );
+ if( U_FAILURE( *status ) )
+ return;
+
+ /* Update current hash item with the converted value. */
+ MAKE_STD_ZVAL( znew_val );
+ ZVAL_STRINGL( znew_val, (char*)new_val, new_val_len, FALSE );
+
+ if( hashKeyType == HASH_KEY_IS_STRING )
+ {
+ zend_hash_update( hash, hashKey, strlen( hashKey ) + 1,
+ (void*) &znew_val, sizeof(zval*), NULL );
+ }
+ else /* hashKeyType == HASH_KEY_IS_LONG */
+ {
+ zend_hash_index_update( hash, hashIndex,
+ (void*) &znew_val, sizeof(zval*), NULL );
+ }
+}
+/* }}} */
+
+/* {{{ collator_convert_hash_from_utf8_to_utf16
+ * Convert values of the given hash from UTF-8 encoding to UTF-16LE.
+ */
+void collator_convert_hash_from_utf8_to_utf16( HashTable* hash, UErrorCode* status )
+{
+ ulong hashIndex = 0;
+ char* hashKey = NULL;
+ int hashKeyType = 0;
+
+ zend_hash_internal_pointer_reset( hash );
+ while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) )
+ != HASH_KEY_NON_EXISTANT )
+ {
+ /* Convert current hash item from UTF-8 to UTF-16LE. */
+ collator_convert_hash_item_from_utf8_to_utf16(
+ hash, hashKeyType, hashKey, hashIndex, status );
+ if( U_FAILURE( *status ) )
+ return;
+
+ /* Proceed to the next item. */
+ zend_hash_move_forward( hash );
+ }
+}
+/* }}} */
+
+/* {{{ collator_convert_hash_from_utf16_to_utf8
+ * Convert values of the given hash from UTF-16LE encoding to UTF-8.
+ */
+void collator_convert_hash_from_utf16_to_utf8( HashTable* hash, UErrorCode* status )
+{
+ ulong hashIndex = 0;
+ char* hashKey = NULL;
+ int hashKeyType = 0;
+
+ zend_hash_internal_pointer_reset( hash );
+ while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) )
+ != HASH_KEY_NON_EXISTANT )
+ {
+ /* Convert current hash item from UTF-16LE to UTF-8. */
+ collator_convert_hash_item_from_utf16_to_utf8(
+ hash, hashKeyType, hashKey, hashIndex, status );
+ if( U_FAILURE( *status ) ) {
+ return;
+ }
+
+ /* Proceed to the next item. */
+ zend_hash_move_forward( hash );
+ }
+}
+/* }}} */
+
+/* {{{ collator_convert_zstr_utf16_to_utf8
+ *
+ * Convert string from utf16 to utf8.
+ *
+ * @param zval* utf16_zval String to convert.
+ *
+ * @return zval* Converted string.
+ */
+zval* collator_convert_zstr_utf16_to_utf8( zval* utf16_zval )
+{
+ zval* utf8_zval = NULL;
+ char* str = NULL;
+ int str_len = 0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ /* Convert to utf8 then. */
+ intl_convert_utf16_to_utf8( &str, &str_len,
+ (UChar*) Z_STRVAL_P(utf16_zval), UCHARS( Z_STRLEN_P(utf16_zval) ), &status );
+ if( U_FAILURE( status ) )
+ php_error( E_WARNING, "Error converting utf16 to utf8 in collator_convert_zval_utf16_to_utf8()" );
+
+ ALLOC_INIT_ZVAL( utf8_zval );
+ ZVAL_STRINGL( utf8_zval, str, str_len, FALSE );
+
+ return utf8_zval;
+}
+/* }}} */
+
+/* {{{ collator_convert_zstr_utf8_to_utf16
+ *
+ * Convert string from utf8 to utf16.
+ *
+ * @param zval* utf8_zval String to convert.
+ *
+ * @return zval* Converted string.
+ */
+zval* collator_convert_zstr_utf8_to_utf16( zval* utf8_zval )
+{
+ zval* zstr = NULL;
+ UChar* ustr = NULL;
+ int ustr_len = 0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ /* Convert the string to UTF-16. */
+ intl_convert_utf8_to_utf16(
+ &ustr, &ustr_len,
+ Z_STRVAL_P( utf8_zval ), Z_STRLEN_P( utf8_zval ),
+ &status );
+ if( U_FAILURE( status ) )
+ php_error( E_WARNING, "Error casting object to string in collator_convert_zstr_utf8_to_utf16()" );
+
+ /* Set string. */
+ ALLOC_INIT_ZVAL( zstr );
+ ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE );
+
+ return zstr;
+}
+/* }}} */
+
+/* {{{ collator_convert_object_to_string
+ * Convert object to UTF16-encoded string.
+ */
+zval* collator_convert_object_to_string( zval* obj TSRMLS_DC )
+{
+ zval* zstr = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ UChar* ustr = NULL;
+ int ustr_len = 0;
+
+ /* Bail out if it's not an object. */
+ if( Z_TYPE_P( obj ) != IS_OBJECT )
+ {
+ COLLATOR_CONVERT_RETURN_FAILED( obj );
+ }
+
+ /* Try object's handlers. */
+ if( Z_OBJ_HT_P(obj)->get )
+ {
+ zstr = Z_OBJ_HT_P(obj)->get( obj TSRMLS_CC );
+
+ switch( Z_TYPE_P( zstr ) )
+ {
+ case IS_OBJECT:
+ {
+ /* Bail out. */
+ zval_ptr_dtor( &zstr );
+ COLLATOR_CONVERT_RETURN_FAILED( obj );
+ } break;
+
+ case IS_STRING:
+ break;
+
+ default:
+ {
+ convert_to_string( zstr );
+ } break;
+ }
+ }
+ else if( Z_OBJ_HT_P(obj)->cast_object )
+ {
+ ALLOC_INIT_ZVAL( zstr );
+
+ if( Z_OBJ_HT_P(obj)->cast_object( obj, zstr, IS_STRING CAST_OBJECT_SHOULD_FREE TSRMLS_CC ) == FAILURE )
+ {
+ /* cast_object failed => bail out. */
+ zval_ptr_dtor( &zstr );
+ COLLATOR_CONVERT_RETURN_FAILED( obj );
+ }
+ }
+
+ /* Object wasn't successfuly converted => bail out. */
+ if( zstr == NULL )
+ {
+ COLLATOR_CONVERT_RETURN_FAILED( obj );
+ }
+
+ /* Convert the string to UTF-16. */
+ intl_convert_utf8_to_utf16(
+ &ustr, &ustr_len,
+ Z_STRVAL_P( zstr ), Z_STRLEN_P( zstr ),
+ &status );
+ if( U_FAILURE( status ) )
+ php_error( E_WARNING, "Error casting object to string in collator_convert_object_to_string()" );
+
+ /* Cleanup zstr to hold utf16 string. */
+ zval_dtor( zstr );
+
+ /* Set string. */
+ ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE );
+
+ /* Don't free ustr cause it's set in zstr without copy.
+ * efree( ustr );
+ */
+
+ return zstr;
+}
+/* }}} */
+
+/* {{{ collator_convert_string_to_number
+ *
+ * Convert string to number.
+ *
+ * @param zval* str String to convert.
+ *
+ * @return zval* Number. If str is not numeric string return number zero.
+ */
+zval* collator_convert_string_to_number( zval* str )
+{
+ zval* num = collator_convert_string_to_number_if_possible( str );
+ if( num == str )
+ {
+ /* String wasn't converted => return zero. */
+ zval_ptr_dtor( &num );
+
+ ALLOC_INIT_ZVAL( num );
+ ZVAL_LONG( num, 0 );
+ }
+
+ return num;
+}
+/* }}} */
+
+/* {{{ collator_convert_string_to_double
+ *
+ * Convert string to double.
+ *
+ * @param zval* str String to convert.
+ *
+ * @return zval* Number. If str is not numeric string return number zero.
+ */
+zval* collator_convert_string_to_double( zval* str )
+{
+ zval* num = collator_convert_string_to_number( str );
+ if( Z_TYPE_P(num) == IS_LONG )
+ {
+ ZVAL_DOUBLE( num, Z_LVAL_P( num ) );
+ }
+
+ return num;
+}
+/* }}} */
+
+/* {{{ collator_convert_string_to_number_if_possible
+ *
+ * Convert string to numer.
+ *
+ * @param zval* str String to convert.
+ *
+ * @return zval* Number if str is numeric string. Otherwise
+ * original str param.
+ */
+zval* collator_convert_string_to_number_if_possible( zval* str )
+{
+ zval* num = NULL;
+ int is_numeric = 0;
+ long lval = 0;
+ double dval = 0;
+
+ if( Z_TYPE_P( str ) != IS_STRING )
+ {
+ COLLATOR_CONVERT_RETURN_FAILED( str );
+ }
+
+ if( ( is_numeric = collator_is_numeric( (UChar*) Z_STRVAL_P(str), UCHARS( Z_STRLEN_P(str) ), &lval, &dval, 1 ) ) )
+ {
+ ALLOC_INIT_ZVAL( num );
+
+ if( is_numeric == IS_LONG )
+ Z_LVAL_P(num) = lval;
+ if( is_numeric == IS_DOUBLE )
+ Z_DVAL_P(num) = dval;
+
+ Z_TYPE_P(num) = is_numeric;
+ }
+ else
+ {
+ COLLATOR_CONVERT_RETURN_FAILED( str );
+ }
+
+ return num;
+}
+/* }}} */
+
+/* {{{ collator_make_printable_zval
+ *
+ * Returns string from input zval.
+ *
+ * @param zval* arg zval to get string from
+ *
+ * @return zval* UTF16 string.
+ */
+zval* collator_make_printable_zval( zval* arg )
+{
+ zval arg_copy;
+ int use_copy = 0;
+ zval* str = NULL;
+
+ if( Z_TYPE_P(arg) != IS_STRING )
+ {
+ zend_make_printable_zval(arg, &arg_copy, &use_copy);
+
+ if( use_copy )
+ {
+ str = collator_convert_zstr_utf8_to_utf16( &arg_copy );
+ zval_dtor( &arg_copy );
+ }
+ else
+ {
+ str = collator_convert_zstr_utf8_to_utf16( arg );
+ }
+ }
+ else
+ {
+ COLLATOR_CONVERT_RETURN_FAILED( arg );
+ }
+
+ return str;
+}
+/* }}} */
+
+/* {{{ collator_normalize_sort_argument
+ *
+ * Normalize argument to use in sort's compare function.
+ *
+ * @param zval* arg Sort's argument to normalize.
+ *
+ * @return zval* Normalized copy of arg or unmodified arg
+ * if normalization is not needed.
+ */
+zval* collator_normalize_sort_argument( zval* arg )
+{
+ zval* n_arg = NULL;
+
+ if( Z_TYPE_P( arg ) != IS_STRING )
+ {
+ /* If its not a string then nothing to do.
+ * Return original arg.
+ */
+ COLLATOR_CONVERT_RETURN_FAILED( arg );
+ }
+
+ /* Try convert to number. */
+ n_arg = collator_convert_string_to_number_if_possible( arg );
+
+ if( n_arg == arg )
+ {
+ /* Conversion to number failed. */
+ zval_ptr_dtor( &n_arg );
+
+ /* Convert string to utf8. */
+ n_arg = collator_convert_zstr_utf16_to_utf8( arg );
+ }
+
+ return n_arg;
+}
+/* }}} */
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_convert.h b/ext/intl/collator/collator_convert.h
new file mode 100644
index 0000000..8322ea9
--- /dev/null
+++ b/ext/intl/collator/collator_convert.h
@@ -0,0 +1,38 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_CONVERT_H
+#define COLLATOR_CONVERT_H
+
+#include <php.h>
+#include <unicode/utypes.h>
+
+void collator_convert_hash_from_utf8_to_utf16( HashTable* hash, UErrorCode* status );
+void collator_convert_hash_from_utf16_to_utf8( HashTable* hash, UErrorCode* status );
+
+zval* collator_convert_zstr_utf16_to_utf8( zval* utf16_zval );
+zval* collator_convert_zstr_utf8_to_utf16( zval* utf8_zval );
+
+zval* collator_normalize_sort_argument( zval* arg );
+zval* collator_convert_object_to_string( zval* obj TSRMLS_DC );
+zval* collator_convert_string_to_number( zval* arg );
+zval* collator_convert_string_to_number_if_possible( zval* str );
+zval* collator_convert_string_to_double( zval* str );
+
+zval* collator_make_printable_zval( zval* arg );
+
+#endif // COLLATOR_CONVERT_H
diff --git a/ext/intl/collator/collator_create.c b/ext/intl/collator/collator_create.c
new file mode 100644
index 0000000..b2a9968
--- /dev/null
+++ b/ext/intl/collator/collator_create.c
@@ -0,0 +1,87 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator_class.h"
+#include "collator_create.h"
+#include "intl_data.h"
+
+/* {{{ */
+static void collator_ctor(INTERNAL_FUNCTION_PARAMETERS)
+{
+ char* locale;
+ int locale_len = 0;
+ zval* object;
+ Collator_object* co;
+
+ intl_error_reset( NULL TSRMLS_CC );
+ object = return_value;
+ /* Parse parameters. */
+ if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &locale, &locale_len ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_create: unable to parse input params", 0 TSRMLS_CC );
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+
+ INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ if(locale_len == 0) {
+ locale = INTL_G(default_locale);
+ }
+
+ /* Open ICU collator. */
+ co->ucoll = ucol_open( locale, COLLATOR_ERROR_CODE_P( co ) );
+ INTL_CTOR_CHECK_STATUS(co, "collator_create: unable to open ICU collator");
+}
+/* }}} */
+
+/* {{{ proto Collator collator_create( string $locale )
+ * Create collator.
+ */
+PHP_FUNCTION( collator_create )
+{
+ object_init_ex( return_value, Collator_ce_ptr );
+ collator_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto Collator Collator::__construct( string $locale )
+ * Collator object constructor.
+ */
+PHP_METHOD( Collator, __construct )
+{
+ return_value = getThis();
+ collator_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_create.h b/ext/intl/collator/collator_create.h
new file mode 100644
index 0000000..b740e82
--- /dev/null
+++ b/ext/intl/collator/collator_create.h
@@ -0,0 +1,27 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_CREATE_H
+#define COLLATOR_CREATE_H
+
+#include <php.h>
+
+PHP_FUNCTION( collator_create );
+
+PHP_METHOD( Collator, __construct );
+
+#endif // COLLATOR_CREATE_H
diff --git a/ext/intl/collator/collator_error.c b/ext/intl/collator/collator_error.c
new file mode 100644
index 0000000..c4e4125
--- /dev/null
+++ b/ext/intl/collator/collator_error.c
@@ -0,0 +1,94 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator_class.h"
+#include "collator_error.h"
+
+/* {{{ proto int Collator::getErrorCode( Collator $coll )
+ * Get collator's last error code. }}} */
+/* {{{ proto int collator_get_error_code( Collator $coll )
+ * Get collator's last error code.
+ */
+PHP_FUNCTION( collator_get_error_code )
+{
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Collator_ce_ptr ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_get_error_code: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object (without resetting its last error code). */
+ co = (Collator_object *) zend_object_store_get_object(object TSRMLS_CC);
+ if( co == NULL )
+ RETURN_FALSE;
+
+ /* Return collator's last error code. */
+ RETURN_LONG( COLLATOR_ERROR_CODE( co ) );
+}
+/* }}} */
+
+/* {{{ proto string Collator::getErrorMessage( Collator $coll )
+ * Get text description for collator's last error code. }}} */
+/* {{{ proto string collator_get_error_message( Collator $coll )
+ * Get text description for collator's last error code.
+ */
+PHP_FUNCTION( collator_get_error_message )
+{
+ const char* message = NULL;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+ &object, Collator_ce_ptr ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_get_error_message: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object (without resetting its last error code). */
+ co = (Collator_object *) zend_object_store_get_object( object TSRMLS_CC );
+ if( co == NULL )
+ RETURN_FALSE;
+
+ /* Return last error message. */
+ message = intl_error_get_message( COLLATOR_ERROR_P( co ) TSRMLS_CC );
+ RETURN_STRING( (char*)message, FALSE );
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_error.h b/ext/intl/collator/collator_error.h
new file mode 100644
index 0000000..b2f44ea
--- /dev/null
+++ b/ext/intl/collator/collator_error.h
@@ -0,0 +1,26 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_ERROR_H
+#define COLLATOR_ERROR_H
+
+#include <php.h>
+
+PHP_FUNCTION( collator_get_error_code );
+PHP_FUNCTION( collator_get_error_message );
+
+#endif // COLLATOR_ERROR_H
diff --git a/ext/intl/collator/collator_is_numeric.c b/ext/intl/collator/collator_is_numeric.c
new file mode 100644
index 0000000..a8abfac
--- /dev/null
+++ b/ext/intl/collator/collator_is_numeric.c
@@ -0,0 +1,305 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "collator_is_numeric.h"
+
+#if ZEND_MODULE_API_NO < 20071006
+/* not 5.3 */
+#ifndef ALLOCA_FLAG
+#define ALLOCA_FLAG(use_heap)
+#endif
+#define _do_alloca(x, y) do_alloca((x))
+#define _free_alloca(x, y) free_alloca((x))
+#else
+#define _do_alloca do_alloca
+#define _free_alloca free_alloca
+#endif
+/* {{{ collator_u_strtod
+ * Taken from PHP6:zend_u_strtod()
+ */
+static double collator_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */
+{
+ const UChar *u = nptr, *nstart;
+ UChar c = *u;
+ int any = 0;
+ ALLOCA_FLAG(use_heap);
+
+ while (u_isspace(c)) {
+ c = *++u;
+ }
+ nstart = u;
+
+ if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
+ c = *++u;
+ }
+
+ while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
+ any = 1;
+ c = *++u;
+ }
+
+ if (c == 0x2E /*'.'*/) {
+ c = *++u;
+ while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
+ any = 1;
+ c = *++u;
+ }
+ }
+
+ if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) {
+ const UChar *e = u;
+ int any_exp = 0;
+
+ c = *++u;
+ if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
+ c = *++u;
+ }
+
+ while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
+ any_exp = 1;
+ c = *++u;
+ }
+
+ if (!any_exp) {
+ u = e;
+ }
+ }
+
+ if (any) {
+ char buf[64], *numbuf, *bufpos;
+ int length = u - nstart;
+ double value;
+
+ if (length < sizeof(buf)) {
+ numbuf = buf;
+ } else {
+ numbuf = (char *) _do_alloca(length + 1, use_heap);
+ }
+
+ bufpos = numbuf;
+
+ while (nstart < u) {
+ *bufpos++ = (char) *nstart++;
+ }
+
+ *bufpos = '\0';
+ value = zend_strtod(numbuf, NULL);
+
+ if (numbuf != buf) {
+ _free_alloca(numbuf, use_heap);
+ }
+
+ if (endptr != NULL) {
+ *endptr = (UChar *)u;
+ }
+
+ return value;
+ }
+
+ if (endptr != NULL) {
+ *endptr = (UChar *)nptr;
+ }
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ collator_u_strtol
+ * Taken from PHP6:zend_u_strtol()
+ *
+ * Convert a Unicode string to a long integer.
+ *
+ * Ignores `locale' stuff.
+ */
+static long collator_u_strtol(nptr, endptr, base)
+ const UChar *nptr;
+ UChar **endptr;
+ register int base;
+{
+ register const UChar *s = nptr;
+ register unsigned long acc;
+ register UChar c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ if (s == NULL) {
+ errno = ERANGE;
+ if (endptr != NULL) {
+ *endptr = NULL;
+ }
+ return 0;
+ }
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ do {
+ c = *s++;
+ } while (u_isspace(c));
+ if (c == 0x2D /*'-'*/) {
+ neg = 1;
+ c = *s++;
+ } else if (c == 0x2B /*'+'*/)
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ (c == 0x30 /*'0'*/)
+ && (*s == 0x78 /*'x'*/ || *s == 0x58 /*'X'*/)) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = (c == 0x30 /*'0'*/) ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long)base;
+ cutoff /= (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/)
+ c -= 0x30 /*'0'*/;
+ else if (c >= 0x41 /*'A'*/ && c <= 0x5A /*'Z'*/)
+ c -= 0x41 /*'A'*/ - 10;
+ else if (c >= 0x61 /*'a'*/ && c <= 0x7A /*'z'*/)
+ c -= 0x61 /*'a'*/ - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (UChar *)(any ? s - 1 : nptr);
+ return (acc);
+}
+/* }}} */
+
+
+/* {{{ collator_is_numeric]
+ * Taken from PHP6:is_numeric_unicode()
+ */
+zend_uchar collator_is_numeric( UChar *str, int length, long *lval, double *dval, int allow_errors )
+{
+ long local_lval;
+ double local_dval;
+ UChar *end_ptr_long, *end_ptr_double;
+ int conv_base=10;
+
+ if (!length) {
+ return 0;
+ }
+
+ /* handle hex numbers */
+ if (length>=2 && str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
+ conv_base=16;
+ }
+
+ errno=0;
+ local_lval = collator_u_strtol(str, &end_ptr_long, conv_base);
+ if (errno != ERANGE) {
+ if (end_ptr_long == str+length) { /* integer string */
+ if (lval) {
+ *lval = local_lval;
+ }
+ return IS_LONG;
+ } else if (end_ptr_long == str && *end_ptr_long != '\0' && *str != '.' && *str != '-') { /* ignore partial string matches */
+ return 0;
+ }
+ } else {
+ end_ptr_long = NULL;
+ }
+
+ if (conv_base == 16) { /* hex string, under UNIX strtod() messes it up */
+ /* UTODO: keep compatibility with is_numeric_string() here? */
+ return 0;
+ }
+
+ local_dval = collator_u_strtod(str, &end_ptr_double);
+ if (local_dval == 0 && end_ptr_double == str) {
+ end_ptr_double = NULL;
+ } else {
+ if (end_ptr_double == str+length) { /* floating point string */
+ if (!zend_finite(local_dval)) {
+ /* "inf","nan" and maybe other weird ones */
+ return 0;
+ }
+
+ if (dval) {
+ *dval = local_dval;
+ }
+ return IS_DOUBLE;
+ }
+ }
+
+ if (!allow_errors) {
+ return 0;
+ }
+ if (allow_errors == -1) {
+ zend_error(E_NOTICE, "A non well formed numeric value encountered");
+ }
+
+ if (allow_errors) {
+ if (end_ptr_double > end_ptr_long && dval) {
+ *dval = local_dval;
+ return IS_DOUBLE;
+ } else if (end_ptr_long && lval) {
+ *lval = local_lval;
+ return IS_LONG;
+ }
+ }
+ return 0;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_is_numeric.h b/ext/intl/collator/collator_is_numeric.h
new file mode 100644
index 0000000..585d589
--- /dev/null
+++ b/ext/intl/collator/collator_is_numeric.h
@@ -0,0 +1,26 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_IS_NUMERIC_H
+#define COLLATOR_IS_NUMERIC_H
+
+#include <php.h>
+#include <unicode/uchar.h>
+
+zend_uchar collator_is_numeric( UChar *str, int length, long *lval, double *dval, int allow_errors );
+
+#endif // COLLATOR_IS_NUMERIC_H
diff --git a/ext/intl/collator/collator_locale.c b/ext/intl/collator/collator_locale.c
new file mode 100644
index 0000000..b30b021
--- /dev/null
+++ b/ext/intl/collator/collator_locale.c
@@ -0,0 +1,80 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator_class.h"
+#include "collator_locale.h"
+#include "intl_convert.h"
+
+#include <zend_API.h>
+
+/* {{{ proto string Collator::getLocale( int $type )
+ * Gets the locale name of the collator. }}} */
+/* {{{ proto string collator_get_locale( Collator $coll, int $type )
+ * Gets the locale name of the collator.
+ */
+PHP_FUNCTION( collator_get_locale )
+{
+ long type = 0;
+ char* locale_name = NULL;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
+ &object, Collator_ce_ptr, &type ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_get_locale: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ if (!co || !co->ucoll) {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Object not initialized", 0 TSRMLS_CC );
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
+
+ RETURN_FALSE;
+ }
+
+ /* Get locale by specified type. */
+ locale_name = (char*) ucol_getLocaleByType(
+ co->ucoll, type, COLLATOR_ERROR_CODE_P( co ) );
+ COLLATOR_CHECK_STATUS( co, "Error getting locale by type" );
+
+ /* Return it. */
+ RETVAL_STRINGL( locale_name, strlen(locale_name), TRUE );
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_locale.h b/ext/intl/collator/collator_locale.h
new file mode 100644
index 0000000..bda90cd
--- /dev/null
+++ b/ext/intl/collator/collator_locale.h
@@ -0,0 +1,25 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_LOCALE_H
+#define COLLATOR_LOCALE_H
+
+#include <php.h>
+
+PHP_FUNCTION( collator_get_locale );
+
+#endif // COLLATOR_LOCALE_H
diff --git a/ext/intl/collator/collator_sort.c b/ext/intl/collator/collator_sort.c
new file mode 100644
index 0000000..0785111
--- /dev/null
+++ b/ext/intl/collator/collator_sort.c
@@ -0,0 +1,621 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php_intl.h"
+#include "collator.h"
+#include "collator_class.h"
+#include "collator_sort.h"
+#include "collator_convert.h"
+#include "intl_convert.h"
+
+#if !defined(HAVE_PTRDIFF_T) && !defined(_PTRDIFF_T_DEFINED)
+typedef long ptrdiff_t;
+#endif
+
+/**
+ * Declare 'index' which will point to sort key in sort key
+ * buffer.
+ */
+typedef struct _collator_sort_key_index {
+ char* key; /* pointer to sort key */
+ zval** zstr; /* pointer to original string(hash-item) */
+} collator_sort_key_index_t;
+
+ZEND_EXTERN_MODULE_GLOBALS( intl )
+
+static const size_t DEF_SORT_KEYS_BUF_SIZE = 1048576;
+static const size_t DEF_SORT_KEYS_BUF_INCREMENT = 1048576;
+
+static const size_t DEF_SORT_KEYS_INDX_BUF_SIZE = 1048576;
+static const size_t DEF_SORT_KEYS_INDX_BUF_INCREMENT = 1048576;
+
+static const size_t DEF_UTF16_BUF_SIZE = 1024;
+
+/* {{{ collator_regular_compare_function */
+static int collator_regular_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
+{
+ Collator_object* co = NULL;
+
+ int rc = SUCCESS;
+
+ zval* str1 = collator_convert_object_to_string( op1 TSRMLS_CC );
+ zval* str2 = collator_convert_object_to_string( op2 TSRMLS_CC );
+
+ zval* num1 = NULL;
+ zval* num2 = NULL;
+ zval* norm1 = NULL;
+ zval* norm2 = NULL;
+
+ /* If both args are strings AND either of args is not numeric string
+ * then use ICU-compare. Otherwise PHP-compare. */
+ if( Z_TYPE_P(str1) == IS_STRING && Z_TYPE_P(str2) == IS_STRING &&
+ ( str1 == ( num1 = collator_convert_string_to_number_if_possible( str1 ) ) ||
+ str2 == ( num2 = collator_convert_string_to_number_if_possible( str2 ) ) ) )
+ {
+ /* Fetch collator object. */
+ co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
+
+ if (!co || !co->ucoll) {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Object not initialized", 0 TSRMLS_CC );
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
+ }
+
+ /* Compare the strings using ICU. */
+ result->value.lval = ucol_strcoll(
+ co->ucoll,
+ INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
+ INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
+ result->type = IS_LONG;
+ }
+ else
+ {
+ /* num1 is set if str1 and str2 are strings. */
+ if( num1 )
+ {
+ if( num1 == str1 )
+ {
+ /* str1 is string but not numeric string
+ * just convert it to utf8.
+ */
+ norm1 = collator_convert_zstr_utf16_to_utf8( str1 );
+
+ /* num2 is not set but str2 is string => do normalization. */
+ norm2 = collator_normalize_sort_argument( str2 );
+ }
+ else
+ {
+ /* str1 is numeric strings => passthru to PHP-compare. */
+ zval_add_ref( &num1 );
+ norm1 = num1;
+
+ /* str2 is numeric strings => passthru to PHP-compare. */
+ zval_add_ref( &num2 );
+ norm2 = num2;
+ }
+ }
+ else
+ {
+ /* num1 is not set if str1 or str2 is not a string => do normalization. */
+ norm1 = collator_normalize_sort_argument( str1 );
+
+ /* if num1 is not set then num2 is not set as well => do normalization. */
+ norm2 = collator_normalize_sort_argument( str2 );
+ }
+
+ rc = compare_function( result, norm1, norm2 TSRMLS_CC );
+
+ zval_ptr_dtor( &norm1 );
+ zval_ptr_dtor( &norm2 );
+ }
+
+ if( num1 )
+ zval_ptr_dtor( &num1 );
+
+ if( num2 )
+ zval_ptr_dtor( &num2 );
+
+ zval_ptr_dtor( &str1 );
+ zval_ptr_dtor( &str2 );
+
+ return rc;
+}
+/* }}} */
+
+/* {{{ collator_numeric_compare_function
+ * Convert input args to double and compare it.
+ */
+static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
+{
+ int rc = SUCCESS;
+ zval* num1 = NULL;
+ zval* num2 = NULL;
+
+ if( Z_TYPE_P(op1) == IS_STRING )
+ {
+ num1 = collator_convert_string_to_double( op1 );
+ op1 = num1;
+ }
+
+ if( Z_TYPE_P(op2) == IS_STRING )
+ {
+ num2 = collator_convert_string_to_double( op2 );
+ op2 = num2;
+ }
+
+ rc = numeric_compare_function( result, op1, op2 TSRMLS_CC);
+
+ if( num1 )
+ zval_ptr_dtor( &num1 );
+ if( num2 )
+ zval_ptr_dtor( &num2 );
+
+ return rc;
+}
+/* }}} */
+
+/* {{{ collator_icu_compare_function
+ * Direct use of ucol_strcoll.
+*/
+static int collator_icu_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
+{
+ int rc = SUCCESS;
+ Collator_object* co = NULL;
+ zval* str1 = NULL;
+ zval* str2 = NULL;
+
+ str1 = collator_make_printable_zval( op1 );
+ str2 = collator_make_printable_zval( op2 );
+
+ /* Fetch collator object. */
+ co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
+
+ /* Compare the strings using ICU. */
+ result->value.lval = ucol_strcoll(
+ co->ucoll,
+ INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
+ INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
+ result->type = IS_LONG;
+
+ zval_ptr_dtor( &str1 );
+ zval_ptr_dtor( &str2 );
+
+ return rc;
+}
+/* }}} */
+
+/* {{{ collator_compare_func
+ * Taken from PHP5 source (array_data_compare).
+ */
+static int collator_compare_func( const void* a, const void* b TSRMLS_DC )
+{
+ Bucket *f;
+ Bucket *s;
+ zval result;
+ zval *first;
+ zval *second;
+
+ f = *((Bucket **) a);
+ s = *((Bucket **) b);
+
+ first = *((zval **) f->pData);
+ second = *((zval **) s->pData);
+
+ if( INTL_G(compare_func)( &result, first, second TSRMLS_CC) == FAILURE )
+ return 0;
+
+ if( Z_TYPE(result) == IS_DOUBLE )
+ {
+ if( Z_DVAL(result) < 0 )
+ return -1;
+ else if( Z_DVAL(result) > 0 )
+ return 1;
+ else
+ return 0;
+ }
+
+ convert_to_long(&result);
+
+ if( Z_LVAL(result) < 0 )
+ return -1;
+ else if( Z_LVAL(result) > 0 )
+ return 1;
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ collator_cmp_sort_keys
+ * Compare sort keys
+ */
+static int collator_cmp_sort_keys( const void *p1, const void *p2 TSRMLS_DC )
+{
+ char* key1 = ((collator_sort_key_index_t*)p1)->key;
+ char* key2 = ((collator_sort_key_index_t*)p2)->key;
+
+ return strcmp( key1, key2 );
+}
+/* }}} */
+
+/* {{{ collator_get_compare_function
+ * Choose compare function according to sort flags.
+ */
+static collator_compare_func_t collator_get_compare_function( const long sort_flags )
+{
+ collator_compare_func_t func;
+
+ switch( sort_flags )
+ {
+ case COLLATOR_SORT_NUMERIC:
+ func = collator_numeric_compare_function;
+ break;
+
+ case COLLATOR_SORT_STRING:
+ func = collator_icu_compare_function;
+ break;
+
+ case COLLATOR_SORT_REGULAR:
+ default:
+ func = collator_regular_compare_function;
+ break;
+ }
+
+ return func;
+}
+/* }}} */
+
+/* {{{ collator_sort_internal
+ * Common code shared by collator_sort() and collator_asort() API functions.
+ */
+static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
+{
+ zval* array = NULL;
+ HashTable* hash = NULL;
+ zval* saved_collator = NULL;
+ long sort_flags = COLLATOR_SORT_REGULAR;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa|l",
+ &object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_sort_internal: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ /* Set 'compare function' according to sort flags. */
+ INTL_G(compare_func) = collator_get_compare_function( sort_flags );
+
+ hash = HASH_OF( array );
+
+ /* Convert strings in the specified array from UTF-8 to UTF-16. */
+ collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
+ COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
+
+ /* Save specified collator in the request-global (?) variable. */
+ saved_collator = INTL_G( current_collator );
+ INTL_G( current_collator ) = object;
+
+ /* Sort specified array. */
+ zend_hash_sort( hash, zend_qsort, collator_compare_func, renumber TSRMLS_CC );
+
+ /* Restore saved collator. */
+ INTL_G( current_collator ) = saved_collator;
+
+ /* Convert strings in the specified array back to UTF-8. */
+ collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
+ COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool Collator::sort( Collator $coll, array(string) $arr [, int $sort_flags] )
+ * Sort array using specified collator. }}} */
+/* {{{ proto bool collator_sort( Collator $coll, array(string) $arr [, int $sort_flags] )
+ * Sort array using specified collator.
+ */
+PHP_FUNCTION( collator_sort )
+{
+ collator_sort_internal( TRUE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
+}
+/* }}} */
+
+/* {{{ proto bool Collator::sortWithSortKeys( Collator $coll, array(string) $arr )
+ * Equivalent to standard PHP sort using Collator.
+ * Uses ICU ucol_getSortKey for performance. }}} */
+/* {{{ proto bool collator_sort_with_sort_keys( Collator $coll, array(string) $arr )
+ * Equivalent to standard PHP sort using Collator.
+ * Uses ICU ucol_getSortKey for performance.
+ */
+PHP_FUNCTION( collator_sort_with_sort_keys )
+{
+ zval* array = NULL;
+ HashTable* hash = NULL;
+ zval** hashData = NULL; /* currently processed item of input hash */
+
+ char* sortKeyBuf = NULL; /* buffer to store sort keys */
+ uint32_t sortKeyBufSize = DEF_SORT_KEYS_BUF_SIZE; /* buffer size */
+ ptrdiff_t sortKeyBufOffset = 0; /* pos in buffer to store sort key */
+ int32_t sortKeyLen = 0; /* the length of currently processing key */
+ uint32_t bufLeft = 0;
+ uint32_t bufIncrement = 0;
+
+ collator_sort_key_index_t* sortKeyIndxBuf = NULL; /* buffer to store 'indexes' which will be passed to 'qsort' */
+ uint32_t sortKeyIndxBufSize = DEF_SORT_KEYS_INDX_BUF_SIZE;
+ uint32_t sortKeyIndxSize = sizeof( collator_sort_key_index_t );
+
+ uint32_t sortKeyCount = 0;
+ uint32_t j = 0;
+
+ UChar* utf16_buf = NULL; /* tmp buffer to hold current processing string in utf-16 */
+ int utf16_buf_size = DEF_UTF16_BUF_SIZE; /* the length of utf16_buf */
+ int utf16_len = 0; /* length of converted string */
+
+ HashTable* sortedHash = NULL;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
+ &object, Collator_ce_ptr, &array ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_sort_with_sort_keys: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ if (!co || !co->ucoll) {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Object not initialized", 0 TSRMLS_CC );
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
+
+ RETURN_FALSE;
+ }
+
+ /*
+ * Sort specified array.
+ */
+ hash = HASH_OF( array );
+
+ if( !hash || zend_hash_num_elements( hash ) == 0 )
+ RETURN_TRUE;
+
+ /* Create bufers */
+ sortKeyBuf = ecalloc( sortKeyBufSize, sizeof( char ) );
+ sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
+ utf16_buf = eumalloc( utf16_buf_size );
+
+ /* Iterate through input hash and create a sort key for each value. */
+ zend_hash_internal_pointer_reset( hash );
+ while( zend_hash_get_current_data( hash, (void**) &hashData ) == SUCCESS )
+ {
+ /* Convert current hash item from UTF-8 to UTF-16LE and save the result to utf16_buf. */
+
+ utf16_len = utf16_buf_size;
+
+ /* Process string values only. */
+ if( Z_TYPE_PP( hashData ) == IS_STRING )
+ {
+ intl_convert_utf8_to_utf16( &utf16_buf, &utf16_len, Z_STRVAL_PP( hashData ), Z_STRLEN_PP( hashData ), COLLATOR_ERROR_CODE_P( co ) );
+
+ if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
+ {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Sort with sort keys failed", 0 TSRMLS_CC );
+
+ if( utf16_buf )
+ efree( utf16_buf );
+
+ efree( sortKeyIndxBuf );
+ efree( sortKeyBuf );
+
+ RETURN_FALSE;
+ }
+ }
+ else
+ {
+ /* Set empty string */
+ utf16_len = 0;
+ utf16_buf[utf16_len] = 0;
+ }
+
+ if( (utf16_len + 1) > utf16_buf_size )
+ utf16_buf_size = utf16_len + 1;
+
+ /* Get sort key, reallocating the buffer if needed. */
+ bufLeft = sortKeyBufSize - sortKeyBufOffset;
+
+ sortKeyLen = ucol_getSortKey( co->ucoll,
+ utf16_buf,
+ utf16_len,
+ (uint8_t*)sortKeyBuf + sortKeyBufOffset,
+ bufLeft );
+
+ /* check for sortKeyBuf overflow, increasing its size of the buffer if needed */
+ if( sortKeyLen > bufLeft )
+ {
+ bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT;
+
+ sortKeyBufSize += bufIncrement;
+ bufLeft += bufIncrement;
+
+ sortKeyBuf = erealloc( sortKeyBuf, sortKeyBufSize );
+
+ sortKeyLen = ucol_getSortKey( co->ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft );
+ }
+
+ /* check sortKeyIndxBuf overflow, increasing its size of the buffer if needed */
+ if( ( sortKeyCount + 1 ) * sortKeyIndxSize > sortKeyIndxBufSize )
+ {
+ bufIncrement = ( sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT ) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT;
+
+ sortKeyIndxBufSize += bufIncrement;
+
+ sortKeyIndxBuf = erealloc( sortKeyIndxBuf, sortKeyIndxBufSize );
+ }
+
+ sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset; /* remeber just offset, cause address */
+ /* of 'sortKeyBuf' may be changed due to realloc. */
+ sortKeyIndxBuf[sortKeyCount].zstr = hashData;
+
+ sortKeyBufOffset += sortKeyLen;
+ ++sortKeyCount;
+
+ zend_hash_move_forward( hash );
+ }
+
+ /* update ptrs to point to valid keys. */
+ for( j = 0; j < sortKeyCount; j++ )
+ sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
+
+ /* sort it */
+ zend_qsort( sortKeyIndxBuf, sortKeyCount, sortKeyIndxSize, collator_cmp_sort_keys TSRMLS_CC );
+
+ /* for resulting hash we'll assign new hash keys rather then reordering */
+ ALLOC_HASHTABLE( sortedHash );
+ zend_hash_init( sortedHash, 0, NULL, ZVAL_PTR_DTOR, 0 );
+
+ for( j = 0; j < sortKeyCount; j++ )
+ {
+ zval_add_ref( sortKeyIndxBuf[j].zstr );
+ zend_hash_next_index_insert( sortedHash, sortKeyIndxBuf[j].zstr, sizeof(zval **), NULL );
+ }
+
+ /* Save sorted hash into return variable. */
+ zval_dtor( array );
+ (array)->value.ht = sortedHash;
+ (array)->type = IS_ARRAY;
+
+ if( utf16_buf )
+ efree( utf16_buf );
+
+ efree( sortKeyIndxBuf );
+ efree( sortKeyBuf );
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool Collator::asort( Collator $coll, array(string) $arr )
+ * Sort array using specified collator, maintaining index association. }}} */
+/* {{{ proto bool collator_asort( Collator $coll, array(string) $arr )
+ * Sort array using specified collator, maintaining index association.
+ */
+PHP_FUNCTION( collator_asort )
+{
+ collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
+}
+/* }}} */
+
+/* {{{ proto bool Collator::getSortKey( Collator $coll, string $str )
+ * Get a sort key for a string from a Collator. }}} */
+/* {{{ proto bool collator_get_sort_key( Collator $coll, string $str )
+ * Get a sort key for a string from a Collator. }}} */
+PHP_FUNCTION( collator_get_sort_key )
+{
+ char* str = NULL;
+ int str_len = 0;
+ UChar* ustr = NULL;
+ int ustr_len = 0;
+ uint8_t* key = NULL;
+ int key_len = 0;
+
+ COLLATOR_METHOD_INIT_VARS
+
+ /* Parse parameters. */
+ if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
+ &object, Collator_ce_ptr, &str, &str_len ) == FAILURE )
+ {
+ intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "collator_get_sort_key: unable to parse input params", 0 TSRMLS_CC );
+
+ RETURN_FALSE;
+ }
+
+ /* Fetch the object. */
+ COLLATOR_METHOD_FETCH_OBJECT;
+
+ if (!co || !co->ucoll) {
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Object not initialized", 0 TSRMLS_CC );
+ php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
+
+ RETURN_FALSE;
+ }
+
+ /*
+ * Compare given strings (converting them to UTF-16 first).
+ */
+
+ /* First convert the strings to UTF-16. */
+ intl_convert_utf8_to_utf16(
+ &ustr, &ustr_len, str, str_len, COLLATOR_ERROR_CODE_P( co ) );
+ if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
+ {
+ /* Set global error code. */
+ intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
+
+ /* Set error messages. */
+ intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
+ "Error converting first argument to UTF-16", 0 TSRMLS_CC );
+ efree( ustr );
+ RETURN_FALSE;
+ }
+
+ /* ucol_getSortKey is exception in that the key length includes the
+ * NUL terminator*/
+ key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, 0);
+ if(!key_len) {
+ efree( ustr );
+ RETURN_FALSE;
+ }
+ key = emalloc(key_len);
+ key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, key_len);
+ efree( ustr );
+ if(!key_len) {
+ RETURN_FALSE;
+ }
+ RETURN_STRINGL((char *)key, key_len - 1, 0);
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/collator/collator_sort.h b/ext/intl/collator/collator_sort.h
new file mode 100644
index 0000000..a990cdf
--- /dev/null
+++ b/ext/intl/collator/collator_sort.h
@@ -0,0 +1,30 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Vadim Savchuk <vsavchuk@productengine.com> |
+ | Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef COLLATOR_SORT_H
+#define COLLATOR_SORT_H
+
+#include <php.h>
+
+typedef int (*collator_compare_func_t)( zval *result, zval *op1, zval *op2 TSRMLS_DC );
+
+PHP_FUNCTION( collator_sort );
+PHP_FUNCTION( collator_sort_with_sort_keys );
+PHP_FUNCTION( collator_get_sort_key );
+PHP_FUNCTION( collator_asort );
+
+#endif // COLLATOR_SORT_H