Merge intl extension into core

This commit is contained in:
Stanislav Malyshev 2008-07-07 22:51:04 +00:00
parent 3bab7c18ac
commit 0d16b1516b
158 changed files with 23151 additions and 0 deletions

2
ext/intl/CREDITS Executable file
View File

@ -0,0 +1,2 @@
Internationalization
Ed Batutis, Vladimir Iordanov, Dmitry Lakhtyuk, Stanislav Malyshev, Vadim Savchuk, Kirti Velankar

5
ext/intl/TODO Executable file
View File

@ -0,0 +1,5 @@
- Document U_* error constants
- For IntlDateFormatter
-- Accept and produce DateTime objects in 5.3 and 6
-- Create convertor from ICU pattern to PHP pattern

96
ext/intl/collator/collator.c Executable file
View File

@ -0,0 +1,96 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "collator_class.h"
#include "collator.h"
#include <unicode/utypes.h>
#include <unicode/ucol.h>
#include <unicode/ustring.h>
/* {{{ collator_register_constants
* Register constants common for the both (OO and procedural)
* APIs.
*/
void collator_register_constants( INIT_FUNC_ARGS )
{
if( !Collator_ce_ptr )
{
zend_error( E_ERROR, "Collator class not defined" );
return;
}
#define COLLATOR_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS)
#define COLLATOR_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( Collator_ce_ptr, ZEND_STRS( #x ) - 1, UCOL_##x TSRMLS_CC );
#define COLLATOR_EXPOSE_CUSTOM_CLASS_CONST(name, value) zend_declare_class_constant_long( Collator_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );
// UColAttributeValue constants
COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "DEFAULT_VALUE", UCOL_DEFAULT );
COLLATOR_EXPOSE_CLASS_CONST( PRIMARY );
COLLATOR_EXPOSE_CLASS_CONST( SECONDARY );
COLLATOR_EXPOSE_CLASS_CONST( TERTIARY );
COLLATOR_EXPOSE_CLASS_CONST( DEFAULT_STRENGTH );
COLLATOR_EXPOSE_CLASS_CONST( QUATERNARY );
COLLATOR_EXPOSE_CLASS_CONST( IDENTICAL );
COLLATOR_EXPOSE_CLASS_CONST( OFF );
COLLATOR_EXPOSE_CLASS_CONST( ON );
COLLATOR_EXPOSE_CLASS_CONST( SHIFTED );
COLLATOR_EXPOSE_CLASS_CONST( NON_IGNORABLE );
COLLATOR_EXPOSE_CLASS_CONST( LOWER_FIRST );
COLLATOR_EXPOSE_CLASS_CONST( UPPER_FIRST );
// UColAttribute constants
COLLATOR_EXPOSE_CLASS_CONST( FRENCH_COLLATION );
COLLATOR_EXPOSE_CLASS_CONST( ALTERNATE_HANDLING );
COLLATOR_EXPOSE_CLASS_CONST( CASE_FIRST );
COLLATOR_EXPOSE_CLASS_CONST( CASE_LEVEL );
COLLATOR_EXPOSE_CLASS_CONST( NORMALIZATION_MODE );
COLLATOR_EXPOSE_CLASS_CONST( STRENGTH );
COLLATOR_EXPOSE_CLASS_CONST( HIRAGANA_QUATERNARY_MODE );
COLLATOR_EXPOSE_CLASS_CONST( NUMERIC_COLLATION );
// ULocDataLocaleType constants
COLLATOR_EXPOSE_CONST( ULOC_ACTUAL_LOCALE );
COLLATOR_EXPOSE_CONST( ULOC_VALID_LOCALE );
// sort flags
COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "SORT_REGULAR", COLLATOR_SORT_REGULAR );
COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "SORT_STRING", COLLATOR_SORT_STRING );
COLLATOR_EXPOSE_CUSTOM_CLASS_CONST( "SORT_NUMERIC", COLLATOR_SORT_NUMERIC );
#undef COLLATOR_EXPOSE_CUSTOM_CLASS_CONST
#undef COLLATOR_EXPOSE_CLASS_CONST
#undef COLLATOR_EXPOSE_CONST
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

29
ext/intl/collator/collator.h Executable file
View File

@ -0,0 +1,29 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_COLLATOR_H
#define CCOLLATOR_COLLATOR_H
#include <php.h>
#define COLLATOR_SORT_REGULAR 0
#define COLLATOR_SORT_STRING 1
#define COLLATOR_SORT_NUMERIC 2
void collator_register_constants( INIT_FUNC_ARGS );
#endif // COLLATOR_COLLATOR_H

157
ext/intl/collator/collator_attr.c Executable file
View File

@ -0,0 +1,157 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator_class.h"
#include "collator_convert.h"
#include "collator_attr.h"
#include <unicode/ustring.h>
/* {{{ proto int Collator::getAttribute( int $attr )
* Get collation attribute value. }}} */
/* {{{ proto int collator_get_attribute( Collator $coll, int $attr )
* Get collation attribute value.
*/
PHP_FUNCTION( collator_get_attribute )
{
long attribute, value;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
&object, Collator_ce_ptr, &attribute ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_get_attribute: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
value = ucol_getAttribute( co->ucoll, attribute, COLLATOR_ERROR_CODE_P( co ) );
COLLATOR_CHECK_STATUS( co, "Error getting attribute value" );
RETURN_LONG( value );
}
/* }}} */
/* {{{ proto bool Collator::getAttribute( int $attr )
* Get collation attribute value. }}} */
/* {{{ proto bool collator_set_attribute( Collator $coll, int $attr, int $val )
* Set collation attribute.
*/
PHP_FUNCTION( collator_set_attribute )
{
long attribute, value;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll",
&object, Collator_ce_ptr, &attribute, &value ) == FAILURE)
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_set_attribute: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
// Set new value for the given attribute.
ucol_setAttribute( co->ucoll, attribute, value, COLLATOR_ERROR_CODE_P( co ) );
COLLATOR_CHECK_STATUS( co, "Error setting attribute value" );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto int Collator::getStrength()
* Returns the current collation strength. }}} */
/* {{{ proto int collator_get_strength(Collator coll)
* Returns the current collation strength.
*/
PHP_FUNCTION( collator_get_strength )
{
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, Collator_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_get_strength: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
// Get current strength and return it.
RETURN_LONG( ucol_getStrength( co->ucoll ) );
}
/* }}} */
/* {{{ proto bool Collator::setStrength(int strength)
* Set the collation strength. }}} */
/* {{{ proto bool collator_set_strength(Collator coll, int strength)
* Set the collation strength.
*/
PHP_FUNCTION( collator_set_strength )
{
long strength;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
&object, Collator_ce_ptr, &strength ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_set_strength: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
// Set given strength.
ucol_setStrength( co->ucoll, strength );
RETURN_TRUE;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,28 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_ATTR_H
#define CCOLLATOR_ATTR_H
#include <php.h>
PHP_FUNCTION( collator_get_attribute );
PHP_FUNCTION( collator_set_attribute );
PHP_FUNCTION( collator_get_strength );
PHP_FUNCTION( collator_set_strength );
#endif // COLLATOR_ATTR_H

View File

@ -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 <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#include "collator_class.h"
#include "php_intl.h"
#include "collator_attr.h"
#include "collator_compare.h"
#include "collator_sort.h"
#include "collator_convert.h"
#include "collator_locale.h"
#include "collator_create.h"
#include "collator_error.h"
#include "intl_error.h"
#include <unicode/ucol.h>
zend_class_entry *Collator_ce_ptr = NULL;
/////////////////////////////////////////////////////////////////////////////
// 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
*/

View File

@ -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 <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_CLASS_H
#define COLLATOR_CLASS_H
#include <php.h>
#include "intl_common.h"
#include "intl_error.h"
#include <unicode/ucol.h>
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

View File

@ -0,0 +1,119 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator_class.h"
#include "collator_compare.h"
#include "intl_convert.h"
/* {{{ proto int Collator::compare( string $str1, string $str2 )
* Compare two strings. }}} */
/* {{{ proto int collator_compare( Collator $coll, string $str1, string $str2 )
* Compare two strings.
*/
PHP_FUNCTION( collator_compare )
{
char* str1 = NULL;
char* str2 = NULL;
int str1_len = 0;
int str2_len = 0;
UChar* ustr1 = NULL;
UChar* ustr2 = NULL;
int ustr1_len = 0;
int ustr2_len = 0;
UCollationResult result;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oss",
&object, Collator_ce_ptr, &str1, &str1_len, &str2, &str2_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_compare: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
/*
* Compare given strings (converting them to UTF-16 first).
*/
// First convert the strings to UTF-16.
intl_convert_utf8_to_utf16(
&ustr1, &ustr1_len, str1, str1_len, COLLATOR_ERROR_CODE_P( co ) );
if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
{
// Set global error code.
intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
// Set error messages.
intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
"Error converting first argument to UTF-16", 0 TSRMLS_CC );
efree( ustr1 );
RETURN_FALSE;
}
intl_convert_utf8_to_utf16(
&ustr2, &ustr2_len, str2, str2_len, COLLATOR_ERROR_CODE_P( co ) );
if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
{
// Set global error code.
intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
// Set error messages.
intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
"Error converting second argument to UTF-16", 0 TSRMLS_CC );
efree( ustr1 );
efree( ustr2 );
RETURN_FALSE;
}
// Then compare them.
result = ucol_strcoll(
co->ucoll,
ustr1, ustr1_len,
ustr2, ustr2_len );
if( ustr1 )
efree( ustr1 );
if( ustr2 )
efree( ustr2 );
// Return result of the comparison.
RETURN_LONG( result );
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,25 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_COMPARE_H
#define COLLATOR_COMPARE_H
#include <php.h>
PHP_FUNCTION( collator_compare );
#endif // COLLATOR_COMPARE_H

View File

@ -0,0 +1,482 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator_class.h"
#include "collator_is_numeric.h"
#include "collator_convert.h"
#include "intl_convert.h"
#include <unicode/ustring.h>
#include <php.h>
#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1)
#define CAST_OBJECT_SHOULD_FREE ,0
#else
#define CAST_OBJECT_SHOULD_FREE
#endif
#define COLLATOR_CONVERT_RETURN_FAILED(retval) { \
zval_add_ref( &retval ); \
return retval; \
}
/* {{{ collator_convert_hash_item_from_utf8_to_utf16 */
static void collator_convert_hash_item_from_utf8_to_utf16(
HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex,
UErrorCode* status )
{
const char* old_val;
int old_val_len;
UChar* new_val = NULL;
int new_val_len = 0;
zval** hashData = NULL;
zval* znew_val = NULL;
// Get current hash item.
zend_hash_get_current_data( hash, (void**) &hashData );
// Process string values only.
if( Z_TYPE_P( *hashData ) != IS_STRING )
return;
old_val = Z_STRVAL_P( *hashData );
old_val_len = Z_STRLEN_P( *hashData );
// Convert it from UTF-8 to UTF-16LE and save the result to new_val[_len].
intl_convert_utf8_to_utf16( &new_val, &new_val_len, old_val, old_val_len, status );
if( U_FAILURE( *status ) )
return;
// Update current hash item with the converted value.
MAKE_STD_ZVAL( znew_val );
ZVAL_STRINGL( znew_val, (char*)new_val, UBYTES(new_val_len), FALSE );
if( hashKeyType == HASH_KEY_IS_STRING )
{
zend_hash_update( hash, hashKey, strlen( hashKey ) + 1,
(void*) &znew_val, sizeof(zval*), NULL );
}
else // hashKeyType == HASH_KEY_IS_LONG
{
zend_hash_index_update( hash, hashIndex,
(void*) &znew_val, sizeof(zval*), NULL );
}
}
/* }}} */
/* {{{ collator_convert_hash_item_from_utf16_to_utf8 */
static void collator_convert_hash_item_from_utf16_to_utf8(
HashTable* hash, int hashKeyType, char* hashKey, ulong hashIndex,
UErrorCode* status )
{
const char* old_val;
int old_val_len;
char* new_val = NULL;
int new_val_len = 0;
zval** hashData = NULL;
zval* znew_val = NULL;
// Get current hash item.
zend_hash_get_current_data( hash, (void**) &hashData );
// Process string values only.
if( Z_TYPE_P( *hashData ) != IS_STRING )
return;
old_val = Z_STRVAL_P( *hashData );
old_val_len = Z_STRLEN_P( *hashData );
// Convert it from UTF-16LE to UTF-8 and save the result to new_val[_len].
intl_convert_utf16_to_utf8( &new_val, &new_val_len,
(UChar*)old_val, UCHARS(old_val_len), status );
if( U_FAILURE( *status ) )
return;
// Update current hash item with the converted value.
MAKE_STD_ZVAL( znew_val );
ZVAL_STRINGL( znew_val, (char*)new_val, new_val_len, FALSE );
if( hashKeyType == HASH_KEY_IS_STRING )
{
zend_hash_update( hash, hashKey, strlen( hashKey ) + 1,
(void*) &znew_val, sizeof(zval*), NULL );
}
else // hashKeyType == HASH_KEY_IS_LONG
{
zend_hash_index_update( hash, hashIndex,
(void*) &znew_val, sizeof(zval*), NULL );
}
}
/* }}} */
/* {{{ collator_convert_hash_from_utf8_to_utf16
* Convert values of the given hash from UTF-8 encoding to UTF-16LE.
*/
void collator_convert_hash_from_utf8_to_utf16( HashTable* hash, UErrorCode* status )
{
ulong hashIndex = 0;
char* hashKey = NULL;
int hashKeyType = 0;
zend_hash_internal_pointer_reset( hash );
while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) )
!= HASH_KEY_NON_EXISTANT )
{
// Convert current hash item from UTF-8 to UTF-16LE.
collator_convert_hash_item_from_utf8_to_utf16(
hash, hashKeyType, hashKey, hashIndex, status );
if( U_FAILURE( *status ) )
return;
// Proceed to the next item.
zend_hash_move_forward( hash );
}
}
/* }}} */
/* {{{ collator_convert_hash_from_utf16_to_utf8
* Convert values of the given hash from UTF-16LE encoding to UTF-8.
*/
void collator_convert_hash_from_utf16_to_utf8( HashTable* hash, UErrorCode* status )
{
ulong hashIndex = 0;
char* hashKey = NULL;
int hashKeyType = 0;
zend_hash_internal_pointer_reset( hash );
while( ( hashKeyType = zend_hash_get_current_key( hash, &hashKey, &hashIndex, 0 ) )
!= HASH_KEY_NON_EXISTANT )
{
// Convert current hash item from UTF-16LE to UTF-8.
collator_convert_hash_item_from_utf16_to_utf8(
hash, hashKeyType, hashKey, hashIndex, status );
if( U_FAILURE( *status ) )
return;
// Proceed to the next item.
zend_hash_move_forward( hash );
}
}
/* }}} */
/* {{{ collator_convert_zstr_utf16_to_utf8
*
* Convert string from utf16 to utf8.
*
* @param zval* utf16_zval String to convert.
*
* @return zval* Converted string.
*/
zval* collator_convert_zstr_utf16_to_utf8( zval* utf16_zval )
{
zval* utf8_zval = NULL;
char* str = NULL;
int str_len = 0;
UErrorCode status = U_ZERO_ERROR;
// Convert to utf8 then.
intl_convert_utf16_to_utf8( &str, &str_len,
(UChar*) Z_STRVAL_P(utf16_zval), UCHARS( Z_STRLEN_P(utf16_zval) ), &status );
if( U_FAILURE( status ) )
php_error( E_WARNING, "Error converting utf16 to utf8 in collator_convert_zval_utf16_to_utf8()" );
ALLOC_INIT_ZVAL( utf8_zval );
ZVAL_STRINGL( utf8_zval, str, str_len, FALSE );
return utf8_zval;
}
/* }}} */
/* {{{ collator_convert_zstr_utf8_to_utf16
*
* Convert string from utf8 to utf16.
*
* @param zval* utf8_zval String to convert.
*
* @return zval* Converted string.
*/
zval* collator_convert_zstr_utf8_to_utf16( zval* utf8_zval )
{
zval* zstr = NULL;
UChar* ustr = NULL;
int ustr_len = 0;
UErrorCode status = U_ZERO_ERROR;
// Convert the string to UTF-16.
intl_convert_utf8_to_utf16(
&ustr, &ustr_len,
Z_STRVAL_P( utf8_zval ), Z_STRLEN_P( utf8_zval ),
&status );
if( U_FAILURE( status ) )
php_error( E_WARNING, "Error casting object to string in collator_convert_zstr_utf8_to_utf16()" );
// Set string.
ALLOC_INIT_ZVAL( zstr );
ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE );
return zstr;
}
/* }}} */
/* {{{ collator_convert_object_to_string
* Convert object to UTF16-encoded string.
*/
zval* collator_convert_object_to_string( zval* obj TSRMLS_DC )
{
zval* zstr = NULL;
UErrorCode status = U_ZERO_ERROR;
UChar* ustr = NULL;
int ustr_len = 0;
// Bail out if it's not an object.
if( Z_TYPE_P( obj ) != IS_OBJECT )
{
COLLATOR_CONVERT_RETURN_FAILED( obj );
}
// Try object's handlers.
if( Z_OBJ_HT_P(obj)->get )
{
zstr = Z_OBJ_HT_P(obj)->get( obj TSRMLS_CC );
switch( Z_TYPE_P( zstr ) )
{
case IS_OBJECT:
{
// Bail out.
zval_ptr_dtor( &zstr );
COLLATOR_CONVERT_RETURN_FAILED( obj );
} break;
case IS_STRING:
break;
default:
{
convert_to_string( zstr );
} break;
}
}
else if( Z_OBJ_HT_P(obj)->cast_object )
{
ALLOC_INIT_ZVAL( zstr );
if( Z_OBJ_HT_P(obj)->cast_object( obj, zstr, IS_STRING CAST_OBJECT_SHOULD_FREE TSRMLS_CC ) == FAILURE )
{
// cast_object failed => bail out.
zval_ptr_dtor( &zstr );
COLLATOR_CONVERT_RETURN_FAILED( obj );
}
}
// Object wasn't successfuly converted => bail out.
if( zstr == NULL )
{
COLLATOR_CONVERT_RETURN_FAILED( obj );
}
// Convert the string to UTF-16.
intl_convert_utf8_to_utf16(
&ustr, &ustr_len,
Z_STRVAL_P( zstr ), Z_STRLEN_P( zstr ),
&status );
if( U_FAILURE( status ) )
php_error( E_WARNING, "Error casting object to string in collator_convert_object_to_string()" );
// Cleanup zstr to hold utf16 string.
zval_dtor( zstr );
// Set string.
ZVAL_STRINGL( zstr, (char*)ustr, UBYTES(ustr_len), FALSE );
// Don't free ustr cause it's set in zstr without copy.
// efree( ustr );
return zstr;
}
/* }}} */
/* {{{ collator_convert_string_to_number
*
* Convert string to number.
*
* @param zval* str String to convert.
*
* @return zval* Number. If str is not numeric string return number zero.
*/
zval* collator_convert_string_to_number( zval* str )
{
zval* num = collator_convert_string_to_number_if_possible( str );
if( num == str )
{
// String wasn't converted => return zero.
zval_ptr_dtor( &num );
ALLOC_INIT_ZVAL( num );
ZVAL_LONG( num, 0 );
}
return num;
}
/* }}} */
/* {{{ collator_convert_string_to_double
*
* Convert string to double.
*
* @param zval* str String to convert.
*
* @return zval* Number. If str is not numeric string return number zero.
*/
zval* collator_convert_string_to_double( zval* str )
{
zval* num = collator_convert_string_to_number( str );
if( Z_TYPE_P(num) == IS_LONG )
{
ZVAL_DOUBLE( num, Z_LVAL_P( num ) );
}
return num;
}
/* }}} */
/* {{{ collator_convert_string_to_number_if_possible
*
* Convert string to numer.
*
* @param zval* str String to convert.
*
* @return zval* Number if str is numeric string. Otherwise
* original str param.
*/
zval* collator_convert_string_to_number_if_possible( zval* str )
{
zval* num = NULL;
int is_numeric = 0;
long lval = 0;
double dval = 0;
if( Z_TYPE_P( str ) != IS_STRING )
{
COLLATOR_CONVERT_RETURN_FAILED( str );
}
if( ( is_numeric = collator_is_numeric( (UChar*) Z_STRVAL_P(str), UCHARS( Z_STRLEN_P(str) ), &lval, &dval, 1 ) ) )
{
ALLOC_INIT_ZVAL( num );
if( is_numeric == IS_LONG )
Z_LVAL_P(num) = lval;
if( is_numeric == IS_DOUBLE )
Z_DVAL_P(num) = dval;
Z_TYPE_P(num) = is_numeric;
}
else
{
COLLATOR_CONVERT_RETURN_FAILED( str );
}
return num;
}
/* }}} */
/* {{{ collator_make_printable_zval
*
* Returns string from input zval.
*
* @param zval* arg zval to get string from
*
* @return zval* UTF16 string.
*/
zval* collator_make_printable_zval( zval* arg )
{
zval arg_copy;
int use_copy = 0;
zval* str = NULL;
if( Z_TYPE_P(arg) != IS_STRING )
{
zend_make_printable_zval(arg, &arg_copy, &use_copy);
if( use_copy )
{
str = collator_convert_zstr_utf8_to_utf16( &arg_copy );
zval_dtor( &arg_copy );
}
else
{
str = collator_convert_zstr_utf8_to_utf16( arg );
}
}
else
{
COLLATOR_CONVERT_RETURN_FAILED( arg );
}
return str;
}
/* }}} */
/* {{{ collator_normalize_sort_argument
*
* Normalize argument to use in sort's compare function.
*
* @param zval* arg Sort's argument to normalize.
*
* @return zval* Normalized copy of arg or unmodified arg
* if normalization is not needed.
*/
zval* collator_normalize_sort_argument( zval* arg )
{
zval* n_arg = NULL;
if( Z_TYPE_P( arg ) != IS_STRING )
{
// If its not a string then nothing to do.
// Return original arg.
COLLATOR_CONVERT_RETURN_FAILED( arg );
}
// Try convert to number.
n_arg = collator_convert_string_to_number_if_possible( arg );
if( n_arg == arg )
{
// Conversion to number failed.
zval_ptr_dtor( &n_arg );
// Convert string to utf8.
n_arg = collator_convert_zstr_utf16_to_utf8( arg );
}
return n_arg;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,38 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_CONVERT_H
#define COLLATOR_CONVERT_H
#include <php.h>
#include <unicode/utypes.h>
void collator_convert_hash_from_utf8_to_utf16( HashTable* hash, UErrorCode* status );
void collator_convert_hash_from_utf16_to_utf8( HashTable* hash, UErrorCode* status );
zval* collator_convert_zstr_utf16_to_utf8( zval* utf16_zval );
zval* collator_convert_zstr_utf8_to_utf16( zval* utf8_zval );
zval* collator_normalize_sort_argument( zval* arg );
zval* collator_convert_object_to_string( zval* obj TSRMLS_DC );
zval* collator_convert_string_to_number( zval* arg );
zval* collator_convert_string_to_number_if_possible( zval* str );
zval* collator_convert_string_to_double( zval* str );
zval* collator_make_printable_zval( zval* arg );
#endif // COLLATOR_CONVERT_H

View File

@ -0,0 +1,135 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator_class.h"
#include "collator_create.h"
#include "intl_data.h"
/* {{{ 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 = INTL_G(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 = INTL_G(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
*/

View File

@ -0,0 +1,27 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_CREATE_H
#define COLLATOR_CREATE_H
#include <php.h>
PHP_FUNCTION( collator_create );
PHP_METHOD( Collator, __construct );
#endif // COLLATOR_CREATE_H

View File

@ -0,0 +1,94 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator_class.h"
#include "collator_error.h"
/* {{{ proto int Collator::getErrorCode( Collator $coll )
* Get collator's last error code. }}} */
/* {{{ proto int collator_get_error_code( Collator $coll )
* Get collator's last error code.
*/
PHP_FUNCTION( collator_get_error_code )
{
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, Collator_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_get_error_code: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object (without resetting its last error code).
co = (Collator_object *) zend_object_store_get_object(object TSRMLS_CC);
if( co == NULL )
RETURN_FALSE;
// Return collator's last error code.
RETURN_LONG( COLLATOR_ERROR_CODE( co ) );
}
/* }}} */
/* {{{ proto string Collator::getErrorMessage( Collator $coll )
* Get text description for collator's last error code. }}} */
/* {{{ proto string collator_get_error_message( Collator $coll )
* Get text description for collator's last error code.
*/
PHP_FUNCTION( collator_get_error_message )
{
const char* message = NULL;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, Collator_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_get_error_message: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object (without resetting its last error code).
co = (Collator_object *) zend_object_store_get_object( object TSRMLS_CC );
if( co == NULL )
RETURN_FALSE;
// Return last error message.
message = intl_error_get_message( COLLATOR_ERROR_P( co ) TSRMLS_CC );
RETURN_STRING( (char*)message, FALSE );
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,26 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_ERROR_H
#define COLLATOR_ERROR_H
#include <php.h>
PHP_FUNCTION( collator_get_error_code );
PHP_FUNCTION( collator_get_error_message );
#endif // COLLATOR_ERROR_H

View File

@ -0,0 +1,305 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#include "collator_is_numeric.h"
#if ZEND_MODULE_API_NO < 20071006
/* not 5.3 */
#ifndef ALLOCA_FLAG
#define ALLOCA_FLAG(use_heap)
#endif
#define _do_alloca(x, y) do_alloca((x))
#define _free_alloca(x, y) free_alloca((x))
#else
#define _do_alloca do_alloca
#define _free_alloca free_alloca
#endif
/* {{{ collator_u_strtod
* Taken from PHP6:zend_u_strtod()
*/
static double collator_u_strtod(const UChar *nptr, UChar **endptr) /* {{{ */
{
const UChar *u = nptr, *nstart;
UChar c = *u;
int any = 0;
ALLOCA_FLAG(use_heap);
while (u_isspace(c)) {
c = *++u;
}
nstart = u;
if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
c = *++u;
}
while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
any = 1;
c = *++u;
}
if (c == 0x2E /*'.'*/) {
c = *++u;
while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
any = 1;
c = *++u;
}
}
if ((c == 0x65 /*'e'*/ || c == 0x45 /*'E'*/) && any) {
const UChar *e = u;
int any_exp = 0;
c = *++u;
if (c == 0x2D /*'-'*/ || c == 0x2B /*'+'*/) {
c = *++u;
}
while (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/) {
any_exp = 1;
c = *++u;
}
if (!any_exp) {
u = e;
}
}
if (any) {
char buf[64], *numbuf, *bufpos;
int length = u - nstart;
double value;
if (length < sizeof(buf)) {
numbuf = buf;
} else {
numbuf = (char *) _do_alloca(length + 1, use_heap);
}
bufpos = numbuf;
while (nstart < u) {
*bufpos++ = (char) *nstart++;
}
*bufpos = '\0';
value = zend_strtod(numbuf, NULL);
if (numbuf != buf) {
_free_alloca(numbuf, use_heap);
}
if (endptr != NULL) {
*endptr = (UChar *)u;
}
return value;
}
if (endptr != NULL) {
*endptr = (UChar *)nptr;
}
return 0;
}
/* }}} */
/* {{{ collator_u_strtol
* Taken from PHP6:zend_u_strtol()
*
* Convert a Unicode string to a long integer.
*
* Ignores `locale' stuff.
*/
static long collator_u_strtol(nptr, endptr, base)
const UChar *nptr;
UChar **endptr;
register int base;
{
register const UChar *s = nptr;
register unsigned long acc;
register UChar c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
if (s == NULL) {
errno = ERANGE;
if (endptr != NULL) {
*endptr = NULL;
}
return 0;
}
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (u_isspace(c));
if (c == 0x2D /*'-'*/) {
neg = 1;
c = *s++;
} else if (c == 0x2B /*'+'*/)
c = *s++;
if ((base == 0 || base == 16) &&
(c == 0x30 /*'0'*/)
&& (*s == 0x78 /*'x'*/ || *s == 0x58 /*'X'*/)) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = (c == 0x30 /*'0'*/) ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (c >= 0x30 /*'0'*/ && c <= 0x39 /*'9'*/)
c -= 0x30 /*'0'*/;
else if (c >= 0x41 /*'A'*/ && c <= 0x5A /*'Z'*/)
c -= 0x41 /*'A'*/ - 10;
else if (c >= 0x61 /*'a'*/ && c <= 0x7A /*'z'*/)
c -= 0x61 /*'a'*/ - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (UChar *)(any ? s - 1 : nptr);
return (acc);
}
/* }}} */
/* {{{ collator_is_numeric]
* Taken from PHP6:is_numeric_unicode()
*/
zend_uchar collator_is_numeric( UChar *str, int length, long *lval, double *dval, int allow_errors )
{
long local_lval;
double local_dval;
UChar *end_ptr_long, *end_ptr_double;
int conv_base=10;
if (!length) {
return 0;
}
/* handle hex numbers */
if (length>=2 && str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
conv_base=16;
}
errno=0;
local_lval = collator_u_strtol(str, &end_ptr_long, conv_base);
if (errno != ERANGE) {
if (end_ptr_long == str+length) { /* integer string */
if (lval) {
*lval = local_lval;
}
return IS_LONG;
} else if (end_ptr_long == str && *end_ptr_long != '\0' && *str != '.' && *str != '-') { /* ignore partial string matches */
return 0;
}
} else {
end_ptr_long = NULL;
}
if (conv_base == 16) { /* hex string, under UNIX strtod() messes it up */
/* UTODO: keep compatibility with is_numeric_string() here? */
return 0;
}
local_dval = collator_u_strtod(str, &end_ptr_double);
if (local_dval == 0 && end_ptr_double == str) {
end_ptr_double = NULL;
} else {
if (end_ptr_double == str+length) { /* floating point string */
if (!zend_finite(local_dval)) {
/* "inf","nan" and maybe other weird ones */
return 0;
}
if (dval) {
*dval = local_dval;
}
return IS_DOUBLE;
}
}
if (!allow_errors) {
return 0;
}
if (allow_errors == -1) {
zend_error(E_NOTICE, "A non well formed numeric value encountered");
}
if (allow_errors) {
if (end_ptr_double > end_ptr_long && dval) {
*dval = local_dval;
return IS_DOUBLE;
} else if (end_ptr_long && lval) {
*lval = local_lval;
return IS_LONG;
}
}
return 0;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,26 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_IS_NUMERIC_H
#define COLLATOR_IS_NUMERIC_H
#include <php.h>
#include <unicode/uchar.h>
zend_uchar collator_is_numeric( UChar *str, int length, long *lval, double *dval, int allow_errors );
#endif // COLLATOR_IS_NUMERIC_H

View File

@ -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 <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator_class.h"
#include "collator_locale.h"
#include "intl_convert.h"
#include <zend_API.h>
/* {{{ proto string Collator::getLocale( int $type )
* Gets the locale name of the collator. }}} */
/* {{{ proto string collator_get_locale( Collator $coll, int $type )
* Gets the locale name of the collator.
*/
PHP_FUNCTION( collator_get_locale )
{
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.
RETVAL_STRINGL( locale_name, strlen(locale_name), TRUE );
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,25 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_LOCALE_H
#define COLLATOR_LOCALE_H
#include <php.h>
PHP_FUNCTION( collator_get_locale );
#endif // COLLATOR_LOCALE_H

532
ext/intl/collator/collator_sort.c Executable file
View File

@ -0,0 +1,532 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "collator.h"
#include "collator_class.h"
#include "collator_sort.h"
#include "collator_convert.h"
#include "intl_convert.h"
#if !defined(HAVE_PTRDIFF_T) && !defined(_PTRDIFF_T_DEFINED)
typedef long ptrdiff_t;
#endif
/**
* Declare 'index' which will point to sort key in sort key
* buffer.
*/
typedef struct _collator_sort_key_index {
char* key; // pointer to sort key
zval** zstr; // pointer to original string(hash-item)
} collator_sort_key_index_t;
ZEND_EXTERN_MODULE_GLOBALS( intl )
static const size_t DEF_SORT_KEYS_BUF_SIZE = 1048576;
static const size_t DEF_SORT_KEYS_BUF_INCREMENT = 1048576;
static const size_t DEF_SORT_KEYS_INDX_BUF_SIZE = 1048576;
static const size_t DEF_SORT_KEYS_INDX_BUF_INCREMENT = 1048576;
static const size_t DEF_UTF16_BUF_SIZE = 1024;
/* {{{ collator_regular_compare_function */
static int collator_regular_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
{
Collator_object* co = NULL;
int rc = SUCCESS;
zval* str1 = collator_convert_object_to_string( op1 TSRMLS_CC );
zval* str2 = collator_convert_object_to_string( op2 TSRMLS_CC );
zval* num1 = NULL;
zval* num2 = NULL;
zval* norm1 = NULL;
zval* norm2 = NULL;
// If both args are strings AND either of args is not numeric string
// then use ICU-compare. Otherwise PHP-compare.
if( Z_TYPE_P(str1) == IS_STRING && Z_TYPE_P(str2) == IS_STRING &&
( str1 == ( num1 = collator_convert_string_to_number_if_possible( str1 ) ) ||
str2 == ( num2 = collator_convert_string_to_number_if_possible( str2 ) ) ) )
{
// Fetch collator object.
co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
// Compare the strings using ICU.
result->value.lval = ucol_strcoll(
co->ucoll,
INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
result->type = IS_LONG;
}
else
{
// num1 is set if str1 and str2 are strings.
if( num1 )
{
if( num1 == str1 )
{
// str1 is string but not numeric string
// just convert it to utf8.
norm1 = collator_convert_zstr_utf16_to_utf8( str1 );
// num2 is not set but str2 is string => do normalization.
norm2 = collator_normalize_sort_argument( str2 );
}
else
{
// str1 is numeric strings => passthru to PHP-compare.
zval_add_ref( &num1 );
norm1 = num1;
// str2 is numeric strings => passthru to PHP-compare.
zval_add_ref( &num2 );
norm2 = num2;
}
}
else
{
// num1 is not set if str1 or str2 is not a string => do normalization.
norm1 = collator_normalize_sort_argument( str1 );
// if num1 is not set then num2 is not set as well => do normalization.
norm2 = collator_normalize_sort_argument( str2 );
}
rc = compare_function( result, norm1, norm2 TSRMLS_CC );
zval_ptr_dtor( &norm1 );
zval_ptr_dtor( &norm2 );
}
if( num1 )
zval_ptr_dtor( &num1 );
if( num2 )
zval_ptr_dtor( &num2 );
zval_ptr_dtor( &str1 );
zval_ptr_dtor( &str2 );
return rc;
}
/* }}} */
/* {{{ collator_numeric_compare_function
* Convert input args to double and compare it.
*/
static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
{
int rc = SUCCESS;
zval* num1 = NULL;
zval* num2 = NULL;
if( Z_TYPE_P(op1) == IS_STRING )
{
num1 = collator_convert_string_to_double( op1 );
op1 = num1;
}
if( Z_TYPE_P(op2) == IS_STRING )
{
num2 = collator_convert_string_to_double( op2 );
op2 = num2;
}
rc = numeric_compare_function( result, op1, op2 TSRMLS_CC);
if( num1 )
zval_ptr_dtor( &num1 );
if( num2 )
zval_ptr_dtor( &num2 );
return rc;
}
/* }}} */
/* {{{ collator_icu_compare_function
* Direct use of ucol_strcoll.
*/
static int collator_icu_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
{
int rc = SUCCESS;
Collator_object* co = NULL;
zval* str1 = NULL;
zval* str2 = NULL;
str1 = collator_make_printable_zval( op1 );
str2 = collator_make_printable_zval( op2 );
// Fetch collator object.
co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
// Compare the strings using ICU.
result->value.lval = ucol_strcoll(
co->ucoll,
INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
result->type = IS_LONG;
zval_ptr_dtor( &str1 );
zval_ptr_dtor( &str2 );
return rc;
}
/* }}} */
/* {{{ collator_compare_func
* Taken from PHP5 source (array_data_compare).
*/
static int collator_compare_func( const void* a, const void* b TSRMLS_DC )
{
Bucket *f;
Bucket *s;
zval result;
zval *first;
zval *second;
f = *((Bucket **) a);
s = *((Bucket **) b);
first = *((zval **) f->pData);
second = *((zval **) s->pData);
if( INTL_G(compare_func)( &result, first, second TSRMLS_CC) == FAILURE )
return 0;
if( Z_TYPE(result) == IS_DOUBLE )
{
if( Z_DVAL(result) < 0 )
return -1;
else if( Z_DVAL(result) > 0 )
return 1;
else
return 0;
}
convert_to_long(&result);
if( Z_LVAL(result) < 0 )
return -1;
else if( Z_LVAL(result) > 0 )
return 1;
return 0;
}
/* }}} */
/* {{{ collator_cmp_sort_keys
* Compare sort keys
*/
static int collator_cmp_sort_keys( const void *p1, const void *p2 TSRMLS_DC )
{
char* key1 = ((collator_sort_key_index_t*)p1)->key;
char* key2 = ((collator_sort_key_index_t*)p2)->key;
return strcmp( key1, key2 );
}
/* }}} */
/* {{{ collator_get_compare_function
* Choose compare function according to sort flags.
*/
static collator_compare_func_t collator_get_compare_function( const long sort_flags )
{
collator_compare_func_t func;
switch( sort_flags )
{
case COLLATOR_SORT_NUMERIC:
func = collator_numeric_compare_function;
break;
case COLLATOR_SORT_STRING:
func = collator_icu_compare_function;
break;
case COLLATOR_SORT_REGULAR:
default:
func = collator_regular_compare_function;
break;
}
return func;
}
/* }}} */
/* {{{ collator_sort_internal
* Common code shared by collator_sort() and collator_asort() API functions.
*/
static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
{
zval* array = NULL;
HashTable* hash = NULL;
zval* saved_collator = NULL;
long sort_flags = COLLATOR_SORT_REGULAR;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa|l",
&object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_sort_internal: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
// Set 'compare function' according to sort flags.
INTL_G(compare_func) = collator_get_compare_function( sort_flags );
hash = HASH_OF( array );
// Convert strings in the specified array from UTF-8 to UTF-16.
collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
// Save specified collator in the request-global (?) variable.
saved_collator = INTL_G( current_collator );
INTL_G( current_collator ) = object;
// Sort specified array.
zend_hash_sort( hash, zend_qsort, collator_compare_func, renumber TSRMLS_CC );
// Restore saved collator.
INTL_G( current_collator ) = saved_collator;
// Convert strings in the specified array back to UTF-8.
collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool Collator::sort( Collator $coll, array(string) $arr [, int $sort_flags] )
* Sort array using specified collator. }}} */
/* {{{ proto bool collator_sort( Collator $coll, array(string) $arr [, int $sort_flags] )
* Sort array using specified collator.
*/
PHP_FUNCTION( collator_sort )
{
collator_sort_internal( TRUE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
}
/* }}} */
/* {{{ proto bool Collator::sortWithSortKeys( Collator $coll, array(string) $arr )
* Equivalent to standard PHP sort using Collator.
* Uses ICU ucol_getSortKey for performance. }}} */
/* {{{ proto bool collator_sort_with_sort_keys( Collator $coll, array(string) $arr )
* Equivalent to standard PHP sort using Collator.
* Uses ICU ucol_getSortKey for performance.
*/
PHP_FUNCTION( collator_sort_with_sort_keys )
{
zval* array = NULL;
HashTable* hash = NULL;
zval** hashData = NULL; // currently processed item of input hash
char* sortKeyBuf = NULL; // buffer to store sort keys
uint32_t sortKeyBufSize = DEF_SORT_KEYS_BUF_SIZE; // buffer size
ptrdiff_t sortKeyBufOffset = 0; // pos in buffer to store sort key
int32_t sortKeyLen = 0; // the length of currently processing key
uint32_t bufLeft = 0;
uint32_t bufIncrement = 0;
collator_sort_key_index_t* sortKeyIndxBuf = NULL; // buffer to store 'indexes' which will be passed to 'qsort'
uint32_t sortKeyIndxBufSize = DEF_SORT_KEYS_INDX_BUF_SIZE;
uint32_t sortKeyIndxSize = sizeof( collator_sort_key_index_t );
uint32_t sortKeyCount = 0;
uint32_t j = 0;
UChar* utf16_buf = NULL; // tmp buffer to hold current processing string in utf-16
int utf16_buf_size = DEF_UTF16_BUF_SIZE; // the length of utf16_buf
int utf16_len = 0; // length of converted string
HashTable* sortedHash = NULL;
COLLATOR_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
&object, Collator_ce_ptr, &array ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"collator_sort_with_sort_keys: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
COLLATOR_METHOD_FETCH_OBJECT;
/*
* Sort specified array.
*/
hash = HASH_OF( array );
if( !hash || zend_hash_num_elements( hash ) == 0 )
RETURN_TRUE;
// Create bufers
sortKeyBuf = ecalloc( sortKeyBufSize, sizeof( char ) );
sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
utf16_buf = eumalloc( utf16_buf_size );
// Iterate through input hash and create a sort key for each value.
zend_hash_internal_pointer_reset( hash );
while( zend_hash_get_current_data( hash, (void**) &hashData ) == SUCCESS )
{
// Convert current hash item from UTF-8 to UTF-16LE and save the result to utf16_buf.
utf16_len = utf16_buf_size;
// Process string values only.
if( Z_TYPE_PP( hashData ) == IS_STRING )
{
intl_convert_utf8_to_utf16( &utf16_buf, &utf16_len, Z_STRVAL_PP( hashData ), Z_STRLEN_PP( hashData ), COLLATOR_ERROR_CODE_P( co ) );
if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
{
intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Sort with sort keys failed", 0 TSRMLS_CC );
if( utf16_buf )
efree( utf16_buf );
efree( sortKeyIndxBuf );
efree( sortKeyBuf );
RETURN_FALSE;
}
}
else
{
// Set empty string
utf16_len = 0;
utf16_buf[utf16_len] = 0;
}
if( (utf16_len + 1) > utf16_buf_size )
utf16_buf_size = utf16_len + 1;
// Get sort key, reallocating the buffer if needed.
bufLeft = sortKeyBufSize - sortKeyBufOffset;
sortKeyLen = ucol_getSortKey( co->ucoll,
utf16_buf,
utf16_len,
(uint8_t*)sortKeyBuf + sortKeyBufOffset,
bufLeft );
// check for sortKeyBuf overflow, increasing its size of the buffer if needed
if( sortKeyLen > bufLeft )
{
bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT;
sortKeyBufSize += bufIncrement;
bufLeft += bufIncrement;
sortKeyBuf = erealloc( sortKeyBuf, sortKeyBufSize );
sortKeyLen = ucol_getSortKey( co->ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft );
}
// check sortKeyIndxBuf overflow, increasing its size of the buffer if needed
if( ( sortKeyCount + 1 ) * sortKeyIndxSize > sortKeyIndxBufSize )
{
bufIncrement = ( sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT ) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT;
sortKeyIndxBufSize += bufIncrement;
sortKeyIndxBuf = erealloc( sortKeyIndxBuf, sortKeyIndxBufSize );
}
sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset; // remeber just offset, cause address
// of 'sortKeyBuf' may be changed due to realloc.
sortKeyIndxBuf[sortKeyCount].zstr = hashData;
sortKeyBufOffset += sortKeyLen;
++sortKeyCount;
zend_hash_move_forward( hash );
}
// update ptrs to point to valid keys.
for( j = 0; j < sortKeyCount; j++ )
sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
// sort it
zend_qsort( sortKeyIndxBuf, sortKeyCount, sortKeyIndxSize, collator_cmp_sort_keys TSRMLS_CC );
// for resulting hash we'll assign new hash keys rather then reordering
ALLOC_HASHTABLE( sortedHash );
zend_hash_init( sortedHash, 0, NULL, ZVAL_PTR_DTOR, 0 );
for( j = 0; j < sortKeyCount; j++ )
{
zval_add_ref( sortKeyIndxBuf[j].zstr );
zend_hash_next_index_insert( sortedHash, sortKeyIndxBuf[j].zstr, sizeof(zval **), NULL );
}
// Save sorted hash into return variable.
zval_dtor( array );
(array)->value.ht = sortedHash;
(array)->type = IS_ARRAY;
if( utf16_buf )
efree( utf16_buf );
efree( sortKeyIndxBuf );
efree( sortKeyBuf );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool Collator::asort( Collator $coll, array(string) $arr )
* Sort array using specified collator, maintaining index association. }}} */
/* {{{ proto bool collator_asort( Collator $coll, array(string) $arr )
* Sort array using specified collator, maintaining index association.
*/
PHP_FUNCTION( collator_asort )
{
collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
}
/* }}} */
/*
* 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
*/

View File

@ -0,0 +1,29 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef COLLATOR_SORT_H
#define COLLATOR_SORT_H
#include <php.h>
typedef int (*collator_compare_func_t)( zval *result, zval *op1, zval *op2 TSRMLS_DC );
PHP_FUNCTION( collator_sort );
PHP_FUNCTION( collator_sort_with_sort_keys );
PHP_FUNCTION( collator_asort );
#endif // COLLATOR_SORT_H

266
ext/intl/common/common_error.c Executable file
View File

@ -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 <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#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
*/

30
ext/intl/common/common_error.h Executable file
View File

@ -0,0 +1,30 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef INTL_COMMON_ERROR_H
#define INTL_COMMON_ERROR_H
#include <php.h>
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

66
ext/intl/config.m4 Executable file
View File

@ -0,0 +1,66 @@
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(INTL_SHARED_LIBADD)
PHP_SUBST(INTL_SHARED_LIBADD)
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 \
dateformat/dateformat.c \
dateformat/dateformat_class.c \
dateformat/dateformat_attr.c \
dateformat/dateformat_data.c \
dateformat/dateformat_format.c \
dateformat/dateformat_parse.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/dateformat)
PHP_ADD_BUILD_DIR($ext_builddir/locale)
PHP_ADD_BUILD_DIR($ext_builddir/msgformat)
PHP_ADD_BUILD_DIR($ext_builddir/grapheme)
fi

71
ext/intl/config.w32 Executable file
View File

@ -0,0 +1,71 @@
// $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 + "/grapheme", "\
grapheme_string.c grapheme_util.c \
", "intl");
ADD_SOURCES(configure_module_dirname + "/normalizer", "\
normalizer.c \
normalizer_class.c \
normalizer_normalize.c \
", "intl");
ADD_SOURCES(configure_module_dirname + "/dateformat", "\
dateformat.c \
dateformat_class.c \
dateformat_attr.c \
dateformat_format.c \
dateformat_parse.c \
dateformat_data.c \
", "intl");
ADD_FLAG("LIBS_INTL", "icudt.lib icuin.lib icuio.lib icule.lib iculx.lib");
AC_DEFINE("HAVE_INTL", 1, "Internationalization support enabled");
} else {
WARNING("intl not enabled; libraries and/or headers not found");
}
}

239
ext/intl/doc/Tutorial.txt Executable file
View File

@ -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, <language>_<script>_<region>_<keyword>.
Not all the elements are required. Valid values for locale elements are general valid values
for RFC4646 locale naming, and RFC 4647 lookup algorithm.
Example:
Locale="sv" (Swedish) "Kypper" < "Kopfe"
Locale="de" (German) "Kopfe" < "Kypper"
7. Collator::get/setAttribute.
ICU uses UCA as a default starting point for ordering. Not all languages have sorting sequences
that correspond with the UCA because UCA cannot simultaneously encompass the specifics of all
the languages currently in use. Therefore, ICU provides a data-driven, flexible, and run-time
customizable mechanism called "tailoring". Tailoring overrides the default order of code points
and the values of the ICU Collation Service attributes.
Collator have followed attributes:
- FRENCH_COLLATION, possible values are:
ON
OFF (default)
DEFAULT
- CASE_FIRST, possible values are:
OFF (default)
LOWER_FIRST
UPPER_FIRST
DEFAULT
- CASE_LEVEL, possible values are:
OFF (default)
ON
DEFAULT
- NORMALIZATION_MODE, possible values are:
OFF (default)
ON
DEFAULT
- STRENGTH, possible values are:
PRIMARY
SECONDARY
TERTIARY (default)
QUATERNARY
IDENTICAL
DEFAULT
- ALTERNATE_HANDLING, possible values are:
NON_IGNORABLE (default)
SHIFTED
DEFAULT
- HIRAGANA_QUATERNARY_MODE, possible values are:
ON
OFF (default)
DEFAULT
- NUMERIC_COLLATION, possible values are:
ON
OFF (default)
DEFAULT
Description of all of this attributes:
FRENCH_COLLATION - Sort strings with different accents from the back of the string. This attribute
is automatically set to On for the French locales and a few others. Users normally would
not need to explicitly set this attribute. There is a string comparison performance cost when
it is set On, but sort key length is unaffected.
Example:
F=X cote < cote < cote < cote
F=O cote < cote < cote < cote
CASE_FIRST - The Case_First attribute is used to control whether uppercase letters come before
lowercase letters or vice versa, in the absence of other differences in the strings. The possible
values are Uppercase_First (U) and Lowercase_First (L), plus the standard Default and Off.
There is almost no difference between the Off and Lowercase_First options in terms of results,
so typically users will not use Lowercase_First: only Off or Uppercase_First. (People interested
in the detailed differences between X and L should consult the Collation Customization).
Specifying either L or U won't affect string comparison performance, but will affect the sort key
length.
Example:
C=X or C=L "china" < "China" < "denmark" <
"Denmark"
C=U "China" < "china" < "Denmark" < "denmark"
CASE_LEVEL - The Case_Level attribute is used when ignoring accents but not case. In such a situation,
set Strength to be Primary, and Case_Level to be On. In most locales, this setting is Off by default.
There is a small string comparison performance and sort key impact if this attribute is set to be On.
Example:
S=1, E=X role = Role = role
S=1, E=O role = role < Role
NORMALIZATION_MODE - The Normalization setting determines whether text is thoroughly normalized
or not in comparison. Even if the setting is off (which is the default for many locales), text as
represented in common usage will compare correctly (for details, see UTN #5). Only if the accent
marks are in noncanonical order will there be a problem. If the setting is On, then the best
results are guaranteed for all possible text input. There is a medium string comparison performance
cost if this attribute is On, depending on the frequency of sequences that require normalization.
There is no significant effect on sort key length. If the input text is known to be in NFD or NFKD
normalization forms, there is no need to enable this Normalization option.
STRENGTH - see Collator::setStrength chapter.
ALTERNATE_HANDLING - The Alternate attribute is used to control the handling of the socalled
variable characters in the UCA: whitespace, punctuation and symbols. If Alternate is set to
NonIgnorable (N), then differences among these characters are of the same importance as
differences among letters. If Alternate is set to Shifted (S), then these characters are of only
minor importance. The Shifted value is often used in combination with Strength set to Quaternary.
In such a case, whitespace, punctuation, and symbols are considered when comparing strings,
but only if all other aspects of the strings (base letters, accents, and case) are identical.
If Alternate is not set to Shifted, then there is no difference between a Strength of 3 and
a Strength of 4. For more information and examples, see
Variable_Weighting in the UCA (http://www.unicode.org/reports/tr10/#Variable_Weighting).
The reason the Alternate values are not simply On and Off is that additional Alternate values
may be added in the future. The UCA option Blanked is expressed with Strength set to 3,
and Alternate set to Shifted. The default for most locales is NonIgnorable. If Shifted is selected,
it may be slower if there are many strings that are the same except for punctuation;
sort key length will not be affected unless the strength level is also increased.
Example:
S=3, A=N di Silva < Di Silva < diSilva < U.S.A. < USA
S=3, A=S di Silva = diSilva < Di Silva < U.S.A. = USA
S=4, A=S di Silva < diSilva < Di Silva < U.S.A. < USA
HIRAGANA_QUATERNARY_MODE - Compatibility with JIS x 4061 requires the introduction of an additional
level to distinguish Hiragana and Katakana characters. If compatibility with that standard is required,
then this attribute should be set On, and the strength set to Quaternary. This will affect sort key
length and string comparison string comparison performance.
NUMERIC_COLLATION - When turned on, this attribute generates a collation key for the
numeric value of substrings of digits. This is a way to get '100' to sort AFTER '2'.

398
ext/intl/doc/collator_api.php Executable file
View File

@ -0,0 +1,398 @@
<?php
#############################################################################
# Object-oriented API
#############################################################################
/**
* Collator class.
*
* This is a wrapper around ICU Collator C API (declared in ucol.h).
*
* Example:
* <code>
*
* </code>
*
* @see http://www.icu-project.org/apiref/icu4c/ucol_8h.html
* @see http://www.icu-project.org/apiref/icu4c/classCollator.html
*
*/
class Collator {
#############################################################################
# Common constants.
#############################################################################
/**
* Locale-related constants.
*
* These will be moved out of Collator when Locale class is created.
*/
const ULOC_ACTUAL_LOCALE = 0;
const ULOC_VALID_LOCALE = 1;
const ULOC_REQUESTED_LOCALE = 2;
/*
* WARNING:
* The values described here are NOT the actual values in PHP code.
* They are references to the ICU C definitions, so the line
* const DEFAULT_STRENGTH = 'UCOL_DEFAULT_STRENGTH';
* actually means that Collator::DEFAULT_STRENGTH is the same as
* UCOL_DEFAULT_STRENGTH constant in the ICU library.
*/
/**
* Valid attribute values.
*
* @see Collator::setAttribute()
* @see collator_set_attribute()
*/
const DEFAULT_VALUE = 'UCOL_DEFAULT';
const PRIMARY = 'UCOL_PRIMARY';
const SECONDARY = 'UCOL_SECONDARY';
const TERTIARY = 'UCOL_TERTIARY';
const DEFAULT_STRENGTH = 'UCOL_DEFAULT_STRENGTH';
const QUATERNARY = 'UCOL_QUATERNARY';
const IDENTICAL = 'UCOL_IDENTICAL';
const OFF = 'UCOL_OFF';
const ON = 'UCOL_ON';
const SHIFTED = 'UCOL_SHIFTED';
const NON_IGNORABLE = 'UCOL_NON_IGNORABLE';
const LOWER_FIRST = 'UCOL_LOWER_FIRST';
const UPPER_FIRST = 'UCOL_UPPER_FIRST';
/**
* Valid attribute names.
*
* @see Collator::setAttribute()
* @see collator_set_attribute()
*/
const FRENCH_COLLATION = 'UCOL_FRENCH_COLLATION';
const ALTERNATE_HANDLING = 'UCOL_ALTERNATE_HANDLING';
const CASE_FIRST = 'UCOL_CASE_FIRST';
const CASE_LEVEL = 'UCOL_CASE_LEVEL';
const NORMALIZATION_MODE = 'UCOL_NORMALIZATION_MODE';
const STRENGTH = 'UCOL_STRENGTH';
const HIRAGANA_QUATERNARY_MODE = 'UCOL_HIRAGANA_QUATERNARY_MODE';
const NUMERIC_COLLATION = 'UCOL_NUMERIC_COLLATION';
/**
* Create a collator
*
* @param string $locale The locale whose collation rules
* should be used. Special values for
* locales can be passed in - if null is
* passed for the locale, the default
* locale collation rules will be used. If
* empty string ("") or "root" are passed,
* UCA rules will be used.
*
* @return Collator New instance of Collator object.
*/
public function __construct( $locale ) {}
/**
* Create a collator
*
* Creates a new instance of Collator.
*
* This method is useful when you prefer just to get null on error,
* as if you called collator_create().
*
* @return Collator Newly created Collator instance,
* or null on error.
*
* @see __construct()
* @see collator_create()
*/
public static function create( $locale ) {}
/**
* Get collator's last error code.
*
* @return int Error code returned by the last
* Collator method call.
*/
public function getErrorCode() {}
/**
* Return error text for the last ICU operation.
*
* @return string Description of an error occured in the last
* Collator method call.
*/
public function getErrorMessage() {}
/**
* Compare two strings using PHP strcmp() semantics.
*
* Wrapper around ICU ucol_strcoll().
*
* @param string $str1 First string to compare.
* @param string $str2 Second string to compare.
*
* @return int 1 if $str1 is greater than $str2;
* 0 if $str1 is equal to $str2;
* -1 if $str1 is less than $str2.
* On error false is returned.
*/
public function compare( $str1, $str2 ) {}
/**
* Equivalent to standard PHP sort() using Collator.
*
* @param array $arr Array of strings to sort
* @param int $sort_flags Optional sorting type, one of the following:
* - SORT_REGULAR - compare items normally (don't change types)
* - SORT_NUMERIC - compare items numerically
* - SORT_STRING - compare items as strings
* Default sorting type is SORT_REGULAR.
*
* @return bool true on success or false on failure.
*/
public function sort( $arr, $sort_flags ) {}
/**
* Sort array maintaining index association.
*
* Equivalent to standard PHP asort() using Collator.
*
* @param array $arr Array of strings to sort
* @param int $sort_flags Optional sorting type
*
* @return bool true on success or false on failure.
*
* @see Collator::sort()
*/
public function asort( $arr, $sort_flags ) {}
/**
* Equivalent to standard PHP sort() using Collator.
*
* Similar to Collator::sort().
* Uses ICU ucol_getSortKey() to gain more speed on large arrays.
*
* @param array $arr Array of strings to sort
*
* @return bool true on success or false on failure.
*/
public function sortWithSortKeys( $arr ) {}
/**
* @todo Do we want to support other standard PHP sort functions: ksort, rsort, asort?
*/
/**
* Get collation attribute value.
*
* Wrapper around ICU ucol_getAttribute().
*
* @param int $attr Attribute to get value for.
*
* @return int Attribute value, or false on error.
*/
public function getAttribute( $attr ) {}
/**
* Set collation attribute.
*
* Wrapper around ICU ucol_setAttribute().
*
* @param int $attr Attribute.
* @param int $val Attribute value.
*
* @return bool true on success, false otherwise.
*/
public function setAttribute( $attr, $val ) {}
/**
* Get current collation strength.
*
* Wrapper around ICU ucol_getStrength().
*
* @return int Current collation strength, or false on error.
*/
public function getStrength() {}
/**
* Set collation strength.
*
* Wrapper around ICU ucol_setStrength().
*
* @param int $strength Strength to set.
*
* @return bool true on success, false otherwise.
*/
public function setStrength( $strength ) {}
/**
* Get the locale name of the collator.
*
* Wrapper around ICU ucol_getLocaleByType().
*
* @param int $type You can choose between requested, valid
* and actual locale
* (ULOC_REQUESTED_LOCALE,
* ULOC_VALID_LOCALE, ULOC_ACTUAL_LOCALE,
* respectively).
*
* @return string Real locale name from which the
* collation data comes. If the collator
* was instantiated from rules or an error occured,
* returns false.
*/
public function getLocale( $type ) {}
}
#############################################################################
# Procedural API
#############################################################################
/**
* Create collator.
*
* @param string $locale The locale containing the required
* collation rules. Special values for
* locales can be passed in - if null is
* passed for the locale, the default
* locale collation rules will be used. If
* empty string ("") or "root" are passed,
* UCA rules will be used.
*
* @return Collator New instance of Collator object, or null on error.
*/
function collator_create( $locale ) {}
/**
* Compare two strings.
*
* The strings will be compared using the options already
* specified.
*
* @param Collator $coll Collator object.
* @param string $str1 The first string to compare.
* @param string $str2 The second string to compare.
*
* @return int 1 if $str1 is greater than $str2;
* 0 if $str1 is equal to $str2;
* -1 if $str1 is less than $str2.
* On error false is returned.
*
*/
function collator_compare( $coll, $str1, $str2 ) {}
/**
* Sort array using specified collator.
*
* @param Collator $coll Collator object.
* @param array $arr Array of strings to sort.
* @param int $sort_flags Optional sorting type, one of the following:
* - SORT_REGULAR - compare items normally (don't change types)
* - SORT_NUMERIC - compare items numerically
* - SORT_STRING - compare items as strings
* Default sorting type is SORT_REGULAR.
*
* @return bool true on success or false on failure.
*/
function collator_sort( $coll, $arr, $sort_flags ) {}
/**
* Sort array maintaining index association.
*
* @param Collator $coll Collator object.
* @param array $arr Array of strings to sort.
* @param int $sort_flags Optional sorting type.
*
* @return bool true on success or false on failure.
*
* @see collator_sort()
*/
function collator_asort( $coll, $arr, $sort_flags ) {}
/**
* Sort array using specified collator.
*
* Similar to collator_sort().
* Uses ICU ucol_getSortKey() to gain more speed on large arrays.
*
* @param Collator $coll Collator object.
* @param array $arr Array of strings to sort
*
* @return bool true on success or false on failure.
*/
function collator_sort_with_sort_keys( $coll, $arr ) {}
/**
* Get the locale name of the collator.
*
* @param Collator $coll Collator object.
* @param int $type You can choose between valid and
* actual locale
* (ULOC_VALID_LOCALE, ULOC_ACTUAL_LOCALE
* respectively).
*
* @return string Real locale name from which the
* collation data comes. If the collator
* was instantiated from rules or an error occured,
* returns false.
*/
function collator_get_locale( $coll, $type ) {}
/**
* Get collation attribute value.
*
* @param Collator $coll Collator object.
* @param int $attr Attribute to get value for.
*
* @return int Attribute value, or false on error.
*/
function collator_get_attribute( $coll, $attr ) {}
/**
* Get current collation strength.
*
* @param Collator $coll Collator object.
*
* @return int Current collation strength, or false on error.
*/
function collator_get_strength( $coll ) {}
/**
* Set collation strength.
*
* @param Collator $coll Collator object.
* @param int $strength Strength to set.
*
* @return bool true on success, false otherwise.
*/
function collator_set_strength( $coll, $strength ) {}
/**
* Set collation attribute.
*
* @param Collator $coll Collator object.
* @param int $attr Attribute.
* @param int $val Attribute value.
*
* @return bool true on success, false otherwise.
*/
function collator_set_attribute( $coll, $attr, $val ) {}
/**
* Get collator's last error code.
*
* @param Collator $coll Collator object.
*
* @return int Error code returned by the last
* Collator API function call.
*/
function collator_get_error_code( $coll ) {}
/**
* Get text for collator's last error code.
*
* @param Collator $coll Collator object.
*
* @return string Description of an error occured in the last
* Collator API function call.
*/
function collator_get_error_message( $coll ) {}
?>

58
ext/intl/doc/common_api.php Executable file
View File

@ -0,0 +1,58 @@
<?php
/**
* Handling of errors occured in static methods
* when there's no object to get error code/message from.
*
* Example #1:
* <code>
* $coll = collator_create( '<bad_param>' );
* if( !$coll )
* handle_error( intl_get_error_code() );
* </code>
*
* Example #2:
* <code>
* if( Collator::getAvailableLocales() === false )
* show_error( intl_get_error_message() );
* </code>
*/
/**
* Get the last error code.
*
* @return int Error code returned by the last
* API function call.
*/
function intl_get_error_code() {}
/**
* Get description of the last error.
*
* @return string Description of an error occured in the last
* API function call.
*/
function intl_get_error_message() {}
/**
* Check whether the given error code indicates failure.
*
* @param int $code ICU error code.
*
* @return bool true if it the code indicates some failure,
* and false in case of success or a warning.
*/
function intl_is_failure($code) {}
/**
* Get symbolic name for a given error code.
*
* The returned string will be the same as the name of the error code constant.
*
* @param int $code ICU error code.
*
* @return string Error code name.
*/
function intl_error_name($code) {}
?>

439
ext/intl/doc/datefmt_api.php Executable file
View File

@ -0,0 +1,439 @@
<?php
/**
* Date Formatter class - locale-dependent formatting/parsing of dates using pattern strings and/or canned patterns.
*
* This class represents the ICU date formatting functionality. It allows users to
* display dates in a localized format or to parse strings
* into PHP date values using pattern strings and/or canned patterns.
*
* Example:
* <code>
* $datefmt = new DateFormatter("de-DE", LONG, SHORT, date_default_timezone_get());
* echo $formatter->format(time());
* </code>
*
* <code>
* $datefmt = new DateFormatter("de-DE", LONG, SHORT, date_default_timezone_get() , GREGORIAN , "yyyy-MM-dd HH:mm:ss z");
* echo $formatter->format(time());
* </code>
*
* @see http://www.icu-project.org/apiref/icu4c/udat_8h.html
*
*/
class DateFormatter {
#############################################################################
# Common constants.
#############################################################################
/**
* The following constants are used to specify different formats
* in the constructor.
*/
const NONE = -1;
const FULL = 0;
const LONG = 1;
const MEDIUM = 2;
const SHORT = 3;
/**
* The following int constants are used to specify the calendar.
* These calendars are all based directly on the Gregorian calendar
* Non-Gregorian calendars need to be specified in locale.
* Examples might include locale="hi@calendar=BUDDHIST"
*/
const TRADITIONAL = 0; // non-Gregorian calendar that is locale-defined, required by ICU
const GREGORIAN = 1 ;// Gregorian calendar
#############################################################################
# Object-oriented API
#############################################################################
/**
* Create a date formatter
*
* @param string $locale Locale to use when formatting or parsing
* @param integer $datetype Date type to use (none, short, medium, long, full)
* @param integer $timetype Time type to use (none, short, medium, long, full)
* @param [String] $timezone Time zone ID ; default is system default
* @param [integer] $calendar Calendar to use for formatting or parsing; default is
* GREGORIAN
* @param [string] $pattern Optional pattern to use when formatting or parsing
* @return DateFormatter
* @see __construct
* @see datefmt_create
*/
public function __construct($locale, $datetype, $timetype, $timezone = null, $calendar= null , $pattern= null) {}
/**
* Create a date formatter
*
* @param string $locale Locale to use when formatting or parsing
* @param integer $datetype Date type to use (none, short, medium, long, full)
* @param integer $timetype Time type to use (none, short, medium, long, full)
* @param [string] $timezone Time zone ID ; default is system default
* @param [integer] $calendar Calendar to use for formatting or parsing; default is
* GREGORIAN
* @param [string] $pattern Optional pattern to use when formatting or parsing
* @return DateFormatter
* @see __construct
* @see datefmt_create
*/
public static function create($locale, $datetype, $timetype, $timezone = null, $calendar= null , $pattern= null) {}
/**
* formats the time value as a string.
* @param mixed $value - value to format
* integer: a unix timestamp value (seconds since epoch, UTC)
* array: a localtime array - uses 24 hour clock in tm_hour field
* @return string a formatted string or, if an error occurred, 'null'.
*/
public function format($value) {}
/**
* converts string $value to an incremental time value, starting at
* $parse_pos and consuming as much of the input value as possible
* If no error occurs before $value is consumed, $parse_pos will contain -1
* otherwise it will contain the position at which parsing ended (and the error
* occurred).
* @param string $value string to convert to a time
* @param integer $parse_pos position at which to start the parsing in $value (zero-based)
* This variable will contain the end position if the parse fails
* If $parse_pos > strlen($value), the parse fails immediately.
* @return integer timestamp parsed value
*/
public function parse($value, $parse_pos=0) {}
/**
* converts string $value to a field-based time value, starting at
* $parse_pos and consuming as much of the input value as possible
* If no error occurs before $value is consumed, $parse_pos will contain -1
* otherwise it will contain the position at which parsing ended (and the error
* occurred).
* @param string $value string to convert to a time
* @param integer $parse_pos position at which to start the parsing in $value (zero-based)
* This variable will contain the end position if the parse fails
* If $parse_pos > strlen($value), the parse fails immediately.
* @return array localtime compatible array of integers - uses 24 hour clock in tm_hour field
*/
public function localtime($value, $parse_pos=0) {}
/**
* Gets the datetype in use
* @return integer the current 'datetype' value of the formatter
*/
public function getDateType() {}
/**
* Gets the timetype in use
* @return integer the current 'timetype' value of the formatter
*/
public function getTimeType() {}
/**
* Gets the leniency in use
* @return boolean 'true' if parser is lenient, 'false' if parser is strict
* default value for parser is 'false'.
*/
public function isLenient() {}
/**
* Sets the leniency to use
* @param boolean $lenient sets whether the parser is lenient or not, default is 'false'
* 'true' sets the parser to accept otherwise flawed date or
* time patterns, parsing as much as possible to obtain a value.
* 'false' sets the parser to strictly parse strings into dates.
* Extra space, unrecognized tokens, or invalid values
* ("Feburary 30th") are not accepted.
*
* @return boolean 'true' if successful; 'false' if an error occurred.
*/
public function setLenient($lenient) {}
/**
* Gets the locale in use
* @param [integer] which locale should be returned?
* values may include ULOC_ACTUAL_LOCALE,
* ULOC_VALID_LOCALE. By default the actual
* locale is returned.
* @return string the locale of this formatter or 'false' if error
*/
public function getLocale($type = ULOC_ACTUAL_LOCALE) {}
/**
* @return string ID string for the time zone used by this formatter
*/
public function getTimeZoneId() {}
/**
* sets the time zone to use
* @param string $zone zone ID string of the time zone to use.
* if null or the empty string, the default time zone for
* the runtime is used.
* @return boolean 'true' on successful setting of the time zone, 'false'
* if an error occurred (such as the time zone wasn't recognized).
*/
public function setTimeZoneId($zone) {}
/**
* Sets the calendar used to the appropriate calendar, which must be
* one of the constants defined above. Some examples include:
* - Gregorian calendar
* - Traditional
* Default value is GREGORIAN
* @param integer $which the calendar (an enumerated constant) to use.
* @return boolean 'true' if successful, 'false' if an error occurred or if the calendar was not recognized
*/
public function setCalendar($which) {}
/**
* Gets the Calendar in use
* @return integer the calendar being used by the formatter
*/
public function getCalendar() {}
/**
* Gets the pattern in use
* @return string the pattern string being used to format/parse
*/
public function getPattern() {}
/**
* Sets the pattern to use
* @param string $pattern new pattern string to use
* @return boolean 'true' if successful, 'false' if an error occured. Bad format
* strings are usually the cause of the latter.
*/
public function setPattern($pattern) {}
/**
* Get the error code from last operation
*
* Returns error code from the last number formatting operation.
*
* @return integer the error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
public function getErrorCode() {}
/**
* Get the error text from the last operation.
*
* @return string Description of the last error.
*/
public function getErrorMessage() {}
}
#############################################################################
# Procedural API
#############################################################################
/**
* Create a date formatter
*
* @param string $locale Locale to use when formatting or parsing
* @param integer $datetype Date type to use (none, short, medium, long, full)
* @param integer $timetype Time type to use (none, short, medium, long, full)
* @param [string] $timezone Time zone ID ; default is system default
* @param [integer] $calendar Calendar to use for formatting or parsing; default is
* GREGORIAN
* @param [string] $pattern Optional pattern to use when formatting or parsing
* @return DateFormatter
* @see datefmt_create
*/
function datefmt_create($locale, $datetype, $timetype, $timezone = null, $calendar= null ,$pattern=null ) {}
/**
* formats the time value as a string.
* @param DateFormatter $fmt The date formatter resource
* @param mixed $value - value to format
* integer: a unix timestamp value (seconds since epoch, UTC)
* array: a localtime array - uses 24 hour clock in tm_hour field
* @return string a formatted string or, if an error occurred, 'null'.
*/
function datefmt_format($fmt , $value) {}
/**
* converts string $value to an incremental time value, starting at
* $parse_pos and consuming as much of the input value as possible
* If no error occurs before $value is consumed, $parse_pos will contain -1
* otherwise it will contain the position at which parsing ended (and the error
* occurred).
* @param DateFormatter $fmt The date formatter resource
* @param string $value string to convert to a time
* @param integer $parse_pos position at which to start the parsing in $value (zero-based)
* This variable will contain the end position if the parse fails
* If $parse_pos > strlen($value), the parse fails immediately.
* @return integer timestamp parsed value
*/
function datefmt_parse($fmt , $value, $parse_pos=0) {}
/**
* converts string $value to a field-based time value, starting at
* $parse_pos and consuming as much of the input value as possible
* If no error occurs before $value is consumed, $parse_pos will contain -1
* otherwise it will contain the position at which parsing ended (and the error
* occurred).
* @param DateFormatter $fmt The date formatter resource
* @param string $value string to convert to a time
* @param integer $parse_pos position at which to start the parsing in $value (zero-based)
* This variable will contain the end position if the parse fails
* If $parse_pos > strlen($value), the parse fails immediately.
* @return array localtime compatible array of integers - uses 24 hour clock in tm_hour field
*/
function datefmt_localtime($fmt , $value, $parse_pos=0) {}
/**
* Gets the Datetype in use
* @param DateFormatter $fmt The date formatter resource
* @return integer the current 'datetype' value of the formatter
*/
function datefmt_get_datetype($fmt ) {}
/**
* Gets the timetype in use
* @param DateFormatter $fmt The date formatter resource
* @return integer the current 'timetype' value of the formatter
*/
function datefmt_get_timetype($fmt) {}
/**
* Gets the leniency of the formatter
* @param DateFormatter $fmt The date formatter resource
* @return boolean 'true' if parser is lenient, 'false' if parser is strict
* default value for parser is 'false'.
*/
function datefmt_is_lenient($fmt) {}
/**
* Sets the leniency of the formatter
* @param DateFormatter $fmt The date formatter resource
* @param boolean $lenient sets whether the parser is lenient or not, default is 'false'
* 'true' sets the parser to accept otherwise flawed date or
* time patterns, parsing as much as possible to obtain a value.
* 'false' sets the parser to strictly parse strings into dates.
* Extra space, unrecognized tokens, or invalid values
* ("Feburary 30th") are not accepted.
*
* @return boolean 'true' if successful; 'false' if an error occurred.
*/
function datefmt_set_lenient($fmt , $lenient) {}
/**
* Gets the locale in use
* @param DateFormatter $fmt The date formatter resource
* @param [integer] which locale should be returned?
* values may include ULOC_ACTUAL_LOCALE,
* ULOC_VALID_LOCALE. By default the actual
* locale is returned.
* @return string the locale of this formatter or 'false' if error
*/
function datefmt_get_locale($fmt , $type = ULOC_ACTUAL_LOCALE) {}
/**
* Gets the time zone id in use
* @param DateFormatter $fmt The date formatter resource
* @return string ID string for the time zone used by this formatter
*/
function datefmt_get_timezone_id($fmt) {}
/**
* Sets the time zone to use
* @param DateFormatter $fmt The date formatter resource
* @param string $zone zone ID string of the time zone to use.
* if null or the empty string, the default time zone for
* the runtime is used.
* @return boolean 'true' on successful setting of the time zone, 'false'
* if an error occurred (such as the time zone wasn't recognized).
*/
function datefmt_set_timezone_id($fmt , $zone) {}
/**
* Sets the calendar used to the appropriate calendar, which must be
* one of the constants defined above. Some examples include:
* - Gregorian calendar
* - Traditional
* Default value is GREGORIAN
* @param DateFormatter $fmt The date formatter resource
* @param integer $which the calendar (an enumerated constant) to use.
* @return boolean 'true' if successful, 'false' if an error occurred or if the calendar was not recognized
*/
function datefmt_set_calendar($fmt , $which) {}
/**
* Gets the calendar in use
* @param DateFormatter $fmt The date formatter resource
* @return integer the calendar being used by the formatter
*/
function datefmt_get_calendar($fmt) {}
/**
* Gets the pattern in use
* @param DateFormatter $fmt The date formatter resource
* @return string the pattern string being used to format/parse
*/
function datefmt_get_pattern($fmt) {}
/**
* Sets the pattern to use
* @param DateFormatter $fmt The date formatter resource
* @param string $pattern new pattern string to use
* @return boolean 'true' if successful, 'false' if an error occured. Bad format
* strings are usually the cause of the latter.
*/
function datefmt_set_pattern($fmt , $pattern) {}
/**
* Get the error code from last operation
*
* @param DateFormatter $fmt The date formatter resource
* Returns error code from the last number formatting operation.
*
* @return integer the error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
function datefmt_get_error_code($fmt) {}
/**
* Get the error text from the last operation.
*
* @param DateFormatter $fmt The date formatter resource
* @return string Description of the last error.
*/
function datefmt_get_error_message($fmt) {}
?>

502
ext/intl/doc/formatter_api.php Executable file
View File

@ -0,0 +1,502 @@
<?php
/**
* Number formatter class - locale-dependent number formatting/parsing.
*
* This class represents the ICU number formatting functionality. It allows to display
* number according to the localized format or given pattern or set of rules, and to
* parse strings into numbers according to the above patterns.
*
* Example:
* <code>
* $value = 1234567;
* $formatter = new NumberFormatter("de_DE", NumberFormatter::DECIMAL);
* echo $formatter->format($value);
* </code>
*
* @see http://www.icu-project.org/apiref/icu4c/unum_8h.html
* @see http://www.icu-project.org/apiref/icu4c/classNumberFormat.html
*
* The class would also contain all the constants listed in the following enums:
* UNumberFormatStyle, UNumberFormatRoundingMode, UNumberFormatPadPosition,
* UNumberFormatAttribute, UNumberFormatTextAttribute, UNumberFormatSymbol.
*/
class NumberFormatter {
#############################################################################
# Common constants.
#############################################################################
/*
* WARNING:
* The values described here are NOT the actual values in PHP code.
* They are references to the ICU C definitions, so the line
* const PATTERN_DECIMAL = 'UNUM_PATTERN_DECIMAL';
* actually means that NumberFormatter::PATTERN_DECIMAL is the same as
* UNUM_PATTERN_DECIMAL constant in the ICU library.
*/
/*
* These constants define formatter/parser argument type - integer, floating point or currency.
*/
const TYPE_DEFAULT = 'FORMAT_TYPE_DEFAULT';
const TYPE_INT32 = 'FORMAT_TYPE_INT32';
const TYPE_INT64 = 'FORMAT_TYPE_INT64';
const TYPE_DOUBLE = 'FORMAT_TYPE_DOUBLE';
const TYPE_CURRENCY = 'FORMAT_TYPE_CURRENCY';
/*
* UNumberFormatStyle constants
*/
const PATTERN_DECIMAL = 'UNUM_PATTERN_DECIMAL';
const DECIMAL = 'UNUM_DECIMAL';
const CURRENCY = 'UNUM_CURRENCY';
const PERCENT = 'UNUM_PERCENT';
const SCIENTIFIC = 'UNUM_SCIENTIFIC';
const SPELLOUT = 'UNUM_SPELLOUT';
const ORDINAL = 'UNUM_ORDINAL';
const DURATION = 'UNUM_DURATION';
const PATTERN_RULEBASED = 'UNUM_PATTERN_RULEBASED';
const DEFAULT = 'UNUM_DEFAULT';
const IGNORE = 'UNUM_IGNORE';
/*
* UNumberFormatRoundingMode
*/
const ROUND_CEILING = 'UNUM_ROUND_CEILING';
const ROUND_FLOOR = 'UNUM_ROUND_FLOOR';
const ROUND_DOWN = 'UNUM_ROUND_DOWN';
const ROUND_UP = 'UNUM_ROUND_UP';
const ROUND_HALFEVEN = 'UNUM_ROUND_HALFEVEN';
const ROUND_HALFDOWN = 'UNUM_ROUND_HALFDOWN';
const ROUND_HALFUP = 'UNUM_ROUND_HALFUP';
/*
* UNumberFormatPadPosition
*/
const PAD_BEFORE_PREFIX = 'UNUM_PAD_BEFORE_PREFIX';
const PAD_AFTER_PREFIX = 'UNUM_PAD_AFTER_PREFIX';
const PAD_BEFORE_SUFFIX = 'UNUM_PAD_BEFORE_SUFFIX';
const PAD_AFTER_SUFFIX = 'UNUM_PAD_AFTER_SUFFIX';
/*
* UNumberFormatAttribute
*/
const PARSE_INT_ONLY = 'UNUM_PARSE_INT_ONLY';
const GROUPING_USED = 'UNUM_GROUPING_USED';
const DECIMAL_ALWAYS_SHOWN = 'UNUM_DECIMAL_ALWAYS_SHOWN';
const MAX_INTEGER_DIGITS = 'UNUM_MAX_INTEGER_DIGITS';
const MIN_INTEGER_DIGITS = 'UNUM_MIN_INTEGER_DIGITS';
const INTEGER_DIGITS = 'UNUM_INTEGER_DIGITS';
const MAX_FRACTION_DIGITS = 'UNUM_MAX_FRACTION_DIGITS';
const MIN_FRACTION_DIGITS = 'UNUM_MIN_FRACTION_DIGITS';
const FRACTION_DIGITS = 'UNUM_FRACTION_DIGITS';
const MULTIPLIER = 'UNUM_MULTIPLIER';
const GROUPING_SIZE = 'UNUM_GROUPING_SIZE';
const ROUNDING_MODE = 'UNUM_ROUNDING_MODE';
const ROUNDING_INCREMENT = 'UNUM_ROUNDING_INCREMENT';
const FORMAT_WIDTH = 'UNUM_FORMAT_WIDTH';
const PADDING_POSITION = 'UNUM_PADDING_POSITION';
const SECONDARY_GROUPING_SIZE = 'UNUM_SECONDARY_GROUPING_SIZE';
const SIGNIFICANT_DIGITS_USED = 'UNUM_SIGNIFICANT_DIGITS_USED';
const MIN_SIGNIFICANT_DIGITS = 'UNUM_MIN_SIGNIFICANT_DIGITS';
const MAX_SIGNIFICANT_DIGITS = 'UNUM_MAX_SIGNIFICANT_DIGITS';
const LENIENT_PARSE = 'UNUM_LENIENT_PARSE';
/*
* UNumberFormatTextAttribute
*/
const POSITIVE_PREFIX = 'UNUM_POSITIVE_PREFIX';
const POSITIVE_SUFFIX = 'UNUM_POSITIVE_SUFFIX';
const NEGATIVE_PREFIX = 'UNUM_NEGATIVE_PREFIX';
const NEGATIVE_SUFFIX = 'UNUM_NEGATIVE_SUFFIX';
const PADDING_CHARACTER = 'UNUM_PADDING_CHARACTER';
const CURRENCY_CODE = 'UNUM_CURRENCY_CODE';
const DEFAULT_RULESET = 'UNUM_DEFAULT_RULESET';
const PUBLIC_RULESETS = 'UNUM_PUBLIC_RULESETS';
/*
* UNumberFormatSymbol
*/
const DECIMAL_SEPARATOR_SYMBOL = 'UNUM_DECIMAL_SEPARATOR_SYMBOL';
const GROUPING_SEPARATOR_SYMBOL = 'UNUM_GROUPING_SEPARATOR_SYMBOL';
const PATTERN_SEPARATOR_SYMBOL = 'UNUM_PATTERN_SEPARATOR_SYMBOL';
const PERCENT_SYMBOL = 'UNUM_PERCENT_SYMBOL';
const ZERO_DIGIT_SYMBOL = 'UNUM_ZERO_DIGIT_SYMBOL';
const DIGIT_SYMBOL = 'UNUM_DIGIT_SYMBOL';
const MINUS_SIGN_SYMBOL = 'UNUM_MINUS_SIGN_SYMBOL';
const PLUS_SIGN_SYMBOL = 'UNUM_PLUS_SIGN_SYMBOL';
const CURRENCY_SYMBOL = 'UNUM_CURRENCY_SYMBOL';
const INTL_CURRENCY_SYMBOL = 'UNUM_INTL_CURRENCY_SYMBOL';
const MONETARY_SEPARATOR_SYMBOL = 'UNUM_MONETARY_SEPARATOR_SYMBOL';
const EXPONENTIAL_SYMBOL = 'UNUM_EXPONENTIAL_SYMBOL';
const PERMILL_SYMBOL = 'UNUM_PERMILL_SYMBOL';
const PAD_ESCAPE_SYMBOL = 'UNUM_PAD_ESCAPE_SYMBOL';
const INFINITY_SYMBOL = 'UNUM_INFINITY_SYMBOL';
const NAN_SYMBOL = 'UNUM_NAN_SYMBOL';
const SIGNIFICANT_DIGIT_SYMBOL = 'UNUM_SIGNIFICANT_DIGIT_SYMBOL';
const MONETARY_GROUPING_SEPARATOR_SYMBOL = 'UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL';
/**
* Create a number formatter
*
* Creates a number formatter from locale and pattern. This formatter would be used to
* format or parse numbers.
*
* @param integer $style Style of the formatting, one of the UNumberFormatStyle constants
* @param string $locale Locale in which the number would be formatted
* @param [string] $pattern Pattern string in case chose style requires pattern
* @return NumberFormatter
*/
public function __construct($locale, $style, $pattern = null) {}
/**
* Create a number formatter
*
* Creates a number formatter from locale and pattern. This formatter would be used to
* format or parse numbers.
*
* This method is useful when you prefer just to get null on error,
* as if you called numfmt_create().
*
* @param integer $style Style of the formatting, one of the UNumberFormatStyle constants
* @param string $locale Locale in which the number would be formatted
* @param [string] $pattern Pattern string in case chose style requires pattern
* @return NumberFormatter
* @see __construct
* @see numfmt_create
*/
public static function create($locale, $style, $pattern = null) {}
/**
* Format a number according to current formatting rules.
*
* If the type is not specified, the type is derived from the $number parameter. I.e., if it's
* integer then INT32 would be chosen on 32-bit, INT64 on 64-bit, if it's double, DOUBLE would be
* chosen. It is possible to format 64-bit number on 32-bit machine by passing it as double and using
* TYPE_INT64.
* When formatting currency, default formatter's currency code is used.
*
* @param integer|double $number Number to format
* @param [integer] $type Type of the formatting - one of TYPE constants. If not specified, default for the type.
* @return string formatted number
*/
public function format($number, $type = 0) {}
/**
* Parse a number according to current formatting rules.
*
* @param string $string String to parse
* @param [integer] $type Type of the formatting - one of TYPE constants.
* TYPE_DOUBLE is used by default.
* @param [integer] $position On input, the position to start parsing, default is 0;
* on output, moved to after the last successfully parse character;
* on parse failure, does not change.
* @return integer|double|false Parsed number, false if parsing failed
*/
public function parse($string, $type, &$position) {}
/**
* Format number as currency.
*
* Uses user-defined currency string.
*
* @param double $number Number to format
* @param string $currency 3-letter currency code (ISO 4217) to use in format
*/
public function formatCurrency($number, $currency) {}
/**
* Parse currency string
*
* This parser would use parseCurrency API string to parse currency string. The format is defined by the
* formatter, returns both number and currency code.
*
* @param string $string String to parse
* @param string $currency Parameter to return parsed currency code
* @param [integer] $position On input, the position within text to match, default is 0;
* on output, the position after the last matched character;
* on parse failure, does not change.
* @return double currency number
*/
public function parseCurrency($string, &$currency, &$position) {}
/**
* Set formatter attribute.
*
* This function is used to set any of the formatter attributes. Example:
*
* $formatter->setAttribute(NumberFormat::FORMAT_WIDTH, 10);
*
* @param integer $attr One of UNumberFormatAttribute constants
* @param integer|double $value Value of the attribute
* @return false if attribute is unknown or can not be set, true otherwise
*/
public function setAttribute($attr, $value) {}
/**
* Set formatter attribute.
*
* This function is used to set any of the formatter attributes. Example:
*
* $formatter->setTextAttribute(NumberFormat::POSITIVE_PREFIX, "+");
*
* @param integer $attr One of UNumberFormatTextAttribute constants
* @param string $value Value of the attribute
* @return false if attribute is unknown or can not be set, true otherwise
*/
public function setTextAttribute($attr, $value) {}
/**
* Set formatting symbol.
*
* Example:
*
* $formatter->setSymbol(NumberFormat::EXPONENTIAL_SYMBOL, "E");
*
* @param integer|array $attr One of UNumberFormatSymbol constants or array of symbols, indexed by
* these constants
* @param string $value Value of the symbol
*/
public function setSymbol($attr, $value) {}
/**
* Set pattern used by the formatter
*
* Valid only if the formatter is using pattern and is not rule-based.
* @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html
* Localized patterns are not currently supported.
*
* @param string $pattern The pattern to be used.
* @return boolean false if formatter pattern could not be set, true otherwise
*/
public function setPattern($pattern) {}
/**
* Get value of the formatter attribute
*
* @param integer $attr One of UNumberFormatAttribute constants
* @return integer|double value of the attribute or false if the value can not be obtained
*/
public function getAttribute($attr) {}
/**
* Get value of the formatter attribute
*
* @param integer $attr One of UNumberFormatTextAttribute constants
* @return string value of the attribute or false if the value can not be obtained
*/
public function getTextAttribute($attr) {}
/**
* Get value of the formatter symbol
*
* @param integer $attr One of UNumberFormatSymbol constants specifying the symbol
* @return string|false The symbol value, or false if the value can not be obtained
*/
public function getSymbol($attr) {}
/**
* Get pattern used by the formatter.
*
* Gets current state of the formatter as a pattern.
* Localized patterns are not currently supported.
*
* Valid only if the formatter is UNUM_PATTERN_DECIMAL
* @return string|false The pattern used by the formatter or false if formatter is of a type
* that does not support patterns.
*/
public function getPattern() {}
/**
* Get the locale for which the formatter was created.
*
* @param [integer] $type One of ULocDataLocaleType values
* @return string locale name
*/
public function getLocale($type = 0) {}
/**
* Get the error code from last operation
*
* Returns error code from the last number formatting operation.
*
* @return integer the error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
public function getErrorCode() {}
/**
* Get the error text from the last operation.
*
* @return string Description of the last occured error.
*/
public public function getErrorMessage() {}
}
/** Now the same as procedural API */
/**
* Create a number formatter
*
* Creates a number formatter from locale and pattern. This formatter would be used to
* format or parse numbers.
*
* @param string $locale Locale in which the number would be formatted
* @param integer $style Style of the formatting, one of the UNumberFormatStyle constants
* @param [string] $pattern Pattern string in case chose style requires pattern
* @return Numberformatter resource NumberFormatter
*/
function numfmt_create($locale, $style, $pattern = null) {}
/**
* Format a number according to current formatting rules.
*
* If the type is not specified, the type is derived from the $number parameter. I.e., if it's
* integer then INT32 would be chosen on 32-bit, INT64 on 64-bit, if it's double, DOUBLE would be
* chosen. It is possible to format 64-bit number on 32-bit machine by passing it as double and using
* TYPE_INT64.
*
* @param NumberFormatter $formatter The formatter resource
* @param integer|double $number Number to format
* @param [integer] $type Type of the formatting - one of TYPE constants. If not specified, default for the type.
* @return string formatted number
*/
function numfmt_format($formatter, $number, $type = null) {}
/**
* Parse a number according to current formatting rules.
*
* This parser uses DOUBLE type by default. When parsing currency,
* default currency definitions are used.
*
* @param NumberFormatter $formatter The formatter resource
* @param string $string String to parse
* @param [integer] $type Type of the formatting - one of TYPE constants.
* @param [integer] $position String position after the end of parsed data.
* @return integer|double|false Parsed number, false if parsing failed
*/
function numfmt_parse($formatter, $string, $type, &$position) {}
/**
* Format number as currency.
*
* Uses user-defined currency string.
*
* @param NumberFormatter $formatter The formatter resource
* @param double $number Number to format
* @param string $currency 3-letter currency code (ISO 4217) to use in format
*/
function numfmt_format_currency($formatter, $number, $currency) {}
/**
* Parse currency string
*
* This parser would use parseCurrency API string to parse currency string. The format is defined by the
* formatter, returns both number and currency code.
*
* @param NumberFormatter $formatter The formatter resource
* @param string $string String to parse
* @param string $currency Parameter to return parsed currency code
* @param [integer] $position String position after the end of parsed data.
* @return double currency number
*/
function numfmt_parse_currency($formatter, $string, &$currency, &$position) {}
/**
* Set formatter attribute.
*
* This function is used to set any of the formatter attributes. Example:
*
* numfmt_format_set_attribute($formatter, NumberFormat::FORMAT_WIDTH, 10);
*
* @param NumberFormatter $formatter The formatter resource
* @param integer $attr One of UNumberFormatAttribute constants
* @param integer|double $value Value of the attribute
* @return false if attribute is unknown or can not be set, true otherwise
*/
function numfmt_set_attribute($formatter, $attribute, $value) {}
/**
* Set formatter attribute.
*
* This function is used to set any of the formatter attributes. Example:
*
* numfmt_format_set_text_attribute($formatter, NumberFormat::POSITIVE_PREFIX, "+");
*
* @param NumberFormatter $formatter The formatter resource
* @param integer $attr One of UNumberFormatTextAttribute constants
* @param string $value Value of the attribute
* @return false if attribute is unknown or can not be set, true otherwise
*/
function numfmt_set_text_attribute($formatter, $attribute, $value) {}
/**
* Set formatting symbol.
*
* Example:
*
* $formatter->setSymbol(NumberFormat::EXPONENTIAL_SYMBOL, "E");
*
* @param NumberFormatter $formatter The formatter resource
* @param integer|array $attr One of UNumberFormatSymbol constants or array of symbols,
* indexed by these constants
* @param string $value Value of the symbol
*/
function numfmt_set_symbol($formatter, $attribute, $value) {}
/**
* Set pattern used by the formatter
*
* Valid only if the formatter is using pattern and is not rule-based.
* @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html
* Localized patterns are not currently supported.
*
* @param NumberFormatter $formatter The formatter resource
* @param string $pattern The pattern to be used.
* @return boolean false if formatter pattern could not be set, true otherwise
*/
function numfmt_set_pattern($formatter, $pattern) {}
/**
* Get value of the formatter attribute
*
* @param NumberFormatter $formatter The formatter resource
* @param integer $attribute One of UNumberFormatAttribute constants
* @return integer|double value of the attribute or false if the value can not be obtained
*/
function numfmt_get_attribute($formatter, $attribute) {}
/**
* Get value of the formatter attribute
*
* @param NumberFormatter $formatter The formatter resource
* @param integer $attribute One of UNumberFormatTextAttribute constants
* @return string value of the attribute or false if the value can not be obtained
*/
function numfmt_get_text_attribute($formatter, $attribute) {}
/**
* Get value of the formatter symbol
*
* @param NumberFormatter $formatter The formatter resource
* @param integer $attribute One of UNumberFormatSymbol constants specifying the symbol
* @return string|false The symbol value, or false if the value can not be obtained
*/
function numfmt_get_symbol($formatter, $attribute) {}
/**
* Get pattern used by the formatter.
*
* Gets current state of the formatter as a pattern.
* Localized patterns are not currently supported.
*
* Valid only if the formatter is UNUM_PATTERN_DECIMAL
* @param NumberFormatter $formatter The formatter resource
* @return string|false The pattern used by the formatter or false if formatter is of a type
* that does not support patterns.
*/
function numfmt_get_pattern($formatter) {}
/**
* Get the locale for which the formatter was created.
*
* @param NumberFormatter $formatter The formatter resource
* @param [integer] $type One of ULocDataLocaleType values
* @return string locale name
*/
function numfmt_get_locale($formatter, $type = 0) {}
/**
* Get the error code from last operation
*
* Returns error code from the last number formatting operation.
*
* @param NumberFormatter $formatter The formatter resource
* @return integer the error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
function numfmt_get_error_code($formatter) {}
/**
* Get the error text from the last operation.
*
* @param NumberFormatter $formatter The formatter resource
* @return string Description of the last occured error.
*/
function numfmt_get_error_message($formatter) {}
?>

132
ext/intl/doc/grapheme_api.php Executable file
View File

@ -0,0 +1,132 @@
<?php
#############################################################################
# Grapheme constants.
#############################################################################
/**
* grapheme_extract extract_type
*
*/
/** Extract the given number of whole grapheme clusters from the string: */
define('GRAPHEME_EXTR_COUNT', 0);
/** Extract as many whole grapheme clusters as will fit into the given number of bytes: */
define('GRAPHEME_EXTR_MAXBYTES', 1);
/** Extract whole grapheme clusters up to a maximum number of UTF-8 characters: */
define('GRAPHEME_EXTR_MAXCHARS', 2);
#############################################################################
# Grapheme API
#############################################################################
/**
* Get string length in grapheme units
* @param string $input The string being measured for length.
* @return int The length of the string on success, and 0 if the string is empty.
*/
function grapheme_strlen($input) {}
/**
* Find position (in grapheme units) of first occurrence of a string
* @param string $haystack The string to look in
* @param string $needle The string to look for
* @param [int] $offset The optional offset parameter allows you to specify
which character in haystack to start searching. The position
returned is still relative to the beginning of haystack.
* @return int Returns the position as an integer. If needle is not found, strpos() will return boolean FALSE.
*/
function grapheme_strpos($haystack, $needle, $offset = 0) {}
/**
* Find position (in grapheme units) of first occurrence of a case-insensitive string
* @param string $haystack The string to look in
* @param string $needle The string to look for
* @param [int] $offset The optional offset parameter allows you to specify
which character in haystack to start searching. The position
returned is still relative to the beginning of haystack.
* @return int Returns the position as an integer. If needle is not found, grapheme_stripos() will return boolean FALSE.
*/
function grapheme_stripos($haystack, $needle, $offset = 0) {}
/**
* Find position (in grapheme units) of last occurrence of a string
* @param string $haystack The string to look in
* @param string $needle The string to look for
* @param [int] $offset The optional offset parameter allows you to specify
which character in haystack to start searching. The position
returned is still relative to the beginning of haystack.
* @return int Returns the position as an integer. If needle is not found, grapheme_strrpos() will return boolean FALSE.
*/
function grapheme_strrpos($haystack, $needle, $offset = 0) {}
/**
* Find position (in grapheme units) of last occurrence of a case-insensitive string
* @param string $haystack The string to look in
* @param string $needle The string to look for
* @param [int] $offset The optional offset parameter allows you to specify
which character in haystack to start searching. The position
returned is still relative to the beginning of haystack.
* @return int Returns the position as an integer. If needle is not found, grapheme_strripos() will return boolean FALSE.
*/
function grapheme_strripos($haystack, $needle, $offset = 0) {}
/**
* Return part of a string
* @param string $string The input string.
* @param int $start If start is non-negative, the returned string will start at the
start'th position in string, counting from zero. If start is negative,
the returned string will start at the start'th character from the
end of string.
* @param [int] $length If length is given and is positive, the string returned will contain
at most length characters beginning from start (depending on the
length of string). If string is less than or equal to start characters
long, FALSE will be returned. If length is given and is negative, then
that many characters will be omitted from the end of string (after the
start position has been calculated when a start is negative). If start
denotes a position beyond this truncation, an empty string will be returned.
* @return int Returns the extracted part of string.
*/
function grapheme_substr($string, $start, $length = -1) {}
/**
* Returns part of haystack string from the first occurrence of needle to the end of haystack.
* @param string $haystack The input string.
* @param string $needle The string to look for.
* @param [boolean] $before_needle If TRUE (the default is FALSE), grapheme_strstr() returns the part of the
haystack before the first occurence of the needle.
* @return string Returns the portion of string, or FALSE if needle is not found.
*/
function grapheme_strstr($haystack, $needle, $before_needle = FALSE) {}
/**
* Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack.
* @param string $haystack The input string.
* @param string $needle The string to look for.
* @param [boolean] $before_needle If TRUE (the default is FALSE), grapheme_strstr() returns the part of the
haystack before the first occurence of the needle.
* @return string Returns the portion of string, or FALSE if needle is not found.
*/
function grapheme_stristr($haystack, $needle, $before_needle = FALSE) {}
/**
* Function to extract a sequence of default grapheme clusters from a text buffer, which must be encoded in UTF-8.
* @param string $haystack string to search
* @param int $size maximum number of units - based on the $extract_type - to return
* @param [int] $extract_type one of GRAPHEME_EXTR_COUNT (default), GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS
* @param [int] $start starting position in $haystack in bytes
* @param [&int] $next set to next starting position in bytes
* @return string A string starting at offset $start containing no more than $size grapheme clusters
and ending on a default grapheme cluster boundary.
*/
function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_COUNT, $start = 0, &$next) {}
?>

432
ext/intl/doc/locale_api.php Executable file
View File

@ -0,0 +1,432 @@
<?php
/**
* A "Locale" is an identifier used to get language, culture, or regionally-specific
* behavior from an API. PHP locales are organized and identified the same
* way that the CLDR locales used by ICU (and many vendors of Unix-like operating
* systems, the Mac, Java, and so forth) use. Locales are identified using
* RFC 4646 language tags (which use hyphen, not underscore) in addition to the
* more traditional underscore-using identifiers. Unless otherwise noted
* the functions in this class are tolerant of both formats.
*
* Examples of identifiers include:
*
* * en-US (English, United States)
* * zh-Hant-TW (Chinese, Traditional Script, Taiwan)
* * fr-CA, fr-FR (French for Canada and France respectively)
*
* The Locale class (and related procedural functions) are used to interact
* with locale identifiers--to verify that an ID is well-formed, valid,
* etc. The extensions used by CLDR in UAX #35 (and inherited by ICU) are
* valid and used wherever they would be in ICU normally.
*
* Locales cannot be instantiated as objects. All of the functions/methods
* provided are static.
*
* * The null or empty string obtains the "root" locale.
* The "root" locale is equivalent to "en_US_POSIX" in CLDR.
* * Language tags (and thus locale identifiers) are case insensitive. There
* exists a canonicalization function to make case match the specification.
*
* @see http://www.icu-project.org/apiref/icu4c/uloc_8h.html
* @see http://www.unicode.org/reports/tr35/
*
*/
class Locale {
#############################################################################
# Common constants.
#############################################################################
/**
* The following static members are used with the getLocale methods of
* the various locale affected classes, such as numfmt.
*/
const DEFAULT_LOCALE = default_locale;
/**
* identifiers for the actual locale, valid locale
* WARNING:
* The values described here are NOT the actual values in PHP code.
* They are references to the ICU C definitions, so the line
* const ACTUAL_LOCALE = 'ULOC_ACTUAL_LOCALE';
* actually means that Locale::ACTUAL_LOCALE is the same as
* ULOC_ACTUAL_LOCALE constant in the ICU library.
*/
const ACTUAL_LOCALE = 'ULOC_ACTUAL_LOCALE';
const VALID_LOCALE = 'ULOC_VALID_LOCALE';
/**
* Valid locale tag and subtag values
*/
LANG_TAG = "language";
EXTLANG_TAG = "extlang";
SCRIPT_TAG = "script";
REGION_TAG = "region";
VARIANT_TAG = "variant";
GRANDFATHERED_LANG_TAG = "grandfathered";
PRIVATE_TAG = "private";
#############################################################################
# Object-oriented API
#############################################################################
/**
* Gets the default locale value from the INTL global 'default_locale'
* At the PHP initilaization (MINIT) this value is set to
* 'intl.default_locale' value from php.ini if that value exists
* or from ICU's function uloc_getDefault()
* Then onwards picks up changes from setDefault() calls also
*
* @return string the current runtime locale
*/
public static function getDefault() {}
/**
* sets the default runtime locale to $locale
* This changes the value of INTL global 'default_locale'
*
* @param string $locale is a BCP 47 compliant language tag containing the
* locale identifier. UAX #35 extensions are accepted.
* @return boolean 'true' if okay, 'false' if an error
*/
public static function setDefault($locale) {}
/**
* Gets the primary language for the input locale
*
* @param string $locale the locale to extract the primary language code from
* @return string the language code associated with the language
* or null in case of error.
*/
public static function getPrimaryLanguage($locale) {}
/**
* Gets the script for the input locale
*
* @param string $locale the locale to extract the script code from
* @return string the script subtag for the locale or null if not present
*/
public static function getScript($locale) {}
/**
* Gets the region for the input locale
*
* @param string $locale the locale to extract the region code from
* @return string the region subtag for the locale or null if not present
*/
public static function getRegion($locale) {}
/**
* Gets the variants for the input locale
*
* @param string $locale the locale to extract the variants from
* @return array the array containing the list of all variants
* subtag for the locale or null if not present
*/
public static function getAllVariants($locale) {}
/**
* Gets the keywords for the input locale
*
* @param string $locale the locale to extract the keywords from
* @return array associative array containing the keyword-value pairs for this locale
*/
public static function getKeywords($locale) {}
/**
* Returns an appropriately localized display name for the input locale
*
* @param string $locale the locale to return a displayname for
* @param [string] $in_locale optional format locale
* If is 'null' then the default locale is used.
* @return string display name of the locale in the format
* appropriate for $in_locale.
*/
public static function getDisplayName($locale, $in_locale = null) {}
/**
* Returns an appropriately localized display name for language of the input locale
*
* @param string $locale the locale to return a display language for
* @param [string] $in_locale optional format locale to use to display the language name
* If is 'null' then the default locale is used.
* @return string display name of the language for the $locale in the format
* appropriate for $in_locale.
*/
public static function getDisplayLanguage($lang, $in_locale = null) {}
/**
* Returns an appropriately localized display name for script of the input locale
*
* @param string $locale the locale to return a display script for
* @param [string] $in_locale optional format locale to use to display the script name
* If is 'null' then the default locale is used.
* @return string display name of the script for the $locale in the format
* appropriate for $in_locale.
*/
public static function getDisplayScript($script, $in_locale = null) {}
/**
* Returns an appropriately localized display name for region of the input locale
*
* @param string $locale the locale to return a display region for
* @param [string] $in_locale optional format locale to use to display the region name
* If is 'null' then the default locale is used.
* @return string display name of the region for the $locale in the format
* appropriate for $in_locale.
*/
public static function getDisplayRegion($region, $in_locale = null) {}
/**
* Returns an appropriately localized display name for variants of the input locale
*
* @param string $locale the locale to return a display variant for
* @param [string] $in_locale optional format locale to use to display the variant name
* If is 'null' then the default locale is used.
* @return string display name of the variant for the $locale in the format
* appropriate for $in_locale.
*/
public static function getDisplayVariant($variant, $in_locale = null) {}
/**
* Checks if a $langtag filter matches with $locale according to
* RFC 4647's basic filtering algorithm
*
* @param string $langtag the language tag to check
* @param string $locale the language range to check against
* @return boolean 'true' if $locale matches $langtag 'false' otherwise
*/
public static function filterMatches($langtag, $locale) {}
/**
* Searchs the items in $langtag for the best match to the language
* range specified in $locale according to RFC 4647's lookup algorithm.
*
* @param array $langtag an array containing a list of language tags to compare
* to $locale
* @param string $locale the locale to use as the language range when matching
* @param string $default the locale to use if no match is found
* @return string closest matching language tag, $default,
* or empty string
*/
public static function lookup(array $langtag, $locale, $default = null) {}
/**
* Returns a correctly ordered and delimited locale ID
*
* @param array $subtags an array containing a list of key-value pairs, where
* the keys identify the particular locale ID subtags,
* and the values are the associated subtag values.
*
* @return string the corresponding locale identifier.
*/
public static function composeLocale(array $subtags) {}
/**
* Returns a key-value array of locale ID subtag elements.
*
* @param string $locale the locale to extract the subtag array from
*
* @return array $subtags an array containing a list of key-value pairs, where
* the keys identify the particular locale ID subtags,
* and the values are the associated subtag values.
*/
public static function parseLocale($locale) {}
}
#############################################################################
# Procedural API
#############################################################################
/**
* Gets the default locale value from the INTL global 'default_locale'
* At the PHP initilaization (MINIT) this value is set to
* 'intl.default_locale' value from php.ini if that value exists
* or from ICU's function uloc_getDefault()
* Then onwards picks up changes from setDefault() calls also
*
* @return string the current runtime locale
*/
public static function locale_get_default() {}
/**
* sets the default runtime locale to $locale
* This changes the value of INTL global 'default_locale'
*
* @param string $locale is a BCP 47 compliant language tag containing the
* locale identifier. UAX #35 extensions are accepted.
* @return boolean 'true' if okay, 'false' if an error
*/
public static function locale_set_default($locale) {}
/**
* Gets the primary language for the input locale
*
* @param string $locale the locale to extract the primary language code from
* @return string the language code associated with the language
* or null in case of error.
*/
public static function locale_get_primary_language($locale) {}
/**
* Gets the script for the input locale
*
* @param string $locale the locale to extract the script code from
* @return string the script subtag for the locale or null if not present
*/
public static function locale_get_script($locale) {}
/**
* Gets the region for the input locale
*
* @param string $locale the locale to extract the region code from
* @return string the region subtag for the locale or null if not present
*/
public static function locale_get_region($locale) {}
/**
* Gets the variants for the input locale
*
* @param string $locale the locale to extract the variants from
* @return array the array containing the list of all variants
* subtag for the locale or null if not present
*/
public static function locale_get_all_variants($locale) {}
/**
* Gets the keywords for the input locale
*
* @param string $locale the locale to extract the keywords from
* @return array associative array containing the keyword-value pairs for this locale
*/
public static function locale_get_keywords($locale) {}
/**
* Returns an appropriately localized display name for the input locale
*
* @param string $locale the locale to return a displayname for
* @param [string] $in_locale optional format locale
* If is 'null' then the default locale is used.
* @return string display name of the locale in the format
* appropriate for $in_locale.
*/
public static function locale_get_display_name($locale, $in_locale = null) {}
/**
* Returns an appropriately localized display name for language of the input locale
*
* @param string $locale the locale to return a display language for
* @param [string] $in_locale optional format locale to use to display the language name
* If is 'null' then the default locale is used.
* @return string display name of the language for the $locale in the format
* appropriate for $in_locale.
*/
public static function locale_get_display_language($lang, $in_locale = null) {}
/**
* Returns an appropriately localized display name for script of the input locale
*
* @param string $locale the locale to return a display script for
* @param [string] $in_locale optional format locale to use to display the script name
* If is 'null' then the default locale is used.
* @return string display name of the script for the $locale in the format
* appropriate for $in_locale.
*/
public static function locale_get_display_script($script, $in_locale = null) {}
/**
* Returns an appropriately localized display name for region of the input locale
*
* @param string $locale the locale to return a display region for
* @param [string] $in_locale optional format locale to use to display the region name
* If is 'null' then the default locale is used.
* @return string display name of the region for the $locale in the format
* appropriate for $in_locale.
*/
public static function locale_get_display_region($region, $in_locale = null) {}
/**
* Returns an appropriately localized display name for variants of the input locale
*
* @param string $locale the locale to return a display variant for
* @param [string] $in_locale optional format locale to use to display the variant name
* If is 'null' then the default locale is used.
* @return string display name of the variant for the $locale in the format
* appropriate for $in_locale.
*/
public static function locale_get_display_variant($variant, $in_locale = null) {}
/**
* Checks if a $langtag filter matches with $locale according to
* RFC 4647's basic filtering algorithm
*
* @param string $langtag the language tag to check
* @param string $locale the language range to check against
* @return boolean 'true' if $locale matches $langtag 'false' otherwise
*/
public static function locale_filter_matches($langtag, $locale) {}
/**
* Searchs the items in $langtag for the best match to the language
* range specified in $locale according to RFC 4647's lookup algorithm.
*
* @param array $langtag an array containing a list of language tags to compare
* to $locale
* @param string $locale the locale to use as the language range when matching
* @param string $default the locale to use if no match is found
* @return string closest matching language tag, $default,
* or empty string
*/
public static function locale_lookup(array $langtag, $locale, $default = null) {}
/**
* Returns a correctly ordered and delimited locale ID
*
* @param array $subtags an array containing a list of key-value pairs, where
* the keys identify the particular locale ID subtags,
* and the values are the associated subtag values.
*
* @return string the corresponding locale identifier.
*/
public static function locale_compose_locale(array $subtags) {}
/**
* Returns a key-value array of locale ID subtag elements.
*
* @param string $locale the locale to extract the subtag array from
*
* @return array $subtags an array containing a list of key-value pairs, where
* the keys identify the particular locale ID subtags,
* and the values are the associated subtag values.
*/
public static function locale_parse_locale($locale) {}
?>

209
ext/intl/doc/msgfmt_api.php Executable file
View File

@ -0,0 +1,209 @@
<?php
/**
* Message formatter class.
*
* Message Format provides for runtime formatting of messages in a manner
* somewhat similar to sprintf. The pattern string has its component parts
* replaced in a locale-sensitive manner using items in the arguments array.
*
* @see http://www.icu-project.org/apiref/icu4c/umsg_8h.html
*
*/
class MessageFormatter {
/**
* Constructs a new Message Formatter
*
* @param string $locale the locale to use when formatting arguments
* @param string $pattern the pattern string to stick arguments into
*/
public function __construct($locale, $pattern) {}
/**
* Constructs a new Message Formatter
*
* @param string $locale the locale to use when formatting arguments
* @param string $pattern the pattern string to stick arguments into
*/
public static function create($locale, $pattern) {}
/**
* Format the message
* @param array $args arguments to insert into the pattern string
* @return string the formatted string, or false if an error ocurred
*/
public function format($args) {}
/**
* Parse input string and returns any extracted items as an array
*
* $error will contain any error code. If an error occurs, $parse_pos contains
* the position of the error.
*
* @param string $value string to parse for items
* @return array array containing items extracted
*
*/
public function parse($value) {}
/**
* Inserts the items in $args into $pattern, formatting them
* according to $locale. This is the static implementation.
*
* @param string $locale the locale to use when formatting numbers and dates and suchlike
* @param string $pattern the pattern string to insert things into
* @param array $args the array of values to insert into $pattern
* @return string the formatted pattern string or false if an error occured
*/
public static function formatMessage($locale, $pattern, $args) {}
/**
* parses input string and returns any extracted items as an array
*
* $error will contain any error code. If an error occurs, $parse_pos contains
* the position of the error.
*
* @param string $locale the locale to use when formatting numbers and dates and suchlike
* @param string $value string to parse for items
* @return array array containing items extracted
*
*/
public static function parseMessage($locale, $value) {}
/**
* Get the pattern used by the formatter
*
* @return string the pattern string for this message formatter
*/
public function getPattern() {}
/**
* Set the pattern used by the formatter
*
* @param string $pattern the pattern string to use in this message formatter
* @return boolean 'true' if successful, 'false' if an error
*/
public function setPattern($pattern) {}
/**
* Get the error code from last operation
*
* Returns error code from the last number formatting operation.
*
* @return integer the error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
public function getErrorCode() {}
/**
* Get the error text from the last operation.
*
* @return string Description of the last error.
*/
public function getErrorMessage() {}
/**
* Get the locale for which the formatter was created.
*
* @return string locale name
*/
public function getLocale() {}
}
/** Now the same as procedural API */
/**
* Constructs a new Message Formatter
*
* @param string $locale the locale to use when formatting arguments
* @param string $pattern the pattern string to stick arguments into
* @return MessageFormatter formatter object
*/
function msgfmt_create($locale, $pattern) {}
/**
* Format the message
* @param MessageFormatter $fmt The message formatter
* @param array $args arguments to insert into the pattern string
* @return string the formatted string, or false if an error ocurred
*/
function msgfmt_format($fmt, $args) {}
/**
* parses input string and returns any extracted items as an array
*
* $error will contain any error code. If an error occurs, $parse_pos contains
* the position of the error.
*
* @param MessageFormatter $fmt The message formatter
* @param string $value string to parse for items
* @return array array containing items extracted
*
*/
function msgfmt_parse($fmt, $value) {}
/**
* Inserts the items in $args into $pattern, formatting them
* according to $locale. This is the static implementation.
*
* @param string $locale the locale to use when formatting numbers and dates and suchlike
* @param string $pattern the pattern string to insert things into
* @param array $args the array of values to insert into $pattern
* @return string the formatted pattern string or false if an error occured
*/
function msgfmt_format_message($locale, $pattern, $args) {}
/**
* parses input string and returns any extracted items as an array
*
* $error will contain any error code. If an error occurs, $parse_pos contains
* the position of the error.
*
* @param string $locale the locale to use when formatting numbers and dates and suchlike
* @param string $value string to parse for items
* @return array array containing items extracted
*
*/
function msgfmt_parse_message($locale, $value) {}
/**
* Get the pattern used by the formatter
*
* @param MessageFormatter $fmt The message formatter
* @return string the pattern string for this message formatter
*/
function msgfmt_get_pattern($fmt) {}
/**
* Set the pattern used by the formatter
*
* @param MessageFormatter $fmt The message formatter
* @param string $pattern the pattern string to use in this message formatter
* @return boolean 'true' if successful, 'false' if an error
*/
function msgfmt_set_pattern($fmt, $pattern) {}
/**
* Get the error code from last operation
*
* Returns error code from the last number formatting operation.
*
* @param MessageFormatter $fmt The message formatter
* @return integer the error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
function msgfmt_get_error_code($fmt) {}
/**
* Get the error text from the last operation.
*
* @param MessageFormatter $fmt The message formatter
* @return string Description of the last error.
*/
function msgfmt_get_error_message($fmt) {}
/**
* Get the locale for which the formatter was created.
*
* @param NumberFormatter $formatter The formatter resource
* @return string locale name
*/
function msgfmt_get_locale($formatter) {}
?>

92
ext/intl/doc/normalizer_api.php Executable file
View File

@ -0,0 +1,92 @@
<?php
#############################################################################
# Object-oriented API
#############################################################################
/**
* Normalizer class.
*
* Normalizer provides access to Unicode normalization of strings. This class consists
* only of static methods. The iterator interface to normalizer is rarely used, so is
* not provided here.
*
* Example:
* <code>
*
* </code>
*
* @see http://www.icu-project.org/apiref/icu4c/unorm_8h.html
* @see http://www.icu-project.org/apiref/icu4c/classNormalizer.html
*
*/
class Normalizer {
#############################################################################
# Common constants.
#############################################################################
/**
* Valid normalization form values.
*
* @see Normalizer::normalize()
* @see Normalizer::isNormalize()
* @see normalizer_normalize()
* @see normalizer_is_normalized()
*/
const NONE = 1;
/** Canonical decomposition. */
const NFD = 2;
const FORM_D = NFD;
/** Compatibility decomposition. */
const NFKD = 3;
const FORM_KD = NFKD;
/** Canonical decomposition followed by canonical composition. */
const NFC = 4;
const FORM_C = NFC;
/** Compatibility decomposition followed by canonical composition. */
const NFKC =5;
const FORM_KC = NFKC;
/**
* Normalizes the input provided and returns the normalized string
* @param string $input The input string to normalize
* @param [int] $form One of the normalization forms
* @return string The normalized string or null if an error occurred.
*/
public static function normalize($input, $form = Normalizer::FORM_C) {}
/**
* Checks if the provided string is already in the specified normalization form.
* @param string $input The input string to normalize
* @param [int] $form One of the normalization forms
* @return boolean True if normalized, false otherwise or if there is an error
*/
public static function isNormalized($input, $form = Normalizer::FORM_C) {}
}
#############################################################################
# Procedural API
#############################################################################
/**
* Normalizes the input provided and returns the normalized string
* @param string $input The input string to normalize
* @param [int] $form One of the normalization forms
* @return string The normalized string or null if an error occurred.
*/
function normalizer_normalize($input, $form = Normalizer::FORM_C) {}
/**
* Checks if the provided string is already in the specified normalization form.
* @param string $input The input string to normalize
* @param [int] $form One of the normalization forms
* @return boolean True if normalized, false otherwise or if there an error
*/
function normalizer_is_normalized($input, $form = Normalizer::FORM_C) {}
?>

152
ext/intl/formatter/formatter.c Executable file
View File

@ -0,0 +1,152 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/utypes.h>
#include <unicode/unum.h>
#include <unicode/ustring.h>
#include "php_intl.h"
#include "formatter_class.h"
#include "formatter_format.h"
#if U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM <= 4
#define UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL 17
#endif
/* {{{ formatter_register_constants
* Register constants common for the both (OO and procedural)
* APIs.
*/
void formatter_register_constants( INIT_FUNC_ARGS )
{
if( NumberFormatter_ce_ptr == NULL) {
zend_error(E_ERROR, "NumberFormatter class not defined");
}
#define FORMATTER_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS)
#define FORMATTER_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( NumberFormatter_ce_ptr, ZEND_STRS( #x ) - 1, UNUM_##x TSRMLS_CC );
#define FORMATTER_EXPOSE_CUSTOM_CLASS_CONST(name, value) zend_declare_class_constant_long( NumberFormatter_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );
// UNumberFormatStyle constants
FORMATTER_EXPOSE_CLASS_CONST( PATTERN_DECIMAL );
FORMATTER_EXPOSE_CLASS_CONST( DECIMAL );
FORMATTER_EXPOSE_CLASS_CONST( CURRENCY );
FORMATTER_EXPOSE_CLASS_CONST( PERCENT );
FORMATTER_EXPOSE_CLASS_CONST( SCIENTIFIC );
FORMATTER_EXPOSE_CLASS_CONST( SPELLOUT );
FORMATTER_EXPOSE_CLASS_CONST( ORDINAL );
FORMATTER_EXPOSE_CLASS_CONST( DURATION );
FORMATTER_EXPOSE_CLASS_CONST( PATTERN_RULEBASED );
FORMATTER_EXPOSE_CLASS_CONST( IGNORE );
FORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "DEFAULT_STYLE", UNUM_DEFAULT );
/* workaround for ICU bug */
#if U_ICU_VERSION_MAJOR_NUM == 3 && U_ICU_VERSION_MINOR_NUM < 8
#define UNUM_ROUND_HALFEVEN UNUM_FOUND_HALFEVEN
#endif
// UNumberFormatRoundingMode
FORMATTER_EXPOSE_CLASS_CONST( ROUND_CEILING );
FORMATTER_EXPOSE_CLASS_CONST( ROUND_FLOOR );
FORMATTER_EXPOSE_CLASS_CONST( ROUND_DOWN );
FORMATTER_EXPOSE_CLASS_CONST( ROUND_UP );
FORMATTER_EXPOSE_CLASS_CONST( ROUND_HALFEVEN );
FORMATTER_EXPOSE_CLASS_CONST( ROUND_HALFDOWN );
FORMATTER_EXPOSE_CLASS_CONST( ROUND_HALFUP );
// UNumberFormatPadPosition
FORMATTER_EXPOSE_CLASS_CONST( PAD_BEFORE_PREFIX );
FORMATTER_EXPOSE_CLASS_CONST( PAD_AFTER_PREFIX );
FORMATTER_EXPOSE_CLASS_CONST( PAD_BEFORE_SUFFIX );
FORMATTER_EXPOSE_CLASS_CONST( PAD_AFTER_SUFFIX );
// UNumberFormatAttribute
FORMATTER_EXPOSE_CLASS_CONST( PARSE_INT_ONLY );
FORMATTER_EXPOSE_CLASS_CONST( GROUPING_USED );
FORMATTER_EXPOSE_CLASS_CONST( DECIMAL_ALWAYS_SHOWN );
FORMATTER_EXPOSE_CLASS_CONST( MAX_INTEGER_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( MIN_INTEGER_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( INTEGER_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( MAX_FRACTION_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( MIN_FRACTION_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( FRACTION_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( MULTIPLIER );
FORMATTER_EXPOSE_CLASS_CONST( GROUPING_SIZE );
FORMATTER_EXPOSE_CLASS_CONST( ROUNDING_MODE );
FORMATTER_EXPOSE_CLASS_CONST( ROUNDING_INCREMENT );
FORMATTER_EXPOSE_CLASS_CONST( FORMAT_WIDTH );
FORMATTER_EXPOSE_CLASS_CONST( PADDING_POSITION );
FORMATTER_EXPOSE_CLASS_CONST( SECONDARY_GROUPING_SIZE );
FORMATTER_EXPOSE_CLASS_CONST( SIGNIFICANT_DIGITS_USED );
FORMATTER_EXPOSE_CLASS_CONST( MIN_SIGNIFICANT_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( MAX_SIGNIFICANT_DIGITS );
FORMATTER_EXPOSE_CLASS_CONST( LENIENT_PARSE );
// UNumberFormatTextAttribute
FORMATTER_EXPOSE_CLASS_CONST( POSITIVE_PREFIX );
FORMATTER_EXPOSE_CLASS_CONST( POSITIVE_SUFFIX );
FORMATTER_EXPOSE_CLASS_CONST( NEGATIVE_PREFIX );
FORMATTER_EXPOSE_CLASS_CONST( NEGATIVE_SUFFIX );
FORMATTER_EXPOSE_CLASS_CONST( PADDING_CHARACTER );
FORMATTER_EXPOSE_CLASS_CONST( CURRENCY_CODE );
FORMATTER_EXPOSE_CLASS_CONST( DEFAULT_RULESET );
FORMATTER_EXPOSE_CLASS_CONST( PUBLIC_RULESETS );
// UNumberFormatSymbol
FORMATTER_EXPOSE_CLASS_CONST( DECIMAL_SEPARATOR_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( GROUPING_SEPARATOR_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( PATTERN_SEPARATOR_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( PERCENT_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( ZERO_DIGIT_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( DIGIT_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( MINUS_SIGN_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( PLUS_SIGN_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( CURRENCY_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( INTL_CURRENCY_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( MONETARY_SEPARATOR_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( EXPONENTIAL_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( PERMILL_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( PAD_ESCAPE_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( INFINITY_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( NAN_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( SIGNIFICANT_DIGIT_SYMBOL );
FORMATTER_EXPOSE_CLASS_CONST( MONETARY_GROUPING_SEPARATOR_SYMBOL );
FORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "TYPE_DEFAULT", FORMAT_TYPE_DEFAULT );
FORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "TYPE_INT32", FORMAT_TYPE_INT32 );
FORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "TYPE_INT64", FORMAT_TYPE_INT64 );
FORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "TYPE_DOUBLE", FORMAT_TYPE_DOUBLE );
FORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "TYPE_CURRENCY", FORMAT_TYPE_CURRENCY );
#undef FORMATTER_EXPOSE_CUSTOM_CLASS_CONST
#undef FORMATTER_EXPOSE_CLASS_CONST
#undef FORMATTER_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
*/

24
ext/intl/formatter/formatter.h Executable file
View File

@ -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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_FORMATTER_H
#define FORMATTER_FORMATTER_H
#include <php.h>
void formatter_register_constants( INIT_FUNC_ARGS );
#endif // FORMATTER_FORMATTER_H

View File

@ -0,0 +1,443 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "formatter_class.h"
#include "formatter_attr.h"
#include "intl_convert.h"
#include <unicode/ustring.h>
/* {{{ proto mixed NumberFormatter::getAttribute( int $attr )
* Get formatter attribute value. }}} */
/* {{{ proto mixed numfmt_get_attribute( NumberFormatter $nf, int $attr )
* Get formatter attribute value.
*/
PHP_FUNCTION( numfmt_get_attribute )
{
long attribute, value;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
&object, NumberFormatter_ce_ptr, &attribute ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_attribute: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
switch(attribute) {
case UNUM_PARSE_INT_ONLY:
case UNUM_GROUPING_USED:
case UNUM_DECIMAL_ALWAYS_SHOWN:
case UNUM_MAX_INTEGER_DIGITS:
case UNUM_MIN_INTEGER_DIGITS:
case UNUM_INTEGER_DIGITS:
case UNUM_MAX_FRACTION_DIGITS:
case UNUM_MIN_FRACTION_DIGITS:
case UNUM_FRACTION_DIGITS:
case UNUM_MULTIPLIER:
case UNUM_GROUPING_SIZE:
case UNUM_ROUNDING_MODE:
case UNUM_FORMAT_WIDTH:
case UNUM_PADDING_POSITION:
case UNUM_SECONDARY_GROUPING_SIZE:
case UNUM_SIGNIFICANT_DIGITS_USED:
case UNUM_MIN_SIGNIFICANT_DIGITS:
case UNUM_MAX_SIGNIFICANT_DIGITS:
case UNUM_LENIENT_PARSE:
value = unum_getAttribute(FORMATTER_OBJECT(nfo), attribute);
if(value == -1) {
INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
} else {
RETVAL_LONG(value);
}
break;
case UNUM_ROUNDING_INCREMENT:
{
double value = unum_getDoubleAttribute(FORMATTER_OBJECT(nfo), attribute);
if(value == -1) {
INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
} else {
RETVAL_DOUBLE(value);
}
}
break;
default:
INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
break;
}
INTL_METHOD_CHECK_STATUS( nfo, "Error getting attribute value" );
}
/* }}} */
/* {{{ proto string NumberFormatter::getTextAttribute( int $attr )
* Get formatter attribute value. }}} */
/* {{{ proto string numfmt_get_text_attribute( NumberFormatter $nf, int $attr )
* Get formatter attribute value.
*/
PHP_FUNCTION( numfmt_get_text_attribute )
{
long attribute;
UChar value_buf[64];
int value_buf_size = USIZE( value_buf );
UChar* value = value_buf;
int length = 0;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
&object, NumberFormatter_ce_ptr, &attribute ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_text_attribute: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, value_buf_size, &INTL_DATA_ERROR_CODE(nfo) );
if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= value_buf_size) {
++length; // to avoid U_STRING_NOT_TERMINATED_WARNING
INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
value = eumalloc(length);
length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, length, &INTL_DATA_ERROR_CODE(nfo) );
if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
efree(value);
value = value_buf;
}
}
INTL_METHOD_CHECK_STATUS( nfo, "Error getting attribute value" );
INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
}
/* }}} */
/* {{{ proto bool NumberFormatter::setAttribute( int $attr, mixed $value )
* Get formatter attribute value. }}} */
/* {{{ proto bool numfmt_set_attribute( NumberFormatter $nf, int $attr, mixed $value )
* Get formatter attribute value.
*/
PHP_FUNCTION( numfmt_set_attribute )
{
long attribute;
zval **value;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OlZ",
&object, NumberFormatter_ce_ptr, &attribute, &value ) == FAILURE)
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_set_attribute: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
switch(attribute) {
case UNUM_PARSE_INT_ONLY:
case UNUM_GROUPING_USED:
case UNUM_DECIMAL_ALWAYS_SHOWN:
case UNUM_MAX_INTEGER_DIGITS:
case UNUM_MIN_INTEGER_DIGITS:
case UNUM_INTEGER_DIGITS:
case UNUM_MAX_FRACTION_DIGITS:
case UNUM_MIN_FRACTION_DIGITS:
case UNUM_FRACTION_DIGITS:
case UNUM_MULTIPLIER:
case UNUM_GROUPING_SIZE:
case UNUM_ROUNDING_MODE:
case UNUM_FORMAT_WIDTH:
case UNUM_PADDING_POSITION:
case UNUM_SECONDARY_GROUPING_SIZE:
case UNUM_SIGNIFICANT_DIGITS_USED:
case UNUM_MIN_SIGNIFICANT_DIGITS:
case UNUM_MAX_SIGNIFICANT_DIGITS:
case UNUM_LENIENT_PARSE:
convert_to_long_ex(value);
unum_setAttribute(FORMATTER_OBJECT(nfo), attribute, Z_LVAL_PP(value));
break;
case UNUM_ROUNDING_INCREMENT:
convert_to_double_ex(value);
unum_setDoubleAttribute(FORMATTER_OBJECT(nfo), attribute, Z_DVAL_PP(value));
break;
default:
INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
break;
}
INTL_METHOD_CHECK_STATUS( nfo, "Error setting attribute value" );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto bool NumberFormatter::setTextAttribute( int $attr, string $value )
* Get formatter attribute value. }}} */
/* {{{ proto bool numfmt_set_text_attribute( NumberFormatter $nf, int $attr, string $value )
* Get formatter attribute value.
*/
PHP_FUNCTION( numfmt_set_text_attribute )
{
int slength = 0;
UChar *svalue = NULL;
long attribute;
char *value;
int len;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ols",
&object, NumberFormatter_ce_ptr, &attribute, &value, &len ) == FAILURE)
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_set_text_attribute: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
// Convert given attribute value to UTF-16.
intl_convert_utf8_to_utf16(&svalue, &slength, value, len, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "Error converting attribute value to UTF-16" );
// Actually set new attribute value.
unum_setTextAttribute(FORMATTER_OBJECT(nfo), attribute, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
efree(svalue);
INTL_METHOD_CHECK_STATUS( nfo, "Error setting text attribute" );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string NumberFormatter::getSymbol( int $attr )
* Get formatter symbol value. }}} */
/* {{{ proto string numfmt_get_symbol( NumberFormatter $nf, int $attr )
* Get formatter symbol value.
*/
PHP_FUNCTION( numfmt_get_symbol )
{
long symbol;
UChar value_buf[4];
UChar *value = value_buf;
int length = USIZE(value);
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol",
&object, NumberFormatter_ce_ptr, &symbol ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_symbol: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value_buf, length, &INTL_DATA_ERROR_CODE(nfo));
if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value )) {
++length; // to avoid U_STRING_NOT_TERMINATED_WARNING
INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
value = eumalloc(length);
length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value, length, &INTL_DATA_ERROR_CODE(nfo));
if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
efree(value);
value = value_buf;
}
}
INTL_METHOD_CHECK_STATUS( nfo, "Error getting symbol value" );
INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value_buf != value ) );
}
/* }}} */
/* {{{ proto bool NumberFormatter::setSymbol( int $attr, string $symbol )
* Set formatter symbol value. }}} */
/* {{{ proto bool numfmt_set_symbol( NumberFormatter $nf, int $attr, string $symbol )
* Set formatter symbol value.
*/
PHP_FUNCTION( numfmt_set_symbol )
{
long symbol;
char* value = NULL;
int value_len = 0;
UChar* svalue = 0;
int slength = 0;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ols",
&object, NumberFormatter_ce_ptr, &symbol, &value, &value_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_set_symbol: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
// Convert given symbol to UTF-16.
intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "Error converting symbol value to UTF-16" );
// Actually set the symbol.
unum_setSymbol(FORMATTER_OBJECT(nfo), symbol, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
efree(svalue);
INTL_METHOD_CHECK_STATUS( nfo, "Error setting symbol value" );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string NumberFormatter::getPattern( )
* Get formatter pattern. }}} */
/* {{{ proto string numfmt_get_pattern( NumberFormatter $nf )
* Get formatter pattern.
*/
PHP_FUNCTION( numfmt_get_pattern )
{
UChar value_buf[64];
int length = USIZE( value_buf );
UChar* value = value_buf;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, NumberFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_pattern: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
length = unum_toPattern(FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo));
if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
++length; // to avoid U_STRING_NOT_TERMINATED_WARNING
INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
value = eumalloc(length);
length = unum_toPattern( FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo) );
if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
efree(value);
value = value_buf;
}
}
INTL_METHOD_CHECK_STATUS( nfo, "Error getting formatter pattern" );
INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
}
/* }}} */
/* {{{ proto bool NumberFormatter::setPattern( string $pattern )
* Set formatter pattern. }}} */
/* {{{ proto bool numfmt_set_pattern( NumberFormatter $nf, string $pattern )
* Set formatter pattern.
*/
PHP_FUNCTION( numfmt_set_pattern )
{
char* value = NULL;
int value_len = 0;
int slength = 0;
UChar* svalue = NULL;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
&object, NumberFormatter_ce_ptr, &value, &value_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_set_pattern: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
FORMATTER_METHOD_FETCH_OBJECT;
// Convert given pattern to UTF-16.
intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "Error converting pattern to UTF-16" );
// TODO: add parse error information
unum_applyPattern(FORMATTER_OBJECT(nfo), 0, svalue, slength, NULL, &INTL_DATA_ERROR_CODE(nfo));
efree(svalue);
INTL_METHOD_CHECK_STATUS( nfo, "Error setting pattern value" );
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string NumberFormatter::getLocale([int type])
* Get formatter locale. }}} */
/* {{{ proto string numfmt_get_locale( NumberFormatter $nf[, int type] )
* Get formatter locale.
*/
PHP_FUNCTION( numfmt_get_locale )
{
long type = ULOC_ACTUAL_LOCALE;
char* loc;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l",
&object, NumberFormatter_ce_ptr, &type ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_locale: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
loc = (char *)unum_getLocaleByType(FORMATTER_OBJECT(nfo), type, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "Error getting locale" );
RETURN_STRING(loc, 1);
}
/* }}} */
/*
* 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_ATTR_H
#define FORMATTER_ATTR_H
#include <php.h>
PHP_FUNCTION( numfmt_set_attribute );
PHP_FUNCTION( numfmt_get_attribute );
PHP_FUNCTION( numfmt_set_text_attribute );
PHP_FUNCTION( numfmt_get_text_attribute );
PHP_FUNCTION( numfmt_set_symbol );
PHP_FUNCTION( numfmt_get_symbol );
PHP_FUNCTION( numfmt_set_pattern );
PHP_FUNCTION( numfmt_get_pattern );
PHP_FUNCTION( numfmt_get_locale );
#endif // FORMATTER_ATTR_H

View File

@ -0,0 +1,147 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#include <unicode/unum.h>
#include "formatter_class.h"
#include "php_intl.h"
#include "formatter_data.h"
#include "formatter_format.h"
#include "formatter_parse.h"
#include "formatter_main.h"
#include "formatter_attr.h"
zend_class_entry *NumberFormatter_ce_ptr = NULL;
/////////////////////////////////////////////////////////////////////////////
// Auxiliary functions needed by objects of 'NumberFormatter' class
/////////////////////////////////////////////////////////////////////////////
/* {{{ NumberFormatter_objects_dtor */
static void NumberFormatter_object_dtor(
void *object,
zend_object_handle handle TSRMLS_DC )
{
zend_objects_destroy_object( object, handle TSRMLS_CC );
}
/* }}} */
/* {{{ NumberFormatter_objects_free */
void NumberFormatter_object_free( zend_object *object TSRMLS_DC )
{
NumberFormatter_object* nfo = (NumberFormatter_object*)object;
zend_object_std_dtor( &nfo->zo TSRMLS_CC );
formatter_data_free( &nfo->nf_data TSRMLS_CC );
efree( nfo );
}
/* }}} */
/* {{{ NumberFormatter_object_create */
zend_object_value NumberFormatter_object_create(
zend_class_entry *ce TSRMLS_DC )
{
zend_object_value retval;
NumberFormatter_object* intern;
intern = ecalloc( 1, sizeof(NumberFormatter_object) );
formatter_data_init( &intern->nf_data TSRMLS_CC );
zend_object_std_init( &intern->zo, ce TSRMLS_CC );
retval.handle = zend_objects_store_put(
intern,
NumberFormatter_object_dtor,
(zend_objects_free_object_storage_t)NumberFormatter_object_free,
NULL TSRMLS_CC );
retval.handlers = zend_get_std_object_handlers();
return retval;
}
/* }}} */
/////////////////////////////////////////////////////////////////////////////
// 'NumberFormatter' class registration structures & functions
/////////////////////////////////////////////////////////////////////////////
/* {{{ NumberFormatter_class_functions
* Every 'NumberFormatter' class method has an entry in this table
*/
static ZEND_BEGIN_ARG_INFO_EX( number_parse_arginfo, 0, 0, 1 )
ZEND_ARG_INFO( 0, string )
ZEND_ARG_INFO( 0, type )
ZEND_ARG_INFO( 1, position )
ZEND_END_ARG_INFO()
static ZEND_BEGIN_ARG_INFO_EX( number_parse_currency_arginfo, 0, 0, 2 )
ZEND_ARG_INFO( 0, string )
ZEND_ARG_INFO( 1, currency )
ZEND_ARG_INFO( 1, position )
ZEND_END_ARG_INFO()
static function_entry NumberFormatter_class_functions[] = {
PHP_ME( NumberFormatter, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
ZEND_FENTRY( create, ZEND_FN( numfmt_create ), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
PHP_NAMED_FE( format, ZEND_FN( numfmt_format ), NULL )
PHP_NAMED_FE( parse, ZEND_FN( numfmt_parse ), number_parse_arginfo )
PHP_NAMED_FE( formatCurrency, ZEND_FN( numfmt_format_currency ), NULL )
PHP_NAMED_FE( parseCurrency, ZEND_FN( numfmt_parse_currency ), number_parse_currency_arginfo )
PHP_NAMED_FE( setAttribute, ZEND_FN( numfmt_set_attribute ), NULL )
PHP_NAMED_FE( getAttribute, ZEND_FN( numfmt_get_attribute ), NULL )
PHP_NAMED_FE( setTextAttribute, ZEND_FN( numfmt_set_text_attribute ), NULL )
PHP_NAMED_FE( getTextAttribute, ZEND_FN( numfmt_get_text_attribute ), NULL )
PHP_NAMED_FE( setSymbol, ZEND_FN( numfmt_set_symbol ), NULL )
PHP_NAMED_FE( getSymbol, ZEND_FN( numfmt_get_symbol ), NULL )
PHP_NAMED_FE( setPattern, ZEND_FN( numfmt_set_pattern ), NULL )
PHP_NAMED_FE( getPattern, ZEND_FN( numfmt_get_pattern ), NULL )
PHP_NAMED_FE( getLocale, ZEND_FN( numfmt_get_locale ), NULL )
PHP_NAMED_FE( getErrorCode, ZEND_FN( numfmt_get_error_code ), NULL )
PHP_NAMED_FE( getErrorMessage, ZEND_FN( numfmt_get_error_message ), NULL )
{ NULL, NULL, NULL }
};
/* }}} */
/* {{{ formatter_register_class
* Initialize 'NumberFormatter' class
*/
void formatter_register_class( TSRMLS_D )
{
zend_class_entry ce;
// Create and register 'NumberFormatter' class.
INIT_CLASS_ENTRY( ce, "NumberFormatter", NumberFormatter_class_functions );
ce.create_object = NumberFormatter_object_create;
NumberFormatter_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
// Declare 'NumberFormatter' class properties.
if( !NumberFormatter_ce_ptr )
{
zend_error(E_ERROR, "Failed to register NumberFormatter class");
return;
}
}
/* }}} */
/*
* 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
*/

View File

@ -0,0 +1,41 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_CLASS_H
#define FORMATTER_CLASS_H
#include <php.h>
#include "intl_common.h"
#include "intl_error.h"
#include "intl_data.h"
#include "formatter_data.h"
typedef struct {
zend_object zo;
formatter_data nf_data;
} NumberFormatter_object;
void formatter_register_class( TSRMLS_D );
extern zend_class_entry *NumberFormatter_ce_ptr;
/* Auxiliary macros */
#define FORMATTER_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(NumberFormatter, nfo)
#define FORMATTER_METHOD_FETCH_OBJECT INTL_METHOD_FETCH_OBJECT(NumberFormatter, nfo)
#define FORMATTER_OBJECT(nfo) (nfo)->nf_data.unum
#endif // #ifndef FORMATTER_CLASS_H

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "formatter_data.h"
/* {{{ void formatter_data_init( formatter_data* nf_data )
* Initialize internals of formatter_data.
*/
void formatter_data_init( formatter_data* nf_data TSRMLS_DC )
{
if( !nf_data )
return;
nf_data->unum = NULL;
intl_error_reset( &nf_data->error TSRMLS_CC );
}
/* }}} */
/* {{{ void formatter_data_free( formatter_data* nf_data )
* Clean up mem allocted by internals of formatter_data
*/
void formatter_data_free( formatter_data* nf_data TSRMLS_DC )
{
if( !nf_data )
return;
if( nf_data->unum )
unum_close( nf_data->unum );
nf_data->unum = NULL;
intl_error_reset( &nf_data->error TSRMLS_CC );
}
/* }}} */
/* {{{ formatter_data* formatter_data_create()
* Alloc mem for formatter_data and initialize it with default values.
*/
formatter_data* formatter_data_create( TSRMLS_D )
{
formatter_data* nf_data = ecalloc( 1, sizeof(formatter_data) );
formatter_data_init( nf_data TSRMLS_CC );
return nf_data;
}
/* }}} */
/*
* 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
*/

View File

@ -0,0 +1,38 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_DATA_H
#define FORMATTER_DATA_H
#include <php.h>
#include <unicode/unum.h>
#include "intl_error.h"
typedef struct {
// error hangling
intl_error error;
// formatter handling
UNumberFormat* unum;
} formatter_data;
formatter_data* formatter_data_create( TSRMLS_D );
void formatter_data_init( formatter_data* nf_data TSRMLS_DC );
void formatter_data_free( formatter_data* nf_data TSRMLS_DC );
#endif // FORMATTER_DATA_H

View File

@ -0,0 +1,207 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include "php_intl.h"
#include "formatter_class.h"
#include "formatter_format.h"
#include "intl_convert.h"
/* {{{ proto mixed NumberFormatter::format( mixed $num[, int $type] )
* Format a number. }}} */
/* {{{ proto mixed numfmt_format( NumberFormatter $nf, mixed $num[, int type] )
* Format a number.
*/
PHP_FUNCTION( numfmt_format )
{
zval **number;
long type = FORMAT_TYPE_DEFAULT;
UChar format_buf[32];
UChar* formatted = format_buf;
int formatted_len = USIZE(format_buf);
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OZ|l",
&object, NumberFormatter_ce_ptr, &number, &type ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_format: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
if(type == FORMAT_TYPE_DEFAULT) {
if(Z_TYPE_PP(number) == IS_STRING) {
SEPARATE_ZVAL_IF_NOT_REF(number);
if ((Z_TYPE_PP(number)=is_numeric_string(Z_STRVAL_PP(number), Z_STRLEN_PP(number),
&Z_LVAL_PP(number), &Z_DVAL_PP(number), 1)) == 0) {
ZVAL_LONG(*number, 0);
}
}
if(Z_TYPE_PP(number) == IS_LONG) {
// take INT32 on 32-bit, int64 on 64-bit
type = (sizeof(long) == 8)?FORMAT_TYPE_INT64:FORMAT_TYPE_INT32;
} else if(Z_TYPE_PP(number) == IS_DOUBLE) {
type = FORMAT_TYPE_DOUBLE;
} else {
type = FORMAT_TYPE_INT32;
}
}
if(Z_TYPE_PP(number) != IS_DOUBLE && Z_TYPE_PP(number) != IS_LONG) {
SEPARATE_ZVAL_IF_NOT_REF(number);
convert_scalar_to_number( *number TSRMLS_CC );
}
switch(type) {
case FORMAT_TYPE_INT32:
convert_to_long_ex(number);
formatted_len = unum_format(FORMATTER_OBJECT(nfo), (int32_t)Z_LVAL_PP(number),
formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) {
intl_error_reset(INTL_DATA_ERROR_P(nfo) TSRMLS_CC);
formatted = eumalloc(formatted_len);
formatted_len = unum_format(FORMATTER_OBJECT(nfo), (int32_t)Z_LVAL_PP(number),
formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
if (U_FAILURE( INTL_DATA_ERROR_CODE(nfo) ) ) {
efree(formatted);
}
}
INTL_METHOD_CHECK_STATUS( nfo, "Number formatting failed" );
break;
case FORMAT_TYPE_INT64:
{
int64_t value = (Z_TYPE_PP(number) == IS_DOUBLE)?(int64_t)Z_DVAL_PP(number):Z_LVAL_PP(number);
formatted_len = unum_formatInt64(FORMATTER_OBJECT(nfo), value, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) {
intl_error_reset(INTL_DATA_ERROR_P(nfo) TSRMLS_CC);
formatted = eumalloc(formatted_len);
formatted_len = unum_formatInt64(FORMATTER_OBJECT(nfo), value, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
if (U_FAILURE( INTL_DATA_ERROR_CODE(nfo) ) ) {
efree(formatted);
}
}
INTL_METHOD_CHECK_STATUS( nfo, "Number formatting failed" );
}
break;
case FORMAT_TYPE_DOUBLE:
convert_to_double_ex(number);
formatted_len = unum_formatDouble(FORMATTER_OBJECT(nfo), Z_DVAL_PP(number), formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) {
intl_error_reset(INTL_DATA_ERROR_P(nfo) TSRMLS_CC);
formatted = eumalloc(formatted_len);
unum_formatDouble(FORMATTER_OBJECT(nfo), Z_DVAL_PP(number), formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
if (U_FAILURE( INTL_DATA_ERROR_CODE(nfo) ) ) {
efree(formatted);
}
}
INTL_METHOD_CHECK_STATUS( nfo, "Number formatting failed" );
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported format type %ld", type);
RETURN_FALSE;
break;
}
INTL_METHOD_RETVAL_UTF8( nfo, formatted, formatted_len, ( formatted != format_buf ) );
}
/* }}} */
/* {{{ proto mixed NumberFormatter::formatCurrency( double $num, string $currency )
* Format a number as currency. }}} */
/* {{{ proto mixed numfmt_format_currency( NumberFormatter $nf, double $num, string $currency )
* Format a number as currency.
*/
PHP_FUNCTION( numfmt_format_currency )
{
double number;
UChar format_buf[32];
UChar* formatted = format_buf;
int formatted_len = USIZE(format_buf);
char* currency = NULL;
int currency_len = 0;
UChar* scurrency = NULL;
int scurrency_len = 0;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ods",
&object, NumberFormatter_ce_ptr, &number, &currency, &currency_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_format_currency: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
// Convert currency to UTF-16.
intl_convert_utf8_to_utf16(&scurrency, &scurrency_len, currency, currency_len, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "Currency conversion to UTF-16 failed" );
// Format the number using a fixed-length buffer.
formatted_len = unum_formatDoubleCurrency(FORMATTER_OBJECT(nfo), number, scurrency, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
// If the buffer turned out to be too small
// then allocate another buffer dynamically
// and use it to format the number.
if (INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR) {
intl_error_reset(INTL_DATA_ERROR_P(nfo) TSRMLS_CC);
formatted = eumalloc(formatted_len);
unum_formatDoubleCurrency(FORMATTER_OBJECT(nfo), number, scurrency, formatted, formatted_len, NULL, &INTL_DATA_ERROR_CODE(nfo));
}
if( U_FAILURE( INTL_DATA_ERROR_CODE((nfo)) ) ) {
intl_error_set_code( NULL, INTL_DATA_ERROR_CODE((nfo)) TSRMLS_CC );
intl_errors_set_custom_msg( INTL_DATA_ERROR_P(nfo), "Number formatting failed", 0 TSRMLS_CC );
RETVAL_FALSE;
if (formatted != format_buf) {
efree(formatted);
}
} else {
INTL_METHOD_RETVAL_UTF8( nfo, formatted, formatted_len, ( formatted != format_buf ) );
}
if(scurrency) {
efree(scurrency);
}
}
/* }}} */
/*
* 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
*/

View File

@ -0,0 +1,31 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_FORMAT_H
#define FORMATTER_FORMAT_H
#include <php.h>
PHP_FUNCTION( numfmt_format );
PHP_FUNCTION( numfmt_format_currency );
#define FORMAT_TYPE_DEFAULT 0
#define FORMAT_TYPE_INT32 1
#define FORMAT_TYPE_INT64 2
#define FORMAT_TYPE_DOUBLE 3
#define FORMAT_TYPE_CURRENCY 4
#endif // FORMATTER_FORMAT_H

View File

@ -0,0 +1,220 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include "php_intl.h"
#include "formatter_class.h"
#include "intl_convert.h"
/* {{{ proto NumberFormatter NumberFormatter::create( string $locale, int style[, string $pattern ] )
* Create formatter. }}} */
/* {{{ proto NumberFormatter numfmt_create( string $locale, int style[, string $pattern ] )
* Create formatter.
*/
PHP_FUNCTION( numfmt_create )
{
char* locale;
char* pattern = NULL;
int locale_len = 0, pattern_len = 0;
long style;
UChar* spattern = NULL;
int spattern_len = 0;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sl|s",
&locale, &locale_len, &style, &pattern, &pattern_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_create: unable to parse input parameters", 0 TSRMLS_CC );
RETURN_NULL();
}
INTL_CHECK_LOCALE_LEN(locale_len);
// Create a NumberFormatter 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, NumberFormatter_ce_ptr );
FORMATTER_METHOD_FETCH_OBJECT;
// Convert pattern (if specified) to UTF-16.
if(pattern && pattern_len) {
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo));
if( U_FAILURE( INTL_DATA_ERROR_CODE((nfo)) ) )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_create: error converting pattern to UTF-16", 0 TSRMLS_CC );
zval_dtor(return_value);
RETURN_NULL();
}
}
if(locale_len == 0) {
locale = INTL_G(default_locale);
}
// Create an ICU number formatter.
FORMATTER_OBJECT(nfo) = unum_open(style, spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(nfo));
if(spattern) {
efree(spattern);
}
if( U_FAILURE( INTL_DATA_ERROR_CODE((nfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE( nfo ),
"numfmt_create: number formatter creation failed", 0 TSRMLS_CC );
zval_dtor(return_value);
RETURN_NULL();
}
}
/* }}} */
/* {{{ proto void NumberFormatter::__construct( string $locale, int style[, string $pattern ] )
* NumberFormatter object constructor.
*/
PHP_METHOD( NumberFormatter, __construct )
{
char* locale;
char* pattern = NULL;
int locale_len = 0, pattern_len = 0;
long style;
UChar* spattern = NULL;
int spattern_len = 0;
FORMATTER_METHOD_INIT_VARS;
object = getThis();
// Parse parameters.
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sl|s",
&locale, &locale_len, &style, &pattern, &pattern_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);
FORMATTER_METHOD_FETCH_OBJECT;
// Convert pattern (if specified) to UTF-16.
if(pattern && pattern_len) {
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo));
if( U_FAILURE( INTL_DATA_ERROR_CODE((nfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE( nfo ),
"__construct: Error converting pattern to UTF-16", 0 TSRMLS_CC );
zval_dtor(object);
ZVAL_NULL(object);
RETURN_NULL();
}
}
if(locale_len == 0) {
locale = INTL_G(default_locale);
}
// Create an ICU number formatter.
FORMATTER_OBJECT(nfo) = unum_open(style, spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(nfo));
if(spattern) {
efree(spattern);
}
if( U_FAILURE( INTL_DATA_ERROR_CODE((nfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE( nfo ),
"__construct: number formatter creation failed", 0 TSRMLS_CC );
zval_dtor(object);
ZVAL_NULL(object);
RETURN_NULL();
}
}
/* }}} */
/* {{{ proto int NumberFormatter::getErrorCode()
* Get formatter's last error code. }}} */
/* {{{ proto int numfmt_get_error_code( NumberFormatter $nf )
* Get formatter's last error code.
*/
PHP_FUNCTION( numfmt_get_error_code )
{
FORMATTER_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, NumberFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_error_code: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
nfo = (NumberFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
// Return formatter's last error code.
RETURN_LONG( INTL_DATA_ERROR_CODE(nfo) );
}
/* }}} */
/* {{{ proto string NumberFormatter::getErrorMessage( )
* Get text description for formatter's last error code. }}} */
/* {{{ proto string numfmt_get_error_message( NumberFormatter $nf )
* Get text description for formatter's last error code.
*/
PHP_FUNCTION( numfmt_get_error_message )
{
char* message = NULL;
FORMATTER_METHOD_INIT_VARS
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, NumberFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"numfmt_get_error_message: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
nfo = (NumberFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
// Return last error message.
message = intl_error_get_message( &INTL_DATA_ERROR(nfo) TSRMLS_CC );
RETURN_STRING( message, 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_MAIN_H
#define FORMATTER_MAIN_H
#include <php.h>
PHP_FUNCTION( numfmt_create );
PHP_FUNCTION( numfmt_get_error_code );
PHP_FUNCTION( numfmt_get_error_message );
PHP_METHOD( NumberFormatter, __construct );
#endif // FORMATTER_FORMAT_H

View File

@ -0,0 +1,173 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include "php_intl.h"
#include "formatter_class.h"
#include "formatter_format.h"
#include "formatter_parse.h"
#include "intl_convert.h"
/* {{{ proto mixed NumberFormatter::parse( string $str[, int $type, int &$position ])
* Parse a number. }}} */
/* {{{ proto mixed numfmt_parse( NumberFormatter $nf, string $str[, int $type, int &$position ])
* Parse a number.
*/
PHP_FUNCTION( numfmt_parse )
{
long type = FORMAT_TYPE_DOUBLE;
UChar* sstr = NULL;
int sstr_len = 0;
char* str = NULL;
int str_len;
int32_t val32, position = 0;
int64_t val64;
double val_double;
int32_t* position_p = NULL;
zval *zposition = NULL;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|lz!",
&object, NumberFormatter_ce_ptr, &str, &str_len, &type, &zposition ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"number_parse: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
// Convert given string to UTF-16.
intl_convert_utf8_to_utf16(&sstr, &sstr_len, str, str_len, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" );
if(zposition) {
convert_to_long(zposition);
position = (int32_t)Z_LVAL_P( zposition );
position_p = &position;
}
switch(type) {
case FORMAT_TYPE_INT32:
val32 = unum_parse(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, &INTL_DATA_ERROR_CODE(nfo));
RETVAL_LONG(val32);
break;
case FORMAT_TYPE_INT64:
val64 = unum_parseInt64(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, &INTL_DATA_ERROR_CODE(nfo));
if(val64 > LONG_MAX || val64 < -LONG_MAX) {
RETVAL_DOUBLE(val64);
} else {
val32 = (int32_t)val64;
RETVAL_LONG(val32);
}
break;
case FORMAT_TYPE_DOUBLE:
val_double = unum_parseDouble(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, &INTL_DATA_ERROR_CODE(nfo));
RETVAL_DOUBLE(val_double);
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported format type %ld", type);
RETVAL_FALSE;
break;
}
if(zposition) {
zval_dtor(zposition);
ZVAL_LONG(zposition, position);
}
efree(sstr);
INTL_METHOD_CHECK_STATUS( nfo, "Number parsing failed" );
}
/* }}} */
/* {{{ proto double NumberFormatter::parseCurrency( string $str, string $&currency[, int $&position] )
* Parse a number as currency. }}} */
/* {{{ proto double numfmt_parse_currency( NumberFormatter $nf, string $str, string $&currency[, int $&position] )
* Parse a number as currency.
*/
PHP_FUNCTION( numfmt_parse_currency )
{
double number;
UChar currency[5] = {0};
UChar* sstr = NULL;
int sstr_len = 0;
char *currency_str = NULL;
int currency_len = 0;
char *str;
int str_len;
int32_t* position_p = NULL;
int32_t position = 0;
zval *zcurrency, *zposition = NULL;
FORMATTER_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osz|z!",
&object, NumberFormatter_ce_ptr, &str, &str_len, &zcurrency, &zposition ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"number_parse_currency: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
FORMATTER_METHOD_FETCH_OBJECT;
// Convert given string to UTF-16.
intl_convert_utf8_to_utf16(&sstr, &sstr_len, str, str_len, &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" );
if(zposition) {
convert_to_long(zposition);
position = (int32_t)Z_LVAL_P( zposition );
position_p = &position;
}
number = unum_parseDoubleCurrency(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, currency, &INTL_DATA_ERROR_CODE(nfo));
if(zposition) {
zval_dtor(zposition);
ZVAL_LONG(zposition, position);
}
efree(sstr);
INTL_METHOD_CHECK_STATUS( nfo, "Number parsing failed" );
// Convert parsed currency to UTF-8 and pass it back to caller.
intl_convert_utf16_to_utf8(&currency_str, &currency_len, currency, u_strlen(currency), &INTL_DATA_ERROR_CODE(nfo));
INTL_METHOD_CHECK_STATUS( nfo, "Currency conversion to UTF-8 failed" );
zval_dtor( zcurrency );
ZVAL_STRINGL(zcurrency, currency_str, currency_len, 0);
RETVAL_DOUBLE( number );
}
/* }}} */
/*
* 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef FORMATTER_PARSE_H
#define FORMATTER_PARSE_H
#include <php.h>
PHP_FUNCTION( numfmt_parse );
PHP_FUNCTION( numfmt_parse_currency );
#endif // FORMATTER_PARSE_H

37
ext/intl/grapheme/grapheme.h Executable file
View File

@ -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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifndef GRAPHEME_GRAPHEME_H
#define GRAPHEME_GRAPHEME_H
#include <php.h>
#include <unicode/utypes.h>
#include <unicode/ubrk.h>
PHP_FUNCTION(grapheme_strlen);
PHP_FUNCTION(grapheme_strpos);
PHP_FUNCTION(grapheme_stripos);
PHP_FUNCTION(grapheme_strrpos);
PHP_FUNCTION(grapheme_strripos);
PHP_FUNCTION(grapheme_substr);
PHP_FUNCTION(grapheme_strstr);
PHP_FUNCTION(grapheme_stristr);
PHP_FUNCTION(grapheme_extract);
void grapheme_register_constants( INIT_FUNC_ARGS );
void grapheme_close_global_iterator( TSRMLS_D );
#endif // GRAPHEME_GRAPHEME_H

View File

@ -0,0 +1,913 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
/* {{{ includes */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include "grapheme.h"
#include "grapheme_util.h"
#include <unicode/utypes.h>
#include <unicode/ucol.h>
#include <unicode/ustring.h>
#include <unicode/ubrk.h>
#include "ext/standard/php_string.h"
/* }}} */
#define GRAPHEME_EXTRACT_TYPE_COUNT 0
#define GRAPHEME_EXTRACT_TYPE_MAXBYTES 1
#define GRAPHEME_EXTRACT_TYPE_MAXCHARS 2
#define GRAPHEME_EXTRACT_TYPE_MIN GRAPHEME_EXTRACT_TYPE_COUNT
#define GRAPHEME_EXTRACT_TYPE_MAX GRAPHEME_EXTRACT_TYPE_MAXCHARS
/* {{{ grapheme_register_constants
* Register API constants
*/
void grapheme_register_constants( INIT_FUNC_ARGS )
{
REGISTER_LONG_CONSTANT("GRAPHEME_EXTR_COUNT", GRAPHEME_EXTRACT_TYPE_COUNT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("GRAPHEME_EXTR_MAXBYTES", GRAPHEME_EXTRACT_TYPE_MAXBYTES, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("GRAPHEME_EXTR_MAXCHARS", GRAPHEME_EXTRACT_TYPE_MAXCHARS, CONST_CS | CONST_PERSISTENT);
}
/* }}} */
/* {{{ proto int grapheme_strlen(string str)
Get number of graphemes in a string */
PHP_FUNCTION(grapheme_strlen)
{
unsigned char* string;
int string_len;
UChar* ustring = NULL;
int ustring_len = 0;
int ret_len;
UErrorCode status;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", (char **)&string, &string_len) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_strlen: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
ret_len = grapheme_ascii_check(string, string_len);
if ( ret_len >= 0 )
RETURN_LONG(ret_len);
/* convert the string to UTF-16. */
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&ustring, &ustring_len, (char*) string, string_len, &status );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( ustring );
RETURN_NULL();
}
ret_len = grapheme_split_string(ustring, ustring_len, NULL, 0 TSRMLS_CC );
efree( ustring );
if (ret_len >= 0) {
RETVAL_LONG(ret_len);
} else {
RETVAL_FALSE;
}
}
/* }}} */
/* {{{ proto int grapheme_strpos(string haystack, string needle [, int offset ])
Find position of first occurrence of a string within another */
PHP_FUNCTION(grapheme_strpos)
{
unsigned char *haystack, *needle;
int haystack_len, needle_len;
unsigned char *found;
long loffset = 0;
int32_t offset = 0;
int ret_pos, uchar_pos;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", (char **)&haystack, &haystack_len, (char **)&needle, &needle_len, &loffset) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_strpos: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( OUTSIDE_STRING(loffset, haystack_len) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Offset not contained in string", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* we checked that it will fit: */
offset = (int32_t) loffset;
/* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */
if (needle_len == 0) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Empty delimiter", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* quick check to see if the string might be there
* I realize that 'offset' is 'grapheme count offset' but will work in spite of that
*/
found = (unsigned char *)php_memnstr((char *)haystack + offset, (char *)needle, needle_len, (char *)haystack + haystack_len);
/* if it isn't there the we are done */
if (!found) {
RETURN_FALSE;
}
/* if it is there, and if the haystack is ascii, we are all done */
if ( grapheme_ascii_check(haystack, haystack_len) >= 0 ) {
RETURN_LONG(found - haystack);
}
/* do utf16 part of the strpos */
ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, &uchar_pos, 0 /* fIgnoreCase */ TSRMLS_CC );
if ( ret_pos >= 0 ) {
RETURN_LONG(ret_pos + offset);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int grapheme_stripos(string haystack, string needle [, int offset ])
Find position of first occurrence of a string within another, ignoring case differences */
PHP_FUNCTION(grapheme_stripos)
{
unsigned char *haystack, *needle, *haystack_dup, *needle_dup;
int haystack_len, needle_len;
unsigned char *found;
long loffset = 0;
int32_t offset = 0;
int ret_pos, uchar_pos;
int is_ascii;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", (char **)&haystack, &haystack_len, (char **)&needle, &needle_len, &loffset) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_stripos: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( OUTSIDE_STRING(loffset, haystack_len) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_stripos: Offset not contained in string", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* we checked that it will fit: */
offset = (int32_t) loffset;
/* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */
if (needle_len == 0) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_stripos: Empty delimiter", 1 TSRMLS_CC );
RETURN_FALSE;
}
is_ascii = ( grapheme_ascii_check(haystack, haystack_len) >= 0 );
if ( is_ascii ) {
needle_dup = (unsigned char *)estrndup((char *)needle, needle_len);
php_strtolower((char *)needle_dup, needle_len);
haystack_dup = (unsigned char *)estrndup((char *)haystack, haystack_len);
php_strtolower((char *)haystack_dup, haystack_len);
found = (unsigned char*) php_memnstr((char *)haystack_dup + offset, (char *)needle_dup, needle_len, (char *)haystack_dup + haystack_len);
efree(haystack_dup);
efree(needle_dup);
if (found) {
RETURN_LONG(found - haystack_dup);
}
/* if needle was ascii too, we are all done, otherwise we need to try using Unicode to see what we get */
if ( grapheme_ascii_check(needle, needle_len) >= 0 ) {
RETURN_FALSE;
}
}
/* do utf16 part of the strpos */
ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, offset, &uchar_pos, 1 /* fIgnoreCase */ TSRMLS_CC );
if ( ret_pos >= 0 ) {
RETURN_LONG(ret_pos + offset);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int grapheme_strrpos(string haystack, string needle [, int offset])
Find position of last occurrence of a string within another */
PHP_FUNCTION(grapheme_strrpos)
{
unsigned char *haystack, *needle;
int haystack_len, needle_len;
long loffset = 0;
int32_t offset = 0;
int32_t ret_pos;
int is_ascii;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", (char **)&haystack, &haystack_len, (char **)&needle, &needle_len, &loffset) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_strrpos: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( OUTSIDE_STRING(loffset, haystack_len) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Offset not contained in string", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* we checked that it will fit: */
offset = (int32_t) loffset;
/* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */
if (needle_len == 0) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Empty delimiter", 1 TSRMLS_CC );
RETURN_FALSE;
}
is_ascii = grapheme_ascii_check(haystack, haystack_len) >= 0;
if ( is_ascii ) {
ret_pos = grapheme_strrpos_ascii(haystack, haystack_len, needle, needle_len, offset);
if ( ret_pos >= 0 ) {
RETURN_LONG(ret_pos);
}
/* if the needle was ascii too, we are done */
if ( grapheme_ascii_check(needle, needle_len) >= 0 ) {
RETURN_FALSE;
}
/* else we need to continue via utf16 */
}
ret_pos = grapheme_strrpos_utf16(haystack, haystack_len, needle, needle_len, offset, 0 /* f_ignore_case */ TSRMLS_CC);
if ( ret_pos >= 0 ) {
RETURN_LONG(ret_pos);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int grapheme_strripos(string haystack, string needle [, int offset])
Find position of last occurrence of a string within another, ignoring case */
PHP_FUNCTION(grapheme_strripos)
{
unsigned char *haystack, *needle;
int haystack_len, needle_len;
long loffset = 0;
int32_t offset = 0;
int32_t ret_pos;
int is_ascii;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", (char **)&haystack, &haystack_len, (char **)&needle, &needle_len, &loffset) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_strrpos: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( OUTSIDE_STRING(loffset, haystack_len) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Offset not contained in string", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* we checked that it will fit: */
offset = (int32_t) loffset;
/* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */
if (needle_len == 0) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Empty delimiter", 1 TSRMLS_CC );
RETURN_FALSE;
}
is_ascii = grapheme_ascii_check(haystack, haystack_len) >= 0;
if ( is_ascii ) {
unsigned char *needle_dup, *haystack_dup;
needle_dup = (unsigned char *)estrndup((char *)needle, needle_len);
php_strtolower((char *)needle_dup, needle_len);
haystack_dup = (unsigned char *)estrndup((char *)haystack, haystack_len);
php_strtolower((char *)haystack_dup, haystack_len);
ret_pos = grapheme_strrpos_ascii(haystack_dup, haystack_len, needle_dup, needle_len, offset);
efree(haystack_dup);
efree(needle_dup);
if ( ret_pos >= 0 ) {
RETURN_LONG(ret_pos);
}
/* if the needle was ascii too, we are done */
if ( grapheme_ascii_check(needle, needle_len) >= 0 ) {
RETURN_FALSE;
}
/* else we need to continue via utf16 */
}
ret_pos = grapheme_strrpos_utf16(haystack, haystack_len, needle, needle_len, offset, 1 /* f_ignore_case */ TSRMLS_CC);
if ( ret_pos >= 0 ) {
RETURN_LONG(ret_pos);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string grapheme_substr(string str, int start [, int length])
Returns part of a string */
PHP_FUNCTION(grapheme_substr)
{
unsigned char *str, *sub_str;
UChar *ustr;
int str_len, sub_str_len, ustr_len;
long lstart = 0, length = 0;
int32_t start = 0;
int iter_val;
UErrorCode status;
unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
UBreakIterator* bi = NULL;
int sub_str_start_pos, sub_str_end_pos;
int32_t (*iter_func)(UBreakIterator *);
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", (char **)&str, &str_len, &lstart, &length) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_substr: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( OUTSIDE_STRING(lstart, str_len) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_substr: start not contained in string", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* we checked that it will fit: */
start = (int32_t) lstart;
/* the offset is 'grapheme count offset' so it still might be invalid - we'll check it later */
if ( grapheme_ascii_check(str, str_len) >= 0 ) {
grapheme_substr_ascii((char *)str, str_len, start, length, ZEND_NUM_ARGS(), (char **) &sub_str, &sub_str_len);
if ( NULL == sub_str ) {
RETURN_FALSE;
}
RETURN_STRINGL(((char *)sub_str), sub_str_len, 1);
}
ustr = NULL;
ustr_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&ustr, &ustr_len, (char *)str, str_len, &status);
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( ustr );
RETURN_FALSE;
}
bi = grapheme_get_break_iterator((void*)u_break_iterator_buffer, &status TSRMLS_CC );
if( U_FAILURE(status) ) {
RETURN_FALSE;
}
ubrk_setText(bi, ustr, ustr_len, &status);
if ( start < 0 ) {
iter_func = ubrk_previous;
ubrk_last(bi);
iter_val = 1;
}
else {
iter_func = ubrk_next;
iter_val = -1;
}
sub_str_start_pos = 0;
while ( start ) {
sub_str_start_pos = iter_func(bi);
if ( UBRK_DONE == sub_str_start_pos ) {
break;
}
start += iter_val;
}
if ( 0 != start || sub_str_start_pos >= ustr_len ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_substr: start not contained in string", 1 TSRMLS_CC );
efree(ustr);
ubrk_close(bi);
RETURN_FALSE;
}
if (ZEND_NUM_ARGS() <= 2) {
/* no length supplied, return the rest of the string */
sub_str = NULL;
sub_str_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf16_to_utf8((char **)&sub_str, &sub_str_len, ustr + sub_str_start_pos, ustr_len - sub_str_start_pos, &status);
efree( ustr );
ubrk_close( bi );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting output string to UTF-8", 1 TSRMLS_CC );
efree( sub_str );
RETURN_FALSE;
}
/* return the allocated string, not a duplicate */
RETURN_STRINGL(((char *)sub_str), sub_str_len, 0);
}
/* find the end point of the string to return */
if ( length < 0 ) {
iter_func = ubrk_previous;
ubrk_last(bi);
iter_val = 1;
}
else {
iter_func = ubrk_next;
iter_val = -1;
}
sub_str_end_pos = 0;
while ( length ) {
sub_str_end_pos = iter_func(bi);
if ( UBRK_DONE == sub_str_end_pos ) {
break;
}
length += iter_val;
}
if ( UBRK_DONE == sub_str_end_pos ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_substr: length not contained in string", 1 TSRMLS_CC );
efree(ustr);
ubrk_close(bi);
RETURN_FALSE;
}
sub_str = NULL;
status = U_ZERO_ERROR;
intl_convert_utf16_to_utf8((char **)&sub_str, &sub_str_len, ustr + sub_str_start_pos, ( sub_str_end_pos - sub_str_start_pos ), &status);
efree( ustr );
ubrk_close( bi );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting output string to UTF-8", 1 TSRMLS_CC );
if ( NULL != sub_str )
efree( sub_str );
RETURN_FALSE;
}
/* return the allocated string, not a duplicate */
RETURN_STRINGL(((char *)sub_str), sub_str_len, 0);
}
/* }}} */
/* {{{ strstr_common_handler */
static void strstr_common_handler(INTERNAL_FUNCTION_PARAMETERS, int f_ignore_case)
{
unsigned char *haystack, *needle, *found;
int haystack_len, needle_len;
int ret_pos, uchar_pos;
zend_bool part = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", (char **)&haystack, &haystack_len, (char **)&needle, &needle_len, &part) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_strstr: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if (needle_len == 0) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Empty delimiter", 1 TSRMLS_CC );
RETURN_FALSE;
}
if ( !f_ignore_case ) {
/* ASCII optimization: quick check to see if the string might be there
* I realize that 'offset' is 'grapheme count offset' but will work in spite of that
*/
found = (unsigned char *)php_memnstr((char *)haystack, (char *)needle, needle_len, (char *)haystack + haystack_len);
/* if it isn't there the we are done */
if ( !found ) {
RETURN_FALSE;
}
/* if it is there, and if the haystack is ascii, we are all done */
if ( grapheme_ascii_check(haystack, haystack_len) >= 0 ) {
size_t found_offset = found - haystack;
if (part) {
RETURN_STRINGL(((char *)haystack) , found_offset, 1);
} else {
RETURN_STRINGL(((char *)found), haystack_len - found_offset, 1);
}
}
}
/* need to work in utf16 */
ret_pos = grapheme_strpos_utf16(haystack, haystack_len, needle, needle_len, 0, &uchar_pos, f_ignore_case TSRMLS_CC );
if ( ret_pos < 0 ) {
RETURN_FALSE;
}
/* uchar_pos is the 'nth' Unicode character position of the needle */
ret_pos = 0;
U8_FWD_N(haystack, ret_pos, haystack_len, uchar_pos);
if (part) {
RETURN_STRINGL(((char *)haystack), ret_pos, 1);
}
else {
RETURN_STRINGL(((char *)haystack) + ret_pos, haystack_len - ret_pos, 1);
}
}
/* }}} */
/* {{{ proto string grapheme_strstr(string haystack, string needle[, bool part])
Finds first occurrence of a string within another */
PHP_FUNCTION(grapheme_strstr)
{
strstr_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0 /* f_ignore_case */);
}
/* }}} */
/* {{{ proto string grapheme_stristr(string haystack, string needle[, bool part])
Finds first occurrence of a string within another */
PHP_FUNCTION(grapheme_stristr)
{
strstr_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1 /* f_ignore_case */);
}
/* }}} */
/* {{{ grapheme_extract_charcount_iter - grapheme iterator for grapheme_extract MAXCHARS */
inline int32_t
grapheme_extract_charcount_iter(UBreakIterator *bi, int32_t csize, unsigned char *pstr, int32_t str_len)
{
int pos = 0, prev_pos = 0;
int ret_pos = 0, prev_ret_pos = 0;
while ( 1 ) {
pos = ubrk_next(bi);
if ( UBRK_DONE == pos ) {
break;
}
/* if we are beyond our limit, then the loop is done */
if ( pos > csize ) {
break;
}
/* update our pointer in the original UTF-8 buffer by as many characters
as ubrk_next iterated over */
prev_ret_pos = ret_pos;
U8_FWD_N(pstr, ret_pos, str_len, pos - prev_pos);
if ( prev_ret_pos == ret_pos ) {
/* something wrong - malformed utf8? */
break;
}
prev_pos = pos;
}
return ret_pos;
}
/* }}} */
/* {{{ grapheme_extract_bytecount_iter - grapheme iterator for grapheme_extract MAXBYTES */
inline int32_t
grapheme_extract_bytecount_iter(UBreakIterator *bi, int32_t bsize, unsigned char *pstr, int32_t str_len)
{
int pos = 0, prev_pos = 0;
int ret_pos = 0, prev_ret_pos = 0;
while ( 1 ) {
pos = ubrk_next(bi);
if ( UBRK_DONE == pos ) {
break;
}
prev_ret_pos = ret_pos;
U8_FWD_N(pstr, ret_pos, str_len, pos - prev_pos);
if ( ret_pos > bsize ) {
ret_pos = prev_ret_pos;
break;
}
if ( prev_ret_pos == ret_pos ) {
/* something wrong - malformed utf8? */
break;
}
prev_pos = pos;
}
return ret_pos;
}
/* }}} */
/* {{{ grapheme_extract_count_iter - grapheme iterator for grapheme_extract COUNT */
inline int32_t
grapheme_extract_count_iter(UBreakIterator *bi, int32_t size, unsigned char *pstr, int32_t str_len)
{
int pos = 0, next_pos = 0;
int ret_pos = 0;
while ( size ) {
next_pos = ubrk_next(bi);
if ( UBRK_DONE == next_pos ) {
break;
}
pos = next_pos;
size--;
}
/* pos is one past the last UChar - and represent the number of code units to
advance in the utf-8 buffer
*/
U8_FWD_N(pstr, ret_pos, str_len, pos);
return ret_pos;
}
/* }}} */
/* {{{ grapheme extract iter function pointer array */
typedef int32_t (*grapheme_extract_iter)(UBreakIterator * /*bi*/, int32_t /*size*/, unsigned char * /*pstr*/, int32_t /*str_len*/);
static grapheme_extract_iter grapheme_extract_iters[] = {
&grapheme_extract_count_iter,
&grapheme_extract_bytecount_iter,
&grapheme_extract_charcount_iter,
};
/* }}} */
/* {{{ proto string grapheme_extract(string str, int size[, int extract_type[, int start[, int next]]])
Function to extract a sequence of default grapheme clusters */
PHP_FUNCTION(grapheme_extract)
{
unsigned char *str, *pstr;
UChar *ustr;
int str_len, ustr_len;
long size; /* maximum number of grapheme clusters, bytes, or characters (based on extract_type) to return */
long lstart = 0; /* starting position in str in bytes */
int32_t start = 0;
long extract_type = GRAPHEME_EXTRACT_TYPE_COUNT;
UErrorCode status;
unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
UBreakIterator* bi = NULL;
int ret_pos;
zval *next = NULL; // return offset of next part of the string
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|llz", (char **)&str, &str_len, &size, &extract_type, &lstart, &next) == FAILURE) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_extract: unable to parse input param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( NULL != next ) {
if ( !PZVAL_IS_REF(next) ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_extract: 'next' was not passed by reference", 0 TSRMLS_CC );
RETURN_FALSE;
}
else {
/* initialize next */
ZVAL_LONG(next, start);
}
}
if ( extract_type < GRAPHEME_EXTRACT_TYPE_MIN || extract_type > GRAPHEME_EXTRACT_TYPE_MAX ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_extract: unknown extract type param", 0 TSRMLS_CC );
RETURN_FALSE;
}
if ( lstart > INT32_MAX || lstart < 0 || lstart >= str_len ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_extract: start not contained in string", 1 TSRMLS_CC );
RETURN_FALSE;
}
/* we checked that it will fit: */
start = (int32_t) lstart;
pstr = str + start;
/* just in case pstr points in the middle of a character, move forward to the start of the next char */
if ( !UTF8_IS_SINGLE(*pstr) && !U8_IS_LEAD(*pstr) ) {
unsigned char *str_end = str + str_len;
while ( !UTF8_IS_SINGLE(*pstr) && !U8_IS_LEAD(*pstr) ) {
pstr++;
if ( pstr >= str_end ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"grapheme_extract: invalid input string", 0 TSRMLS_CC );
RETURN_FALSE;
}
}
}
str_len -= (pstr - str);
/* if the string is all ASCII up to size+1 - or str_len whichever is first - then we are done.
(size + 1 because the size-th character might be the beginning of a grapheme cluster)
*/
if ( -1 != grapheme_ascii_check(pstr, size + 1 < str_len ? size + 1 : str_len ) ) {
if ( NULL != next ) {
ZVAL_LONG(next, start+size);
}
RETURN_STRINGL(((char *)pstr), size, 1);
}
/* convert the strings to UTF-16. */
ustr = NULL;
ustr_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&ustr, &ustr_len, (char *)pstr, str_len, &status );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
if ( NULL != ustr )
efree( ustr );
RETURN_FALSE;
}
bi = NULL;
status = U_ZERO_ERROR;
bi = grapheme_get_break_iterator(u_break_iterator_buffer, &status TSRMLS_CC );
ubrk_setText(bi, ustr, ustr_len, &status);
/* if the caller put us in the middle of a grapheme, we can't detect it in all cases since we
can't back up. So, we will not do anything. */
/* now we need to find the end of the chunk the user wants us to return */
ret_pos = (*grapheme_extract_iters[extract_type])(bi, size, pstr, str_len);
efree(ustr);
ubrk_close(bi);
if ( NULL != next ) {
ZVAL_LONG(next, start+ret_pos);
}
RETURN_STRINGL(((char *)pstr), ret_pos, 1);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: fdm=marker
* vim: noet sw=4 ts=4
*/

619
ext/intl/grapheme/grapheme_util.c Executable file
View File

@ -0,0 +1,619 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
/* {{{ includes */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include "grapheme.h"
#include "grapheme_util.h"
#include "intl_common.h"
#include <unicode/utypes.h>
#include <unicode/ucol.h>
#include <unicode/ustring.h>
#include <unicode/ubrk.h>
#include "ext/standard/php_string.h"
ZEND_EXTERN_MODULE_GLOBALS( intl )
/* }}} */
/* {{{ grapheme_close_global_iterator - clean up */
void
grapheme_close_global_iterator( TSRMLS_D )
{
UBreakIterator *global_break_iterator = INTL_G( grapheme_iterator );
if ( NULL != global_break_iterator ) {
ubrk_close(global_break_iterator);
}
}
/* }}} */
/* {{{ grapheme_intl_case_fold: convert string to lowercase */
void
grapheme_intl_case_fold(UChar** ptr_to_free, UChar **str, int32_t *str_len, UErrorCode *pstatus )
{
UChar *dest;
int32_t dest_len, size_required;
/* allocate a destination string that is a bit larger than the src, hoping that is enough */
dest_len = (*str_len) + ( *str_len / 10 );
dest = (UChar*) eumalloc(dest_len);
*pstatus = U_ZERO_ERROR;
size_required = u_strFoldCase(dest, dest_len, *str, *str_len, U_FOLD_CASE_DEFAULT, pstatus);
dest_len = size_required;
if ( U_BUFFER_OVERFLOW_ERROR == *pstatus ) {
dest = (UChar*) eurealloc(dest, dest_len);
*pstatus = U_ZERO_ERROR;
size_required = u_strFoldCase(dest, dest_len, *str, *str_len, U_FOLD_CASE_DEFAULT, pstatus);
}
if ( U_FAILURE(*pstatus) ) {
return;
}
if ( NULL != ptr_to_free) {
efree(*ptr_to_free);
*ptr_to_free = dest;
}
*str = dest;
*str_len = dest_len;
return;
}
/* }}} */
/* {{{ grapheme_substr_ascii f='from' - starting point, l='length' */
void
grapheme_substr_ascii(char *str, int str_len, int f, int l, int argc, char **sub_str, int *sub_str_len)
{
*sub_str = NULL;
if (argc > 2) {
if ((l < 0 && -l > str_len)) {
return;
} else if (l > str_len) {
l = str_len;
}
} else {
l = str_len;
}
if (f > str_len || (f < 0 && -f > str_len)) {
return;
}
if (l < 0 && (l + str_len - f) < 0) {
return;
}
/* if "from" position is negative, count start position from the end
* of the string
*/
if (f < 0) {
f = str_len + f;
if (f < 0) {
f = 0;
}
}
/* if "length" position is negative, set it to the length
* needed to stop that many chars from the end of the string
*/
if (l < 0) {
l = (str_len - f) + l;
if (l < 0) {
l = 0;
}
}
if (f >= str_len) {
return;
}
if ((f + l) > str_len) {
l = str_len - f;
}
*sub_str = str + f;
*sub_str_len = l;
return;
}
/* }}} */
/* {{{ grapheme_strrpos_utf16 - strrpos using utf16 */
int
grapheme_strrpos_utf16(unsigned char *haystack, int32_t haystack_len, unsigned char*needle, int32_t needle_len, int32_t offset, int f_ignore_case TSRMLS_DC)
{
UChar *uhaystack, *puhaystack, *uhaystack_end, *uneedle;
int32_t uhaystack_len, uneedle_len;
UErrorCode status;
unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
UBreakIterator* bi = NULL;
int ret_pos, pos;
/* convert the strings to UTF-16. */
uhaystack = NULL;
uhaystack_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&uhaystack, &uhaystack_len, (char *) haystack, haystack_len, &status );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( uhaystack );
return -1;
}
if ( f_ignore_case ) {
grapheme_intl_case_fold(&uhaystack, &uhaystack, &uhaystack_len, &status );
}
/* get a pointer to the haystack taking into account the offset */
bi = NULL;
status = U_ZERO_ERROR;
bi = grapheme_get_break_iterator(u_break_iterator_buffer, &status TSRMLS_CC );
puhaystack = grapheme_get_haystack_offset(bi, uhaystack, uhaystack_len, offset);
if ( NULL == puhaystack ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Offset not contained in string", 1 TSRMLS_CC );
efree( uhaystack );
ubrk_close (bi);
return -1;
}
uneedle = NULL;
uneedle_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&uneedle, &uneedle_len, (char *) needle, needle_len, &status );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( uhaystack );
efree( uneedle );
ubrk_close (bi);
return -1;
}
if ( f_ignore_case ) {
grapheme_intl_case_fold(&uneedle, &uneedle, &uneedle_len, &status );
}
ret_pos = -1; /* -1 represents 'not found' */
/* back up until there's needle_len characters to compare */
uhaystack_end = uhaystack + uhaystack_len;
pos = ubrk_last(bi);
puhaystack = uhaystack + pos;
while ( uhaystack_end - puhaystack < uneedle_len ) {
pos = ubrk_previous(bi);
if ( UBRK_DONE == pos ) {
break;
}
puhaystack = uhaystack + pos;
}
/* is there enough haystack left to hold the needle? */
if ( ( uhaystack_end - puhaystack ) < uneedle_len ) {
/* not enough, not found */
goto exit;
}
while ( UBRK_DONE != pos ) {
if (!u_memcmp(uneedle, puhaystack, uneedle_len)) { /* needle_len - 1 in zend memnstr? */
/* does the grapheme in the haystack end at the same place as the last grapheme in the needle? */
if ( ubrk_isBoundary(bi, pos + uneedle_len) ) {
/* found it, get grapheme count offset */
ret_pos = grapheme_count_graphemes(bi, uhaystack, pos);
break;
}
/* set position back */
ubrk_isBoundary(bi, pos);
}
pos = ubrk_previous(bi);
puhaystack = uhaystack + pos;
}
exit:
efree( uhaystack );
efree( uneedle );
ubrk_close (bi);
return ret_pos;
}
/* }}} */
/* {{{ grapheme_strpos_utf16 - strrpos using utf16*/
int
grapheme_strpos_utf16(unsigned char *haystack, int32_t haystack_len, unsigned char*needle, int32_t needle_len, int32_t offset, int32_t *puchar_pos, int f_ignore_case TSRMLS_DC)
{
UChar *uhaystack, *puhaystack, *uneedle;
int32_t uhaystack_len, uneedle_len;
int ret_pos;
unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
UBreakIterator* bi;
UErrorCode status;
*puchar_pos = -1;
/* convert the strings to UTF-16. */
uhaystack = NULL;
uhaystack_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&uhaystack, &uhaystack_len, (char *) haystack, haystack_len, &status );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( uhaystack );
return -1;
}
/* get a pointer to the haystack taking into account the offset */
bi = NULL;
status = U_ZERO_ERROR;
bi = grapheme_get_break_iterator(u_break_iterator_buffer, &status TSRMLS_CC );
puhaystack = grapheme_get_haystack_offset(bi, uhaystack, uhaystack_len, offset);
uhaystack_len = (uhaystack_len - ( puhaystack - uhaystack));
if ( NULL == puhaystack ) {
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "grapheme_strpos: Offset not contained in string", 1 TSRMLS_CC );
efree( uhaystack );
ubrk_close (bi);
return -1;
}
if ( f_ignore_case ) {
grapheme_intl_case_fold(&uhaystack, &puhaystack, &uhaystack_len, &status );
}
uneedle = NULL;
uneedle_len = 0;
status = U_ZERO_ERROR;
intl_convert_utf8_to_utf16(&uneedle, &uneedle_len, (char *) needle, needle_len, &status );
if ( U_FAILURE( status ) ) {
/* Set global error code. */
intl_error_set_code( NULL, status TSRMLS_CC );
/* Set error messages. */
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( uhaystack );
efree( uneedle );
ubrk_close (bi);
return -1;
}
if ( f_ignore_case ) {
grapheme_intl_case_fold(&uneedle, &uneedle, &uneedle_len, &status );
}
ret_pos = grapheme_memnstr_grapheme(bi, puhaystack, uneedle, uneedle_len, puhaystack + uhaystack_len );
*puchar_pos = ubrk_current(bi);
efree( uhaystack );
efree( uneedle );
ubrk_close (bi);
return ret_pos;
}
/* }}} */
/* {{{ grapheme_ascii_check: ASCII check */
int grapheme_ascii_check(const unsigned char *day, int32_t len)
{
int ret_len = len;
while ( len-- ) {
if ( *day++ > 0x7f )
return -1;
}
return ret_len;
}
/* }}} */
/* {{{ grapheme_split_string: find and optionally return grapheme boundaries */
int grapheme_split_string(const UChar *text, int32_t text_length, int boundary_array[], int boundary_array_len TSRMLS_DC )
{
unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
UErrorCode status = U_ZERO_ERROR;
int ret_len, pos;
UBreakIterator* bi;
bi = grapheme_get_break_iterator((void*)u_break_iterator_buffer, &status TSRMLS_CC );
if( U_FAILURE(status) ) {
return -1;
}
ubrk_setText(bi, text, text_length, &status);
pos = 0;
for ( ret_len = 0; pos != UBRK_DONE; ) {
pos = ubrk_next(bi);
if ( pos != UBRK_DONE ) {
if ( NULL != boundary_array && ret_len < boundary_array_len ) {
boundary_array[ret_len] = pos;
}
ret_len++;
}
}
ubrk_close(bi);
return ret_len;
}
/* }}} */
/* {{{ grapheme_count_graphemes */
inline int32_t
grapheme_count_graphemes(UBreakIterator *bi, UChar *string, int32_t string_len)
{
int ret_len = 0;
int pos = 0;
UErrorCode status = U_ZERO_ERROR;
ubrk_setText(bi, string, string_len, &status);
do {
pos = ubrk_next(bi);
if ( UBRK_DONE != pos ) {
ret_len++;
}
} while ( UBRK_DONE != pos );
return ret_len;
}
/* }}} */
/* {{{ grapheme_memnstr_grapheme: find needle in haystack using grapheme boundaries */
inline int32_t
grapheme_memnstr_grapheme(UBreakIterator *bi, UChar *haystack, UChar *needle, int32_t needle_len, UChar *end)
{
UChar *p = haystack;
UChar ne = needle[needle_len-1];
UErrorCode status;
int32_t grapheme_offset;
end -= needle_len;
while (p <= end) {
if ((p = u_memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
if (!u_memcmp(needle, p, needle_len - 1)) { /* needle_len - 1 works because if needle_len is 1, we've already tested the char */
/* does the grapheme end here? */
status = U_ZERO_ERROR;
ubrk_setText (bi, haystack, (end - haystack) + needle_len, &status);
if ( ubrk_isBoundary (bi, (p - haystack) + needle_len) ) {
/* found it, get grapheme count offset */
grapheme_offset = grapheme_count_graphemes(bi, haystack, (p - haystack));
return grapheme_offset;
}
}
}
if (p == NULL) {
return -1;
}
p++;
}
return -1;
}
/* }}} */
/* {{{ grapheme_memrstr_grapheme: reverse find needle in haystack using grapheme boundaries */
inline void *grapheme_memrchr_grapheme(const void *s, int c, int32_t n)
{
register unsigned char *e;
if (n <= 0) {
return NULL;
}
for (e = (unsigned char *)s + n - 1; e >= (unsigned char *)s; e--) {
if (*e == (unsigned char)c) {
return (void *)e;
}
}
return NULL;
}
/* }}} */
/* {{{ grapheme_get_haystack_offset - bump the haystack pointer based on the grapheme count offset */
UChar *
grapheme_get_haystack_offset(UBreakIterator* bi, UChar *uhaystack, int32_t uhaystack_len, int32_t offset)
{
UErrorCode status;
int32_t pos;
int32_t (*iter_op)(UBreakIterator* bi);
int iter_incr;
if ( NULL != bi ) {
status = U_ZERO_ERROR;
ubrk_setText (bi, uhaystack, uhaystack_len, &status);
}
if ( 0 == offset ) {
return uhaystack;
}
if ( offset < 0 ) {
iter_op = ubrk_previous;
ubrk_last(bi); /* one past the end */
iter_incr = 1;
}
else {
iter_op = ubrk_next;
iter_incr = -1;
}
pos = 0;
while ( pos != UBRK_DONE && offset != 0 ) {
pos = iter_op(bi);
if ( UBRK_DONE != pos ) {
offset += iter_incr;
}
}
if ( offset != 0 ) {
return NULL;
}
return uhaystack + pos;
}
/* }}} */
/* {{{ grapheme_strrpos_ascii: borrowed from the php ext/standard/string.c */
int32_t
grapheme_strrpos_ascii(unsigned char *haystack, int32_t haystack_len, unsigned char *needle, int32_t needle_len, int32_t offset)
{
unsigned char *p, *e;
if (offset >= 0) {
p = haystack + offset;
e = haystack + haystack_len - needle_len;
} else {
p = haystack;
if (needle_len > -offset) {
e = haystack + haystack_len - needle_len;
} else {
e = haystack + haystack_len + offset;
}
}
if (needle_len == 1) {
/* Single character search can shortcut memcmps */
while (e >= p) {
if (*e == *needle) {
return (e - p + (offset > 0 ? offset : 0));
}
e--;
}
return -1;
}
while (e >= p) {
if (memcmp(e, needle, needle_len) == 0) {
return (e - p + (offset > 0 ? offset : 0));
}
e--;
}
return -1;
}
/* }}} */
/* {{{ grapheme_get_break_iterator: get a clone of the global character break iterator */
UBreakIterator*
grapheme_get_break_iterator(void *stack_buffer, UErrorCode *status TSRMLS_DC )
{
int32_t buffer_size;
UBreakIterator *global_break_iterator = INTL_G( grapheme_iterator );
if ( NULL == global_break_iterator ) {
global_break_iterator = ubrk_open(UBRK_CHARACTER,
NULL, /* icu default locale - locale has no effect on this iterator */
NULL, /* text not set in global iterator */
0, /* text length = 0 */
status);
INTL_G(grapheme_iterator) = global_break_iterator;
}
buffer_size = U_BRK_SAFECLONE_BUFFERSIZE;
return ubrk_safeClone(global_break_iterator, stack_buffer, &buffer_size, status);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: fdm=marker
* vim: noet sw=4 ts=4
*/

View File

@ -0,0 +1,59 @@
/*
+----------------------------------------------------------------------+
| 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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifndef GRAPHEME_GRAPHEME_UTIL_H
#define GRAPHEME_GRAPHEME_UTIL_H
#include "php_intl.h"
#include "intl_convert.h"
/* get_break_interator: get a break iterator from the global structure */
UBreakIterator* grapheme_get_break_iterator(void *stack_buffer, UErrorCode *status TSRMLS_DC );
void
grapheme_substr_ascii(char *str, int32_t str_len, int32_t f, int32_t l, int argc, char **sub_str, int *sub_str_len);
int
grapheme_strrpos_utf16(unsigned char *haystack, int32_t haystack_len, unsigned char*needle, int32_t needle_len, int32_t offset, int f_ignore_case TSRMLS_DC);
int
grapheme_strpos_utf16(unsigned char *haystack, int32_t haystack_len, unsigned char*needle, int32_t needle_len, int32_t offset, int *puchar_pos, int f_ignore_case TSRMLS_DC);
int grapheme_ascii_check(const unsigned char *day, int32_t len);
int grapheme_split_string(const UChar *text, int32_t text_length, int boundary_array[], int boundary_array_len TSRMLS_DC );
inline int32_t
grapheme_count_graphemes(UBreakIterator *bi, UChar *string, int32_t string_len);
inline int32_t
grapheme_memnstr_grapheme(UBreakIterator *bi, UChar *haystack, UChar *needle, int32_t needle_len, UChar *end);
inline void *grapheme_memrchr_grapheme(const void *s, int c, int32_t n);
UChar *
grapheme_get_haystack_offset(UBreakIterator* bi, UChar *uhaystack, int32_t uhaystack_len, int32_t offset);
int32_t
grapheme_strrpos_ascii(unsigned char *haystack, int32_t haystack_len, unsigned char *needle, int32_t needle_len, int32_t offset);
UBreakIterator*
grapheme_get_break_iterator(void *stack_buffer, UErrorCode *status TSRMLS_DC );
/* OUTSIDE_STRING: check if (possibly negative) long offset is outside the string with int32_t length */
#define OUTSIDE_STRING(offset, max_len) ( offset < INT32_MIN || offset > INT32_MAX || (offset < 0 ? -offset > (long) max_len : offset >= (long) max_len) )
#endif // GRAPHEME_GRAPHEME_UTIL_H

44
ext/intl/intl_common.h Executable file
View File

@ -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: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
| Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef INTL_COMMON_H
#define INTL_COMMON_H
/* Auxiliary macros */
#include <php.h>
#include <unicode/utypes.h>
#ifndef UBYTES
# define UBYTES(len) ((len) * sizeof(UChar))
#endif
#ifndef eumalloc
# define eumalloc(size) (UChar*)safe_emalloc(size, sizeof(UChar), 0)
#endif
#ifndef eurealloc
# define eurealloc(ptr, size) (UChar*)erealloc((ptr), size * sizeof(UChar))
#endif
#define USIZE(data) sizeof((data))/sizeof(UChar)
#define UCHARS(len) ((len) / sizeof(UChar))
#define INTL_Z_STRVAL_P(str) (UChar*) Z_STRVAL_P(str)
#define INTL_Z_STRLEN_P(str) UCHARS( Z_STRLEN_P(str) )
#endif /* INTL_COMMON_H */

154
ext/intl/intl_convert.c Executable file
View File

@ -0,0 +1,154 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include "intl_common.h"
#include "intl_convert.h"
/* {{{ intl_convert_utf8_to_utf16
* Convert given string from UTF-8 to UTF-16 to *target buffer.
*
* It *target is NULL then we allocate a large enough buffer,
* store the converted string into it, and make target point to it.
*
* Otherwise, if *target is non-NULL, we assume that it points to a
* dynamically allocated buffer of *target_len bytes length.
* In this case the buffer will be used to store the converted string to,
* and may be resized (made larger) if needed.
*
* @param target Where to place the result.
* @param target_len Result length.
* @param source String to convert.
* @param source_len Length of the source string.
* @param status Conversion status.
*
* @return void This function does not return anything.
*/
void intl_convert_utf8_to_utf16(
UChar** target, int* target_len,
const char* src, int src_len,
UErrorCode* status )
{
UChar* dst_buf = NULL;
int32_t dst_len = 0;
// If *target is NULL determine required destination buffer size (pre-flighting).
// Otherwise, attempt to convert source string; if *target buffer is not large enough
// it will be resized appropriately.
*status = U_ZERO_ERROR;
u_strFromUTF8( *target, *target_len, &dst_len, src, src_len, status );
if( *status == U_ZERO_ERROR )
{
// String is converted successfuly
(*target)[dst_len] = 0;
*target_len = dst_len;
return;
}
// Bail out if an unexpected error occured.
// (U_BUFFER_OVERFLOW_ERROR means that *target buffer is not large enough).
// (U_STRING_NOT_TERMINATED_WARNING usually means that the input string is empty).
if( *status != U_BUFFER_OVERFLOW_ERROR && *status != U_STRING_NOT_TERMINATED_WARNING )
return;
// Allocate memory for the destination buffer (it will be zero-terminated).
dst_buf = eumalloc( dst_len + 1 );
// Convert source string from UTF-8 to UTF-16.
*status = U_ZERO_ERROR;
u_strFromUTF8( dst_buf, dst_len+1, NULL, src, src_len, status );
if( U_FAILURE( *status ) )
{
efree( dst_buf );
return;
}
dst_buf[dst_len] = 0;
if( *target )
efree( *target );
*target = dst_buf;
*target_len = dst_len;
}
/* }}} */
/* {{{ intl_convert_utf16_to_utf8
* Convert given string from UTF-16 to UTF-8.
*
* @param target Where to place the result.
* @param target_len Result length.
* @param source String to convert.
* @param source_len Length of the source string.
* @param status Conversion status.
*
* @return void This function does not return anything.
*/
void intl_convert_utf16_to_utf8(
char** target, int* target_len,
const UChar* src, int src_len,
UErrorCode* status )
{
char* dst_buf = NULL;
int32_t dst_len;
// Determine required destination buffer size (pre-flighting).
*status = U_ZERO_ERROR;
u_strToUTF8( NULL, 0, &dst_len, src, src_len, status );
// Bail out if an unexpected error occured.
// (U_BUFFER_OVERFLOW_ERROR means that *target buffer is not large enough).
// (U_STRING_NOT_TERMINATED_WARNING usually means that the input string is empty).
if( *status != U_BUFFER_OVERFLOW_ERROR && *status != U_STRING_NOT_TERMINATED_WARNING )
return;
// Allocate memory for the destination buffer (it will be zero-terminated).
dst_buf = emalloc( dst_len+1 );
// Convert source string from UTF-8 to UTF-16.
*status = U_ZERO_ERROR;
u_strToUTF8( dst_buf, dst_len, NULL, src, src_len, status );
if( U_FAILURE( *status ) )
{
efree( dst_buf );
return;
}
// U_STRING_NOT_TERMINATED_WARNING is OK for us => reset 'status'.
*status = U_ZERO_ERROR;
dst_buf[dst_len] = 0;
*target = dst_buf;
*target_len = dst_len;
}
/* }}} */
/*
* 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
*/

33
ext/intl/intl_convert.h Executable file
View File

@ -0,0 +1,33 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
+----------------------------------------------------------------------+
*/
#ifndef INTL_CONVERT_H
#define INTL_CONVERT_H
#include <unicode/ustring.h>
void intl_convert_utf8_to_utf16(
UChar** target, int* target_len,
const char* src, int src_len,
UErrorCode* status );
void intl_convert_utf16_to_utf8(
char** target, int* target_len,
const UChar* src, int src_len,
UErrorCode* status );
#endif // INTL_CONVERT_H

87
ext/intl/intl_data.h Executable file
View File

@ -0,0 +1,87 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
| Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef INTL_DATA_H
#define INTL_DATA_H
#include <unicode/utypes.h>
#include "intl_error.h"
/* Mock object to generalize error handling in sub-modules.
Sub-module data structures should always have error as first element
for this to work!
*/
typedef struct _intl_data {
zend_object zo;
intl_error error;
} intl_object;
#define INTL_METHOD_INIT_VARS(oclass, obj) \
zval* object = NULL; \
oclass##_object* obj = NULL; \
intl_error_reset( NULL TSRMLS_CC );
#define INTL_DATA_ERROR(obj) (((intl_object *)(obj))->error)
#define INTL_DATA_ERROR_P(obj) (&(INTL_DATA_ERROR((obj))))
#define INTL_DATA_ERROR_CODE(obj) INTL_ERROR_CODE(INTL_DATA_ERROR((obj)))
#define INTL_METHOD_FETCH_OBJECT(oclass, obj) \
obj = (oclass##_object *) zend_object_store_get_object( object TSRMLS_CC ); \
intl_error_reset( INTL_DATA_ERROR_P(obj) TSRMLS_CC ); \
#define INTL_METHOD_CHECK_STATUS(obj, msg) \
intl_error_set_code( NULL, INTL_DATA_ERROR_CODE((obj)) TSRMLS_CC ); \
if( U_FAILURE( INTL_DATA_ERROR_CODE((obj)) ) ) \
{ \
intl_errors_set_custom_msg( INTL_DATA_ERROR_P((obj)), msg, 0 TSRMLS_CC ); \
RETURN_FALSE; \
}
#define INTL_METHOD_RETVAL_UTF8(obj, ustring, ulen, free_it) \
{ \
char *u8value; \
int u8len; \
intl_convert_utf16_to_utf8(&u8value, &u8len, ustring, ulen, &INTL_DATA_ERROR_CODE((obj))); \
if((free_it)) { \
efree(ustring); \
} \
INTL_METHOD_CHECK_STATUS((obj), "Error converting value to UTF-8"); \
RETVAL_STRINGL(u8value, u8len, 0); \
}
#define INTL_MAX_LOCALE_LEN 64
#define INTL_CHECK_LOCALE_LEN(locale_len) \
if((locale_len) > INTL_MAX_LOCALE_LEN) { \
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, \
"Locale string too long, should be no longer than 64 characters", 0 TSRMLS_CC ); \
RETURN_NULL(); \
}
#define INTL_CHECK_LOCALE_LEN_OBJ(locale_len, object) \
if((locale_len) > INTL_MAX_LOCALE_LEN) { \
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, \
"Locale string too long, should be no longer than 64 characters", 0 TSRMLS_CC ); \
zval_dtor(object); \
ZVAL_NULL(object); \
RETURN_NULL(); \
}
#endif // INTL_DATA_H

215
ext/intl/intl_error.c Executable file
View File

@ -0,0 +1,215 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
| Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <php.h>
#include "php_intl.h"
#include "intl_error.h"
ZEND_EXTERN_MODULE_GLOBALS( intl )
/* {{{ intl_error* intl_g_error_get()
* Return global error structure.
*/
static intl_error* intl_g_error_get( TSRMLS_D )
{
return &INTL_G( g_error );
}
/* }}} */
/* {{{ void intl_free_custom_error_msg( intl_error* err )
* Free mem.
*/
static void intl_free_custom_error_msg( intl_error* err TSRMLS_DC )
{
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return;
if( !err->free_custom_error_message )
return;
efree( err->custom_error_message );
err->custom_error_message = NULL;
err->free_custom_error_message = 0;
}
/* }}} */
/* {{{ intl_error* intl_error_create()
* Create and initialize internals of 'intl_error'.
*/
intl_error* intl_error_create( TSRMLS_D )
{
intl_error* err = ecalloc( 1, sizeof( intl_error ) );
intl_error_init( err TSRMLS_CC );
return err;
}
/* }}} */
/* {{{ void intl_error_init( intl_error* coll_error )
* Initialize internals of 'intl_error'.
*/
void intl_error_init( intl_error* err TSRMLS_DC )
{
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return;
err->code = U_ZERO_ERROR;
err->custom_error_message = NULL;
err->free_custom_error_message = 0;
}
/* }}} */
/* {{{ void intl_error_reset( intl_error* err )
* Set last error code to 0 and unset last error message
*/
void intl_error_reset( intl_error* err TSRMLS_DC )
{
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return;
err->code = U_ZERO_ERROR;
intl_free_custom_error_msg( err TSRMLS_CC );
}
/* }}} */
/* {{{ void intl_error_set_custom_msg( intl_error* err, char* msg, int copyMsg )
* Set last error message to msg copying it if needed.
*/
void intl_error_set_custom_msg( intl_error* err, char* msg, int copyMsg TSRMLS_DC )
{
if( !msg )
return;
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return;
// Free previous message if any
intl_free_custom_error_msg( err TSRMLS_CC );
// Mark message copied if any
err->free_custom_error_message = copyMsg;
// Set user's error text message
err->custom_error_message = copyMsg ? estrdup( msg ) : msg;
}
/* }}} */
/* {{{ const char* intl_error_get_message( intl_error* err )
* Create output message in format "<intl_error_text>: <extra_user_error_text>".
*/
char* intl_error_get_message( intl_error* err TSRMLS_DC )
{
const char* uErrorName = NULL;
char* errMessage = 0;
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return estrdup( "" );
uErrorName = u_errorName( err->code );
// Format output string
if( err->custom_error_message )
{
spprintf( &errMessage, 0, "%s: %s", err->custom_error_message, uErrorName );
}
else
{
spprintf( &errMessage, 0, "%s", uErrorName );
}
return errMessage;
}
/* }}} */
/* {{{ void intl_error_set_code( intl_error* err, UErrorCode err_code )
* Set last error code.
*/
void intl_error_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC )
{
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return;
err->code = err_code;
}
/* }}} */
/* {{{ void intl_error_get_code( intl_error* err )
* Return last error code.
*/
UErrorCode intl_error_get_code( intl_error* err TSRMLS_DC )
{
if( !err && !( err = intl_g_error_get( TSRMLS_C ) ) )
return U_ZERO_ERROR;
return err->code;
}
/* }}} */
/* {{{ void intl_error_set( intl_error* err, UErrorCode code, char* msg, int copyMsg )
* Set error code and message.
*/
void intl_error_set( intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC )
{
intl_error_set_code( err, code TSRMLS_CC );
intl_error_set_custom_msg( err, msg, copyMsg TSRMLS_CC );
}
/* }}} */
/* {{{ void intl_errors_reset( intl_error* err )
*/
void intl_errors_reset( intl_error* err TSRMLS_DC )
{
intl_error_reset( err TSRMLS_CC );
intl_error_reset( NULL TSRMLS_CC );
}
/* }}} */
/* {{{ void intl_errors_set_custom_msg( intl_error* err, char* msg, int copyMsg )
*/
void intl_errors_set_custom_msg( intl_error* err, char* msg, int copyMsg TSRMLS_DC )
{
intl_error_set_custom_msg( err, msg, copyMsg TSRMLS_CC );
intl_error_set_custom_msg( NULL, msg, copyMsg TSRMLS_CC );
}
/* }}} */
/* {{{ intl_errors_set_code( intl_error* err, UErrorCode err_code )
*/
void intl_errors_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC )
{
intl_error_set_code( err, err_code TSRMLS_CC );
intl_error_set_code( NULL, err_code 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
*/

46
ext/intl/intl_error.h Executable file
View File

@ -0,0 +1,46 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
| Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef INTL_ERROR_H
#define INTL_ERROR_H
#include <unicode/utypes.h>
#define INTL_ERROR_CODE(e) (e).code
typedef struct _intl_error {
UErrorCode code;
char* custom_error_message;
int free_custom_error_message;
} intl_error;
intl_error* intl_error_create( TSRMLS_D );
void intl_error_init( intl_error* err TSRMLS_DC );
void intl_error_reset( intl_error* err TSRMLS_DC );
void intl_error_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC );
void intl_error_set_custom_msg( intl_error* err, char* msg, int copyMsg TSRMLS_DC );
void intl_error_set( intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC );
UErrorCode intl_error_get_code( intl_error* err TSRMLS_DC );
char* intl_error_get_message( intl_error* err TSRMLS_DC );
// Wrappers to synchonize object's and global error structures.
void intl_errors_reset( intl_error* err TSRMLS_DC );
void intl_errors_set_custom_msg( intl_error* err, char* msg, int copyMsg TSRMLS_DC );
void intl_errors_set_code( intl_error* err, UErrorCode err_code TSRMLS_DC );
#endif // INTL_ERROR_H

70
ext/intl/locale/locale.c Executable file
View File

@ -0,0 +1,70 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Kirti Velankar <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "locale_class.h"
#include "locale.h"
#include <unicode/utypes.h>
#include <unicode/uloc.h>
#include <unicode/ustring.h>
/* {{{ locale_register_constants
* Register constants common for the both (OO and procedural)
* APIs.
*/
void locale_register_constants( INIT_FUNC_ARGS )
{
if( !Locale_ce_ptr )
{
zend_error( E_ERROR, "Locale class not defined" );
return;
}
#define LOCALE_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS)
#define LOCALE_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( Locale_ce_ptr, ZEND_STRS( #x ) - 1, ULOC_##x TSRMLS_CC );
#define LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR(name, value) zend_declare_class_constant_string( Locale_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );
LOCALE_EXPOSE_CLASS_CONST( ACTUAL_LOCALE );
LOCALE_EXPOSE_CLASS_CONST( VALID_LOCALE );
zend_declare_class_constant_null(Locale_ce_ptr, ZEND_STRS("DEFAULT_LOCALE") - 1 TSRMLS_CC);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "LANG_TAG", LOC_LANG_TAG);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "EXTLANG_TAG", LOC_EXTLANG_TAG);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "SCRIPT_TAG", LOC_SCRIPT_TAG);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "REGION_TAG", LOC_REGION_TAG);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "VARIANT_TAG",LOC_VARIANT_TAG);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "GRANDFATHERED_LANG_TAG",LOC_GRANDFATHERED_LANG_TAG);
LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR( "PRIVATE_TAG",LOC_PRIVATE_TAG);
#undef LOCALE_EXPOSE_CUSTOM_CLASS_CONST_STR
#undef LOCALE_EXPOSE_CLASS_CONST
#undef LOCALE_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
*/

36
ext/intl/locale/locale.h Executable file
View File

@ -0,0 +1,36 @@
/*
+----------------------------------------------------------------------+
| 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 <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifndef LOCALE_LOCALE_H
#define LOCALE_LOCALE_H
#include <php.h>
void locale_register_constants( INIT_FUNC_ARGS );
#define OPTION_DEFAULT NULL
#define LOC_LANG_TAG "language"
#define LOC_SCRIPT_TAG "script"
#define LOC_REGION_TAG "region"
#define LOC_VARIANT_TAG "variant"
#define LOC_EXTLANG_TAG "extlang"
#define LOC_GRANDFATHERED_LANG_TAG "grandfathered"
#define LOC_PRIVATE_TAG "private"
#define LOC_CANONICALIZE_TAG "canonicalize"
#define LOCALE_INI_NAME "intl.default_locale"
#endif // LOCALE_LOCALE_H

126
ext/intl/locale/locale_class.c Executable file
View File

@ -0,0 +1,126 @@
/*
+----------------------------------------------------------------------+
| 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 <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#include <unicode/uloc.h>
#include "php_intl.h"
#include "intl_error.h"
#include "locale_class.h"
#include "locale_methods.h"
#include "locale.h"
zend_class_entry *Locale_ce_ptr = NULL;
/////////////////////////////////////////////////////////////////////////////
// 'Locale' class registration structures & functions
/////////////////////////////////////////////////////////////////////////////
/* {{{ Locale methods arguments info */
// NOTE: modifying 'locale_XX_args' do not forget to
// modify approptiate 'locale_XX_args' for
// the procedural API.
static
ZEND_BEGIN_ARG_INFO_EX( locale_0_args, 0, 0, 0 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_1_arg, 0, 0, 1 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_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( locale_3_args, 0, 0, 3 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_ARG_INFO( 0, arg2 )
ZEND_ARG_INFO( 0, arg3 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_4_args, 0, 0, 4 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_ARG_INFO( 0, arg2 )
ZEND_ARG_INFO( 0, arg3 )
ZEND_ARG_INFO( 0, arg4 )
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ Locale_class_functions
* Every 'Locale' class method has an entry in this table
*/
function_entry Locale_class_functions[] = {
ZEND_FENTRY( getDefault, zif_locale_get_default , locale_0_args , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( setDefault, zif_locale_set_default , locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getPrimaryLanguage, ZEND_FN( locale_get_primary_language ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getScript, ZEND_FN( locale_get_script ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getRegion, ZEND_FN( locale_get_region ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getKeywords, ZEND_FN( locale_get_keywords ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getDisplayScript, ZEND_FN( locale_get_display_script ), locale_2_args , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getDisplayRegion, ZEND_FN( locale_get_display_region ), locale_2_args , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getDisplayName, ZEND_FN( locale_get_display_name ), locale_2_args , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getDisplayLanguage, ZEND_FN( locale_get_display_language ), locale_2_args , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getDisplayVariant, ZEND_FN( locale_get_display_variant ), locale_2_args , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( composeLocale, ZEND_FN( locale_compose ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( parseLocale, ZEND_FN( locale_parse ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( getAllVariants, ZEND_FN( locale_get_all_variants ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( filterMatches, ZEND_FN( locale_filter_matches ), locale_3_args, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( lookup, ZEND_FN( locale_lookup ), locale_4_args, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( canonicalize, ZEND_FN( locale_canonicalize ), locale_1_arg , ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
{ NULL, NULL, NULL }
};
/* }}} */
/* {{{ locale_register_Locale_class
* Initialize 'Locale' class
*/
void locale_register_Locale_class( TSRMLS_D )
{
zend_class_entry ce;
// Create and register 'Locale' class.
INIT_CLASS_ENTRY( ce, "Locale", Locale_class_functions );
ce.create_object = NULL;
Locale_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
// Declare 'Locale' class properties.
if( !Locale_ce_ptr )
{
zend_error( E_ERROR,
"Locale: Failed to register Locale class.");
return;
}
}
/* }}} */
/*
* 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
*/

46
ext/intl/locale/locale_class.h Executable file
View File

@ -0,0 +1,46 @@
/*
+----------------------------------------------------------------------+
| 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 <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifndef LOCALE_CLASS_H
#define LOCALE_CLASS_H
#include <php.h>
#include "intl_common.h"
#include "intl_error.h"
#include <unicode/uloc.h>
typedef struct {
zend_object zo;
// ICU locale
char* uloc1;
} Locale_object;
void locale_register_Locale_class( TSRMLS_D );
extern zend_class_entry *Locale_ce_ptr;
/* Auxiliary macros */
#define LOCALE_METHOD_INIT_VARS \
zval* object = NULL; \
intl_error_reset( NULL TSRMLS_CC ); \
#endif // #ifndef LOCALE_CLASS_H

1732
ext/intl/locale/locale_methods.c Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Author: Kirti Velankar <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifndef LOCALE_METHODS_H
#define LOCALE_METHODS_H
#include <php.h>
PHP_FUNCTION( locale_get_primary_language );
PHP_FUNCTION( locale_get_script );
PHP_FUNCTION( locale_get_region );
PHP_FUNCTION( locale_get_all_variants);
PHP_NAMED_FUNCTION( zif_locale_get_default );
PHP_NAMED_FUNCTION( zif_locale_set_default );
PHP_FUNCTION( locale_get_display_name );
PHP_FUNCTION( locale_get_display_language );
PHP_FUNCTION( locale_get_display_script );
PHP_FUNCTION( locale_get_display_region );
PHP_FUNCTION( locale_get_display_variant );
PHP_FUNCTION( locale_get_keywords );
PHP_FUNCTION( locale_canonicalize);
PHP_FUNCTION( locale_compose);
PHP_FUNCTION( locale_parse);
PHP_FUNCTION( locale_filter_matches);
PHP_FUNCTION( locale_lookup);
PHP_FUNCTION( locale_canonicalize);
#endif // LOCALE_METHODS_H

256
ext/intl/msgformat/msgformat.c Executable file
View File

@ -0,0 +1,256 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include <unicode/umsg.h>
#include "php_intl.h"
#include "msgformat_class.h"
#include "intl_convert.h"
/* {{{ proto MessageFormatter MesssageFormatter::create( string $locale, string $pattern )
* Create formatter. }}} */
/* {{{ proto MessageFormatter msgfmt_create( string $locale, string $pattern )
* Create formatter.
*/
PHP_FUNCTION( msgfmt_create )
{
char* locale;
char* pattern;
int locale_len = 0, pattern_len = 0;
UChar* spattern = NULL;
int spattern_len = 0;
zval* object;
MessageFormatter_object* mfo;
intl_error_reset( NULL TSRMLS_CC );
// Parse parameters.
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss",
&locale, &locale_len, &pattern, &pattern_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_create: unable to parse input parameters", 0 TSRMLS_CC );
RETURN_NULL();
}
INTL_CHECK_LOCALE_LEN(locale_len);
// Create a MessageFormatter 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, MessageFormatter_ce_ptr );
MSG_FORMAT_METHOD_FETCH_OBJECT;
// Convert pattern (if specified) to UTF-16.
if(pattern && pattern_len) {
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo));
if( U_FAILURE( INTL_DATA_ERROR_CODE((mfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE( mfo ),
"msgfmt_create: error converting pattern to UTF-16", 0 TSRMLS_CC );
zval_dtor(return_value);
RETURN_NULL();
}
} else {
spattern_len = 0;
spattern = NULL;
}
if(locale_len == 0) {
locale = INTL_G(default_locale);
}
if(msfgotmat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
"msgfmt_create: error converting pattern to quote-friendly format", 0 TSRMLS_CC );
zval_dtor(return_value);
RETURN_NULL();
}
(mfo)->mf_data.orig_format = estrndup(pattern, pattern_len);
(mfo)->mf_data.orig_format_len = pattern_len;
// Create an ICU message formatter.
MSG_FORMAT_OBJECT(mfo) = umsg_open(spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(mfo));
if(spattern) {
efree(spattern);
}
if( U_FAILURE( INTL_DATA_ERROR_CODE((mfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE( mfo ),
"msgfmt_create: message formatter creation failed", 0 TSRMLS_CC );
zval_dtor(return_value);
RETURN_NULL();
}
}
/* }}} */
/* {{{ proto void MessageFormatter::__construct( string $locale, string $pattern )
* MessageFormatter object constructor.
*/
PHP_METHOD( MessageFormatter, __construct )
{
char* locale;
char* pattern;
int locale_len, pattern_len = 0;
UChar* spattern = NULL;
int spattern_len = 0;
zval* object;
MessageFormatter_object* mfo;
intl_error_reset( NULL TSRMLS_CC );
object = getThis();
// Parse parameters.
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss",
&locale, &locale_len, &pattern, &pattern_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);
mfo = (MessageFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
intl_error_reset( &mfo->mf_data.error TSRMLS_CC );
// Convert pattern to UTF-16.
if(pattern && pattern_len) {
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo));
if( U_FAILURE( INTL_DATA_ERROR_CODE((mfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE( mfo ),
"__construct: Error converting pattern to UTF-16", 0 TSRMLS_CC );
zval_dtor(object);
ZVAL_NULL(object);
RETURN_NULL();
}
} else {
spattern_len = 0;
spattern = NULL;
}
if(locale_len == 0) {
locale = INTL_G(default_locale);
}
if(msfgotmat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
"__construct: error converting pattern to quote-friendly format", 0 TSRMLS_CC );
zval_dtor(object);
ZVAL_NULL(object);
RETURN_NULL();
}
(mfo)->mf_data.orig_format = estrndup(pattern, pattern_len);
(mfo)->mf_data.orig_format_len = pattern_len;
// Create an ICU message formatter.
MSG_FORMAT_OBJECT(mfo) = umsg_open(spattern, spattern_len, locale, NULL, &INTL_DATA_ERROR_CODE(mfo));
if(spattern && spattern_len) {
efree(spattern);
}
if( U_FAILURE( INTL_DATA_ERROR_CODE((mfo)) ) )
{
intl_error_set( NULL, INTL_DATA_ERROR_CODE(mfo),
"__construct: message formatter creation failed", 0 TSRMLS_CC );
zval_dtor(object);
ZVAL_NULL(object);
RETURN_NULL();
}
}
/* }}} */
/* {{{ proto int MessageFormatter::getErrorCode()
* Get formatter's last error code. }}} */
/* {{{ proto int msgfmt_get_error_code( MessageFormatter $nf )
* Get formatter's last error code.
*/
PHP_FUNCTION( msgfmt_get_error_code )
{
zval* object = NULL;
MessageFormatter_object* mfo = NULL;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, MessageFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_get_error_code: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
mfo = (MessageFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
// Return formatter's last error code.
RETURN_LONG( INTL_DATA_ERROR_CODE(mfo) );
}
/* }}} */
/* {{{ proto string MessageFormatter::getErrorMessage( )
* Get text description for formatter's last error code. }}} */
/* {{{ proto string msgfmt_get_error_message( MessageFormatter $coll )
* Get text description for formatter's last error code.
*/
PHP_FUNCTION( msgfmt_get_error_message )
{
char* message = NULL;
zval* object = NULL;
MessageFormatter_object* mfo = NULL;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, MessageFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_get_error_message: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
mfo = (MessageFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
// Return last error message.
message = intl_error_get_message( &mfo->mf_data.error TSRMLS_CC );
RETURN_STRING( message, 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
*/

27
ext/intl/msgformat/msgformat.h Executable file
View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMATTER_H
#define MSG_FORMATTER_H
#include <php.h>
PHP_FUNCTION( msgfmt_create );
PHP_FUNCTION( msgfmt_get_error_code );
PHP_FUNCTION( msgfmt_get_error_message );
PHP_METHOD( MessageFormatter, __construct );
#endif // MSG_FORMAT_H

View File

@ -0,0 +1,144 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "msgformat_class.h"
#include "msgformat_attr.h"
#include "intl_convert.h"
#include <unicode/ustring.h>
/* {{{ proto string MessageFormatter::getPattern( )
* Get formatter pattern. }}} */
/* {{{ proto string msgfmt_get_pattern( MessageFormatter $mf )
* Get formatter pattern.
*/
PHP_FUNCTION( msgfmt_get_pattern )
{
UChar value_buf[64];
int length = USIZE( value_buf );
UChar* value = value_buf;
MSG_FORMAT_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, MessageFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( INTL_DATA_ERROR_P(mfo), U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_get_pattern: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
MSG_FORMAT_METHOD_FETCH_OBJECT;
if(mfo->mf_data.orig_format) {
RETURN_STRINGL(mfo->mf_data.orig_format, mfo->mf_data.orig_format_len, 1);
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto bool MessageFormatter::setPattern( string $pattern )
* Set formatter pattern. }}} */
/* {{{ proto bool msgfmt_set_pattern( MessageFormatter $mf, string $pattern )
* Set formatter pattern.
*/
PHP_FUNCTION( msgfmt_set_pattern )
{
char* value = NULL;
int value_len = 0;
int spattern_len = 0;
UChar* spattern = NULL;
MSG_FORMAT_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
&object, MessageFormatter_ce_ptr, &value, &value_len ) == FAILURE )
{
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_set_pattern: unable to parse input params", 0 TSRMLS_CC);
RETURN_FALSE;
}
MSG_FORMAT_METHOD_FETCH_OBJECT;
// Convert given pattern to UTF-16.
intl_convert_utf8_to_utf16(&spattern, &spattern_len, value, value_len, &INTL_DATA_ERROR_CODE(mfo));
INTL_METHOD_CHECK_STATUS(mfo, "Error converting pattern to UTF-16" );
if(msfgotmat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
"msgfmt_set_pattern: error converting pattern to quote-friendly format", 0 TSRMLS_CC );
RETURN_FALSE;
}
// TODO: add parse error information
umsg_applyPattern(MSG_FORMAT_OBJECT(mfo), spattern, spattern_len, NULL, &INTL_DATA_ERROR_CODE(mfo));
efree(spattern);
INTL_METHOD_CHECK_STATUS(mfo, "Error setting symbol value");
if(mfo->mf_data.orig_format) {
efree(mfo->mf_data.orig_format);
}
mfo->mf_data.orig_format = estrndup(value, value_len);
mfo->mf_data.orig_format_len = value_len;
RETURN_TRUE;
}
/* }}} */
/* {{{ proto string MessageFormatter::getLocale()
* Get formatter locale. }}} */
/* {{{ proto string msgfmt_get_locale(MessageFormatter $mf)
* Get formatter locale.
*/
PHP_FUNCTION( msgfmt_get_locale )
{
char *loc;
MSG_FORMAT_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, MessageFormatter_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_get_locale: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
MSG_FORMAT_METHOD_FETCH_OBJECT;
loc = (char *)umsg_getLocale(MSG_FORMAT_OBJECT(mfo));
RETURN_STRING(loc, 1);
}
/* }}} */
/*
* 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMAT_ATTR_H
#define MSG_FORMAT_ATTR_H
#include <php.h>
PHP_FUNCTION( msgfmt_set_pattern );
PHP_FUNCTION( msgfmt_get_pattern );
PHP_FUNCTION( msgfmt_get_locale );
#endif // MSG_FORMAT_ATTR_H

View File

@ -0,0 +1,127 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#include <unicode/unum.h>
#include "msgformat_class.h"
#include "php_intl.h"
#include "msgformat_data.h"
#include "msgformat_format.h"
#include "msgformat_parse.h"
#include "msgformat.h"
#include "msgformat_attr.h"
zend_class_entry *MessageFormatter_ce_ptr = NULL;
/////////////////////////////////////////////////////////////////////////////
// Auxiliary functions needed by objects of 'MessageFormatter' class
/////////////////////////////////////////////////////////////////////////////
/* {{{ MessageFormatter_objects_dtor */
static void MessageFormatter_object_dtor(void *object, zend_object_handle handle TSRMLS_DC )
{
zend_objects_destroy_object( object, handle TSRMLS_CC );
}
/* }}} */
/* {{{ MessageFormatter_objects_free */
void MessageFormatter_object_free( zend_object *object TSRMLS_DC )
{
MessageFormatter_object* mfo = (MessageFormatter_object*)object;
zend_object_std_dtor( &mfo->zo TSRMLS_CC );
msgformat_data_free( &mfo->mf_data TSRMLS_CC );
efree( mfo );
}
/* }}} */
/* {{{ MessageFormatter_object_create */
zend_object_value MessageFormatter_object_create(zend_class_entry *ce TSRMLS_DC)
{
zend_object_value retval;
MessageFormatter_object* intern;
intern = ecalloc( 1, sizeof(MessageFormatter_object) );
msgformat_data_init( &intern->mf_data TSRMLS_CC );
zend_object_std_init( &intern->zo, ce TSRMLS_CC );
retval.handle = zend_objects_store_put(
intern,
MessageFormatter_object_dtor,
(zend_objects_free_object_storage_t)MessageFormatter_object_free,
NULL TSRMLS_CC );
retval.handlers = zend_get_std_object_handlers();
return retval;
}
/* }}} */
/////////////////////////////////////////////////////////////////////////////
// 'MessageFormatter' class registration structures & functions
/////////////////////////////////////////////////////////////////////////////
/* {{{ MessageFormatter_class_functions
* Every 'MessageFormatter' class method has an entry in this table
*/
static function_entry MessageFormatter_class_functions[] = {
PHP_ME( MessageFormatter, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
ZEND_FENTRY( create, ZEND_FN( msgfmt_create ), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
PHP_NAMED_FE( format, ZEND_FN( msgfmt_format ), NULL )
ZEND_FENTRY( formatMessage, ZEND_FN( msgfmt_format_message ), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
PHP_NAMED_FE( parse, ZEND_FN( msgfmt_parse ), NULL )
ZEND_FENTRY( parseMessage, ZEND_FN( msgfmt_parse_message ), NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
PHP_NAMED_FE( setPattern, ZEND_FN( msgfmt_set_pattern ), NULL )
PHP_NAMED_FE( getPattern, ZEND_FN( msgfmt_get_pattern ), NULL )
PHP_NAMED_FE( getLocale, ZEND_FN( msgfmt_get_locale ), NULL )
PHP_NAMED_FE( getErrorCode, ZEND_FN( msgfmt_get_error_code ), NULL )
PHP_NAMED_FE( getErrorMessage, ZEND_FN( msgfmt_get_error_message ), NULL )
{ NULL, NULL, NULL }
};
/* }}} */
/* {{{ msgformat_register_class
* Initialize 'MessageFormatter' class
*/
void msgformat_register_class( TSRMLS_D )
{
zend_class_entry ce;
// Create and register 'MessageFormatter' class.
INIT_CLASS_ENTRY( ce, "MessageFormatter", MessageFormatter_class_functions );
ce.create_object = MessageFormatter_object_create;
MessageFormatter_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
// Declare 'MessageFormatter' class properties.
if( !MessageFormatter_ce_ptr )
{
zend_error(E_ERROR, "Failed to register MessageFormatter class");
return;
}
}
/* }}} */
/*
* 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
*/

View File

@ -0,0 +1,41 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMAT_CLASS_H
#define MSG_FORMAT_CLASS_H
#include <php.h>
#include "intl_common.h"
#include "intl_error.h"
#include "intl_data.h"
#include "msgformat_data.h"
typedef struct {
zend_object zo;
msgformat_data mf_data;
} MessageFormatter_object;
void msgformat_register_class( TSRMLS_D );
extern zend_class_entry *MessageFormatter_ce_ptr;
/* Auxiliary macros */
#define MSG_FORMAT_METHOD_INIT_VARS INTL_METHOD_INIT_VARS(MessageFormatter, mfo)
#define MSG_FORMAT_METHOD_FETCH_OBJECT INTL_METHOD_FETCH_OBJECT(MessageFormatter, mfo)
#define MSG_FORMAT_OBJECT(mfo) (mfo)->mf_data.umsgf
#endif // #ifndef MSG_FORMAT_CLASS_H

View File

@ -0,0 +1,98 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include "msgformat_data.h"
/* {{{ void msgformat_data_init( msgformat_data* mf_data )
* Initialize internals of msgformat_data.
*/
void msgformat_data_init( msgformat_data* mf_data TSRMLS_DC )
{
if( !mf_data )
return;
mf_data->umsgf = NULL;
mf_data->orig_format = NULL;
intl_error_reset( &mf_data->error TSRMLS_CC );
}
/* }}} */
/* {{{ void msgformat_data_free( msgformat_data* mf_data )
* Clean up memory allocated for msgformat_data
*/
void msgformat_data_free( msgformat_data* mf_data TSRMLS_DC )
{
if( !mf_data )
return;
if( mf_data->umsgf )
umsg_close( mf_data->umsgf );
if(mf_data->orig_format) {
efree(mf_data->orig_format);
mf_data->orig_format = NULL;
}
mf_data->umsgf = NULL;
intl_error_reset( &mf_data->error TSRMLS_CC );
}
/* }}} */
/* {{{ msgformat_data* msgformat_data_create()
* Allocate memory for msgformat_data and initialize it with default values.
*/
msgformat_data* msgformat_data_create( TSRMLS_D )
{
msgformat_data* mf_data = ecalloc( 1, sizeof(msgformat_data) );
msgformat_data_init( mf_data TSRMLS_CC );
return mf_data;
}
/* }}} */
int msfgotmat_fix_quotes(UChar **spattern, uint32_t *spattern_len, UErrorCode *ec)
{
if(*spattern && *spattern_len && u_strchr(*spattern, (UChar)'\'')) {
UChar *npattern = emalloc(sizeof(UChar)*(2*(*spattern_len)+1));
uint32_t npattern_len;
npattern_len = umsg_autoQuoteApostrophe(*spattern, *spattern_len, npattern, 2*(*spattern_len)+1, ec);
efree(*spattern);
if( U_FAILURE(*ec) )
{
return FAILURE;
}
npattern = erealloc(npattern, sizeof(UChar)*(npattern_len+1));
*spattern = npattern;
*spattern_len = npattern_len;
}
return SUCCESS;
}
/*
* 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
*/

View File

@ -0,0 +1,41 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMAT_DATA_H
#define MSG_FORMAT_DATA_H
#include <php.h>
#include <unicode/umsg.h>
#include "intl_error.h"
typedef struct {
// error hangling
intl_error error;
// formatter handling
UMessageFormat* umsgf;
char* orig_format;
ulong orig_format_len;
} msgformat_data;
msgformat_data* msgformat_data_create( TSRMLS_D );
void msgformat_data_init( msgformat_data* mf_data TSRMLS_DC );
void msgformat_data_free( msgformat_data* mf_data TSRMLS_DC );
int msfgotmat_fix_quotes(UChar **spattern, uint32_t *spattern_len, UErrorCode *ec);
#endif // MSG_FORMAT_DATA_H

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include "php_intl.h"
#include "msgformat_class.h"
#include "msgformat_format.h"
#include "msgformat_data.h"
#include "msgformat_helpers.h"
#include "intl_convert.h"
#ifndef Z_ADDREF_P
#define Z_ADDREF_P(z) ((z)->refcount++)
#endif
/* {{{ */
static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *return_value TSRMLS_DC)
{
zval **fargs;
int count;
UChar* formatted = NULL;
int formatted_len = 0;
HashPosition pos;
int i;
count = zend_hash_num_elements(Z_ARRVAL_P(args));
if(count < umsg_format_arg_count(MSG_FORMAT_OBJECT(mfo))) {
// Not enough aguments for format!
intl_error_set( INTL_DATA_ERROR_P(mfo), U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_format: not enough parameters", 0 TSRMLS_CC );
RETVAL_FALSE;
return;
}
fargs = safe_emalloc(count, sizeof(zval *), 0);
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
for(i=0;i<count;i++) {
zval **val;
zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **)&val, &pos);
fargs[i] = *val;
Z_ADDREF_P(fargs[i]);
/* TODO: needs refcount increase here? */
zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos);
}
umsg_format_helper(MSG_FORMAT_OBJECT(mfo), count, fargs, &formatted, &formatted_len, &INTL_DATA_ERROR_CODE(mfo) TSRMLS_CC);
for(i=0;i<count;i++) {
zval_ptr_dtor(&fargs[i]);
}
efree(fargs);
if (formatted && U_FAILURE( INTL_DATA_ERROR_CODE(mfo) ) ) {
efree(formatted);
}
INTL_METHOD_CHECK_STATUS( mfo, "Number formatting failed" );
INTL_METHOD_RETVAL_UTF8( mfo, formatted, formatted_len, 1 );
}
/* }}} */
/* {{{ proto mixed MessageFormatter::format( array $args )
* Format a message. }}} */
/* {{{ proto mixed msgfmt_format( MessageFormatter $nf, array $args )
* Format a message.
*/
PHP_FUNCTION( msgfmt_format )
{
zval *args;
MSG_FORMAT_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
&object, MessageFormatter_ce_ptr, &args ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_format: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
MSG_FORMAT_METHOD_FETCH_OBJECT;
msgfmt_do_format(mfo, args, return_value TSRMLS_CC);
}
/* }}} */
/* {{{ proto mixed MessageFormatter::formatMessage( string $locale, string $pattern, array $args )
* Format a message. }}} */
/* {{{ proto mixed msgfmt_format_message( string $locale, string $pattern, array $args )
* Format a message.
*/
PHP_FUNCTION( msgfmt_format_message )
{
zval *args;
UChar *spattern = NULL;
int spattern_len = 0;
char *pattern = NULL;
int pattern_len = 0;
char *slocale = NULL;
int slocale_len = 0;
MessageFormatter_object mf = {0};
MessageFormatter_object *mfo = &mf;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "ssa",
&slocale, &slocale_len, &pattern, &pattern_len, &args ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_format_message: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
msgformat_data_init(&mfo->mf_data TSRMLS_CC);
if(pattern && pattern_len) {
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo));
if( U_FAILURE(INTL_DATA_ERROR_CODE((mfo))) )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_format_message: error converting pattern to UTF-16", 0 TSRMLS_CC );
RETURN_FALSE;
}
} else {
spattern_len = 0;
spattern = NULL;
}
if(slocale_len == 0) {
slocale = INTL_G(default_locale);
}
if(msfgotmat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
"msgfmt_format_message: error converting pattern to quote-friendly format", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Create an ICU message formatter.
MSG_FORMAT_OBJECT(mfo) = umsg_open(spattern, spattern_len, slocale, NULL, &INTL_DATA_ERROR_CODE(mfo));
if(spattern && spattern_len) {
efree(spattern);
}
INTL_METHOD_CHECK_STATUS(mfo, "Creating message formatter failed");
msgfmt_do_format(mfo, args, return_value TSRMLS_CC);
// drop the temporary formatter
msgformat_data_free(&mfo->mf_data 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMAT_FORMAT_H
#define MSG_FORMAT_FORMAT_H
#include <php.h>
PHP_FUNCTION( msgfmt_format );
PHP_FUNCTION( msgfmt_format_message );
#endif // MSG_FORMAT_FORMAT_H

View File

@ -0,0 +1,211 @@
/*
+----------------------------------------------------------------------+
| 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 <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <unicode/msgfmt.h>
extern "C" {
#include "php_intl.h"
#include "msgformat_class.h"
#include "msgformat_format.h"
#include "msgformat_helpers.h"
#include "intl_convert.h"
}
U_NAMESPACE_BEGIN
/**
* This class isolates our access to private internal methods of
* MessageFormat. It is never instantiated; it exists only for C++
* access management.
*/
class MessageFormatAdapter {
public:
static const Formattable::Type* getArgTypeList(const MessageFormat& m,
int32_t& count);
};
const Formattable::Type*
MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
int32_t& count) {
return m.getArgTypeList(count);
}
U_NAMESPACE_END
U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
{
int32_t fmt_count = 0;
MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
return fmt_count;
}
U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC)
{
int fmt_count = 0;
const Formattable::Type* argTypes =
MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
Formattable* fargs = new Formattable[fmt_count ? fmt_count : 1];
for(int32_t i = 0; i < fmt_count; ++i) {
UChar *stringVal = NULL;
int stringLen = 0;
int64_t tInt64 = 0;
switch(argTypes[i]) {
case Formattable::kDate:
convert_to_long_ex(&args[i]);
fargs[i].setDate(U_MILLIS_PER_SECOND * (double)Z_LVAL_P(args[i]));
break;
case Formattable::kDouble:
convert_to_double_ex(&args[i]);
fargs[i].setDouble(Z_DVAL_P(args[i]));
break;
case Formattable::kLong:
convert_to_long_ex(&args[i]);
fargs[i].setLong(Z_LVAL_P(args[i]));
break;
case Formattable::kInt64:
if(Z_TYPE_P(args[i]) == IS_DOUBLE) {
tInt64 = (int64_t)Z_DVAL_P(args[i]);
} else if(Z_TYPE_P(args[i]) == IS_LONG) {
tInt64 = (int64_t)Z_LVAL_P(args[i]);
} else {
SEPARATE_ZVAL_IF_NOT_REF(&args[i]);
convert_scalar_to_number( args[i] TSRMLS_CC );
tInt64 = (Z_TYPE_P(args[i]) == IS_DOUBLE)?(int64_t)Z_DVAL_P(args[i]):Z_LVAL_P(args[i]);
}
fargs[i].setInt64(tInt64);
break;
case Formattable::kString:
convert_to_string_ex(&args[i]);
intl_convert_utf8_to_utf16(&stringVal, &stringLen, Z_STRVAL_P(args[i]), Z_STRLEN_P(args[i]), status);
if(U_FAILURE(*status)){
delete[] fargs;
return;
}
fargs[i].setString(stringVal);
efree(stringVal);
break;
case Formattable::kArray:
case Formattable::kObject:
*status = U_UNSUPPORTED_ERROR;
delete[] fargs;
return;
}
}
UnicodeString resultStr;
FieldPosition fieldPosition(0);
/* format the message */
((const MessageFormat*)fmt)->format(fargs, fmt_count, resultStr, fieldPosition, *status);
delete[] fargs;
if(U_FAILURE(*status)){
return;
}
*formatted_len = resultStr.length();
*formatted = eumalloc(*formatted_len+1);
resultStr.extract(*formatted, *formatted_len+1, *status);
}
#define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UChar *source, int source_len, UErrorCode *status)
{
UnicodeString srcString(source, source_len);
Formattable *fargs = ((const MessageFormat*)fmt)->parse(srcString, *count, *status);
if(U_FAILURE(*status)) {
return;
}
*args = (zval **)safe_emalloc(*count, sizeof(zval *), 0);
// assign formattables to varargs
for(int32_t i = 0; i < *count; i++) {
int64_t aInt64;
double aDate;
UnicodeString temp;
char *stmp;
int stmp_len;
ALLOC_INIT_ZVAL((*args)[i]);
switch(fargs[i].getType()) {
case Formattable::kDate:
aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
if(aDate > LONG_MAX || aDate < -LONG_MAX) {
ZVAL_DOUBLE((*args)[i], aDate<0?ceil(aDate):floor(aDate));
} else {
ZVAL_LONG((*args)[i], (long)aDate);
}
break;
case Formattable::kDouble:
ZVAL_DOUBLE((*args)[i], (double)fargs[i].getDouble());
break;
case Formattable::kLong:
ZVAL_LONG((*args)[i], fargs[i].getLong());
break;
case Formattable::kInt64:
aInt64 = fargs[i].getInt64();
if(aInt64 > LONG_MAX || aInt64 < -LONG_MAX) {
ZVAL_DOUBLE((*args)[i], (double)aInt64);
} else {
ZVAL_LONG((*args)[i], (long)aInt64);
}
break;
case Formattable::kString:
fargs[i].getString(temp);
intl_convert_utf16_to_utf8(&stmp, &stmp_len, temp.getBuffer(), temp.length(), status);
if(U_FAILURE(*status)) {
cleanup_zvals();
return;
}
ZVAL_STRINGL((*args)[i], stmp, stmp_len, 0);
break;
case Formattable::kObject:
case Formattable::kArray:
*status = U_ILLEGAL_ARGUMENT_ERROR;
cleanup_zvals();
break;
}
}
delete[] fargs;
}
/*
* 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMAT_HELPERS_H
#define MSG_FORMAT_HELPERS_H
int32_t umsg_format_arg_count(UMessageFormat *fmt);
void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args,
UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC);
void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args,
UChar *source, int source_len, UErrorCode *status);
#endif // MSG_FORMAT_HELPERS_H

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unicode/ustring.h>
#include "php_intl.h"
#include "msgformat_class.h"
#include "msgformat_parse.h"
#include "msgformat_data.h"
#include "msgformat_helpers.h"
#include "intl_convert.h"
/* {{{ */
static void msgfmt_do_parse(MessageFormatter_object *mfo, char *source, int src_len, zval *return_value TSRMLS_DC)
{
zval **fargs;
int count = 0;
int i;
UChar *usource = NULL;
int usrc_len = 0;
intl_convert_utf8_to_utf16(&usource, &usrc_len, source, src_len, &INTL_DATA_ERROR_CODE(mfo));
INTL_METHOD_CHECK_STATUS(mfo, "Converting parse string failed");
umsg_parse_helper(MSG_FORMAT_OBJECT(mfo), &count, &fargs, usource, usrc_len, &INTL_DATA_ERROR_CODE(mfo));
efree(usource);
INTL_METHOD_CHECK_STATUS(mfo, "Parsing failed");
array_init(return_value);
for(i=0;i<count;i++) {
add_next_index_zval(return_value, fargs[i]);
}
efree(fargs);
}
/* }}} */
/* {{{ proto array MessageFormatter::parse( string $source )
* Parse a message }}} */
/* {{{ proto array msgfmt_parse( MessageFormatter $nf, string $source )
* Parse a message.
*/
PHP_FUNCTION( msgfmt_parse )
{
char *source;
int source_len;
MSG_FORMAT_METHOD_INIT_VARS;
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
&object, MessageFormatter_ce_ptr, &source, &source_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_parse: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Fetch the object.
MSG_FORMAT_METHOD_FETCH_OBJECT;
msgfmt_do_parse(mfo, source, source_len, return_value TSRMLS_CC);
}
/* }}} */
/* {{{ proto array MessageFormatter::formatMessage( string $locale, string $pattern, string $source )
* Parse a message. }}} */
/* {{{ proto array numfmt_parse_message( string $locale, string $pattern, string $source )
* Parse a message.
*/
PHP_FUNCTION( msgfmt_parse_message )
{
UChar *spattern = NULL;
int spattern_len = 0;
char *pattern = NULL;
int pattern_len = 0;
char *slocale = NULL;
int slocale_len = 0;
char *source = NULL;
int src_len = 0;
MessageFormatter_object mf = {0};
MessageFormatter_object *mfo = &mf;
// Parse parameters.
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sss",
&slocale, &slocale_len, &pattern, &pattern_len, &source, &src_len ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_parse_message: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
msgformat_data_init(&mfo->mf_data TSRMLS_CC);
if(pattern && pattern_len) {
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo));
if( U_FAILURE(INTL_DATA_ERROR_CODE((mfo))) )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"msgfmt_parse_message: error converting pattern to UTF-16", 0 TSRMLS_CC );
RETURN_FALSE;
}
} else {
spattern_len = 0;
spattern = NULL;
}
if(slocale_len == 0) {
slocale = INTL_G(default_locale);
}
if(msfgotmat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
"msgfmt_parse_message: error converting pattern to quote-friendly format", 0 TSRMLS_CC );
RETURN_FALSE;
}
// Create an ICU message formatter.
MSG_FORMAT_OBJECT(mfo) = umsg_open(spattern, spattern_len, slocale, NULL, &INTL_DATA_ERROR_CODE(mfo));
if(spattern && spattern_len) {
efree(spattern);
}
INTL_METHOD_CHECK_STATUS(mfo, "Creating message formatter failed");
msgfmt_do_parse(mfo, source, src_len, return_value TSRMLS_CC);
// drop the temporary formatter
msgformat_data_free(&mfo->mf_data 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
*/

View File

@ -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: Stanislav Malyshev <stas@zend.com> |
+----------------------------------------------------------------------+
*/
#ifndef MSG_FORMAT_PARSE_H
#define MSG_FORMAT_PARSE_H
#include <php.h>
PHP_FUNCTION( msgfmt_parse );
PHP_FUNCTION( msgfmt_parse_message );
#endif // MSG_FORMAT_PARSE_H

View File

@ -0,0 +1,68 @@
/*
+----------------------------------------------------------------------+
| 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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "normalizer_class.h"
#include "normalizer.h"
#include <unicode/utypes.h>
#include <unicode/unorm.h>
#include <unicode/ustring.h>
/* {{{ normalizer_register_constants
* Register constants common for the both (OO and procedural)
* APIs.
*/
void normalizer_register_constants( INIT_FUNC_ARGS )
{
if( !Normalizer_ce_ptr )
{
zend_error( E_ERROR, "Normalizer class not defined" );
return;
}
#define NORMALIZER_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS)
#define NORMALIZER_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( Normalizer_ce_ptr, ZEND_STRS( #x ) - 1, NORMALIZER_##x TSRMLS_CC );
#define NORMALIZER_EXPOSE_CUSTOM_CLASS_CONST(name, value) zend_declare_class_constant_long( Normalizer_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );
// Normalization form constants
NORMALIZER_EXPOSE_CLASS_CONST( NONE );
NORMALIZER_EXPOSE_CLASS_CONST( FORM_D );
NORMALIZER_EXPOSE_CLASS_CONST( NFD );
NORMALIZER_EXPOSE_CLASS_CONST( FORM_KD );
NORMALIZER_EXPOSE_CLASS_CONST( NFKD );
NORMALIZER_EXPOSE_CLASS_CONST( FORM_C );
NORMALIZER_EXPOSE_CLASS_CONST( NFC );
NORMALIZER_EXPOSE_CLASS_CONST( FORM_KC );
NORMALIZER_EXPOSE_CLASS_CONST( NFKC );
#undef NORMALIZER_EXPOSE_CUSTOM_CLASS_CONST
#undef NORMALIZER_EXPOSE_CLASS_CONST
#undef NORMALIZER_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
*/

View File

@ -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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifndef NORMALIZER_NORMALIZER_H
#define NORMALIZER_NORMALIZER_H
#include <php.h>
#include <unicode/utypes.h>
#include <unicode/unorm.h>
#define NORMALIZER_NONE UNORM_NONE
#define NORMALIZER_FORM_D UNORM_NFD
#define NORMALIZER_NFD UNORM_NFD
#define NORMALIZER_FORM_KD UNORM_NFKD
#define NORMALIZER_NFKD UNORM_NFKD
#define NORMALIZER_FORM_C UNORM_NFC
#define NORMALIZER_NFC UNORM_NFC
#define NORMALIZER_FORM_KC UNORM_NFKC
#define NORMALIZER_NFKC UNORM_NFKC
#define NORMALIZER_DEFAULT UNORM_DEFAULT
void normalizer_register_constants( INIT_FUNC_ARGS );
#endif // NORMALIZER_NORMALIZER_H

View File

@ -0,0 +1,82 @@
/*
+----------------------------------------------------------------------+
| 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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#include "normalizer_class.h"
#include "php_intl.h"
#include "normalizer_normalize.h"
#include "intl_error.h"
#include <unicode/unorm.h>
zend_class_entry *Normalizer_ce_ptr = NULL;
/////////////////////////////////////////////////////////////////////////////
// 'Normalizer' class registration structures & functions
/////////////////////////////////////////////////////////////////////////////
/* {{{ Normalizer methods arguments info */
static
ZEND_BEGIN_ARG_INFO_EX( normalizer_3_args, 0, 0, 3 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_ARG_INFO( 0, arg2 )
ZEND_ARG_INFO( 0, arg3 )
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ Normalizer_class_functions
* Every 'Normalizer' class method has an entry in this table
*/
function_entry Normalizer_class_functions[] = {
ZEND_FENTRY( normalize, ZEND_FN( normalizer_normalize ), normalizer_3_args, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
ZEND_FENTRY( isNormalized, ZEND_FN( normalizer_is_normalized ), normalizer_3_args, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
{ NULL, NULL, NULL }
};
/* }}} */
/* {{{ normalizer_register_Normalizer_class
* Initialize 'Normalizer' class
*/
void normalizer_register_Normalizer_class( TSRMLS_D )
{
zend_class_entry ce;
// Create and register 'Normalizer' class.
INIT_CLASS_ENTRY( ce, "Normalizer", Normalizer_class_functions );
ce.create_object = NULL;
Normalizer_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
// Declare 'Normalizer' class properties.
if( !Normalizer_ce_ptr )
{
zend_error( E_ERROR,
"Normalizer: attempt to create properties "
"on a non-registered class." );
return;
}
}
/* }}} */
/*
* 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
*/

View File

@ -0,0 +1,52 @@
/*
+----------------------------------------------------------------------+
| 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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifndef NORMALIZER_CLASS_H
#define NORMALIZER_CLASS_H
#include <php.h>
#include "intl_common.h"
#include "intl_error.h"
#include <unicode/unorm.h>
typedef struct {
zend_object zo;
// error value not used currently
intl_error err;
} Normalizer_object;
#define NORMALIZER_ERROR(co) (co)->err
#define NORMALIZER_ERROR_P(co) &(NORMALIZER_ERROR(co))
#define NORMALIZER_ERROR_CODE(co) INTL_ERROR_CODE(NORMALIZER_ERROR(co))
#define NORMALIZER_ERROR_CODE_P(co) &(INTL_ERROR_CODE(NORMALIZER_ERROR(co)))
void normalizer_register_Normalizer_class( TSRMLS_D );
void normalizer_object_init( Normalizer_object* co TSRMLS_DC );
void normalizer_object_destroy( Normalizer_object* co TSRMLS_DC );
extern zend_class_entry *Normalizer_ce_ptr;
/* Auxiliary macros */
#define NORMALIZER_METHOD_INIT_VARS \
intl_error_reset( NULL TSRMLS_CC ); \
#endif // #ifndef NORMALIZER_CLASS_H

View File

@ -0,0 +1,256 @@
/*
+----------------------------------------------------------------------+
| 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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "unicode/unorm.h"
#include "normalizer.h"
#include "normalizer_class.h"
#include "normalizer_normalize.h"
#include "intl_convert.h"
/* {{{ proto string Normalizer::normalize( string $input [, string $form = FORM_C] )
* Normalize a string. }}} */
/* {{{ proto string normalizer_normalize( string $input [, string $form = FORM_C] )
* Normalize a string.
*/
PHP_FUNCTION( normalizer_normalize )
{
char* input = NULL;
// form is optional, defaults to FORM_C
long form = NORMALIZER_DEFAULT;
int input_len = 0;
UChar* uinput = NULL;
int uinput_len = 0;
int expansion_factor = 1;
UErrorCode status = U_ZERO_ERROR;
UChar* uret_buf = NULL;
int uret_len = 0;
char* ret_buf = NULL;
int32_t ret_len = 0;
int32_t size_needed;
NORMALIZER_METHOD_INIT_VARS
intl_error_reset( NULL TSRMLS_CC );
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "s|l",
&input, &input_len, &form ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"normalizer_normalize: unable to parse input params", 1 TSRMLS_CC );
RETURN_NULL();
}
expansion_factor = 1;
switch(form) {
case NORMALIZER_NONE:
break;
case NORMALIZER_FORM_D:
expansion_factor = 3;
break;
case NORMALIZER_FORM_KD:
expansion_factor = 3;
break;
case NORMALIZER_FORM_C:
case NORMALIZER_FORM_KC:
break;
default:
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"normalizer_normalize: illegal normalization form", 1 TSRMLS_CC );
RETURN_NULL();
}
/*
* Normalize string (converting it to UTF-16 first).
*/
// First convert the string to UTF-16.
intl_convert_utf8_to_utf16(&uinput, &uinput_len, input, input_len, &status );
if( U_FAILURE( status ) )
{
// Set global error code.
intl_error_set_code( NULL, status TSRMLS_CC );
// Set error messages.
intl_error_set_custom_msg( NULL, "Error converting input string to UTF-16", 1 TSRMLS_CC );
efree( uinput );
RETURN_NULL();
}
// Allocate memory for the destination buffer for normalization
uret_len = uinput_len * expansion_factor;
uret_buf = eumalloc( uret_len + 1 );
// normalize
size_needed = unorm_normalize( uinput, uinput_len, form, (int32_t) 0 /* options */, uret_buf, uret_len, &status);
// Bail out if an unexpected error occured.
// (U_BUFFER_OVERFLOW_ERROR means that *target buffer is not large enough).
// (U_STRING_NOT_TERMINATED_WARNING usually means that the input string is empty).
if( U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR && status != U_STRING_NOT_TERMINATED_WARNING ) {
efree( uret_buf );
efree( uinput );
RETURN_NULL();
}
if ( size_needed > uret_len ) {
// realloc does not seem to work properly - memory is corrupted
// uret_buf = eurealloc(uret_buf, size_needed + 1);
efree( uret_buf );
uret_buf = eumalloc( size_needed + 1 );
uret_len = size_needed;
status = U_ZERO_ERROR;
// try normalize again
size_needed = unorm_normalize( uinput, uinput_len, form, (int32_t) 0 /* options */, uret_buf, uret_len, &status);
// Bail out if an unexpected error occured.
if( U_FAILURE(status) ) {
// Set error messages.
intl_error_set_custom_msg( NULL,"Error normalizing string", 1 TSRMLS_CC );
efree( uret_buf );
efree( uinput );
RETURN_NULL();
}
}
efree( uinput );
// the buffer we actually used
uret_len = size_needed;
// Convert normalized string from UTF-16 to UTF-8.
intl_convert_utf16_to_utf8( &ret_buf, &ret_len, uret_buf, uret_len, &status );
efree( uret_buf );
if( U_FAILURE( status ) )
{
intl_error_set( NULL, status,
"normalizer_normalize: error converting normalized text UTF-8", 1 TSRMLS_CC );
RETURN_NULL();
}
// Return it.
RETVAL_STRINGL( ret_buf, ret_len, FALSE );
}
/* }}} */
/* {{{ proto bool Normalizer::isNormalized( string $input [, string $form = FORM_C] )
* Test if a string is in a given normalization form. }}} */
/* {{{ proto bool normalizer_is_normalize( string $input [, string $form = FORM_C] )
* Test if a string is in a given normalization form.
*/
PHP_FUNCTION( normalizer_is_normalized )
{
char* input = NULL;
// form is optional, defaults to FORM_C
long form = NORMALIZER_DEFAULT;
int input_len = 0;
UChar* uinput = NULL;
int uinput_len = 0;
UErrorCode status = U_ZERO_ERROR;
UBool uret = FALSE;
NORMALIZER_METHOD_INIT_VARS
intl_error_reset( NULL TSRMLS_CC );
// Parse parameters.
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "s|l",
&input, &input_len, &form) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"normalizer_is_normalized: unable to parse input params", 1 TSRMLS_CC );
RETURN_FALSE;
}
switch(form) {
// case NORMALIZER_NONE: not allowed - doesn't make sense
case NORMALIZER_FORM_D:
case NORMALIZER_FORM_KD:
case NORMALIZER_FORM_C:
case NORMALIZER_FORM_KC:
break;
default:
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"normalizer_normalize: illegal normalization form", 1 TSRMLS_CC );
RETURN_NULL();
}
/*
* Test normalization of string (converting it to UTF-16 first).
*/
// First convert the string to UTF-16.
intl_convert_utf8_to_utf16(&uinput, &uinput_len, input, input_len, &status );
if( U_FAILURE( status ) )
{
// Set global error code.
intl_error_set_code( NULL, status TSRMLS_CC );
// Set error messages.
intl_error_set_custom_msg( NULL, "Error converting string to UTF-16.", 1 TSRMLS_CC );
efree( uinput );
RETURN_FALSE;
}
// test string
uret = unorm_isNormalizedWithOptions( uinput, uinput_len, form, (int32_t) 0 /* options */, &status);
efree( uinput );
// Bail out if an unexpected error occured.
if( U_FAILURE(status) ) {
// Set error messages.
intl_error_set_custom_msg( NULL,"Error testing if string is the given normalization form.", 1 TSRMLS_CC );
RETURN_FALSE;
}
if ( uret )
RETURN_TRUE;
RETURN_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
*/

View File

@ -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: Ed Batutis <ed@batutis.com> |
+----------------------------------------------------------------------+
*/
#ifndef NORMALIZER_NORMALIZE_H
#define NORMALIZER_NORMALIZE_H
#include <php.h>
PHP_FUNCTION( normalizer_normalize );
PHP_FUNCTION( normalizer_is_normalized );
#endif // NORMALIZER_NORMALIZE_H

490
ext/intl/php_intl.c Executable file
View File

@ -0,0 +1,490 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
| Stanislav Malyshev <stas@zend.com> |
| Kirti Velankar <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "intl_error.h"
#include "collator/collator_class.h"
#include "collator/collator.h"
#include "collator/collator_attr.h"
#include "collator/collator_compare.h"
#include "collator/collator_sort.h"
#include "collator/collator_convert.h"
#include "collator/collator_locale.h"
#include "collator/collator_create.h"
#include "collator/collator_error.h"
#include "formatter/formatter.h"
#include "formatter/formatter_class.h"
#include "formatter/formatter_attr.h"
#include "formatter/formatter_format.h"
#include "formatter/formatter_main.h"
#include "formatter/formatter_parse.h"
#include "msgformat/msgformat.h"
#include "msgformat/msgformat_class.h"
#include "msgformat/msgformat_attr.h"
#include "msgformat/msgformat_format.h"
#include "msgformat/msgformat_parse.h"
#include "normalizer/normalizer.h"
#include "normalizer/normalizer_class.h"
#include "normalizer/normalizer_normalize.h"
#include "locale/locale.h"
#include "locale/locale_class.h"
#include "locale/locale_methods.h"
#include "dateformat/dateformat.h"
#include "dateformat/dateformat_class.h"
#include "dateformat/dateformat_attr.h"
#include "dateformat/dateformat_format.h"
#include "dateformat/dateformat_parse.h"
#include "dateformat/dateformat_data.h"
#include "msgformat/msgformat.h"
#include "common/common_error.h"
#include <unicode/uloc.h>
#include <ext/standard/info.h>
#include "php_ini.h"
#define INTL_MODULE_VERSION PHP_INTL_VERSION
/*
* locale_get_default has a conflict since ICU also has
* a function with the same name
* in fact ICU appends the version no. to it also
* Hence the following undef for ICU version
* Same true for the locale_set_default function
*/
#undef locale_get_default
#undef locale_set_default
ZEND_DECLARE_MODULE_GLOBALS( intl )
/* {{{ Arguments info */
static
ZEND_BEGIN_ARG_INFO_EX( collator_static_0_args, 0, 0, 0 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( collator_static_1_arg, 0, 0, 1 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( collator_static_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_0_args, 0, 0, 1 )
ZEND_ARG_OBJ_INFO( 0, object, Collator, 0 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( collator_1_arg, 0, 0, 2 )
ZEND_ARG_OBJ_INFO( 0, object, Collator, 0 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( collator_2_args, 0, 0, 3 )
ZEND_ARG_OBJ_INFO( 0, object, Collator, 0 )
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, 2 )
ZEND_ARG_OBJ_INFO( 0, object, Collator, 0 )
ZEND_ARG_ARRAY_INFO( 1, arr, 0 )
ZEND_ARG_INFO( 0, sort_flags )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( numfmt_parse_arginfo, 0, 0, 2 )
ZEND_ARG_INFO( 0, formatter )
ZEND_ARG_INFO( 0, string )
ZEND_ARG_INFO( 0, type )
ZEND_ARG_INFO( 1, position )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( numfmt_parse_currency_arginfo, 0, 0, 3 )
ZEND_ARG_INFO( 0, formatter )
ZEND_ARG_INFO( 0, string )
ZEND_ARG_INFO( 1, currency )
ZEND_ARG_INFO( 1, position )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_0_args, 0, 0, 0 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_1_arg, 0, 0, 1 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_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( locale_3_args, 0, 0, 3 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_ARG_INFO( 0, arg2 )
ZEND_ARG_INFO( 0, arg3 )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( locale_4_args, 0, 0, 4 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_ARG_INFO( 0, arg2 )
ZEND_ARG_INFO( 0, arg3 )
ZEND_ARG_INFO( 0, arg4 )
ZEND_END_ARG_INFO()
#define intl_0_args collator_static_0_args
#define intl_1_arg collator_static_1_arg
static
ZEND_BEGIN_ARG_INFO_EX( normalizer_args, 0, 0, 1 )
ZEND_ARG_INFO( 0, input )
ZEND_ARG_INFO( 0, form )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( grapheme_1_arg, 0, 0, 1 )
ZEND_ARG_INFO( 0, string )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( grapheme_search_args, 0, 0, 2 )
ZEND_ARG_INFO( 0, haystack )
ZEND_ARG_INFO( 0, needle )
ZEND_ARG_INFO( 0, offset )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( grapheme_substr_args, 0, 0, 2 )
ZEND_ARG_INFO( 0, string )
ZEND_ARG_INFO( 0, start )
ZEND_ARG_INFO( 0, length )
ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO_EX( grapheme_strstr_args, 0, 0, 2 )
ZEND_ARG_INFO( 0, haystack )
ZEND_ARG_INFO( 0, needle )
ZEND_ARG_INFO( 0, before_needle )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( grapheme_extract_args, 0, 0, 2 )
ZEND_ARG_INFO( 0, arg1 )
ZEND_ARG_INFO( 0, arg2 )
ZEND_ARG_INFO( 0, arg3 )
ZEND_ARG_INFO( 0, arg4 )
ZEND_ARG_INFO( 1, arg5 ) /* 1 = pass by reference */
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ intl_functions
*
* Every user visible function must have an entry in intl_functions[].
*/
zend_function_entry intl_functions[] = {
// collator functions
PHP_FE( collator_create, collator_static_1_arg )
PHP_FE( collator_compare, collator_2_args )
PHP_FE( collator_get_attribute, collator_1_arg )
PHP_FE( collator_set_attribute, collator_2_args )
PHP_FE( collator_get_strength, collator_0_args )
PHP_FE( collator_set_strength, collator_1_arg )
PHP_FE( collator_sort, collator_sort_args )
PHP_FE( collator_sort_with_sort_keys, collator_sort_args )
PHP_FE( collator_asort, collator_sort_args )
PHP_FE( collator_get_locale, collator_1_arg )
PHP_FE( collator_get_error_code, collator_0_args )
PHP_FE( collator_get_error_message, collator_0_args )
// formatter functions
PHP_FE( numfmt_create, NULL )
PHP_FE( numfmt_format, NULL )
PHP_FE( numfmt_parse, numfmt_parse_arginfo )
PHP_FE( numfmt_format_currency, NULL )
PHP_FE( numfmt_parse_currency, numfmt_parse_currency_arginfo )
PHP_FE( numfmt_set_attribute, NULL )
PHP_FE( numfmt_get_attribute, NULL )
PHP_FE( numfmt_set_text_attribute, NULL )
PHP_FE( numfmt_get_text_attribute, NULL )
PHP_FE( numfmt_set_symbol, NULL )
PHP_FE( numfmt_get_symbol, NULL )
PHP_FE( numfmt_set_pattern, NULL )
PHP_FE( numfmt_get_pattern, NULL )
PHP_FE( numfmt_get_locale, NULL )
PHP_FE( numfmt_get_error_code, NULL )
PHP_FE( numfmt_get_error_message, NULL )
// normalizer functions
PHP_FE( normalizer_normalize, normalizer_args )
PHP_FE( normalizer_is_normalized, normalizer_args )
//Locale functions
PHP_NAMED_FE( locale_get_default, zif_locale_get_default, locale_0_args )
PHP_NAMED_FE( locale_set_default, zif_locale_set_default, locale_1_arg )
PHP_FE( locale_get_primary_language, locale_1_arg )
PHP_FE( locale_get_script, locale_1_arg )
PHP_FE( locale_get_region, locale_1_arg )
PHP_FE( locale_get_keywords, locale_1_arg )
PHP_FE( locale_get_display_script, locale_2_args )
PHP_FE( locale_get_display_region, locale_2_args )
PHP_FE( locale_get_display_name, locale_2_args )
PHP_FE( locale_get_display_language, locale_2_args)
PHP_FE( locale_get_display_variant, locale_2_args )
PHP_FE( locale_compose, locale_1_arg )
PHP_FE( locale_parse, locale_1_arg )
PHP_FE( locale_get_all_variants, locale_1_arg )
PHP_FE( locale_filter_matches, locale_3_args )
PHP_FE( locale_canonicalize, locale_1_arg )
PHP_FE( locale_lookup, locale_4_args )
// MessageFormatter functions
PHP_FE( msgfmt_create, NULL )
PHP_FE( msgfmt_format, NULL )
PHP_FE( msgfmt_format_message, NULL )
PHP_FE( msgfmt_parse, NULL )
PHP_FE( msgfmt_parse_message, NULL )
PHP_FE( msgfmt_set_pattern, NULL )
PHP_FE( msgfmt_get_pattern, NULL )
PHP_FE( msgfmt_get_locale, NULL )
PHP_FE( msgfmt_get_error_code, NULL )
PHP_FE( msgfmt_get_error_message, NULL )
// IntlDateFormatter functions
PHP_FE( datefmt_create, NULL )
PHP_FE( datefmt_get_datetype, NULL )
PHP_FE( datefmt_get_timetype, NULL )
PHP_FE( datefmt_get_calendar, NULL )
PHP_FE( datefmt_set_calendar, NULL )
PHP_FE( datefmt_get_locale, NULL )
PHP_FE( datefmt_get_timezone_id, NULL )
PHP_FE( datefmt_set_timezone_id, NULL )
PHP_FE( datefmt_get_pattern, NULL )
PHP_FE( datefmt_set_pattern, NULL )
PHP_FE( datefmt_is_lenient, NULL )
PHP_FE( datefmt_set_lenient, NULL )
PHP_FE( datefmt_format, NULL )
PHP_FE( datefmt_parse, NULL )
PHP_FE( datefmt_localtime , NULL )
PHP_FE( datefmt_get_error_code, NULL )
PHP_FE( datefmt_get_error_message, NULL )
// grapheme functions
PHP_FE( grapheme_strlen, grapheme_1_arg )
PHP_FE( grapheme_strpos, grapheme_search_args )
PHP_FE( grapheme_stripos, grapheme_search_args )
PHP_FE( grapheme_strrpos, grapheme_search_args )
PHP_FE( grapheme_strripos, grapheme_search_args )
PHP_FE( grapheme_substr, grapheme_substr_args )
PHP_FE( grapheme_strstr, grapheme_strstr_args )
PHP_FE( grapheme_stristr, grapheme_strstr_args )
PHP_FE( grapheme_extract, grapheme_extract_args )
// common functions
PHP_FE( intl_get_error_code, intl_0_args )
PHP_FE( intl_get_error_message, intl_0_args )
PHP_FE( intl_is_failure, intl_1_arg )
PHP_FE( intl_error_name, intl_1_arg )
{ NULL, NULL, NULL }
};
/* }}} */
/* {{{ INI Settings */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY(LOCALE_INI_NAME, NULL, PHP_INI_ALL, OnUpdateStringUnempty, default_locale, zend_intl_globals, intl_globals)
PHP_INI_END()
/* }}} */
static PHP_GINIT_FUNCTION(intl);
/* {{{ intl_module_entry */
zend_module_entry intl_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
"intl",
intl_functions,
PHP_MINIT( intl ),
PHP_MSHUTDOWN( intl ),
PHP_RINIT( intl ),
PHP_RSHUTDOWN( intl ),
PHP_MINFO( intl ),
INTL_MODULE_VERSION,
PHP_MODULE_GLOBALS(intl), /* globals descriptor */
PHP_GINIT(intl), /* globals ctor */
NULL, /* globals dtor */
NULL, /* post deactivate */
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
#ifdef COMPILE_DL_INTL
ZEND_GET_MODULE( intl )
#endif
/* {{{ intl_init_globals */
static PHP_GINIT_FUNCTION(intl)
{
memset( intl_globals, 0, sizeof(zend_intl_globals) );
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION( intl )
{
//For the default locale php.ini setting
REGISTER_INI_ENTRIES();
REGISTER_LONG_CONSTANT("INTL_MAX_LOCALE_LEN", INTL_MAX_LOCALE_LEN, CONST_CS);
// Register 'Collator' PHP class
collator_register_Collator_class( TSRMLS_C );
// Expose Collator constants to PHP scripts
collator_register_constants( INIT_FUNC_ARGS_PASSTHRU );
// Register 'NumberFormatter' PHP class
formatter_register_class( TSRMLS_C );
// Expose NumberFormatter constants to PHP scripts
formatter_register_constants( INIT_FUNC_ARGS_PASSTHRU );
// Register 'Normalizer' PHP class
normalizer_register_Normalizer_class( TSRMLS_C );
// Expose Normalizer constants to PHP scripts
normalizer_register_constants( INIT_FUNC_ARGS_PASSTHRU );
// Register 'Locale' PHP class
locale_register_Locale_class( TSRMLS_C );
// Expose Locale constants to PHP scripts
locale_register_constants( INIT_FUNC_ARGS_PASSTHRU );
msgformat_register_class(TSRMLS_C);
grapheme_register_constants( INIT_FUNC_ARGS_PASSTHRU );
// Register 'DateFormat' PHP class
dateformat_register_IntlDateFormatter_class( TSRMLS_C );
// Expose DateFormat constants to PHP scripts
dateformat_register_constants( INIT_FUNC_ARGS_PASSTHRU );
// Expose ICU error codes to PHP scripts.
intl_expose_icu_error_codes( INIT_FUNC_ARGS_PASSTHRU );
// Global error handling.
intl_error_init( NULL TSRMLS_CC );
//Set the default_locale value
if( INTL_G(default_locale) == NULL ) {
INTL_G(default_locale) = pestrdup(uloc_getDefault(), 1) ;
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION( intl )
{
//For the default locale php.ini setting
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION( intl )
{
//Set the default_locale value
if( INTL_G(default_locale) == NULL ) {
INTL_G(default_locale) = pestrdup(uloc_getDefault(), 1) ;
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION( intl )
{
if(INTL_G(current_collator)) {
INTL_G(current_collator) = NULL;
}
if (INTL_G(grapheme_iterator)) {
grapheme_close_global_iterator( TSRMLS_C );
INTL_G(grapheme_iterator) = NULL;
}
intl_error_reset( NULL TSRMLS_CC);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION( intl )
{
php_info_print_table_start();
php_info_print_table_header( 2, "Internationalization support", "enabled" );
php_info_print_table_row( 2, "version", INTL_MODULE_VERSION );
php_info_print_table_end();
//For the default locale php.ini setting
DISPLAY_INI_ENTRIES() ;
}
/* }}} */
/*
* 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
*/

76
ext/intl/php_intl.h Executable file
View File

@ -0,0 +1,76 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Vadim Savchuk <vsavchuk@productengine.com> |
| Dmitry Lakhtyuk <dlakhtyuk@productengine.com> |
| Stanislav Malyshev <stas@zend.com> |
| Kirti Velankar <kirtig@yahoo-inc.com> |
+----------------------------------------------------------------------+
*/
#ifndef PHP_INTL_H
#define PHP_INTL_H
#include <php.h>
#include "collator/collator_sort.h"
#include "grapheme/grapheme.h"
#include "intl_error.h"
extern zend_module_entry intl_module_entry;
#define phpext_intl_ptr &intl_module_entry
#ifdef PHP_WIN32
#define PHP_INTL_API __declspec(dllexport)
#else
#define PHP_INTL_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
ZEND_BEGIN_MODULE_GLOBALS(intl)
zval* current_collator;
char* default_locale;
collator_compare_func_t compare_func;
UBreakIterator* grapheme_iterator;
intl_error g_error;
ZEND_END_MODULE_GLOBALS(intl)
/* Macro to access request-wide global variables. */
#ifdef ZTS
#define INTL_G(v) TSRMG(intl_globals_id, zend_intl_globals *, v)
#else
#define INTL_G(v) (intl_globals.v)
#endif
ZEND_EXTERN_MODULE_GLOBALS(intl)
PHP_MINIT_FUNCTION(intl);
PHP_MSHUTDOWN_FUNCTION(intl);
PHP_RINIT_FUNCTION(intl);
PHP_RSHUTDOWN_FUNCTION(intl);
PHP_MINFO_FUNCTION(intl);
#define PHP_INTL_VERSION "1.0.0"
#endif /* PHP_INTL_H */
/*
* 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
*/

29
ext/intl/tests/bug12887.phpt Executable file
View File

@ -0,0 +1,29 @@
--TEST--
locale_get_keywords() bug #12887
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
function ut_main()
{
$res_str = '';
$keywords_arr = ut_loc_get_keywords( 'de_DE@currency=EUR;collation=PHONEBOOK;sort=PHONEBOOK' );
if ($keywords_arr) {
foreach( $keywords_arr as $key => $value){
$res_str .= "$key = $value\n";
}
}
$res_str .= "\n";
return $res_str;
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
collation = PHONEBOOK
currency = EUR
sort = PHONEBOOK

View File

@ -0,0 +1,70 @@
--TEST--
Collation customization
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Check effects of changing misc collattion options.
*/
function cmp_array( &$coll, $a )
{
$res = '';
$prev = null;
foreach( $a as $i )
{
if( is_null( $prev ) )
$res .= "$i";
else
{
$eqrc = ut_coll_compare( $coll, $prev, $i );
$eq = $eqrc < 0 ? "<" : ( $eqrc > 0 ? ">" : "=" );
$res .= " $eq $i";
}
$prev = $i;
}
$res .= "\n";
return $res;
}
function check_alternate_handling( &$coll )
{
$res = '';
ut_coll_set_strength( $coll, Collator::TERTIARY );
ut_coll_set_attribute( $coll, Collator::ALTERNATE_HANDLING, Collator::NON_IGNORABLE );
$res .= cmp_array( $coll, array( 'di Silva', 'Di Silva', 'diSilva', 'U.S.A.', 'USA' ) );
ut_coll_set_attribute( $coll, Collator::ALTERNATE_HANDLING, Collator::SHIFTED );
$res .= cmp_array( $coll, array( 'di Silva', 'diSilva', 'Di Silva', 'U.S.A.', 'USA' ) );
ut_coll_set_strength( $coll, Collator::QUATERNARY );
$res .= cmp_array( $coll, array( 'di Silva', 'diSilva', 'Di Silva', 'U.S.A.', 'USA' ) );
$res .= "\n";
return $res;
}
function ut_main()
{
$coll = ut_coll_create( 'en_US' );
return
check_alternate_handling( $coll );
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
di Silva < Di Silva < diSilva < U.S.A. < USA
di Silva = diSilva < Di Silva < U.S.A. = USA
di Silva < diSilva < Di Silva < U.S.A. < USA

View File

@ -0,0 +1,242 @@
--TEST--
asort()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Sort associative arrays using various locales.
*/
$test_num = 1;
/*
* Sort various arrays in specified locale.
*/
function sort_arrays( $locale, $test_arrays, $sort_flag = Collator::SORT_REGULAR )
{
$res_str = '';
$coll = ut_coll_create( $locale );
foreach( $test_arrays as $test_array )
{
// Try to sort test data.
$res_val = ut_coll_asort( $coll, $test_array, $sort_flag );
// Return output data.
$res_dump = "\n" . dump( $test_array ) .
"\n Result: " . dump( $res_val );
// Preppend test signature to output string
$md5 = md5( $res_dump );
global $test_num;
$res_str .= "\n\n".
"Test $test_num.$md5:" .
$res_dump;
++$test_num;
}
return $res_str;
}
/*
* Test main function.
*/
function ut_main()
{
global $test_num;
$test_num = 1;
$res_str = '';
// Sort an array in SORT_REGULAR mode using en_US locale.
$test_params = array(
array( 'd' => 'y' ,
'c' => 'i' ,
'a' => 'k' ),
array( 'a' => 'a' ,
'b' => 'aaa',
'c' => 'aa' ),
array( 'a' => 'a' ,
'aaa'=> 'a' ,
'aa' => 'a' ),
array( '1' => 'abc',
'5' => '!' ,
'2' => null ,
'7' => '' ),
array( '1' => '100',
'2' => '25' ,
'3' => '36' ),
array( '1' => 5 ,
'2' => '30' ,
'3' => 2 )
);
$res_str .= sort_arrays( 'en_US', $test_params );
// Sort an array in SORT_STRING mode using en_US locale.
$test_params = array(
array( '1' => '100',
'2' => '25' ,
'3' => '36' ),
array( '1' => 5 ,
'2' => '30' ,
'3' => 2 ),
array( '1' => 'd' ,
'2' => '' ,
'3' => ' a' ),
array( '1' => 'y' ,
'2' => 'k' ,
'3' => 'i' )
);
$res_str .= sort_arrays( 'en_US', $test_params, Collator::SORT_STRING );
// Sort a non-ASCII array using ru_RU locale.
$test_params = array(
array( 'п' => 'у',
'б' => 'в',
'е' => 'а' ),
array( '1' => 'п',
'4' => '',
'7' => 'd',
'2' => 'пп' )
);
$res_str .= sort_arrays( 'ru_RU', $test_params );
// Sort an array using Lithuanian locale.
$test_params = array(
array( 'd' => 'y',
'c' => 'i',
'a' => 'k' )
);
$res_str .= sort_arrays( 'lt_LT', $test_params );
return $res_str . "\n";
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
Test 1.162b81ac12878b817fc39063097e45b5:
array (
'c' => 'i',
'a' => 'k',
'd' => 'y',
)
Result: true
Test 2.93d96e22f692d8a281b0a389f01f8d1e:
array (
'a' => 'a',
'c' => 'aa',
'b' => 'aaa',
)
Result: true
Test 3.9f25de4482bc7b58de508e278113317c:
array (
'aa' => 'a',
'aaa' => 'a',
'a' => 'a',
)
Result: true
Test 4.a85a41ea78e45b651080cfd98c0b431d:
array (
7 => '',
2 => NULL,
5 => '!',
1 => 'abc',
)
Result: true
Test 5.99dc71f405b286e03d489061b36e6900:
array (
2 => '25',
3 => '36',
1 => '100',
)
Result: true
Test 6.bf5bba243307c9d12934e756ad4be190:
array (
3 => 2,
1 => 5,
2 => '30',
)
Result: true
Test 7.e4ee7024c61476e9e7a6c28b5e47df6f:
array (
1 => '100',
2 => '25',
3 => '36',
)
Result: true
Test 8.5fa7033dd43784be0db1474eb48b83c8:
array (
3 => 2,
2 => '30',
1 => 5,
)
Result: true
Test 9.588cdf4692bc09aa92ffe7e48f9e4579:
array (
2 => '',
3 => ' a',
1 => 'd',
)
Result: true
Test 10.be02641a47ebcccd23e4183ca3a415f7:
array (
3 => 'i',
2 => 'k',
1 => 'y',
)
Result: true
Test 11.153d9b11d1e5936afc917a94a4e11f34:
array (
'е' => 'а',
'б' => 'в',
'п' => 'у',
)
Result: true
Test 12.6eaea3fa21b3b7d006ca7dfa27d4e282:
array (
4 => '',
7 => 'd',
1 => 'п',
2 => 'пп',
)
Result: true
Test 13.8800d48abb960a59002eef77f1d73ae0:
array (
'c' => 'i',
'd' => 'y',
'a' => 'k',
)
Result: true

View File

@ -0,0 +1,134 @@
--TEST--
compare()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Compare various string pairs using various locales.
*/
/*
* Converts comparison result to a character.
*/
function cmp_to_char( $comp_res )
{
switch( $comp_res )
{
case 0: // UCOL_EQUAL
return '=';
case 1: // UCOL_GREATER
return '>';
case -1: // UCOL_LESS
return '<';
default:
return '?';
}
}
/*
* Compare string pairs in the given array
* using specified locale.
*/
function compare_pairs( $locale, $test_array )
{
$res_str = '';
$coll = ut_coll_create( $locale );
foreach( $test_array as $test_strings )
{
list( $str1, $str2 ) = $test_strings;
// Compare strings.
$res_val = cmp_to_char( ut_coll_compare( $coll, $str1, $str2 ) );
// Concatenate result strings.
$res_str .= dump( $str1 ) .
' ' . $res_val . ' ' .
dump( $str2 ) . "\n";
}
return $res_str;
}
function ut_main()
{
$res_str = '';
// Compare strings using en_US locale.
$test_params = array(
array( 'abc', 'abc' ),
array( 'Abc', 'abc' ),
array( 'a' , 'abc' ),
array( 'a' , '' ),
array( '' , '' ),
array( 'a' , 'b' ),
array( 'ab' , 'b' ),
array( 'ab' , 'a' ),
array( 123 , 'abc' ),
array( 'ac' , null ),
array( '.' , '.' ),
// Try to compare long strings.
array( 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcde',
'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdea'),
array( null , null )
);
$res_str .= compare_pairs( 'en_US', $test_params );
// Compare strings using ru_RU locale.
$test_params = array(
array( 'а', 'б' ),
array( 'а', 'аа' ),
array( 'аб', 'ба' ),
array( 'а', ',' ),
array( 'а', 'b' ),
array( 'а', 'bb' ),
array( 'а', 'ab' ),
array( 'а', null )
);
$res_str .= compare_pairs( 'ru_RU', $test_params );
// Compare strings using lt_LT locale.
$test_params = array(
array( 'y', 'k' )
);
$res_str .= compare_pairs( 'lt_LT', $test_params );
return $res_str;
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
'abc' = 'abc'
'Abc' > 'abc'
'a' < 'abc'
'a' > ''
'' = ''
'a' < 'b'
'ab' < 'b'
'ab' > 'a'
123 < 'abc'
'ac' > NULL
'.' = '.'
'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcde' < 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdea'
NULL = NULL
'а' < 'б'
'а' < 'аа'
'аб' < 'ба'
'а' > ','
'а' > 'b'
'а' > 'bb'
'а' > 'ab'
'а' > NULL
'y' < 'k'

View File

@ -0,0 +1,81 @@
--TEST--
create()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Try creating collator with different locales
* with Procedural and Object methods.
*/
function ut_main()
{
$res_str = '';
$locales = array(
'EN-US-ODESSA',
'UK_UA_ODESSA',
'uk-ua_CALIFORNIA@currency=;currency=GRN',
'',
'root',
'uk@currency=EURO',
'1234567891113151719212325272931333537394143454749515357596163656769717375777981838587899193959799'
);
foreach( $locales as $locale )
{
// Create Collator with the current locale.
$coll = ut_coll_create( $locale );
if( !is_object($coll) )
{
$res_str .= "Error creating collator with '$locale' locale: " .
intl_get_error_message() . "\n";
continue;
}
// Get the requested, valid and actual locales.
$vloc = ut_coll_get_locale( $coll, Locale::VALID_LOCALE );
$aloc = ut_coll_get_locale( $coll, Locale::ACTUAL_LOCALE );
// Show them.
$res_str .= "Locale: '$locale'\n" .
" ULOC_REQUESTED_LOCALE = '$locale'\n" .
" ULOC_VALID_LOCALE = '$vloc'\n" .
" ULOC_ACTUAL_LOCALE = '$aloc'\n";
}
return $res_str;
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECTF--
Locale: 'EN-US-ODESSA'
ULOC_REQUESTED_LOCALE = 'EN-US-ODESSA'
ULOC_VALID_LOCALE = 'en_US'
ULOC_ACTUAL_LOCALE = 'en'
Locale: 'UK_UA_ODESSA'
ULOC_REQUESTED_LOCALE = 'UK_UA_ODESSA'
ULOC_VALID_LOCALE = 'uk_UA'
ULOC_ACTUAL_LOCALE = 'uk'
Locale: 'uk-ua_CALIFORNIA@currency=;currency=GRN'
ULOC_REQUESTED_LOCALE = 'uk-ua_CALIFORNIA@currency=;currency=GRN'
ULOC_VALID_LOCALE = 'uk_UA'
ULOC_ACTUAL_LOCALE = 'uk'
Locale: ''
ULOC_REQUESTED_LOCALE = ''
ULOC_VALID_LOCALE = '%s'
ULOC_ACTUAL_LOCALE = '%s'
Locale: 'root'
ULOC_REQUESTED_LOCALE = 'root'
ULOC_VALID_LOCALE = 'root'
ULOC_ACTUAL_LOCALE = 'root'
Locale: 'uk@currency=EURO'
ULOC_REQUESTED_LOCALE = 'uk@currency=EURO'
ULOC_VALID_LOCALE = 'uk'
ULOC_ACTUAL_LOCALE = 'uk'
Error creating collator with '1234567891113151719212325272931333537394143454749515357596163656769717375777981838587899193959799' locale: Locale string too long, should be no longer than 64 characters: U_ILLEGAL_ARGUMENT_ERROR

View File

@ -0,0 +1,47 @@
--TEST--
get_error_code()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Retreive error code.
*/
/*
* Check if error code equals to expected one.
*/
function check_rc( $rc, $expected )
{
return ( $rc === $expected ? "ok" : "failed" ) . "\n";
}
function ut_main()
{
$res = '';
$coll = ut_coll_create( 'ru_RU' );
// Try specifying a correct attribute.
ut_coll_get_attribute( $coll, Collator::NORMALIZATION_MODE );
$status = ut_coll_get_error_code( $coll );
$res .= check_rc( $status, U_ZERO_ERROR );
// Try specifying an incorrect attribute.
ut_coll_get_attribute( $coll, 12345 );
$status = ut_coll_get_error_code( $coll );
$res .= check_rc( $status, U_ILLEGAL_ARGUMENT_ERROR );
return $res;
}
# Suppress warning messages.
error_reporting( E_ERROR );
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
ok
ok

View File

@ -0,0 +1,36 @@
--TEST--
get_error_message()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Retreive error message.
*/
function ut_main()
{
$res = '';
$coll = ut_coll_create( 'ru_RU' );
// Try specifying a correct attribute.
ut_coll_get_attribute( $coll, Collator::NORMALIZATION_MODE );
$status = ut_coll_get_error_message( $coll );
$res .= $status . "\n";
// Try specifying an incorrect attribute.
ut_coll_get_attribute( $coll, 12345 );
$status = ut_coll_get_error_message( $coll );
$res .= $status . "\n";
return $res;
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
U_ZERO_ERROR
Error getting attribute value: U_ILLEGAL_ARGUMENT_ERROR

View File

@ -0,0 +1,52 @@
--TEST--
get_locale()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Try to specify valid and invalid locale types when getting locale.
*/
function ut_main()
{
$locales = array(
Locale::VALID_LOCALE,
Locale::ACTUAL_LOCALE,
100,
-100,
-9999999999999,
9999999999999,
1.2,
9999999999999999999999999999999999999999999999
);
$coll = ut_coll_create( 'en_US' );
$res_str = '';
foreach( $locales as $locale )
{
$rc = ut_coll_get_locale( $coll, $locale );
$res_str .= sprintf(
"Locale of type %s is %s\n",
dump( $locale ),
dump( $rc ) );
}
return $res_str . "\n";
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
Locale of type 1 is 'en_US'
Locale of type 0 is 'en'
Locale of type 100 is false
Locale of type -100 is false
Locale of type -9999999999999 is false
Locale of type 9999999999999 is false
Locale of type 1.2 is 'en_US'
Locale of type 1.0E+46 is false

View File

@ -0,0 +1,41 @@
--TEST--
get/set_attribute()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Try to set/get a collation attribute.
*/
/*
* Return current normalication mode.
*/
function check_val( $coll )
{
$val = ut_coll_get_attribute( $coll, Collator::NORMALIZATION_MODE );
return sprintf( "%s\n", ( $val == Collator::OFF ? "off" : "on" ) );
}
function ut_main()
{
$res = '';
$coll = ut_coll_create( 'en_US' );
ut_coll_set_attribute( $coll, Collator::NORMALIZATION_MODE, Collator::OFF );
$res .= check_val( $coll );
ut_coll_set_attribute( $coll, Collator::NORMALIZATION_MODE, Collator::ON );
$res .= check_val( $coll );
return $res;
}
include( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
off
on

View File

@ -0,0 +1,41 @@
--TEST--
get/set_strength()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Try to set/get collation strength.
*/
/*
* Set given collation strength, then get it back
* and check if it's the same.
*/
function check_set_strength( $coll, $val )
{
ut_coll_set_strength( $coll, $val );
$new_val = ut_coll_get_strength( $coll );
return ( $new_val == $val ? "ok" : "failed" ) . "\n";
}
function ut_main()
{
$res = '';
$coll = ut_coll_create( 'en_US' );
$res .= check_set_strength( $coll, Collator::PRIMARY );
$res .= check_set_strength( $coll, Collator::SECONDARY );
$res .= check_set_strength( $coll, Collator::TERTIARY );
return $res;
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
ok
ok
ok

247
ext/intl/tests/collator_sort.phpt Executable file
View File

@ -0,0 +1,247 @@
--TEST--
sort()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Sort arrays using various locales.
*/
$test_num = 1;
/*
* Sort arrays in the given list using specified locale.
*/
function sort_arrays( $locale, $arrays, $sort_flag = Collator::SORT_REGULAR )
{
$res_str = '';
$coll = ut_coll_create( $locale );
foreach( $arrays as $array )
{
// Sort array values
$res_val = ut_coll_sort( $coll, $array, $sort_flag );
// Concatenate the sorted array and function result
// with output string.
$res_dump = "\n" . dump( $array ) .
"\n Result: " . dump( $res_val );
// Preppend test signature to output string
$md5 = md5( $res_dump );
global $test_num;
$res_str .= "\n\n".
"Test $test_num.$md5:" .
$res_dump;
++$test_num;
}
return $res_str;
}
function ut_main()
{
global $test_num;
$test_num = 1;
$res_str = '';
// Sort an array in SORT_REGULAR mode using en_US locale.
$test_params = array(
array( 'abc', 'abd', 'aaa' ),
array( 'm' , '1' , '_' ),
array( 'a' , 'aaa', 'aa' ),
array( 'ba' , 'b' , 'ab' ),
array( 'e' , 'c' , 'a' ),
array( '100', '25' , '36' ),
array( 5 , '30' , 2 ),
array( 'd' , '' , ' a' ),
array( 'd ' , 'f ' , ' a' ),
array( 'a' , null , '3' ),
array( 'y' , 'k' , 'i' )
);
$res_str .= sort_arrays( 'en_US', $test_params );
$test_params = array(
array( '100', '25' , '36' ),
array( 5 , '30' , 2 ),
array( 'd' , '' , ' a' ),
array( 'y' , 'k' , 'i' )
);
// Sort in en_US locale with SORT_STRING flag
$res_str .= sort_arrays( 'en_US', $test_params, Collator::SORT_STRING );
// Sort a non-ASCII array using ru_RU locale.
$test_params = array(
array( 'абг', 'абв', 'ааа', 'abc' ),
array( 'аа', 'ааа' , 'а' )
);
$res_str .= sort_arrays( 'ru_RU', $test_params );
// Sort an array using Lithuanian locale.
$test_params = array(
array( 'y' , 'k' , 'i' )
);
$res_str .= sort_arrays( 'lt_LT', $test_params );
return $res_str;
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
Test 1.e8f1cd28133d79ecd660002f1c660d0e:
array (
0 => 'aaa',
1 => 'abc',
2 => 'abd',
)
Result: true
Test 2.c2ded12173dd2996927378cae37eb275:
array (
0 => '_',
1 => '1',
2 => 'm',
)
Result: true
Test 3.54071c968d71cb98c5d379145f8d7d38:
array (
0 => 'a',
1 => 'aa',
2 => 'aaa',
)
Result: true
Test 4.19abe63d6f6dfef65b0e3c9ab4826b07:
array (
0 => 'ab',
1 => 'b',
2 => 'ba',
)
Result: true
Test 5.9a8dc0a9bc771368c2f1fc3d02754610:
array (
0 => 'a',
1 => 'c',
2 => 'e',
)
Result: true
Test 6.ab530b060e5e54a65bfb8b9f8fc61870:
array (
0 => '25',
1 => '36',
2 => '100',
)
Result: true
Test 7.0718dd838509017bded2ed307a6e785f:
array (
0 => 2,
1 => 5,
2 => '30',
)
Result: true
Test 8.923d65739c5219c634616ffd100a50e4:
array (
0 => '',
1 => ' a',
2 => 'd',
)
Result: true
Test 9.289bc2f28e87d3201ec9d7e8477ae1b0:
array (
0 => ' a',
1 => 'd ',
2 => 'f ',
)
Result: true
Test 10.de0fd958484f2377a645835d7fbcf124:
array (
0 => NULL,
1 => '3',
2 => 'a',
)
Result: true
Test 11.dd2b8f0adb37c45d528cad1a0cc0f361:
array (
0 => 'i',
1 => 'k',
2 => 'y',
)
Result: true
Test 12.1e6b4d6f7df9d4580317634ea46d8208:
array (
0 => '100',
1 => '25',
2 => '36',
)
Result: true
Test 13.cec115dc9850b98dfbdf102efa09e61b:
array (
0 => 2,
1 => '30',
2 => 5,
)
Result: true
Test 14.923d65739c5219c634616ffd100a50e4:
array (
0 => '',
1 => ' a',
2 => 'd',
)
Result: true
Test 15.dd2b8f0adb37c45d528cad1a0cc0f361:
array (
0 => 'i',
1 => 'k',
2 => 'y',
)
Result: true
Test 16.ca0e38a2e3147dd97070f2128f140934:
array (
0 => 'abc',
1 => 'ааа',
2 => 'абв',
3 => 'абг',
)
Result: true
Test 17.91480b10473a0c96a4cd6d88c23c577a:
array (
0 => 'а',
1 => 'аа',
2 => 'ааа',
)
Result: true
Test 18.fdd3fe3981476039164aa000bf9177f2:
array (
0 => 'i',
1 => 'y',
2 => 'k',
)
Result: true

View File

@ -0,0 +1,189 @@
--TEST--
sort_with_sort_keys()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Sort arrays using various locales.
*/
$test_num = 1;
/*
* Sort arrays in the given list using specified locale.
*/
function sort_arrays( $locale, $arrays )
{
$res_str = '';
$coll = ut_coll_create( $locale );
foreach( $arrays as $array )
{
// Sort array values
$res_val = ut_coll_sort_with_sort_keys( $coll, $array );
// Concatenate the sorted array and function result
// with output string.
$res_dump = "\n" . dump( $array ) .
"\n Result: " . dump( $res_val );
// Preppend test signature to output string
$md5 = md5( $res_dump );
global $test_num;
$res_str .= "\n\n".
"Test $test_num.$md5:" .
$res_dump;
++$test_num;
}
return $res_str;
}
function ut_main()
{
global $test_num;
$test_num = 1;
$res_str = '';
// Sort an array in SORT_REGULAR mode using en_US locale.
$test_params = array(
array( 'abc', 'abd', 'aaa' ),
array( 'm' , '1' , '_' ),
array( 'a' , 'aaa', 'aa' ),
array( 'ba' , 'b' , 'ab' ),
array( 'e' , 'c' , 'a' ),
array( 'd' , '' , ' a' ),
array( 'd ' , 'f ' , ' a' ),
array( 'a' , null , '3' ),
array( 'y' , 'i' , 'k' )
);
$res_str .= sort_arrays( 'en_US', $test_params );
// Sort a non-ASCII array using ru_RU locale.
$test_params = array(
array( 'абг', 'абв', 'ааа', 'abc' ),
array( 'аа', 'ааа', 'а' )
);
$res_str .= sort_arrays( 'ru_RU', $test_params );
// Array with data for sorting.
$test_params = array(
array( 'y' , 'i' , 'k' )
);
// Sort an array using Lithuanian locale.
$res_str .= sort_arrays( 'lt_LT', $test_params );
return $res_str . "\n";
}
include_once( 'ut_common.inc' );
ut_run();
?>
--EXPECT--
Test 1.e8f1cd28133d79ecd660002f1c660d0e:
array (
0 => 'aaa',
1 => 'abc',
2 => 'abd',
)
Result: true
Test 2.c2ded12173dd2996927378cae37eb275:
array (
0 => '_',
1 => '1',
2 => 'm',
)
Result: true
Test 3.54071c968d71cb98c5d379145f8d7d38:
array (
0 => 'a',
1 => 'aa',
2 => 'aaa',
)
Result: true
Test 4.19abe63d6f6dfef65b0e3c9ab4826b07:
array (
0 => 'ab',
1 => 'b',
2 => 'ba',
)
Result: true
Test 5.9a8dc0a9bc771368c2f1fc3d02754610:
array (
0 => 'a',
1 => 'c',
2 => 'e',
)
Result: true
Test 6.923d65739c5219c634616ffd100a50e4:
array (
0 => '',
1 => ' a',
2 => 'd',
)
Result: true
Test 7.289bc2f28e87d3201ec9d7e8477ae1b0:
array (
0 => ' a',
1 => 'd ',
2 => 'f ',
)
Result: true
Test 8.de0fd958484f2377a645835d7fbcf124:
array (
0 => NULL,
1 => '3',
2 => 'a',
)
Result: true
Test 9.dd2b8f0adb37c45d528cad1a0cc0f361:
array (
0 => 'i',
1 => 'k',
2 => 'y',
)
Result: true
Test 10.ca0e38a2e3147dd97070f2128f140934:
array (
0 => 'abc',
1 => 'ааа',
2 => 'абв',
3 => 'абг',
)
Result: true
Test 11.91480b10473a0c96a4cd6d88c23c577a:
array (
0 => 'а',
1 => 'аа',
2 => 'ааа',
)
Result: true
Test 12.fdd3fe3981476039164aa000bf9177f2:
array (
0 => 'i',
1 => 'y',
2 => 'k',
)
Result: true

View File

@ -0,0 +1,297 @@
--TEST--
datefmt_format_code()
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
/*
* Test for the datefmt_format function
*/
function ut_main()
{
$locale_arr = array (
'en_US'
);
$datetype_arr = array (
IntlDateFormatter::FULL,
IntlDateFormatter::LONG,
IntlDateFormatter::MEDIUM,
IntlDateFormatter::SHORT,
IntlDateFormatter::NONE
);
$res_str = '';
$time_arr = array (
0,
-1200000,
1200000,
2200000000,
-2200000000,
90099999,
3600,
-3600
);
$localtime_arr1 = array (
'tm_sec' => 24 ,
'tm_min' => 3,
'tm_hour' => 19,
'tm_mday' => 3,
'tm_mon' => 3,
'tm_year' => 105,
'tm_wday' => 0,
'tm_yday' => 93,
'tm_isdst' => 1
);
$localtime_arr2 = array (
'tm_sec' => 24 ,
'tm_min' => 3,
'tm_hour' => 3,
'tm_mday' => 3,
'tm_mon' => 3,
'tm_year' => 205,
'tm_wday' => 5,
'tm_yday' => 93,
'tm_isdst' => 1
);
$localtime_arr3 = array (
'tm_sec' => 24 ,
'tm_min' => 3,
'tm_hour' => 3,
'tm_mday' => 3,
'tm_mon' => 3,
'tm_year' => -5,
'tm_wday' => 3,
'tm_yday' => 93,
'tm_isdst' => 1
);
$localtime_arr = array (
$localtime_arr1,
$localtime_arr2,
$localtime_arr3
);
//Test format with input as a timestamp : integer
foreach( $time_arr as $timestamp_entry){
$res_str .= "\n------------\n";
$res_str .= "\nInput timestamp is : $timestamp_entry";
$res_str .= "\n------------\n";
foreach( $locale_arr as $locale_entry ){
foreach( $datetype_arr as $datetype_entry )
{
$res_str .= "\nIntlDateFormatter locale= $locale_entry ,datetype = $datetype_entry ,timetype =$datetype_entry ";
//$fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry,'America/Los_Angeles', IntlDateFormatter::GREGORIAN ,"dd/mm/yyyy");
$fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry,'America/Los_Angeles', IntlDateFormatter::GREGORIAN );
//$fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry);
$formatted = ut_datefmt_format( $fmt , $timestamp_entry);
$res_str .= "\nFormatted timestamp is : $formatted";
}
}
}
//Test format with input as a localtime :array
foreach( $localtime_arr as $localtime_entry){
$res_str .= "\n------------\n";
$res_str .= "\nInput localtime is : ";
foreach( $localtime_entry as $key => $value){
$res_str .= "$key : '$value' , ";
}
$res_str .= "\n------------\n";
foreach( $locale_arr as $locale_entry ){
foreach( $datetype_arr as $datetype_entry )
{
$res_str .= "\nIntlDateFormatter locale= $locale_entry ,datetype = $datetype_entry ,timetype =$datetype_entry ";
$fmt = ut_datefmt_create( $locale_entry , $datetype_entry ,$datetype_entry);
$formatted1 = ut_datefmt_format( $fmt , $localtime_entry);
if( intl_get_error_code() == U_ZERO_ERROR){
$res_str .= "\nFormatted localtime_array is : $formatted1";
}else{
$res_str .= "\nError while formatting as: '".intl_get_error_message()."'";
}
}
}
}
return $res_str;
}
include_once( 'ut_common.inc' );
// Run the test
ut_run();
?>
--EXPECT--
------------
Input timestamp is : 0
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Wednesday, December 31, 1969 4:00:00 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : December 31, 1969 4:00:00 PM PST
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Dec 31, 1969 4:00:00 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 12/31/69 4:00 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19691231 04:00 PM
------------
Input timestamp is : -1200000
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Wednesday, December 17, 1969 6:40:00 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : December 17, 1969 6:40:00 PM PST
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Dec 17, 1969 6:40:00 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 12/17/69 6:40 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19691217 06:40 PM
------------
Input timestamp is : 1200000
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Wednesday, January 14, 1970 1:20:00 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : January 14, 1970 1:20:00 PM PST
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Jan 14, 1970 1:20:00 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 1/14/70 1:20 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19700114 01:20 PM
------------
Input timestamp is : 2200000000
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Sunday, September 18, 2039 4:06:40 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : September 18, 2039 4:06:40 PM PDT
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Sep 18, 2039 4:06:40 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 9/18/39 4:06 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 20390918 04:06 PM
------------
Input timestamp is : -2200000000
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Saturday, April 14, 1900 5:53:20 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : April 14, 1900 5:53:20 PM PDT
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Apr 14, 1900 5:53:20 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 4/14/00 5:53 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19000414 05:53 PM
------------
Input timestamp is : 90099999
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Wednesday, November 8, 1972 11:46:39 AM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : November 8, 1972 11:46:39 AM PST
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Nov 8, 1972 11:46:39 AM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 11/8/72 11:46 AM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19721108 11:46 AM
------------
Input timestamp is : 3600
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Wednesday, December 31, 1969 5:00:00 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : December 31, 1969 5:00:00 PM PST
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Dec 31, 1969 5:00:00 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 12/31/69 5:00 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19691231 05:00 PM
------------
Input timestamp is : -3600
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted timestamp is : Wednesday, December 31, 1969 3:00:00 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted timestamp is : December 31, 1969 3:00:00 PM PST
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted timestamp is : Dec 31, 1969 3:00:00 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted timestamp is : 12/31/69 3:00 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted timestamp is : 19691231 03:00 PM
------------
Input localtime is : tm_sec : '24' , tm_min : '3' , tm_hour : '19' , tm_mday : '3' , tm_mon : '3' , tm_year : '105' , tm_wday : '0' , tm_yday : '93' , tm_isdst : '1' ,
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted localtime_array is : Sunday, April 3, 2005 7:03:24 PM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted localtime_array is : April 3, 2005 7:03:24 PM PDT
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted localtime_array is : Apr 3, 2005 7:03:24 PM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted localtime_array is : 4/3/05 7:03 PM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted localtime_array is : 20050403 07:03 PM
------------
Input localtime is : tm_sec : '24' , tm_min : '3' , tm_hour : '3' , tm_mday : '3' , tm_mon : '3' , tm_year : '205' , tm_wday : '5' , tm_yday : '93' , tm_isdst : '1' ,
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted localtime_array is : Friday, April 3, 2105 3:03:24 AM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted localtime_array is : April 3, 2105 3:03:24 AM PDT
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted localtime_array is : Apr 3, 2105 3:03:24 AM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted localtime_array is : 4/3/05 3:03 AM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted localtime_array is : 21050403 03:03 AM
------------
Input localtime is : tm_sec : '24' , tm_min : '3' , tm_hour : '3' , tm_mday : '3' , tm_mon : '3' , tm_year : '-5' , tm_wday : '3' , tm_yday : '93' , tm_isdst : '1' ,
------------
IntlDateFormatter locale= en_US ,datetype = 0 ,timetype =0
Formatted localtime_array is : Wednesday, April 3, 1895 3:03:24 AM PT
IntlDateFormatter locale= en_US ,datetype = 1 ,timetype =1
Formatted localtime_array is : April 3, 1895 3:03:24 AM PDT
IntlDateFormatter locale= en_US ,datetype = 2 ,timetype =2
Formatted localtime_array is : Apr 3, 1895 3:03:24 AM
IntlDateFormatter locale= en_US ,datetype = 3 ,timetype =3
Formatted localtime_array is : 4/3/95 3:03 AM
IntlDateFormatter locale= en_US ,datetype = -1 ,timetype =-1
Formatted localtime_array is : 18950403 03:03 AM

Some files were not shown because too many files have changed in this diff Show More