From: Stanislav Malyshev Date: Mon, 7 Jul 2008 23:42:30 +0000 (+0000) Subject: Merge intl extension to HEAD X-Git-Tag: BEFORE_HEAD_NS_CHANGE~1350 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3e74c7848d8dae0ae83aa4205cd99f56c4e1e698;p=php Merge intl extension to HEAD # do not use yet in HEAD, needs some adjustment --- diff --git a/ext/intl/CREDITS b/ext/intl/CREDITS new file mode 100755 index 0000000000..3c54042507 --- /dev/null +++ b/ext/intl/CREDITS @@ -0,0 +1,2 @@ +Internationalization +Ed Batutis, Vladimir Iordanov, Dmitry Lakhtyuk, Stanislav Malyshev, Vadim Savchuk, Kirti Velankar diff --git a/ext/intl/TODO b/ext/intl/TODO new file mode 100755 index 0000000000..786c30a1f0 --- /dev/null +++ b/ext/intl/TODO @@ -0,0 +1,3 @@ +- Update dateformat for PHP 6 +- Integrate default locale functionality +- Integrate collator with standard sorting functions \ No newline at end of file diff --git a/ext/intl/collator/collator.c b/ext/intl/collator/collator.c new file mode 100755 index 0000000000..4c1bbc7797 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "collator_class.h" +#include "collator.h" + +#include +#include +#include + +/* {{{ 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 100755 index 0000000000..96e7aa097b --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_COLLATOR_H +#define CCOLLATOR_COLLATOR_H + +#include + +#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 100755 index 0000000000..b4fe0a4e14 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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 + +/* {{{ 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 100755 index 0000000000..85636cc486 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_ATTR_H +#define CCOLLATOR_ATTR_H + +#include + +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 100755 index 0000000000..1d75f71f64 --- /dev/null +++ b/ext/intl/collator/collator_class.c @@ -0,0 +1,197 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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 + +zend_class_entry *Collator_ce_ptr = NULL; + +///////////////////////////////////////////////////////////////////////////// +// 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 ); + + retval.handle = zend_objects_store_put( + intern, + Collator_objects_dtor, + (zend_objects_free_object_storage_t)Collator_objects_free, + NULL TSRMLS_CC ); + + retval.handlers = zend_get_std_object_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. + +static +ZEND_BEGIN_ARG_INFO_EX( collator_0_args, 0, 0, 0 ) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO_EX( collator_1_arg, 0, 0, 1 ) + ZEND_ARG_INFO( 0, arg1 ) +ZEND_END_ARG_INFO() + +static +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() + +static +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 + */ + +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 ) + { NULL, NULL, NULL } +}; +/* }}} */ + +/* {{{ 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 ); + + // 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 100755 index 0000000000..8d4c9d97f4 --- /dev/null +++ b/ext/intl/collator/collator_class.h @@ -0,0 +1,71 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_CLASS_H +#define COLLATOR_CLASS_H + +#include + +#include "intl_common.h" +#include "intl_error.h" + +#include + +typedef struct { + zend_object zo; + + // ICU collator + UCollator* ucoll; + + // error handling + intl_error err; + +} 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 \ + co = (Collator_object *) zend_object_store_get_object( object TSRMLS_CC ); \ + intl_error_reset( COLLATOR_ERROR_P( co ) TSRMLS_CC ); \ + +// 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 100755 index 0000000000..34ff4a4885 --- /dev/null +++ b/ext/intl/collator/collator_compare.c @@ -0,0 +1,79 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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 ) +{ + UChar* str1 = NULL; + UChar* str2 = NULL; + int str1_len = 0; + int str2_len = 0; + + UCollationResult result; + + COLLATOR_METHOD_INIT_VARS + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ouu", + &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; + + + /* + * Compare given strings (converting them to UTF-16 first). + */ + + // Compare given strings. + result = ucol_strcoll( + co->ucoll, + str1, str1_len, + str2, str2_len ); + + // 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 100755 index 0000000000..4e38b79309 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_COMPARE_H +#define COLLATOR_COMPARE_H + +#include + +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 100755 index 0000000000..389f12f204 --- /dev/null +++ b/ext/intl/collator/collator_convert.c @@ -0,0 +1,264 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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 +#include + +#define COLLATOR_CONVERT_RETURN_FAILED( retval ) \ +{ \ + zval_add_ref( &retval ); \ + return retval; \ +} + +/* {{{ collator_convert_object_to_string + * Convert object to UTF16-encoded string. + */ +zval* collator_convert_object_to_string( zval* obj TSRMLS_DC ) +{ + zval* zstr = NULL; + + // 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_UNICODE, 0 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 ); + } + + 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_UNICODE ) + { + 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_UNICODE ) + { + zend_make_printable_zval(arg, &arg_copy, &use_copy); + + if( use_copy ) + { + // Don't copy arg_copy data to str. + ALLOC_ZVAL( str ); + *str = arg_copy; + + // Reset refcounter. + INIT_PZVAL( str ); + } + else + { + zval_add_ref( &arg ); + str = 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_UNICODE ) + { + // 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 ); + + zval_add_ref( &arg ); + n_arg = 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 100755 index 0000000000..98e224c681 --- /dev/null +++ b/ext/intl/collator/collator_convert.h @@ -0,0 +1,32 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_CONVERT_H +#define COLLATOR_CONVERT_H + +#include +#include + +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 100755 index 0000000000..ca0a7148be --- /dev/null +++ b/ext/intl/collator/collator_create.c @@ -0,0 +1,134 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php_intl.h" +#include "collator_class.h" +#include "collator_create.h" +#include "intl_data.h" + +/* {{{ proto Collator collator_create( string $locale ) + * Create collator. + */ +PHP_FUNCTION( collator_create ) +{ + char* locale; + int locale_len = 0; + zval* object; + Collator_object* co; + + intl_error_reset( NULL TSRMLS_CC ); + + // 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 ); + + RETURN_NULL(); + } + + INTL_CHECK_LOCALE_LEN(locale_len); + // Create a Collator object and save the ICU collator into it. + if( ( object = getThis() ) == NULL ) + object = return_value; + + if( Z_TYPE_P( object ) != IS_OBJECT ) + object_init_ex( object, Collator_ce_ptr ); + + co = (Collator_object *) zend_object_store_get_object( object TSRMLS_CC ); + + intl_error_reset( COLLATOR_ERROR_P( co ) TSRMLS_CC ); + + if(locale_len == 0) { + locale = UG(default_locale); + } + + // Open ICU collator. + co->ucoll = ucol_open( locale, COLLATOR_ERROR_CODE_P( co ) ); + + if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) || co->ucoll == NULL ) + { + intl_error_set( NULL, COLLATOR_ERROR_CODE( co ), + "collator_create: unable to open ICU collator", 0 TSRMLS_CC ); + + // Collator creation failed. + RETURN_NULL(); + } +} +/* }}} */ + +/* {{{ proto Collator Collator::__construct( string $locale ) + * Collator object constructor. + */ +PHP_METHOD( Collator, __construct ) +{ + char* locale = NULL; + int locale_len = 0; + + COLLATOR_METHOD_INIT_VARS + + object = getThis(); + // Parse parameters. + if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", + &locale, &locale_len ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "__construct: unable to parse input params", 0 TSRMLS_CC ); + + zval_dtor(object); + ZVAL_NULL(object); + RETURN_NULL(); + } + + INTL_CHECK_LOCALE_LEN_OBJ(locale_len, object); + /* Fetch the object. */ + co = (Collator_object*) zend_object_store_get_object( object TSRMLS_CC ); + + intl_error_reset( COLLATOR_ERROR_P( co ) TSRMLS_CC ); + + if(locale_len == 0) { + locale = UG(default_locale); + } + + // Open ICU collator. + co->ucoll = ucol_open( locale, COLLATOR_ERROR_CODE_P( co ) ); + + if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) || co->ucoll == NULL ) + { + intl_error_set( NULL, COLLATOR_ERROR_CODE( co ), + "__construct: unable to open ICU collator", 0 TSRMLS_CC ); + + zval_dtor(object); + ZVAL_NULL(object); + RETURN_NULL(); + } +} +/* }}} */ + +/* + * 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 100755 index 0000000000..b740e82d68 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_CREATE_H +#define COLLATOR_CREATE_H + +#include + +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 100755 index 0000000000..55e366ccba --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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 100755 index 0000000000..b2f44ea2a3 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_ERROR_H +#define COLLATOR_ERROR_H + +#include + +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 100755 index 0000000000..4f84b4da64 --- /dev/null +++ b/ext/intl/collator/collator_is_numeric.c @@ -0,0 +1,294 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#include "collator_is_numeric.h" + +/* {{{ 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 100755 index 0000000000..585d58917a --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_IS_NUMERIC_H +#define COLLATOR_IS_NUMERIC_H + +#include +#include + +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 100755 index 0000000000..cfcdf0aaf1 --- /dev/null +++ b/ext/intl/collator/collator_locale.c @@ -0,0 +1,72 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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 + +/* {{{ 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 ) +{ + int 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; + + // 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. + RETURN_ASCII_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 100755 index 0000000000..bda90cd3b9 --- /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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_LOCALE_H +#define COLLATOR_LOCALE_H + +#include + +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 100755 index 0000000000..b28aef0954 --- /dev/null +++ b/ext/intl/collator/collator_sort.c @@ -0,0 +1,498 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#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; + +/* {{{ 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_UNICODE && Z_TYPE_P(str2) == IS_UNICODE && + ( 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 ); + + // 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 + zval_add_ref( &num1 ); + norm1 = num1; + + // 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_UNICODE ) + { + num1 = collator_convert_string_to_double( op1 ); + op1 = num1; + } + + if( Z_TYPE_P(op2) == IS_UNICODE ) + { + 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 ); + + // 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; + + 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_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; + + + /* + * 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 ) ); + + // 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 ) + { + // Process string values only. + + if( Z_TYPE_PP( hashData ) == IS_UNICODE ) + { + utf16_buf = INTL_Z_STRVAL_P( *hashData ); + utf16_len = INTL_Z_STRLEN_P( *hashData ); + } + else + { + // Set empty string + utf16_len = 0; + utf16_buf = (UChar*) ""; + } + + // 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; + + 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 ); +} +/* }}} */ + +/* + * 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 100755 index 0000000000..0fafb9f35a --- /dev/null +++ b/ext/intl/collator/collator_sort.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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef COLLATOR_SORT_H +#define COLLATOR_SORT_H + +#include + +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_asort ); + +#endif // COLLATOR_SORT_H diff --git a/ext/intl/common/common_error.c b/ext/intl/common/common_error.c new file mode 100755 index 0000000000..3468cd520e --- /dev/null +++ b/ext/intl/common/common_error.c @@ -0,0 +1,266 @@ +/* + +----------------------------------------------------------------------+ + | 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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php_intl.h" +#include "intl_error.h" +#include "common_error.h" + +/* {{{ proto int intl_get_error_code() + * Get code of the last occured error. + */ +PHP_FUNCTION( intl_get_error_code ) +{ + RETURN_LONG( intl_error_get_code( NULL TSRMLS_CC ) ); +} +/* }}} */ + +/* {{{ proto string intl_get_error_message() + * Get text description of the last occured error. + */ +PHP_FUNCTION( intl_get_error_message ) +{ + char* message = intl_error_get_message( NULL TSRMLS_CC ); + RETURN_STRING( message, FALSE ); +} +/* }}} */ + +/* {{{ proto bool intl_is_failure() + * Check whether the given error code indicates a failure. + * Returns true if it does, and false if the code + * indicates success or a warning. + */ +PHP_FUNCTION( intl_is_failure ) +{ + long err_code; + + // Parse parameters. + if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "l", + &err_code ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intl_is_failure: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + RETURN_BOOL( U_FAILURE( err_code ) ); +} + +/* {{{ proto string intl_error_name() + * Return a string for a given error code. + * The string will be the same as the name of the error code constant. + */ +PHP_FUNCTION( intl_error_name ) +{ + long err_code; + + // Parse parameters. + if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "l", + &err_code ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "intl_error_name: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + RETURN_STRING( (char*)u_errorName( err_code ), 1 ); +} +/* }}} */ + +/* {{{ intl_expose_icu_error_codes + * Expose ICU error codes + */ +void intl_expose_icu_error_codes( INIT_FUNC_ARGS ) +{ + #define INTL_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS) + + // Warnings + INTL_EXPOSE_CONST( U_USING_FALLBACK_WARNING ); + INTL_EXPOSE_CONST( U_ERROR_WARNING_START ); + INTL_EXPOSE_CONST( U_USING_DEFAULT_WARNING ); + INTL_EXPOSE_CONST( U_SAFECLONE_ALLOCATED_WARNING ); + INTL_EXPOSE_CONST( U_STATE_OLD_WARNING ); + INTL_EXPOSE_CONST( U_STRING_NOT_TERMINATED_WARNING ); + INTL_EXPOSE_CONST( U_SORT_KEY_TOO_SHORT_WARNING ); + INTL_EXPOSE_CONST( U_AMBIGUOUS_ALIAS_WARNING ); + INTL_EXPOSE_CONST( U_DIFFERENT_UCA_VERSION ); + INTL_EXPOSE_CONST( U_ERROR_WARNING_LIMIT ); + + // Standard errors + INTL_EXPOSE_CONST( U_ZERO_ERROR ); + INTL_EXPOSE_CONST( U_ILLEGAL_ARGUMENT_ERROR ); + INTL_EXPOSE_CONST( U_MISSING_RESOURCE_ERROR ); + INTL_EXPOSE_CONST( U_INVALID_FORMAT_ERROR ); + INTL_EXPOSE_CONST( U_FILE_ACCESS_ERROR ); + INTL_EXPOSE_CONST( U_INTERNAL_PROGRAM_ERROR ); + INTL_EXPOSE_CONST( U_MESSAGE_PARSE_ERROR ); + INTL_EXPOSE_CONST( U_MEMORY_ALLOCATION_ERROR ); + INTL_EXPOSE_CONST( U_INDEX_OUTOFBOUNDS_ERROR ); + INTL_EXPOSE_CONST( U_PARSE_ERROR ); + INTL_EXPOSE_CONST( U_INVALID_CHAR_FOUND ); + INTL_EXPOSE_CONST( U_TRUNCATED_CHAR_FOUND ); + INTL_EXPOSE_CONST( U_ILLEGAL_CHAR_FOUND ); + INTL_EXPOSE_CONST( U_INVALID_TABLE_FORMAT ); + INTL_EXPOSE_CONST( U_INVALID_TABLE_FILE ); + INTL_EXPOSE_CONST( U_BUFFER_OVERFLOW_ERROR ); + INTL_EXPOSE_CONST( U_UNSUPPORTED_ERROR ); + INTL_EXPOSE_CONST( U_RESOURCE_TYPE_MISMATCH ); + INTL_EXPOSE_CONST( U_ILLEGAL_ESCAPE_SEQUENCE ); + INTL_EXPOSE_CONST( U_UNSUPPORTED_ESCAPE_SEQUENCE ); + INTL_EXPOSE_CONST( U_NO_SPACE_AVAILABLE ); + INTL_EXPOSE_CONST( U_CE_NOT_FOUND_ERROR ); + INTL_EXPOSE_CONST( U_PRIMARY_TOO_LONG_ERROR ); + INTL_EXPOSE_CONST( U_STATE_TOO_OLD_ERROR ); + INTL_EXPOSE_CONST( U_TOO_MANY_ALIASES_ERROR ); + INTL_EXPOSE_CONST( U_ENUM_OUT_OF_SYNC_ERROR ); + INTL_EXPOSE_CONST( U_INVARIANT_CONVERSION_ERROR ); + INTL_EXPOSE_CONST( U_INVALID_STATE_ERROR ); + INTL_EXPOSE_CONST( U_COLLATOR_VERSION_MISMATCH ); + INTL_EXPOSE_CONST( U_USELESS_COLLATOR_ERROR ); + INTL_EXPOSE_CONST( U_NO_WRITE_PERMISSION ); + INTL_EXPOSE_CONST( U_STANDARD_ERROR_LIMIT ); + + // The error code range 0x10000 0x10100 are reserved for Transliterator + INTL_EXPOSE_CONST( U_BAD_VARIABLE_DEFINITION ); + INTL_EXPOSE_CONST( U_PARSE_ERROR_START ); + INTL_EXPOSE_CONST( U_MALFORMED_RULE ); + INTL_EXPOSE_CONST( U_MALFORMED_SET ); + INTL_EXPOSE_CONST( U_MALFORMED_SYMBOL_REFERENCE ); + INTL_EXPOSE_CONST( U_MALFORMED_UNICODE_ESCAPE ); + INTL_EXPOSE_CONST( U_MALFORMED_VARIABLE_DEFINITION ); + INTL_EXPOSE_CONST( U_MALFORMED_VARIABLE_REFERENCE ); + INTL_EXPOSE_CONST( U_MISMATCHED_SEGMENT_DELIMITERS ); + INTL_EXPOSE_CONST( U_MISPLACED_ANCHOR_START ); + INTL_EXPOSE_CONST( U_MISPLACED_CURSOR_OFFSET ); + INTL_EXPOSE_CONST( U_MISPLACED_QUANTIFIER ); + INTL_EXPOSE_CONST( U_MISSING_OPERATOR ); + INTL_EXPOSE_CONST( U_MISSING_SEGMENT_CLOSE ); + INTL_EXPOSE_CONST( U_MULTIPLE_ANTE_CONTEXTS ); + INTL_EXPOSE_CONST( U_MULTIPLE_CURSORS ); + INTL_EXPOSE_CONST( U_MULTIPLE_POST_CONTEXTS ); + INTL_EXPOSE_CONST( U_TRAILING_BACKSLASH ); + INTL_EXPOSE_CONST( U_UNDEFINED_SEGMENT_REFERENCE ); + INTL_EXPOSE_CONST( U_UNDEFINED_VARIABLE ); + INTL_EXPOSE_CONST( U_UNQUOTED_SPECIAL ); + INTL_EXPOSE_CONST( U_UNTERMINATED_QUOTE ); + INTL_EXPOSE_CONST( U_RULE_MASK_ERROR ); + INTL_EXPOSE_CONST( U_MISPLACED_COMPOUND_FILTER ); + INTL_EXPOSE_CONST( U_MULTIPLE_COMPOUND_FILTERS ); + INTL_EXPOSE_CONST( U_INVALID_RBT_SYNTAX ); + INTL_EXPOSE_CONST( U_INVALID_PROPERTY_PATTERN ); + INTL_EXPOSE_CONST( U_MALFORMED_PRAGMA ); + INTL_EXPOSE_CONST( U_UNCLOSED_SEGMENT ); + INTL_EXPOSE_CONST( U_ILLEGAL_CHAR_IN_SEGMENT ); + INTL_EXPOSE_CONST( U_VARIABLE_RANGE_EXHAUSTED ); + INTL_EXPOSE_CONST( U_VARIABLE_RANGE_OVERLAP ); + INTL_EXPOSE_CONST( U_ILLEGAL_CHARACTER ); + INTL_EXPOSE_CONST( U_INTERNAL_TRANSLITERATOR_ERROR ); + INTL_EXPOSE_CONST( U_INVALID_ID ); + INTL_EXPOSE_CONST( U_INVALID_FUNCTION ); + INTL_EXPOSE_CONST( U_PARSE_ERROR_LIMIT ); + + // The error code range 0x10100 0x10200 are reserved for formatting API parsing error + INTL_EXPOSE_CONST( U_UNEXPECTED_TOKEN ); + INTL_EXPOSE_CONST( U_FMT_PARSE_ERROR_START ); + INTL_EXPOSE_CONST( U_MULTIPLE_DECIMAL_SEPARATORS ); + INTL_EXPOSE_CONST( U_MULTIPLE_DECIMAL_SEPERATORS ); // Typo: kept for backward compatibility. Use U_MULTIPLE_DECIMAL_SEPARATORS + INTL_EXPOSE_CONST( U_MULTIPLE_EXPONENTIAL_SYMBOLS ); + INTL_EXPOSE_CONST( U_MALFORMED_EXPONENTIAL_PATTERN ); + INTL_EXPOSE_CONST( U_MULTIPLE_PERCENT_SYMBOLS ); + INTL_EXPOSE_CONST( U_MULTIPLE_PERMILL_SYMBOLS ); + INTL_EXPOSE_CONST( U_MULTIPLE_PAD_SPECIFIERS ); + INTL_EXPOSE_CONST( U_PATTERN_SYNTAX_ERROR ); + INTL_EXPOSE_CONST( U_ILLEGAL_PAD_POSITION ); + INTL_EXPOSE_CONST( U_UNMATCHED_BRACES ); + INTL_EXPOSE_CONST( U_UNSUPPORTED_PROPERTY ); + INTL_EXPOSE_CONST( U_UNSUPPORTED_ATTRIBUTE ); + INTL_EXPOSE_CONST( U_FMT_PARSE_ERROR_LIMIT ); + + // The error code range 0x10200 0x102ff are reserved for Break Iterator related error + INTL_EXPOSE_CONST( U_BRK_INTERNAL_ERROR ); + INTL_EXPOSE_CONST( U_BRK_ERROR_START ); + INTL_EXPOSE_CONST( U_BRK_HEX_DIGITS_EXPECTED ); + INTL_EXPOSE_CONST( U_BRK_SEMICOLON_EXPECTED ); + INTL_EXPOSE_CONST( U_BRK_RULE_SYNTAX ); + INTL_EXPOSE_CONST( U_BRK_UNCLOSED_SET ); + INTL_EXPOSE_CONST( U_BRK_ASSIGN_ERROR ); + INTL_EXPOSE_CONST( U_BRK_VARIABLE_REDFINITION ); + INTL_EXPOSE_CONST( U_BRK_MISMATCHED_PAREN ); + INTL_EXPOSE_CONST( U_BRK_NEW_LINE_IN_QUOTED_STRING ); + INTL_EXPOSE_CONST( U_BRK_UNDEFINED_VARIABLE ); + INTL_EXPOSE_CONST( U_BRK_INIT_ERROR ); + INTL_EXPOSE_CONST( U_BRK_RULE_EMPTY_SET ); + INTL_EXPOSE_CONST( U_BRK_UNRECOGNIZED_OPTION ); + INTL_EXPOSE_CONST( U_BRK_MALFORMED_RULE_TAG ); + INTL_EXPOSE_CONST( U_BRK_ERROR_LIMIT ); + + // The error codes in the range 0x10300-0x103ff are reserved for regular expression related errrs + INTL_EXPOSE_CONST( U_REGEX_INTERNAL_ERROR ); + INTL_EXPOSE_CONST( U_REGEX_ERROR_START ); + INTL_EXPOSE_CONST( U_REGEX_RULE_SYNTAX ); + INTL_EXPOSE_CONST( U_REGEX_INVALID_STATE ); + INTL_EXPOSE_CONST( U_REGEX_BAD_ESCAPE_SEQUENCE ); + INTL_EXPOSE_CONST( U_REGEX_PROPERTY_SYNTAX ); + INTL_EXPOSE_CONST( U_REGEX_UNIMPLEMENTED ); + INTL_EXPOSE_CONST( U_REGEX_MISMATCHED_PAREN ); + INTL_EXPOSE_CONST( U_REGEX_NUMBER_TOO_BIG ); + INTL_EXPOSE_CONST( U_REGEX_BAD_INTERVAL ); + INTL_EXPOSE_CONST( U_REGEX_MAX_LT_MIN ); + INTL_EXPOSE_CONST( U_REGEX_INVALID_BACK_REF ); + INTL_EXPOSE_CONST( U_REGEX_INVALID_FLAG ); + INTL_EXPOSE_CONST( U_REGEX_LOOK_BEHIND_LIMIT ); + INTL_EXPOSE_CONST( U_REGEX_SET_CONTAINS_STRING ); + INTL_EXPOSE_CONST( U_REGEX_ERROR_LIMIT ); + + // The error code in the range 0x10400-0x104ff are reserved for IDNA related error codes +#if defined(U_IDNA_PROHIBITED_ERROR) + INTL_EXPOSE_CONST( U_IDNA_PROHIBITED_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_ERROR_START ); + INTL_EXPOSE_CONST( U_IDNA_UNASSIGNED_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_CHECK_BIDI_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_STD3_ASCII_RULES_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_ACE_PREFIX_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_VERIFICATION_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_LABEL_TOO_LONG_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_ZERO_LENGTH_LABEL_ERROR ); + INTL_EXPOSE_CONST( U_IDNA_ERROR_LIMIT ); +#endif + + // Aliases for StringPrep + INTL_EXPOSE_CONST( U_STRINGPREP_PROHIBITED_ERROR ); + INTL_EXPOSE_CONST( U_STRINGPREP_UNASSIGNED_ERROR ); + INTL_EXPOSE_CONST( U_STRINGPREP_CHECK_BIDI_ERROR ); + + INTL_EXPOSE_CONST( U_ERROR_LIMIT ); + + #undef INTL_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/common/common_error.h b/ext/intl/common/common_error.h new file mode 100755 index 0000000000..8716222124 --- /dev/null +++ b/ext/intl/common/common_error.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 | + | Dmitry Lakhtyuk | + +----------------------------------------------------------------------+ + */ + +#ifndef INTL_COMMON_ERROR_H +#define INTL_COMMON_ERROR_H + +#include + +PHP_FUNCTION( intl_get_error_code ); +PHP_FUNCTION( intl_get_error_message ); +PHP_FUNCTION( intl_is_failure ); +PHP_FUNCTION( intl_error_name ); + +void intl_expose_icu_error_codes( INIT_FUNC_ARGS ); + +#endif // INTL_COMMON_ERROR_H diff --git a/ext/intl/config.m4 b/ext/intl/config.m4 new file mode 100755 index 0000000000..135593cec4 --- /dev/null +++ b/ext/intl/config.m4 @@ -0,0 +1,58 @@ +dnl config.m4 for extension intl + +dnl ########################################################################## +dnl Initialize the extension +PHP_ARG_ENABLE(intl, whether to enable internationalization support, +[ --enable-intl Enable internationalization support]) + +if test "$PHP_INTL" != "no"; then + PHP_SETUP_ICU + PHP_REQUIRE_CXX() + + PHP_NEW_EXTENSION(intl, + php_intl.c \ + intl_error.c \ + intl_convert.c \ + collator/collator.c \ + collator/collator_class.c \ + collator/collator_sort.c \ + collator/collator_convert.c \ + collator/collator_locale.c \ + collator/collator_compare.c \ + collator/collator_attr.c \ + collator/collator_create.c \ + collator/collator_is_numeric.c \ + collator/collator_error.c \ + common/common_error.c \ + formatter/formatter.c \ + formatter/formatter_main.c \ + formatter/formatter_class.c \ + formatter/formatter_attr.c \ + formatter/formatter_data.c \ + formatter/formatter_format.c \ + formatter/formatter_parse.c \ + normalizer/normalizer.c \ + normalizer/normalizer_class.c \ + normalizer/normalizer_normalize.c \ + locale/locale.c \ + locale/locale_class.c \ + locale/locale_methods.c \ + msgformat/msgformat.c \ + msgformat/msgformat_attr.c \ + msgformat/msgformat_class.c \ + msgformat/msgformat_data.c \ + msgformat/msgformat_format.c \ + msgformat/msgformat_helpers.cpp \ + msgformat/msgformat_parse.c \ + grapheme/grapheme_string.c \ + grapheme/grapheme_util.c \ + ,$ext_shared,,$ICU_INCS) + + PHP_ADD_BUILD_DIR($ext_builddir/collator) + PHP_ADD_BUILD_DIR($ext_builddir/common) + PHP_ADD_BUILD_DIR($ext_builddir/formatter) + PHP_ADD_BUILD_DIR($ext_builddir/normalizer) + PHP_ADD_BUILD_DIR($ext_builddir/locale) + PHP_ADD_BUILD_DIR($ext_builddir/msgformat) + PHP_ADD_BUILD_DIR($ext_builddir/grapheme) +fi diff --git a/ext/intl/config.w32 b/ext/intl/config.w32 new file mode 100755 index 0000000000..4ae35e5f68 --- /dev/null +++ b/ext/intl/config.w32 @@ -0,0 +1,65 @@ +// $Id$ +// vim:ft=javascript + +ARG_ENABLE("intl", "Enable internationalization support", "no"); + +if (PHP_INTL != "no") { + if (CHECK_LIB("icuuc.lib", "intl", PHP_INTL) && + CHECK_HEADER_ADD_INCLUDE("unicode/utf.h", "CFLAGS_INTL")) { + // always build as shared - zend_strtod.c/ICU type conflict + EXTENSION("intl", "php_intl.c intl_convert.c intl_error.c ", true, + "/I \"" + configure_module_dirname + "\""); + ADD_SOURCES(configure_module_dirname + "/collator", "\ + collator.c \ + collator_attr.c \ + collator_class.c \ + collator_compare.c \ + collator_convert.c \ + collator_create.c \ + collator_error.c \ + collator_is_numeric.c \ + collator_locale.c \ + collator_sort.c \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/common", "\ + common_error.c \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/formatter", "\ + formatter.c \ + formatter_attr.c \ + formatter_class.c \ + formatter_data.c \ + formatter_format.c \ + formatter_main.c \ + formatter_parse.c \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/locale", "\ + locale.c \ + locale_class.c \ + locale_methods.c \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/msgformat", "\ + msgformat.c \ + msgformat_attr.c \ + msgformat_class.c \ + msgformat_data.c \ + msgformat_format.c \ + msgformat_helpers.cpp \ + msgformat_parse.c \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/normalizer", "\ + normalizer.c \ + normalizer_class.c \ + normalizer_normalize.c \ + ", "intl"); + ADD_SOURCES(configure_module_dirname + "/grapheme", "\ + grapheme_string.c grapheme_util.c \ + ", "intl"); + ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib icule.lib iculx.lib"); + // if int32_t and uint32_t types are made available in PHP, uncomment next line + // ADD_FLAG("CFLAGS_INTL", "/D U_HAVE_INT32_T /D U_HAVE_UINT32_T"); + AC_DEFINE("HAVE_INTL", 1, "Internationalization support enabled"); + } else { + WARNING("intl not enabled; libraries and/or headers not found"); + } +} diff --git a/ext/intl/dateformat/dateformat.c b/ext/intl/dateformat/dateformat.c new file mode 100755 index 0000000000..b61d268d72 --- /dev/null +++ b/ext/intl/dateformat/dateformat.c @@ -0,0 +1,363 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "php_intl.h" +#include "intl_convert.h" +#include "dateformat_class.h" +#include "dateformat.h" + +/* {{{ dateformat_register_constants + * Register constants common for the both (OO and procedural) + * APIs. + */ +void dateformat_register_constants( INIT_FUNC_ARGS ) +{ + if( IntlDateFormatter_ce_ptr == NULL) { + zend_error(E_ERROR, "DateFormat class not defined"); + return; + } + + #define DATEFORMATTER_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS) + #define DATEFORMATTER_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( IntlDateFormatter_ce_ptr, ZEND_STRS( #x ) - 1, UDAT_##x TSRMLS_CC ); + #define DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST(name, value) zend_declare_class_constant_long( IntlDateFormatter_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC ); + + #define DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST(x) zend_declare_class_constant_long( IntlDateFormatter_ce_ptr, ZEND_STRS( #x ) - 1, UCAL_##x TSRMLS_CC ); + + // UDateFormatStyle constants + DATEFORMATTER_EXPOSE_CLASS_CONST( FULL ); + DATEFORMATTER_EXPOSE_CLASS_CONST( LONG ); + DATEFORMATTER_EXPOSE_CLASS_CONST( MEDIUM ); + DATEFORMATTER_EXPOSE_CLASS_CONST( SHORT ); + DATEFORMATTER_EXPOSE_CLASS_CONST( NONE ); + +/* + DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "GREGORIAN", DATEF_GREGORIAN ); + DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "CUSTOMARY", DATEF_CUSTOMARY ); + DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "BUDDHIST", DATEF_BUDDHIST ); + DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "JAPANESE_IMPERIAL", DATEF_JAPANESE_IMPERIAL ); +*/ + + DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST( GREGORIAN ); + DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST( TRADITIONAL ); + + #undef DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST + #undef DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST + #undef DATEFORMATTER_EXPOSE_CLASS_CONST + #undef DATEFORMATTER_EXPOSE_CONST +} +/* }}} */ + +/* {{{ proto IntlDateFormatter IntlDateFormatter::create( string $locale , long date_type, long time_type[,string $timezone_str, long $calendar , string $pattern] ) + * Create formatter. }}} */ +/* {{{ proto IntlDateFormatter datefmt_create( string $locale, long date_type, long time_type[,string $timezone_str, long $calendar , string $pattern] ) + + * Create formatter. + */ +PHP_FUNCTION( datefmt_create ) +{ + char* locale; + int locale_len = 0; + zval* object; + + long date_type = 0; + long time_type = 0; + long calendar = 1; + int all_done = 0; + //zval* timezone = NULL; + + char* timezone_str = NULL; + int timezone_str_len = 0; + char* pattern_str = NULL; + int pattern_str_len = 0; + UChar* svalue = NULL; //UTF-16 pattern_str + int slength = 0; + UChar* timezone_utf16 = NULL; //UTF-16 timezone_str + int timezone_utf16_len = 0; + UCalendar ucal_obj = NULL; + + + IntlDateFormatter_object* mfo; + + intl_error_reset( NULL TSRMLS_CC ); + + // Parse parameters. + if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sll|sls", + &locale, &locale_len, &date_type, & time_type , &timezone_str, &timezone_str_len , &calendar ,&pattern_str , &pattern_str_len ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_create: unable to parse input params", 0 TSRMLS_CC ); + RETURN_NULL(); + } + + + // Create a IntlDateFormatter object and save the ICU formatter into it. + if( ( object = getThis() ) == NULL ) + object = return_value; + + if( Z_TYPE_P( object ) != IS_OBJECT ) + object_init_ex( object, IntlDateFormatter_ce_ptr ); + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + if(locale_len == 0) { + locale = INTL_G(default_locale); + } + + // Convert pattern (if specified) to UTF-16. + if( pattern_str && pattern_str_len>0 ){ + intl_convert_utf8_to_utf16(&svalue, &slength, pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting pattern to UTF-16" ); + } + + // Convert pattern (if specified) to UTF-16. + if( timezone_str && timezone_str_len >0 ){ + intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, timezone_str, timezone_str_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting timezone_str to UTF-16" ); + } + + // Create an ICU date formatter. + while( U_FAILURE( INTL_DATA_ERROR_CODE(mfo)) || (all_done==0) ){ + // Convert pattern (if specified) to UTF-16. + if( pattern_str && pattern_str_len>0 ){ + DATE_FORMAT_OBJECT(mfo) = udat_open(UDAT_IGNORE,UDAT_IGNORE, locale, timezone_utf16, timezone_utf16_len ,svalue ,slength , &INTL_DATA_ERROR_CODE((mfo))); + }else{ + DATE_FORMAT_OBJECT(mfo) = udat_open(time_type,date_type, locale, timezone_utf16, timezone_utf16_len ,svalue ,slength , &INTL_DATA_ERROR_CODE((mfo))); + } + + //Set the calendar if passed + if( calendar) { + ucal_obj = ucal_open( timezone_utf16 , timezone_utf16_len , locale , calendar , &INTL_DATA_ERROR_CODE(mfo) ); + udat_setCalendar( DATE_FORMAT_OBJECT(mfo), ucal_obj ); + } + all_done = 1; + + }//end of while + + + if( U_FAILURE( INTL_DATA_ERROR_CODE((mfo)) ) ) + { + intl_error_set( NULL, INTL_DATA_ERROR_CODE((mfo)) , + "__construct: date formatter creation failed", 0 TSRMLS_CC ); + zval_dtor(object); + ZVAL_NULL(object); + if( svalue){ + efree(svalue); + } + if( timezone_utf16){ + efree(timezone_utf16); + } + RETURN_NULL(); + } + + if( svalue){ + efree(svalue); + } + if( timezone_utf16){ + efree(timezone_utf16); + } + //Set the class variables + mfo->date_type = date_type; + mfo->time_type = time_type; + mfo->calendar = calendar; + if( timezone_str && timezone_str_len > 0){ + if( mfo->timezone_id ){ + efree(mfo->timezone_id); + } + mfo->timezone_id = estrndup( timezone_str, timezone_str_len); + } +} +/* }}} */ + +/* {{{ proto void IntlDateFormatter::__construct( string $locale, string $pattern ) + * IntlDateFormatter object constructor. + */ +PHP_METHOD( IntlDateFormatter, __construct ) +{ + char* locale = NULL; + int locale_len = 0; + long date_type = 0; + long time_type = 0; + long calendar = 1; + + char* timezone_str = NULL; + int timezone_str_len = 0; + char* pattern_str = NULL; + int pattern_str_len = 0; + UChar* svalue = NULL; + int slength = 0; + UChar* timezone_utf16 = NULL; //UTF-16 timezone_str + int timezone_utf16_len = 0; + + UCalendar ucal_obj = NULL; + int all_done = 0; + + zval* object; + IntlDateFormatter_object* mfo; + + intl_error_reset( NULL TSRMLS_CC ); + + object = getThis(); + + // Parse parameters. + if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sll|slsb", + &locale, &locale_len, &date_type, & time_type , &timezone_str, &timezone_str_len , &calendar ,&pattern_str , &pattern_str_len ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "__construct: unable to parse input params", 0 TSRMLS_CC ); + zval_dtor(object); + ZVAL_NULL(object); + RETURN_NULL(); + } + +/* + //Check if timezone is in proper type + if( (Z_TYPE_P(timezone) != IS_STRING) && (Z_TYPE_P(timezone) != IS_OBJECT) ){ + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "__construct: unable to parse input params", 0 TSRMLS_CC ); + zval_dtor(object); + ZVAL_NULL(object); + RETURN_NULL(); + } +*/ + + mfo = (IntlDateFormatter_object *) zend_object_store_get_object( object TSRMLS_CC ); + + intl_error_reset( &mfo->datef_data.error TSRMLS_CC ); + + if(locale_len == 0) { + locale = INTL_G(default_locale); + } + + // Convert pattern (if specified) to UTF-16. + if( pattern_str && pattern_str_len>0 ){ + intl_convert_utf8_to_utf16(&svalue, &slength, pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting pattern to UTF-16" ); + } + + // Convert pattern (if specified) to UTF-16. + if( timezone_str && timezone_str_len >0 ){ + intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, timezone_str, timezone_str_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting timezone_str to UTF-16" ); + } + + + // Create an ICU date formatter. + while( U_FAILURE( INTL_DATA_ERROR_CODE(mfo)) || (all_done==0) ){ + if( pattern_str && pattern_str_len>0 ){ + DATE_FORMAT_OBJECT(mfo) = udat_open(UDAT_IGNORE,UDAT_IGNORE, locale, timezone_utf16, timezone_utf16_len ,svalue ,slength , &INTL_DATA_ERROR_CODE((mfo))); + }else{ + DATE_FORMAT_OBJECT(mfo) = udat_open(time_type,date_type, locale, timezone_utf16, timezone_utf16_len ,svalue ,slength , &INTL_DATA_ERROR_CODE((mfo))); + } + + + //Set the calendar if passed + if( calendar) { + ucal_obj = ucal_open( timezone_utf16 , timezone_utf16_len , locale , calendar , &INTL_DATA_ERROR_CODE(mfo) ); + udat_setCalendar( DATE_FORMAT_OBJECT(mfo), ucal_obj ); + } + all_done = 1; + + }//end of while + + + if( U_FAILURE( INTL_DATA_ERROR_CODE((mfo)) ) ) + { + intl_error_set( NULL, INTL_DATA_ERROR_CODE(mfo), + "__construct: date formatter creation failed", 0 TSRMLS_CC ); + if( svalue){ + efree(svalue); + } + zval_dtor(object); + ZVAL_NULL(object); + RETURN_NULL(); + } + + if( svalue){ + efree(svalue); + } + + //Set the class variables + mfo->date_type = date_type; + mfo->time_type = time_type; + mfo->calendar = calendar; + if( timezone_str && timezone_str_len > 0){ + mfo->timezone_id = estrndup( timezone_str, timezone_str_len); + } +} +/* }}} */ + +/* {{{ proto int IntlDateFormatter::getErrorCode() + * Get formatter's last error code. }}} */ +/* {{{ proto int datefmt_get_error_code( IntlDateFormatter $nf ) + * Get formatter's last error code. + */ +PHP_FUNCTION( datefmt_get_error_code ) +{ + zval* object = NULL; + IntlDateFormatter_object* mfo = NULL; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_error_code: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + mfo = (IntlDateFormatter_object *) zend_object_store_get_object( object TSRMLS_CC ); + + // Return formatter's last error code. + RETURN_LONG( INTL_DATA_ERROR_CODE(mfo) ); +} +/* }}} */ + +/* {{{ proto string IntlDateFormatter::getErrorMessage( ) + * Get text description for formatter's last error code. }}} */ +/* {{{ proto string datefmt_get_error_message( IntlDateFormatter $coll ) + * Get text description for formatter's last error code. + */ +PHP_FUNCTION( datefmt_get_error_message ) +{ + char* message = NULL; + zval* object = NULL; + IntlDateFormatter_object* mfo = NULL; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_error_message: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + mfo = (IntlDateFormatter_object *) zend_object_store_get_object( object TSRMLS_CC ); + + // Return last error message. + message = intl_error_get_message( &mfo->datef_data.error TSRMLS_CC ); + RETURN_STRING( message, 0); +} +/* }}} */ diff --git a/ext/intl/dateformat/dateformat.h b/ext/intl/dateformat/dateformat.h new file mode 100755 index 0000000000..f11918b79f --- /dev/null +++ b/ext/intl/dateformat/dateformat.h @@ -0,0 +1,45 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifndef DATE_FORMATTER_H +#define DATE_FORMATTER_H + +#include + +PHP_FUNCTION( datefmt_create ); +PHP_FUNCTION( datefmt_get_error_code ); +PHP_FUNCTION( datefmt_get_error_message ); +PHP_METHOD( IntlDateFormatter, __construct ); +void dateformat_register_constants( INIT_FUNC_ARGS ); + +/* +These are not necessary at this point of time +#define DATEF_GREGORIAN 1 +#define DATEF_CUSTOMARY 2 +#define DATEF_BUDDHIST 3 +#define DATEF_JAPANESE_IMPERIAL 4 +*/ + +#define CALENDAR_SEC "tm_sec" +#define CALENDAR_MIN "tm_min" +#define CALENDAR_HOUR "tm_hour" +#define CALENDAR_MDAY "tm_mday" +#define CALENDAR_MON "tm_mon" +#define CALENDAR_YEAR "tm_year" +#define CALENDAR_WDAY "tm_wday" +#define CALENDAR_YDAY "tm_yday" +#define CALENDAR_ISDST "tm_isdst" + +#endif // DATE_FORMATTER_H diff --git a/ext/intl/dateformat/dateformat_attr.c b/ext/intl/dateformat/dateformat_attr.c new file mode 100755 index 0000000000..09997b6ee3 --- /dev/null +++ b/ext/intl/dateformat/dateformat_attr.c @@ -0,0 +1,416 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php_intl.h" +#include "intl_convert.h" +#include "dateformat_class.h" +#include "dateformat_attr.h" + +#include +#include +#include + +static void internal_set_calendar(IntlDateFormatter_object *mfo, char* timezone_id , int timezone_id_len , int calendar ,zval* return_value TSRMLS_DC){ + + int timezone_utf16_len = 0; + UChar* timezone_utf16 = NULL; //timezone_id in UTF-16 + + char* locale = NULL; + int locale_type =ULOC_ACTUAL_LOCALE; + + UCalendar* ucal_obj = NULL; + + //check for the validity of value of calendar passed + intl_error_reset( NULL TSRMLS_CC ); + if( calendar > 1){ + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_calendar: calendar value specified is out of valid range", 0 TSRMLS_CC); + RETURN_FALSE; + } + + // Convert timezone to UTF-16. + intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len, timezone_id, timezone_id_len , &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting timezone to UTF-16" ); + + + //Get the lcoale for the dateformatter + locale = (char *)udat_getLocaleByType(DATE_FORMAT_OBJECT(mfo), locale_type ,&INTL_DATA_ERROR_CODE(mfo)); + + //Set the calendar if passed + ucal_obj = ucal_open( timezone_utf16 , timezone_utf16_len , locale , calendar , &INTL_DATA_ERROR_CODE(mfo) ); + udat_setCalendar( DATE_FORMAT_OBJECT(mfo), ucal_obj ); + INTL_METHOD_CHECK_STATUS(mfo, "Error setting the calendar."); + + if( timezone_utf16){ + efree(timezone_utf16); + } + +} + +/* {{{ proto unicode IntlDateFormatter::getDateType( ) + * Get formatter datetype. }}} */ +/* {{{ proto string datefmt_get_datetype( IntlDateFormatter $mf ) + * Get formatter datetype. + */ +PHP_FUNCTION( datefmt_get_datetype ) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL , U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_datetype: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + INTL_METHOD_CHECK_STATUS(mfo, "Error getting formatter datetype." ); + + RETURN_LONG(mfo->date_type ); +} +/* }}} */ + +/* {{{ proto unicode IntlDateFormatter::getTimeType( ) + * Get formatter timetype. }}} */ +/* {{{ proto string datefmt_get_timetype( IntlDateFormatter $mf ) + * Get formatter timetype. + */ +PHP_FUNCTION( datefmt_get_timetype ) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL , U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_timetype: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + INTL_METHOD_CHECK_STATUS(mfo, "Error getting formatter timetype." ); + + RETURN_LONG(mfo->time_type ); +} +/* }}} */ + + +/* {{{ proto unicode IntlDateFormatter::getCalendar( ) + * Get formatter calendar. }}} */ +/* {{{ proto string datefmt_get_calendar( IntlDateFormatter $mf ) + * Get formatter calendar. + */ +PHP_FUNCTION( datefmt_get_calendar ) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL , U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_calendar: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + INTL_METHOD_CHECK_STATUS(mfo, "Error getting formatter calendar." ); + + RETURN_LONG(mfo->calendar ); +} +/* }}} */ + +/* {{{ proto unicode IntlDateFormatter::getTimeZoneId( ) + * Get formatter timezone_id. }}} */ +/* {{{ proto string datefmt_get_timezone_id( IntlDateFormatter $mf ) + * Get formatter timezone_id. + */ +PHP_FUNCTION( datefmt_get_timezone_id ) +{ + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL , U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_timezone_id: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + INTL_METHOD_CHECK_STATUS(mfo, "Error getting formatter timezone_id." ); + + if( mfo->timezone_id ){ + RETURN_STRING((char*)mfo->timezone_id ,TRUE ); + }else{ + RETURN_NULL(); + } +} + +/* {{{ proto boolean IntlDateFormatter::setTimeZoneId( $timezone_id) + * Set formatter timezone_id. }}} */ +/* {{{ proto boolean datefmt_set_timezone_id( IntlDateFormatter $mf ,$timezone_id) + * Set formatter timezone_id. + */ +PHP_FUNCTION( datefmt_set_timezone_id ) +{ + char* timezone_id = NULL; + int timezone_id_len = 0; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &object, IntlDateFormatter_ce_ptr ,&timezone_id , &timezone_id_len) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_timezone_id: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + //set the timezone for the calendar + internal_set_calendar( mfo , timezone_id , timezone_id_len , mfo->calendar ,return_value TSRMLS_CC ); + + //Set the IntlDateFormatter variable + if( mfo->timezone_id ){ + efree(mfo->timezone_id); + } + mfo->timezone_id = estrndup(timezone_id , timezone_id_len); + + RETURN_TRUE; +} + +/* {{{ proto string IntlDateFormatter::getPattern( ) + * Get formatter pattern. }}} */ +/* {{{ proto string datefmt_get_pattern( IntlDateFormatter $mf ) + * Get formatter pattern. + */ +PHP_FUNCTION( datefmt_get_pattern ) +{ + UChar value_buf[64]; + int length = USIZE( value_buf ); + UChar* value = value_buf; + zend_bool is_pattern_localized =FALSE; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_pattern: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + length = udat_toPattern(DATE_FORMAT_OBJECT(mfo), is_pattern_localized, value, length, &INTL_DATA_ERROR_CODE(mfo)); + if(INTL_DATA_ERROR_CODE(mfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) { + ++length; // to avoid U_STRING_NOT_TERMINATED_WARNING + INTL_DATA_ERROR_CODE(mfo) = U_ZERO_ERROR; + value = eumalloc(length); + length = udat_toPattern(DATE_FORMAT_OBJECT(mfo), is_pattern_localized , value, length, &INTL_DATA_ERROR_CODE(mfo) ); + if(U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) { + efree(value); + value = value_buf; + } + } + INTL_METHOD_CHECK_STATUS(mfo, "Error getting formatter pattern" ); + + INTL_METHOD_RETVAL_UTF8( mfo, value, length, ( value != value_buf ) ); +} +/* }}} */ + +/* {{{ proto bool IntlDateFormatter::setPattern( string $pattern ) + * Set formatter pattern. }}} */ +/* {{{ proto bool datefmt_set_pattern( IntlDateFormatter $mf, string $pattern ) + * Set formatter pattern. + */ +PHP_FUNCTION( datefmt_set_pattern ) +{ + char* value = NULL; + int value_len = 0; + int slength = 0; + UChar* svalue = NULL; + zend_bool is_pattern_localized =FALSE; + + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", + &object, IntlDateFormatter_ce_ptr, &value, &value_len ) == FAILURE ) + { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_pattern: unable to parse input params", 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + // Convert given pattern to UTF-16. + intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting pattern to UTF-16" ); + + udat_applyPattern(DATE_FORMAT_OBJECT(mfo), (UBool)is_pattern_localized , svalue, slength); + + efree(svalue); + INTL_METHOD_CHECK_STATUS(mfo, "Error setting symbol value"); + + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto string IntlDateFormatter::getLocale() + * Get formatter locale. }}} */ +/* {{{ proto string datefmt_get_locale(IntlDateFormatter $mf) + * Get formatter locale. + */ +PHP_FUNCTION( datefmt_get_locale ) +{ + char *loc; + long loc_type =ULOC_ACTUAL_LOCALE; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", + &object, IntlDateFormatter_ce_ptr ,&loc_type) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_get_locale: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + loc = (char *)udat_getLocaleByType(DATE_FORMAT_OBJECT(mfo), loc_type ,&INTL_DATA_ERROR_CODE(mfo)); + RETURN_STRING(loc, 1); +} +/* }}} */ + +/* {{{ proto string IntlDateFormatter::isLenient() + * Get formatter isLenient. }}} */ +/* {{{ proto string datefmt_isLenient(IntlDateFormatter $mf) + * Get formatter locale. + */ +PHP_FUNCTION( datefmt_is_lenient ) +{ + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &object, IntlDateFormatter_ce_ptr ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_is_lenient: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + RETVAL_BOOL(udat_isLenient(DATE_FORMAT_OBJECT(mfo))); +} +/* }}} */ + +/* {{{ proto string IntlDateFormatter::setLenient() + * Set formatter lenient. }}} */ +/* {{{ proto string datefmt_setLenient(IntlDateFormatter $mf) + * Set formatter lenient. + */ +PHP_FUNCTION( datefmt_set_lenient ) +{ + + zend_bool isLenient = FALSE; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ob", + &object, IntlDateFormatter_ce_ptr ,&isLenient ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_lenient: unable to parse input params", 0 TSRMLS_CC ); + + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + udat_setLenient(DATE_FORMAT_OBJECT(mfo) , (UBool)isLenient ); +} +/* }}} */ + +/* {{{ proto bool IntlDateFormatter::setPattern( int $calendar ) + * Set formatter calendar. }}} */ +/* {{{ proto bool datefmt_set_calendar( IntlDateFormatter $mf, int $calendar ) + * Set formatter calendar. + */ +PHP_FUNCTION( datefmt_set_calendar ) +{ + long calendar = 0; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", + &object, IntlDateFormatter_ce_ptr, &calendar ) == FAILURE ) + { + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_calendar: unable to parse input params", 0 TSRMLS_CC); + RETURN_FALSE; + } + + //check for the validity of value of calendar passed + intl_error_reset( NULL TSRMLS_CC ); + if( calendar > 1){ + intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_set_calendar: calendar value specified is out of valid range", 0 TSRMLS_CC); + RETURN_FALSE; + } + + DATE_FORMAT_METHOD_FETCH_OBJECT; + + internal_set_calendar( mfo , mfo->timezone_id , strlen(mfo->timezone_id) , calendar ,return_value TSRMLS_CC ); + + //Set the calendar value in the IntlDateFormatter object + mfo->calendar = calendar ; + + RETURN_TRUE; +} +/* }}} */ + + diff --git a/ext/intl/dateformat/dateformat_attr.h b/ext/intl/dateformat/dateformat_attr.h new file mode 100755 index 0000000000..bf28824d63 --- /dev/null +++ b/ext/intl/dateformat/dateformat_attr.h @@ -0,0 +1,34 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifndef DATE_FORMAT_ATTR_H +#define DATE_FORMAT_ATTR_H + +#include + +//PHP_FUNCTION( datefmt_get_timezone ); +PHP_FUNCTION( datefmt_get_datetype ); +PHP_FUNCTION( datefmt_get_timetype ); +PHP_FUNCTION( datefmt_get_calendar ); +PHP_FUNCTION( datefmt_set_calendar ); +PHP_FUNCTION( datefmt_get_locale ); +PHP_FUNCTION( datefmt_get_timezone_id ); +PHP_FUNCTION( datefmt_set_timezone_id ); +PHP_FUNCTION( datefmt_get_pattern ); +PHP_FUNCTION( datefmt_set_pattern ); +PHP_FUNCTION( datefmt_is_lenient ); +PHP_FUNCTION( datefmt_set_lenient ); + +#endif // DATE_FORMAT_ATTR_H diff --git a/ext/intl/dateformat/dateformat_class.c b/ext/intl/dateformat/dateformat_class.c new file mode 100755 index 0000000000..e582467231 --- /dev/null +++ b/ext/intl/dateformat/dateformat_class.c @@ -0,0 +1,132 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#include + +#include "dateformat_class.h" +#include "php_intl.h" +#include "dateformat_data.h" +#include "dateformat_format.h" +#include "dateformat_parse.h" +#include "dateformat.h" +#include "dateformat_attr.h" + +zend_class_entry *IntlDateFormatter_ce_ptr = NULL; + +///////////////////////////////////////////////////////////////////////////// +// Auxiliary functions needed by objects of 'IntlDateFormatter' class +///////////////////////////////////////////////////////////////////////////// + +/* {{{ IntlDateFormatter_objects_dtor */ +static void IntlDateFormatter_object_dtor(void *object, zend_object_handle handle TSRMLS_DC ) +{ + zend_objects_destroy_object( object, handle TSRMLS_CC ); +} +/* }}} */ + +/* {{{ IntlDateFormatter_objects_free */ +void IntlDateFormatter_object_free( zend_object *object TSRMLS_DC ) +{ + IntlDateFormatter_object* mfo = (IntlDateFormatter_object*)object; + + zend_object_std_dtor( &mfo->zo TSRMLS_CC ); + + dateformat_data_free( &mfo->datef_data TSRMLS_CC ); + + if( mfo->timezone_id ){ + efree(mfo->timezone_id); + } + + efree( mfo ); +} +/* }}} */ + +/* {{{ IntlDateFormatter_object_create */ +zend_object_value IntlDateFormatter_object_create(zend_class_entry *ce TSRMLS_DC) +{ + zend_object_value retval; + IntlDateFormatter_object* intern; + + intern = ecalloc( 1, sizeof(IntlDateFormatter_object) ); + dateformat_data_init( &intern->datef_data TSRMLS_CC ); + zend_object_std_init( &intern->zo, ce TSRMLS_CC ); + intern->date_type = 0; + intern->time_type = 0; + intern->calendar = 1; //Gregorian calendar + intern->timezone_id = NULL; + + retval.handle = zend_objects_store_put( + intern, + IntlDateFormatter_object_dtor, + (zend_objects_free_object_storage_t)IntlDateFormatter_object_free, + NULL TSRMLS_CC ); + + retval.handlers = zend_get_std_object_handlers(); + + return retval; +} +/* }}} */ + +///////////////////////////////////////////////////////////////////////////// +// 'IntlDateFormatter' class registration structures & functions +///////////////////////////////////////////////////////////////////////////// + +/* {{{ IntlDateFormatter_class_functions + * Every 'IntlDateFormatter' class method has an entry in this table + */ + +static function_entry IntlDateFormatter_class_functions[] = { + PHP_ME( IntlDateFormatter, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR ) + ZEND_FENTRY( create, ZEND_FN( datefmt_create ), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC ) + PHP_NAMED_FE( getDateType, ZEND_FN( datefmt_get_datetype ), NULL ) + PHP_NAMED_FE( getTimeType, ZEND_FN( datefmt_get_timetype ), NULL ) + PHP_NAMED_FE( getCalendar, ZEND_FN( datefmt_get_calendar ), NULL ) + PHP_NAMED_FE( setCalendar, ZEND_FN( datefmt_set_calendar ), NULL ) + PHP_NAMED_FE( getTimeZoneId, ZEND_FN( datefmt_get_timezone_id ), NULL ) + PHP_NAMED_FE( setTimeZoneId, ZEND_FN( datefmt_set_timezone_id ), NULL ) + PHP_NAMED_FE( setPattern, ZEND_FN( datefmt_set_pattern ), NULL ) + PHP_NAMED_FE( getPattern, ZEND_FN( datefmt_get_pattern ), NULL ) + PHP_NAMED_FE( getLocale, ZEND_FN( datefmt_get_locale ), NULL ) + PHP_NAMED_FE( setLenient, ZEND_FN( datefmt_set_lenient ), NULL ) + PHP_NAMED_FE( isLenient, ZEND_FN( datefmt_is_lenient ), NULL ) + PHP_NAMED_FE( format, ZEND_FN( datefmt_format ), NULL ) + PHP_NAMED_FE( parse, ZEND_FN( datefmt_parse), NULL ) + PHP_NAMED_FE( localtime, ZEND_FN( datefmt_localtime ), NULL ) + PHP_NAMED_FE( getErrorCode, ZEND_FN( datefmt_get_error_code ), NULL ) + PHP_NAMED_FE( getErrorMessage, ZEND_FN( datefmt_get_error_message ), NULL ) + { NULL, NULL, NULL } +}; +/* }}} */ + +/* {{{ dateformat_register_class + * Initialize 'IntlDateFormatter' class + */ +void dateformat_register_IntlDateFormatter_class( TSRMLS_D ) +{ + zend_class_entry ce; + + // Create and register 'IntlDateFormatter' class. + INIT_CLASS_ENTRY( ce, "IntlDateFormatter", IntlDateFormatter_class_functions ); + ce.create_object = IntlDateFormatter_object_create; + IntlDateFormatter_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC ); + + // Declare 'IntlDateFormatter' class properties. + if( !IntlDateFormatter_ce_ptr ) + { + zend_error(E_ERROR, "Failed to register IntlDateFormatter class"); + return; + } +} +/* }}} */ diff --git a/ext/intl/dateformat/dateformat_class.h b/ext/intl/dateformat/dateformat_class.h new file mode 100755 index 0000000000..039ff1a59a --- /dev/null +++ b/ext/intl/dateformat/dateformat_class.h @@ -0,0 +1,44 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifndef DATE_FORMAT_CLASS_H +#define DATE_FORMAT_CLASS_H + +#include + +#include "intl_common.h" +#include "intl_error.h" +#include "intl_data.h" +#include "dateformat_data.h" + +typedef struct { + zend_object zo; + dateformat_data datef_data; + int date_type ; + int time_type ; + int calendar ; + char* timezone_id; +} IntlDateFormatter_object; + +void dateformat_register_IntlDateFormatter_class( TSRMLS_D ); +extern zend_class_entry *IntlDateFormatter_ce_ptr; + +/* Auxiliary macros */ + +#define DATE_FORMAT_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(IntlDateFormatter, mfo) +#define DATE_FORMAT_METHOD_FETCH_OBJECT INTL_METHOD_FETCH_OBJECT(IntlDateFormatter, mfo) +#define DATE_FORMAT_OBJECT(mfo) (mfo)->datef_data.udatf + +#endif // #ifndef DATE_FORMAT_CLASS_H diff --git a/ext/intl/dateformat/dateformat_data.c b/ext/intl/dateformat/dateformat_data.c new file mode 100755 index 0000000000..33451e1c51 --- /dev/null +++ b/ext/intl/dateformat/dateformat_data.c @@ -0,0 +1,62 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dateformat_data.h" + +/* {{{ void dateformat_data_init( dateformat_data* datef_data ) + * Initialize internals of dateformat_data. + */ +void dateformat_data_init( dateformat_data* datef_data TSRMLS_DC ) +{ + if( !datef_data ) + return; + + datef_data->udatf = NULL; + intl_error_reset( &datef_data->error TSRMLS_CC ); +} +/* }}} */ + +/* {{{ void dateformat_data_free( dateformat_data* datef_data ) + * Clean up memory allocated for dateformat_data + */ +void dateformat_data_free( dateformat_data* datef_data TSRMLS_DC ) +{ + if( !datef_data ) + return; + + if( datef_data->udatf ) + udat_close( datef_data->udatf ); + + datef_data->udatf = NULL; + intl_error_reset( &datef_data->error TSRMLS_CC ); +} +/* }}} */ + +/* {{{ dateformat_data* dateformat_data_create() + * Allocate memory for dateformat_data and initialize it with default values. + */ +dateformat_data* dateformat_data_create( TSRMLS_D ) +{ + dateformat_data* datef_data = ecalloc( 1, sizeof(dateformat_data) ); + + dateformat_data_init( datef_data TSRMLS_CC ); + + return datef_data; +} +/* }}} */ diff --git a/ext/intl/dateformat/dateformat_data.h b/ext/intl/dateformat/dateformat_data.h new file mode 100755 index 0000000000..cde9e363c9 --- /dev/null +++ b/ext/intl/dateformat/dateformat_data.h @@ -0,0 +1,37 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifndef DATE_FORMAT_DATA_H +#define DATE_FORMAT_DATA_H + +#include + +#include + +#include "intl_error.h" + +typedef struct { + // error hangling + intl_error error; + + // formatter handling + UDateFormat * udatf; +} dateformat_data; + +dateformat_data* dateformat_data_create( TSRMLS_D ); +void dateformat_data_init( dateformat_data* datef_data TSRMLS_DC ); +void dateformat_data_free( dateformat_data* datef_data TSRMLS_DC ); + +#endif // DATE_FORMAT_DATA_H diff --git a/ext/intl/dateformat/dateformat_format.c b/ext/intl/dateformat/dateformat_format.c new file mode 100755 index 0000000000..c23ab3203d --- /dev/null +++ b/ext/intl/dateformat/dateformat_format.c @@ -0,0 +1,184 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "php_intl.h" +#include "intl_convert.h" +#include "dateformat.h" +#include "dateformat_class.h" +#include "dateformat_format.h" +#include "dateformat_data.h" + +/* {{{ + * Internal function which calls the udat_format +*/ +static void internal_format(IntlDateFormatter_object *mfo, UDate timestamp , zval *return_value TSRMLS_DC){ + UChar* formatted = NULL; + int32_t resultlengthneeded =0 ; + + resultlengthneeded=udat_format( DATE_FORMAT_OBJECT(mfo), timestamp, NULL, resultlengthneeded, NULL, &INTL_DATA_ERROR_CODE(mfo)); + if(INTL_DATA_ERROR_CODE(mfo)==U_BUFFER_OVERFLOW_ERROR) + { + INTL_DATA_ERROR_CODE(mfo)=U_ZERO_ERROR; + formatted=(UChar*)emalloc(sizeof(UChar) * resultlengthneeded); + udat_format( DATE_FORMAT_OBJECT(mfo), timestamp, formatted, resultlengthneeded, NULL, &INTL_DATA_ERROR_CODE(mfo)); + } + + if (formatted && U_FAILURE( INTL_DATA_ERROR_CODE(mfo) ) ) { + efree(formatted); + } + + INTL_METHOD_CHECK_STATUS( mfo, "Date formatting failed" ); + INTL_METHOD_RETVAL_UTF8( mfo, formatted, resultlengthneeded, 1 ); + +} +/* }}} */ + + +/* {{{ + * Internal function which fetches an element from the passed array for the key_name passed +*/ +static double internal_get_arr_ele(IntlDateFormatter_object *mfo , HashTable* hash_arr ,char* key_name TSRMLS_DC){ + zval** ele_value = NULL; + UDate result = -1; + + if( zend_hash_find( hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ){ + if( Z_TYPE_PP(ele_value)!= IS_LONG ){ + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format: parameter array does not contain a long element.", 0 TSRMLS_CC ); + }else{ + result = Z_LVAL_PP(ele_value); + } + } + //printf("\n Inside internal_get_arr_ele key_name= %s , result = %g \n" , key_name, result); + return result; +} +/* }}} */ + +/* {{{ + * Internal function which creates a UCalendar from the passed array +*/ +static void internal_create_ucal(IntlDateFormatter_object *mfo, HashTable* hash_arr , UCalendar* pcal TSRMLS_DC){ + long year =0; + long month =0; + long hour =0; + long minute =0; + long second =0; + long wday =0; + long yday =0; + long mday =0; + UBool isInDST = FALSE; + + //Fetch values from the incoming array + year = internal_get_arr_ele( mfo , hash_arr , CALENDAR_YEAR TSRMLS_CC) + 1900; //tm_year is years since 1900 + //Month in ICU and PHP starts from January =0 + month = internal_get_arr_ele( mfo , hash_arr , CALENDAR_MON TSRMLS_CC); + hour = internal_get_arr_ele( mfo , hash_arr , CALENDAR_HOUR TSRMLS_CC); + minute = internal_get_arr_ele( mfo , hash_arr , CALENDAR_MIN TSRMLS_CC); + second = internal_get_arr_ele( mfo , hash_arr , CALENDAR_SEC TSRMLS_CC); + wday = internal_get_arr_ele( mfo , hash_arr , CALENDAR_WDAY TSRMLS_CC); + yday = internal_get_arr_ele( mfo , hash_arr , CALENDAR_YDAY TSRMLS_CC); + isInDST = internal_get_arr_ele( mfo , hash_arr , CALENDAR_ISDST TSRMLS_CC); + //For the ucal_setDateTime() function , this is the 'date' value + mday = internal_get_arr_ele( mfo , hash_arr , CALENDAR_MDAY TSRMLS_CC); + + //set the incoming values for the calendar + ucal_setDateTime( pcal, year, month , mday , hour , minute , second , &INTL_DATA_ERROR_CODE(mfo)); + if( INTL_DATA_ERROR_CODE(mfo) != U_ZERO_ERROR){ + return; + } + //ICU UCAL_DAY_OF_WEEK starts from SUNDAY=1 thru SATURDAY=7 + //whereas PHP localtime has tm_wday SUNDAY=0 thru SATURDAY=6 + ucal_set( pcal, UCAL_DAY_OF_WEEK , (wday+1)); + ucal_set( pcal, UCAL_DAY_OF_YEAR , yday); + + //TO DO :How to set the isInDST field?Is it required to set +} + + +/* {{{ proto string IntlDateFormatter::format( [mixed]int $args or array $args ) + * Format the time value as a string. }}}*/ +/* {{{ proto string datefmt_format( [mixed]int $args or array $args ) + * Format the time value as a string. }}}*/ +PHP_FUNCTION(datefmt_format) +{ + UDate timestamp =0; + UDate p_timestamp =0; + UCalendar* temp_cal ; + HashTable* hash_arr = NULL; + zval* zarg = NULL; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &object, IntlDateFormatter_ce_ptr ,&zarg ) == FAILURE ) + { + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + + switch(Z_TYPE_P(zarg) ){ + case IS_LONG: + p_timestamp = Z_LVAL_P(zarg) ; + timestamp = p_timestamp * 1000; + break; + case IS_DOUBLE: + //timestamp*1000 since ICU expects it in milliseconds + p_timestamp = Z_DVAL_P(zarg) ; + timestamp = p_timestamp * 1000; + break; + case IS_ARRAY: + hash_arr = Z_ARRVAL_P(zarg); + if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) + RETURN_FALSE; + //Create a UCalendar object from the array and then format it + temp_cal = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &INTL_DATA_ERROR_CODE(mfo)); + ucal_clear(temp_cal); + INTL_METHOD_CHECK_STATUS( mfo, "datefmt_format: Date formatting failed while creating calendar from the array" ) + internal_create_ucal( mfo , hash_arr , temp_cal TSRMLS_CC); + INTL_METHOD_CHECK_STATUS( mfo, "datefmt_format: Date formatting failed while creating calendar from the array" ) + //Fetch the timestamp from the created UCalendar + timestamp = ucal_getMillis(temp_cal , &INTL_DATA_ERROR_CODE(mfo) ); + INTL_METHOD_CHECK_STATUS( mfo, "datefmt_format: Date formatting failed" ) + break; +/* + case IS_OBJECT: + break; +*/ + default: + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_format: takes either an array or an integer TimeStamp value ", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + internal_format( mfo, timestamp ,return_value TSRMLS_CC); + +} + +/* }}} */ + diff --git a/ext/intl/dateformat/dateformat_format.h b/ext/intl/dateformat/dateformat_format.h new file mode 100755 index 0000000000..49f34c6892 --- /dev/null +++ b/ext/intl/dateformat/dateformat_format.h @@ -0,0 +1,24 @@ +/* + +----------------------------------------------------------------------+ + | 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: Stanislav Malyshev | + +----------------------------------------------------------------------+ + */ + +#ifndef DATE_FORMAT_FORMAT_H +#define DATE_FORMAT_FORMAT_H + +#include + +PHP_FUNCTION( datefmt_format ); + +#endif // DATE_FORMAT_FORMAT_H diff --git a/ext/intl/dateformat/dateformat_parse.c b/ext/intl/dateformat/dateformat_parse.c new file mode 100755 index 0000000000..a27171bfa7 --- /dev/null +++ b/ext/intl/dateformat/dateformat_parse.c @@ -0,0 +1,181 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "php_intl.h" +#include "intl_convert.h" +#include "dateformat.h" +#include "dateformat_class.h" +#include "dateformat_parse.h" +#include "dateformat_data.h" + +/* {{{ + * Internal function which calls the udat_parse + * param int store_error acts like a boolean + * if set to 1 - store any error encountered in the parameter parse_error + * if set to 0 - no need to store any error encountered in the parameter parse_error +*/ +static void internal_parse_to_timestamp(IntlDateFormatter_object *mfo, char* text_to_parse , int32_t text_len, int parse_pos , zval *return_value TSRMLS_DC){ + long result = 0; + UDate timestamp =0; + UChar* text_utf16 = NULL; + int32_t text_utf16_len = 0; + + // Convert timezone to UTF-16. + intl_convert_utf8_to_utf16(&text_utf16 , &text_utf16_len , text_to_parse , text_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting timezone to UTF-16" ); + + timestamp = udat_parse( DATE_FORMAT_OBJECT(mfo), text_utf16 , text_utf16_len , &parse_pos , &INTL_DATA_ERROR_CODE(mfo)); + if( text_utf16 ){ + efree(text_utf16); + } + + INTL_METHOD_CHECK_STATUS( mfo, "Date parsing failed" ); + + //Since return is in sec. + result = (long )( timestamp / 1000 ); + if( result != (timestamp/1000) ) { + intl_error_set( NULL, U_BUFFER_OVERFLOW_ERROR, + "datefmt_parse: parsing of input parametrs resulted in value larger than data type long can handle.\nThe valid range of a timestamp is typically from Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT.", 0 TSRMLS_CC ); + } + RETURN_LONG( result ); +} +/* }}} */ + +static void add_to_localtime_arr( IntlDateFormatter_object *mfo, zval* return_value ,UCalendar parsed_calendar , long calendar_field , char* key_name TSRMLS_DC){ + long calendar_field_val = ucal_get( parsed_calendar , calendar_field , &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS( mfo, "Date parsing - localtime failed : could not get a field from calendar" ); + + if( strcmp(key_name , CALENDAR_YEAR )==0 ){ + //since tm_year is years from 1900 + add_assoc_long( return_value, key_name ,( calendar_field_val-1900) ); + }else if( strcmp(key_name , CALENDAR_WDAY )==0 ){ + //since tm_wday starts from 0 whereas ICU WDAY start from 1 + add_assoc_long( return_value, key_name ,( calendar_field_val-1) ); + }else{ + add_assoc_long( return_value, key_name , calendar_field_val ); + } +} + +/* {{{ + * Internal function which calls the udat_parseCalendar +*/ +static void internal_parse_to_localtime(IntlDateFormatter_object *mfo, char* text_to_parse , int32_t text_len, int parse_pos , zval *return_value TSRMLS_DC){ + UCalendar* parsed_calendar = NULL ; + UChar* text_utf16 = NULL; + int32_t text_utf16_len = 0; + long isInDST = 0; + + // Convert timezone to UTF-16. + intl_convert_utf8_to_utf16(&text_utf16 , &text_utf16_len , text_to_parse , text_len, &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS(mfo, "Error converting timezone to UTF-16" ); + + parsed_calendar = ucal_open(NULL, -1, NULL, UCAL_GREGORIAN, &INTL_DATA_ERROR_CODE(mfo)); + udat_parseCalendar( DATE_FORMAT_OBJECT(mfo), parsed_calendar , text_utf16 , text_utf16_len , &parse_pos , &INTL_DATA_ERROR_CODE(mfo)); + if( text_utf16 ){ + efree(text_utf16); + } + + INTL_METHOD_CHECK_STATUS( mfo, "Date parsing failed" ); + + + array_init( return_value ); + //Add entries from various fields of the obtained parsed_calendar + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_SECOND , CALENDAR_SEC TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_MINUTE , CALENDAR_MIN TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_HOUR_OF_DAY , CALENDAR_HOUR TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_YEAR , CALENDAR_YEAR TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_DAY_OF_MONTH , CALENDAR_MDAY TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_DAY_OF_WEEK , CALENDAR_WDAY TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_DAY_OF_YEAR , CALENDAR_YDAY TSRMLS_CC); + add_to_localtime_arr( mfo , return_value , parsed_calendar , UCAL_MONTH , CALENDAR_MON TSRMLS_CC); + + //Is in DST? + isInDST = ucal_inDaylightTime(parsed_calendar , &INTL_DATA_ERROR_CODE(mfo)); + INTL_METHOD_CHECK_STATUS( mfo, "Date parsing - localtime failed : while checking if currently in DST." ); + add_assoc_long( return_value, CALENDAR_ISDST ,(isInDST==1?1:0)); +} +/* }}} */ + + +/* {{{ proto integer IntlDateFormatter::parse( string $text_to_parse , int $parse_pos ) + * Parse the string $value starting at parse_pos to a Unix timestamp -int }}}*/ +/* {{{ proto integer datefmt_parse( IntlDateFormatter $fmt, string $text_to_parse , int $parse_pos ) + * Parse the string $value starting at parse_pos to a Unix timestamp -int }}}*/ +PHP_FUNCTION(datefmt_parse) +{ + + char* text_to_parse = NULL; + int32_t text_len =0; + long parse_pos =0; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", + &object, IntlDateFormatter_ce_ptr, &text_to_parse , &text_len , &parse_pos ) == FAILURE ){ + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_parse: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + internal_parse_to_timestamp( mfo, text_to_parse , text_len , + parse_pos , + return_value TSRMLS_CC); + +} +/* }}} */ + +/* {{{ proto integer IntlDateFormatter::localtime( string $text_to_parse, int $parse_pos )) + * Parse the string $value to a localtime array }}}*/ +/* {{{ proto integer datefmt_localtime( IntlDateFormatter $fmt, string $text_to_parse, int $parse_pos )) + * Parse the string $value to a localtime array }}}*/ +PHP_FUNCTION(datefmt_localtime) +{ + + char* text_to_parse = NULL; + int32_t text_len =0; + long parse_pos =0; + + DATE_FORMAT_METHOD_INIT_VARS; + + // Parse parameters. + if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osl", + &object, IntlDateFormatter_ce_ptr, &text_to_parse , &text_len , &parse_pos ) == FAILURE ){ + + intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, + "datefmt_parse_to_localtime: unable to parse input params", 0 TSRMLS_CC ); + RETURN_FALSE; + } + + // Fetch the object. + DATE_FORMAT_METHOD_FETCH_OBJECT; + + internal_parse_to_localtime( mfo, text_to_parse , text_len , + parse_pos, + return_value TSRMLS_CC); + +} +/* }}} */ + diff --git a/ext/intl/dateformat/dateformat_parse.h b/ext/intl/dateformat/dateformat_parse.h new file mode 100755 index 0000000000..c74a3d5f15 --- /dev/null +++ b/ext/intl/dateformat/dateformat_parse.h @@ -0,0 +1,24 @@ +/* + +----------------------------------------------------------------------+ + | 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: Kirti Velankar | + +----------------------------------------------------------------------+ +*/ +#ifndef DATE_FORMAT_PARSE_H +#define DATE_FORMAT_PARSE_H + +#include + +PHP_FUNCTION( datefmt_parse ); +PHP_FUNCTION( datefmt_localtime ); + +#endif // DATE_FORMAT_PARSE_H diff --git a/ext/intl/doc/Tutorial.txt b/ext/intl/doc/Tutorial.txt new file mode 100755 index 0000000000..4a66dc1844 --- /dev/null +++ b/ext/intl/doc/Tutorial.txt @@ -0,0 +1,239 @@ +1. Collator::getAvailableLocales(). +Return the locales available at the time of the call, including registered locales. +If a sever error occurs (such as out of memory condition) this will return null. +If there is no locale data, an empty enumeration will be returned. +Returned locales list is a strings in format of RFC4646 standart (see http://www.rfc-editor.org/rfc/rfc4646.txt). +Examle of locales format: 'en_US', 'ru_UA', 'ua_UA' (see http://demo.icu-project.org/icu-bin/locexp). + + +2. Collator::getDisplayName( $obj_locale, $disp_locale ). +Get name of the object for the desired Locale, in the desired langauge. Both arguments +must be from getAvailableLocales method. + + @param string $obj_locale Locale to get display name for. + @param string $disp_locale Specifies the desired locale for output + +Both parameters are case insensitive. +For locale format see RFC4647 standart in ftp://ftp.rfc-editor.org/in-notes/rfc4647.txt + +3. Collator::getLocaleByType( $type ). +Allow user to select whether she wants information on requested, valid or actual locale. +Returned locale tag is a string formatted to a RFC4646 standart and normalize to normal form - +value is a string from +For example, a collator for "en_US_CALIFORNIA" was requested. In the current state of ICU (2.0), +the requested locale is "en_US_CALIFORNIA", the valid locale is "en_US" (most specific locale +supported by ICU) and the actual locale is "root" (the collation data comes unmodified from the UCA) +The locale is considered supported by ICU if there is a core ICU bundle for that locale (although +it may be empty). + + +4. VariableTop +The Variable_Top attribute is only meaningful if the Alternate attribute is not set to NonIgnorable. +In such a case, it controls which characters count as ignorable. The string value specifies +the "highest" character (in UCA order) weight that is to be considered ignorable. +Thus, for example, if a user wanted whitespace to be ignorable, but not any visible characters, +then s/he would use the value Variable_Top="\u0020" (space). The string should only be a +single character. All characters of the same primary weight are equivalent, so +Variable_Top="\u3000" (ideographic space) has the same effect as Variable_Top="\u0020". +This setting (alone) has little impact on string comparison performance; setting it lower or higher +will make sort keys slightly shorter or longer respectively. + + +5. Strength +The ICU Collation Service supports many levels of comparison (named "Levels", but also +known as "Strengths"). Having these categories enables ICU to sort strings precisely +according to local conventions. However, by allowing the levels to be selectively +employed, searching for a string in text can be performed with various matching +conditions. +Performance optimizations have been made for ICU collation with the default level +settings. Performance specific impacts are discussed in the Performance section below. +Following is a list of the names for each level and an example usage: + +1. Primary Level: Typically, this is used to denote differences between base characters +(for example, "a" < "b"). It is the strongest difference. For example, dictionaries are +divided into different sections by base character. This is also called the level1 +strength. + +2. Secondary Level: Accents in the characters are considered secondary differences (for +example, "as" < "as" < "at"). Other differences between letters can also be considered +secondary differences, depending on the language. A secondary difference is ignored +when there is a primary difference anywhere in the strings. This is also called the +level2 strength. +Note: In some languages (such as Danish), certain accented letters are considered to +be separate base characters. In most languages, however, an accented letter only has a +secondary difference from the unaccented version of that letter. + +3. Tertiary Level: Upper and lower case differences in characters are distinguished at the +tertiary level (for example, "ao" < "Ao" < "ao"). In addition, a variant of a letter differs +from the base form on the tertiary level (such as "A" and " "). Another ? example is the +difference between large and small Kana. A tertiary difference is ignored when there is +a primary or secondary difference anywhere in the strings. This is also called the level3 +strength. + +4. Quaternary Level: When punctuation is ignored (see Ignoring Punctuations ) at level +13, an additional level can be used to distinguish words with and without punctuation +(for example, "ab" < "a-b" < "aB"). This difference is ignored when there is a primary, +secondary or tertiary difference. This is also known as the level4 strength. The +quaternary level should only be used if ignoring punctuation is required or when +processing Japanese text (see Hiragana processing). + +5. Identical Level: When all other levels are equal, the identical level is used as a +tiebreaker. The Unicode code point values of the NFD form of each string are +compared at this level, just in case there is no difference at levels 14 +. For example, Hebrew cantillation marks are only distinguished at this level. This level should be +used sparingly, as only code point values differences between two strings is an +extremely rare occurrence. Using this level substantially decreases the performance for +both incremental comparison and sort key generation (as well as increasing the sort +key length). It is also known as level 5 strength. + +For example, people may choose to ignore accents or ignore accents and case when searching +for text. Almost all characters are distinguished by the first three levels, and in most +locales the default value is thus Tertiary. However, if Alternate is set to be Shifted, +then the Quaternary strength can be used to break ties among whitespace, punctuation, and +symbols that would otherwise be ignored. If very fine distinctions among characters are required, +then the Identical strength can be used (for example, Identical Strength distinguishes +between the Mathematical Bold Small A and the Mathematical Italic Small A.). However, using +levels higher than Tertiary the Identical strength result in significantly longer sort +keys, and slower string comparison performance for equal strings. + + + +6. Collator::__construct( $locale ). +The Locale attribute is typically the most important attribute for correct sorting and matching, +according to the user expectations in different countries and regions. The default UCA +ordering will only sort a few languages such as Dutch and Portuguese correctly ("correctly" +meaning according to the normal expectations for users of the languages). +Otherwise, you need to supply the locale to UCA in order to properly collate text for a +given language. Thus a locale needs to be supplied so as to choose a collator that is correctly +tailored for that locale. The choice of a locale will automatically preset the values for +all of the attributes to something that is reasonable for that locale. Thus most of the time the +other attributes do not need to be explicitly set. In some cases, the choice of locale will make a +difference in string comparison performance and/or sort key length. +In short attribute names, _