diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-10-06 18:53:27 +0000 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-10-06 18:53:27 +0000 |
commit | e283f7a7fed6c6b953f64371a981fe1c95dd8f6c (patch) | |
tree | 92cdbb955e31ac1441232269f458a03da2f8a613 /ext/intl/transliterator/transliterator_class.c | |
parent | da6366e74a131a975ec7af1d797c025e1379cefb (diff) | |
download | php-git-e283f7a7fed6c6b953f64371a981fe1c95dd8f6c.tar.gz |
- Added support for ICU Transformations (Transliterator).
- Changes request #52986 to "to be documented".
Diffstat (limited to 'ext/intl/transliterator/transliterator_class.c')
-rw-r--r-- | ext/intl/transliterator/transliterator_class.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/ext/intl/transliterator/transliterator_class.c b/ext/intl/transliterator/transliterator_class.c new file mode 100644 index 0000000000..727cf1e485 --- /dev/null +++ b/ext/intl/transliterator/transliterator_class.c @@ -0,0 +1,434 @@ +/* + +----------------------------------------------------------------------+ + | 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: Gustavo Lopes <cataphract@php.net> | + +----------------------------------------------------------------------+ + */ + +#include "transliterator_class.h" +#include "php_intl.h" +#include "transliterator_methods.h" +#include "intl_error.h" +#include "intl_convert.h" +#include "intl_data.h" + +#include <unicode/utrans.h> + +zend_class_entry *Transliterator_ce_ptr = NULL; + +zend_object_handlers Transliterator_handlers; + +/* {{{ int transliterator_object_construct( zval *object, UTransliterator *utrans, UErrorCode *status TSRMLS_DC ) + * Initialize internals of Transliterator_object. + */ +int transliterator_object_construct( zval *object, + UTransliterator *utrans, + UErrorCode *status TSRMLS_DC ) +{ + const UChar *ustr_id; + int32_t ustr_id_len; + char *str_id; + int str_id_len; + Transliterator_object *to; + + TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; + + assert( to->utrans == NULL ); + /* this assignment must happen before any return with failure because the + * caller relies on it always being made (so it can just destroy the object + * to close the transliterator) */ + to->utrans = utrans; + + ustr_id = utrans_getUnicodeID( utrans, &ustr_id_len ); + intl_convert_utf16_to_utf8( &str_id, &str_id_len, ustr_id, (int ) ustr_id_len, status ); + if( U_FAILURE( *status ) ) + { + return FAILURE; + } + + zend_update_property_stringl( Transliterator_ce_ptr, object, + "id", sizeof( "id" ) - 1, str_id, str_id_len TSRMLS_CC ); + efree( str_id ); + return SUCCESS; +} +/* }}} */ + +/* + * Auxiliary functions needed by objects of 'Transliterator' class + */ + +/* {{{ void transliterator_object_init( Transliterator_object* to ) + * Initialize internals of Transliterator_object. + */ +static void transliterator_object_init( Transliterator_object* to TSRMLS_DC ) +{ + if( !to ) + return; + + intl_error_init( TRANSLITERATOR_ERROR_P( to ) TSRMLS_CC ); +} +/* }}} */ + +/* {{{ void transliterator_object_destroy( Transliterator_object* to ) + * Clean up mem allocted by internals of Transliterator_object + */ +static void transliterator_object_destroy( Transliterator_object* to TSRMLS_DC ) +{ + if( !to ) + return; + + if( to->utrans ) + { + utrans_close( to->utrans ); + to->utrans = NULL; + } + + intl_error_reset( TRANSLITERATOR_ERROR_P( to ) TSRMLS_CC ); +} +/* }}} */ + +/* {{{ Transliterator_objects_dtor */ +static void Transliterator_objects_dtor( + void *object, + zend_object_handle handle TSRMLS_DC ) +{ + zend_objects_destroy_object( object, handle TSRMLS_CC ); +} +/* }}} */ + +/* {{{ Transliterator_objects_free */ +static void Transliterator_objects_free( zend_object *object TSRMLS_DC ) +{ + Transliterator_object* to = (Transliterator_object*) object; + + zend_object_std_dtor( &to->zo TSRMLS_CC ); + + transliterator_object_destroy( to TSRMLS_CC ); + + efree( to ); +} +/* }}} */ + +/* {{{ Transliterator_object_create */ +static zend_object_value Transliterator_object_create( + zend_class_entry *ce TSRMLS_DC ) +{ + zend_object_value retval; + Transliterator_object* intern; + + intern = ecalloc( 1, sizeof( Transliterator_object ) ); + + zend_object_std_init( &intern->zo, ce TSRMLS_CC ); +#if PHP_VERSION_ID < 50399 + zend_hash_copy( intern->zo.properties, &(ce->default_properties ), + (copy_ctor_func_t) zval_add_ref, NULL, sizeof( zval* ) ); +#else + object_properties_init( (zend_object*) intern, ce ); +#endif + transliterator_object_init( intern TSRMLS_CC ); + + retval.handle = zend_objects_store_put( + intern, + Transliterator_objects_dtor, + (zend_objects_free_object_storage_t) Transliterator_objects_free, + NULL TSRMLS_CC ); + + retval.handlers = &Transliterator_handlers; + + return retval; +} +/* }}} */ + +/* + * Object handlers for Transliterator class (and subclasses) + */ + +/* {{{ clone handler for Transliterator */ +static zend_object_value Transliterator_clone_obj( zval *object TSRMLS_DC ) +{ + Transliterator_object *to_orig, + *to_new; + zend_object_value ret_val; + intl_error_reset( NULL TSRMLS_CC ); + + to_orig = zend_object_store_get_object( object TSRMLS_CC ); + intl_error_reset( INTL_DATA_ERROR_P( to_orig ) TSRMLS_CC ); + ret_val = Transliterator_ce_ptr->create_object( Transliterator_ce_ptr TSRMLS_CC ); + to_new = zend_object_store_get_object_by_handle( ret_val.handle TSRMLS_CC ); + + zend_objects_clone_members( &to_new->zo, ret_val, + &to_orig->zo, Z_OBJ_HANDLE_P( object ) TSRMLS_CC ); + + if( to_orig->utrans != NULL ) + { + UTransliterator *utrans = NULL; + zval tempz; /* dummy zval to pass to transliterator_object_construct */ + + /* guaranteed to return NULL if it fails */ + utrans = utrans_clone( to_orig->utrans, TRANSLITERATOR_ERROR_CODE_P( to_orig ) ); + + if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) ) + goto err; + + Z_OBJVAL( tempz ) = ret_val; + transliterator_object_construct( &tempz, utrans, + TRANSLITERATOR_ERROR_CODE_P( to_orig ) TSRMLS_CC ); + + if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) ) + { + char *err_msg; +err: + + if( utrans != NULL ) + transliterator_object_destroy( to_new TSRMLS_CC ); + + /* set the error anyway, in case in the future we decide not to + * throw an error. It also helps build the error message */ + intl_error_set_code( NULL, INTL_DATA_ERROR_CODE( to_orig ) TSRMLS_CC ); + intl_errors_set_custom_msg( TRANSLITERATOR_ERROR_P( to_orig ), + "Could not clone transliterator", 0 TSRMLS_CC ); + + err_msg = intl_error_get_message( TRANSLITERATOR_ERROR_P( to_orig ) TSRMLS_CC ); + php_error_docref( NULL TSRMLS_CC, E_ERROR, "%s", err_msg ); + efree( err_msg ); /* if it's changed into a warning */ + /* do not destroy tempz; we need to return something */ + } + } + else + { + /* We shouldn't have unconstructed objects in the first place */ + php_error_docref( NULL TSRMLS_CC, E_WARNING, + "Cloning unconstructed transliterator." ); + } + + return ret_val; +} +/* }}} */ + +#if PHP_VERSION_ID >= 50399 +# define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG \ + zval tmp_member; \ + if( Z_TYPE_P( member ) != IS_STRING ) \ + { \ + tmp_member = *member; \ + zval_copy_ctor( &tmp_member ); \ + convert_to_string( &tmp_member ); \ + member = &tmp_member; \ + key = NULL; \ + } +#else +# define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG \ + zval tmp_member; \ + if( Z_TYPE_P( member ) != IS_STRING ) \ + { \ + tmp_member = *member; \ + zval_copy_ctor( &tmp_member ); \ + convert_to_string( &tmp_member ); \ + member = &tmp_member; \ + } +#endif + +#define TRANSLITERATOR_PROPERTY_HANDLER_EPILOG \ + if( member == &tmp_member ) \ + { \ + zval_dtor( &tmp_member ); \ + } + +/* {{{ get_property_ptr_ptr handler */ +#if PHP_VERSION_ID < 50399 +static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member TSRMLS_DC ) +#else +static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member, + const struct _zend_literal *key TSRMLS_DC ) +#endif +{ + zval **retval; + + TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; + + if(zend_binary_strcmp( "id", sizeof( "id" ) - 1, + Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) + { + retval = NULL; /* fallback to read_property */ + } + else + { +#if PHP_VERSION_ID < 50399 + retval = std_object_handlers.get_property_ptr_ptr( object, member TSRMLS_CC ); +#else + retval = std_object_handlers.get_property_ptr_ptr( object, member, key TSRMLS_CC ); +#endif + } + + TRANSLITERATOR_PROPERTY_HANDLER_EPILOG; + + return retval; +} +/* }}} */ + +/* {{{ read_property handler */ +#if PHP_VERSION_ID < 50399 +static zval *Transliterator_read_property( zval *object, zval *member, int type TSRMLS_DC ) /* {{{ */ +#else +static zval *Transliterator_read_property( zval *object, zval *member, int type, + const struct _zend_literal *key TSRMLS_DC ) /* {{{ */ +#endif +{ + zval *retval; + + TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; + + if( ( type != BP_VAR_R && type != BP_VAR_IS ) && + ( zend_binary_strcmp( "id", sizeof( "id" ) - 1, + Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) ) + { + php_error_docref0( NULL TSRMLS_CC, E_WARNING, "The property \"id\" is read-only" ); + retval = &EG( uninitialized_zval ); + } + else + { +#if PHP_VERSION_ID < 50399 + retval = std_object_handlers.read_property( object, member, type TSRMLS_CC ); +#else + retval = std_object_handlers.read_property( object, member, type, key TSRMLS_CC ); +#endif + } + + TRANSLITERATOR_PROPERTY_HANDLER_EPILOG; + + return retval; +} + +/* }}} */ + +/* {{{ write_property handler */ +#if PHP_VERSION_ID < 50399 +static void Transliterator_write_property( zval *object, zval *member, zval *value TSRMLS_DC ) +#else +static void Transliterator_write_property( zval *object, zval *member, zval *value, + const struct _zend_literal *key TSRMLS_DC ) +#endif +{ + TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; + + if( ( EG( scope ) != Transliterator_ce_ptr ) && + ( zend_binary_strcmp( "id", sizeof( "id" ) - 1, + Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) ) + { + php_error_docref0( NULL TSRMLS_CC, E_WARNING, "The property \"id\" is read-only" ); + } + else + { +#if PHP_VERSION_ID < 50399 + std_object_handlers.write_property( object, member, value TSRMLS_CC ); +#else + std_object_handlers.write_property( object, member, value, key TSRMLS_CC ); +#endif + } + + TRANSLITERATOR_PROPERTY_HANDLER_EPILOG; +} +/* }}} */ + +/* + * 'Transliterator' class registration structures & functions + */ + +/* {{{ Transliterator methods arguments info */ + +ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_void, 0, 0, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create, 0, 0, 1 ) + ZEND_ARG_INFO( 0, id ) + ZEND_ARG_INFO( 0, direction ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create_from_rules, 0, 0, 1 ) + ZEND_ARG_INFO( 0, rules ) + ZEND_ARG_INFO( 0, direction ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create_inverse, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, orig_trans, Transliterator, 0 ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_me_transliterate, 0, 0, 1 ) + ZEND_ARG_INFO( 0, subject ) + ZEND_ARG_INFO( 0, start ) + ZEND_ARG_INFO( 0, end ) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_error, 0, 0, 1 ) + ZEND_ARG_OBJ_INFO( 0, trans, Transliterator, 0 ) +ZEND_END_ARG_INFO() + +/* }}} */ + +/* {{{ Transliterator_class_functions + * Every 'Transliterator' class method has an entry in this table + */ +zend_function_entry Transliterator_class_functions[] = { + PHP_ME( Transliterator, __construct, ainfo_trans_void, ZEND_ACC_PRIVATE | ZEND_ACC_CTOR | ZEND_ACC_FINAL ) + PHP_ME_MAPPING( create, transliterator_create, ainfo_trans_create, ZEND_ACC_STATIC |ZEND_ACC_PUBLIC ) + PHP_ME_MAPPING( createFromRules,transliterator_create_from_rules, ainfo_trans_create_from_rules, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC ) + PHP_ME_MAPPING( createInverse, transliterator_create_inverse, ainfo_trans_void, ZEND_ACC_PUBLIC ) + PHP_ME_MAPPING( listIDs, transliterator_list_ids, ainfo_trans_void, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC ) + PHP_ME_MAPPING( transliterate, transliterator_transliterate, ainfo_trans_me_transliterate, ZEND_ACC_PUBLIC ) + PHP_ME_MAPPING( getErrorCode, transliterator_get_error_code, ainfo_trans_void, ZEND_ACC_PUBLIC ) + PHP_ME_MAPPING( getErrorMessage,transliterator_get_error_message, ainfo_trans_void, ZEND_ACC_PUBLIC ) + { NULL, NULL, NULL } +}; +/* }}} */ + +/* {{{ transliterator_register_Transliterator_class + * Initialize 'Transliterator' class + */ +void transliterator_register_Transliterator_class( TSRMLS_D ) +{ + zend_class_entry ce; + + /* Create and register 'Transliterator' class. */ + INIT_CLASS_ENTRY( ce, "Transliterator", Transliterator_class_functions ); + ce.create_object = Transliterator_object_create; + Transliterator_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC ); + memcpy( &Transliterator_handlers, zend_get_std_object_handlers(), + sizeof Transliterator_handlers ); + Transliterator_handlers.clone_obj = Transliterator_clone_obj; + Transliterator_handlers.get_property_ptr_ptr = Transliterator_get_property_ptr_ptr; + Transliterator_handlers.read_property = Transliterator_read_property; + Transliterator_handlers.write_property = Transliterator_write_property; + + /* Declare 'Transliterator' class properties */ + if( !Transliterator_ce_ptr ) + { + zend_error( E_ERROR, + "Transliterator: attempt to create properties " + "on a non-registered class." ); + return; + } + zend_declare_property_null( Transliterator_ce_ptr, + "id", sizeof( "id" ) - 1, ZEND_ACC_PUBLIC TSRMLS_CC ); + + /* constants are declared in transliterator_register_constants, called from MINIT */ + +} +/* }}} */ + +/* + * 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 + */ |