Browse Source

- Added support for ICU Transformations (Transliterator).

- Changes request #52986 to "to be documented".
experimental/with_scalar_types
Gustavo André dos Santos Lopes 15 years ago
parent
commit
e283f7a7fe
  1. 4
      ext/intl/config.m4
  2. 5
      ext/intl/config.w32
  3. 46
      ext/intl/php_intl.c
  4. 21
      ext/intl/tests/transliterator_clone.phpt
  5. 20
      ext/intl/tests/transliterator_create_basic.phpt
  6. 21
      ext/intl/tests/transliterator_create_error.phpt
  7. 28
      ext/intl/tests/transliterator_create_from_rule_basic.phpt
  8. 53
      ext/intl/tests/transliterator_create_from_rule_error.phpt
  9. 32
      ext/intl/tests/transliterator_create_inverse_basic.phpt
  10. 21
      ext/intl/tests/transliterator_create_inverse_error.phpt
  11. 25
      ext/intl/tests/transliterator_get_error_code_basic.phpt
  12. 24
      ext/intl/tests/transliterator_get_error_code_error.phpt
  13. 25
      ext/intl/tests/transliterator_get_error_message_basic.phpt
  14. 24
      ext/intl/tests/transliterator_get_error_message_error.phpt
  15. 16
      ext/intl/tests/transliterator_list_ids_basic.phpt
  16. 18
      ext/intl/tests/transliterator_list_ids_error.phpt
  17. 21
      ext/intl/tests/transliterator_property_id.phpt
  18. 20
      ext/intl/tests/transliterator_transliterate_basic.phpt
  19. 60
      ext/intl/tests/transliterator_transliterate_error.phpt
  20. 37
      ext/intl/tests/transliterator_transliterate_variant1.phpt
  21. 138
      ext/intl/transliterator/transliterator.c
  22. 29
      ext/intl/transliterator/transliterator.h
  23. 434
      ext/intl/transliterator/transliterator_class.c
  24. 65
      ext/intl/transliterator/transliterator_class.h
  25. 538
      ext/intl/transliterator/transliterator_methods.c
  26. 38
      ext/intl/transliterator/transliterator_methods.h

4
ext/intl/config.m4

@ -55,6 +55,9 @@ if test "$PHP_INTL" != "no"; then
resourcebundle/resourcebundle.c \
resourcebundle/resourcebundle_class.c \
resourcebundle/resourcebundle_iterator.c \
transliterator/transliterator.c \
transliterator/transliterator_class.c \
transliterator/transliterator_methods.c \
idn/idn.c, $ext_shared,,$ICU_INCS)
PHP_ADD_BUILD_DIR($ext_builddir/collator)
@ -66,5 +69,6 @@ if test "$PHP_INTL" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/msgformat)
PHP_ADD_BUILD_DIR($ext_builddir/grapheme)
PHP_ADD_BUILD_DIR($ext_builddir/resourcebundle)
PHP_ADD_BUILD_DIR($ext_builddir/transliterator)
PHP_ADD_BUILD_DIR($ext_builddir/idn)
fi

5
ext/intl/config.w32

@ -71,6 +71,11 @@ if (PHP_INTL != "no") {
resourcebundle_class.c \
resourcebundle_iterator.c",
"intl");
ADD_SOURCES(configure_module_dirname + "/transliterator", "\
transliterator.c \
transliterator_class.c \
transliterator_methods.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 {

46
ext/intl/php_intl.c

@ -64,6 +64,10 @@
#include "resourcebundle/resourcebundle_class.h"
#include "transliterator/transliterator.h"
#include "transliterator/transliterator_class.h"
#include "transliterator/transliterator_methods.h"
#include "idn/idn.h"
#include "msgformat/msgformat.h"
@ -361,6 +365,33 @@ ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_message_proc, 0, 0, 1 )
ZEND_ARG_INFO( 0, bundle )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_void, 0, 0, 0 )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_create, 0, 0, 1 )
ZEND_ARG_INFO( 0, id )
ZEND_ARG_INFO( 0, direction )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_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( arginfo_transliterator_create_inverse, 0, 0, 1 )
ZEND_ARG_OBJ_INFO( 0, orig_trans, Transliterator, 0 )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_transliterate, 0, 0, 2 )
ZEND_ARG_INFO( 0, trans )
ZEND_ARG_INFO( 0, subject )
ZEND_ARG_INFO( 0, start )
ZEND_ARG_INFO( 0, end )
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX( arginfo_transliterator_error, 0, 0, 1 )
ZEND_ARG_OBJ_INFO( 0, trans, Transliterator, 0 )
ZEND_END_ARG_INFO()
/* }}} */
@ -481,6 +512,15 @@ zend_function_entry intl_functions[] = {
PHP_FE( resourcebundle_get_error_code, arginfo_resourcebundle_get_error_code_proc )
PHP_FE( resourcebundle_get_error_message, arginfo_resourcebundle_get_error_message_proc )
/* Transliterator functions */
PHP_FE( transliterator_create, arginfo_transliterator_create )
PHP_FE( transliterator_create_from_rules, arginfo_transliterator_create_from_rules )
PHP_FE( transliterator_list_ids, arginfo_transliterator_void )
PHP_FE( transliterator_create_inverse, arginfo_transliterator_create_inverse)
PHP_FE( transliterator_transliterate, arginfo_transliterator_transliterate )
PHP_FE( transliterator_get_error_code, arginfo_transliterator_error )
PHP_FE( transliterator_get_error_message, arginfo_transliterator_error )
/* common functions */
PHP_FE( intl_get_error_code, intl_0_args )
PHP_FE( intl_get_error_message, intl_0_args )
@ -581,6 +621,12 @@ PHP_MINIT_FUNCTION( intl )
/* Register 'ResourceBundle' PHP class */
resourcebundle_register_class( TSRMLS_C);
/* Register 'Transliterator' PHP class */
transliterator_register_Transliterator_class( TSRMLS_C );
/* Register Transliterator constants */
transliterator_register_constants( INIT_FUNC_ARGS_PASSTHRU );
/* Expose ICU error codes to PHP scripts. */
intl_expose_icu_error_codes( INIT_FUNC_ARGS_PASSTHRU );

21
ext/intl/tests/transliterator_clone.phpt

@ -0,0 +1,21 @@
--TEST--
Transliterator clone handler
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$str = "a U+4E07";
$t = Transliterator::create("hex-any");
echo $t->id, ": ", $t->transliterate($str), "\n";
$u = clone $t;
echo $u->id, ": ", $u->transliterate($str), "\n";
echo "Done.\n";
--EXPECT--
hex-any: a 万
hex-any: a 万
Done.

20
ext/intl/tests/transliterator_create_basic.phpt

@ -0,0 +1,20 @@
--TEST--
Transliterator::create (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$t = Transliterator::create("any-latin");
echo $t->id,"\n";
$t = transliterator_create("any-latin");
echo $t->id,"\n";
echo "Done.\n";
--EXPECT--
any-latin
any-latin
Done.

21
ext/intl/tests/transliterator_create_error.phpt

@ -0,0 +1,21 @@
--TEST--
Transliterator::create (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
Transliterator::create("inexistant id");
echo intl_get_error_message(), "\n";
Transliterator::create("bad UTF-8 \x8F");
echo intl_get_error_message(), "\n";
echo "Done.\n";
--EXPECTF--
Warning: Transliterator::create(): transliterator_create: unable to open ICU transliterator with id "inexistant id" in %s on line %d
transliterator_create: unable to open ICU transliterator with id "inexistant id": U_INVALID_ID
Warning: Transliterator::create(): String conversion of id to UTF-16 failed in %s on line %d
String conversion of id to UTF-16 failed: U_INVALID_CHAR_FOUND
Done.

28
ext/intl/tests/transliterator_create_from_rule_basic.phpt

@ -0,0 +1,28 @@
--TEST--
Transliterator::createFromRules (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$rules = <<<RULES
α <> y;
\`\` } a > “;
RULES;
$t = Transliterator::createFromRules($rules);
echo $t->id,"\n";
echo $t->transliterate("``akk ``bkk ``aooy"),"\n";
$u = transliterator_create_from_rules($rules, Transliterator::REVERSE);
echo $u->transliterate("``akk ``bkk ``aooy"), "\n";
echo "Done.\n";
--EXPECT--
RulesTransPHP
“akk ``bkk “aooy
``akk ``bkk ``aooα
Done.

53
ext/intl/tests/transliterator_create_from_rule_error.phpt

@ -0,0 +1,53 @@
--TEST--
Transliterator::createFromRules (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$t = Transliterator::createFromRules();
echo intl_get_error_message(),"\n";
$t = Transliterator::createFromRules("a","b");
echo intl_get_error_message(),"\n";
$t = Transliterator::createFromRules("\x8Fss");
echo intl_get_error_message(),"\n";
$rules = <<<RULES
\`\` } a > “;
\`\` } a > b;
RULES;
$t = Transliterator::createFromRules($rules);
echo intl_get_error_message(),"\n";
$rules = <<<RULES
ffff
RULES;
$t = Transliterator::createFromRules($rules);
echo intl_get_error_message(),"\n";
echo "Done.\n";
--EXPECTF--
Warning: Transliterator::createFromRules() expects at least 1 parameter, 0 given in %s on line %d
Warning: Transliterator::createFromRules(): transliterator_create_from_rules: bad arguments in %s on line %d
transliterator_create_from_rules: bad arguments: U_ILLEGAL_ARGUMENT_ERROR
Warning: Transliterator::createFromRules() expects parameter 2 to be long, string given in %s on line %d
Warning: Transliterator::createFromRules(): transliterator_create_from_rules: bad arguments in %s on line %d
transliterator_create_from_rules: bad arguments: U_ILLEGAL_ARGUMENT_ERROR
Warning: Transliterator::createFromRules(): String conversion of rules to UTF-16 failed in %s on line %d
String conversion of rules to UTF-16 failed: U_INVALID_CHAR_FOUND
Warning: Transliterator::createFromRules(): transliterator_create_from_rules: unable to create ICU transliterator from rules (parse error after "{'``'}a > “;", before or at "{'``'}a > b;") in %s on line %d
transliterator_create_from_rules: unable to create ICU transliterator from rules (parse error after "{'``'}a > “;", before or at "{'``'}a > b;"): U_RULE_MASK_ERROR
Warning: Transliterator::createFromRules(): transliterator_create_from_rules: unable to create ICU transliterator from rules (parse error at offset 0, before or at "ffff") in %s on line %d
transliterator_create_from_rules: unable to create ICU transliterator from rules (parse error at offset 0, before or at "ffff"): U_MISSING_OPERATOR
Done.

32
ext/intl/tests/transliterator_create_inverse_basic.phpt

@ -0,0 +1,32 @@
--TEST--
Transliterator::createInverse (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$tr = Transliterator::create("Katakana-Latin");
$orstr = "オーシャンビュー";
$new_str = $tr->transliterate($orstr);
$revtr = $tr->createInverse();
$recovstr = $revtr->transliterate($new_str);
$revtr2 = transliterator_create_inverse($tr);
$recovstr2 = $revtr2->transliterate($new_str);
echo $orstr,"\n";
echo $new_str,"\n";
echo $recovstr,"\n";
var_dump(($orstr == $recovstr) == $recovstr2);
echo "Done.\n";
--EXPECT--
オーシャンビュー
ōshanbyū
オーシャンビュー
bool(true)
Done.

21
ext/intl/tests/transliterator_create_inverse_error.phpt

@ -0,0 +1,21 @@
--TEST--
Transliterator::createInverse (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$tr = Transliterator::create("Katakana-Latin");
$tr->createInverse(array());
$tr = Transliterator::create("Katakana-Latin");
transliterator_create_inverse("jj");
--EXPECTF--
Warning: Transliterator::createInverse() expects exactly 0 parameters, 1 given in %s on line %d
Warning: Transliterator::createInverse(): transliterator_create_inverse: bad arguments in %s on line %d
Catchable fatal error: Argument 1 passed to transliterator_create_inverse() must be an instance of Transliterator, string given in %s on line %d

25
ext/intl/tests/transliterator_get_error_code_basic.phpt

@ -0,0 +1,25 @@
--TEST--
Transliterator::getErrorCode (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$t = Transliterator::create("[\p{Bidi_Mirrored}] Hex");
var_dump($t->transliterate("\x8F"));
echo transliterator_get_error_code($t), "\n";
echo $t->getErrorCode(), "\n";
var_dump($t->transliterate(""));
echo $t->getErrorCode(), "\n";
echo "Done.\n";
--EXPECTF--
Warning: Transliterator::transliterate(): String conversion of string to UTF-16 failed in %s on line %d
bool(false)
10
10
string(0) ""
0
Done.

24
ext/intl/tests/transliterator_get_error_code_error.phpt

@ -0,0 +1,24 @@
--TEST--
Transliterator::getErrorCode (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$t = Transliterator::create("[\p{Bidi_Mirrored}] Hex");
echo transliterator_get_error_code(), "\n";
echo $t->getErrorCode(null), "\n";
echo transliterator_get_error_code(array()), "\n";
--EXPECTF--
Warning: transliterator_get_error_code() expects exactly 1 parameter, 0 given in %s on line %d
Warning: transliterator_get_error_code(): transliterator_get_error_code: unable to parse input params in %s on line %d
Warning: Transliterator::getErrorCode() expects exactly 0 parameters, 1 given in %s on line %d
Warning: Transliterator::getErrorCode(): transliterator_get_error_code: unable to parse input params in %s on line %d
Catchable fatal error: Argument 1 passed to transliterator_get_error_code() must be an instance of Transliterator, array given in %s on line %d

25
ext/intl/tests/transliterator_get_error_message_basic.phpt

@ -0,0 +1,25 @@
--TEST--
Transliterator::getErrorMessage (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$t = Transliterator::create("[\p{Bidi_Mirrored}] Hex");
var_dump($t->transliterate("\x8F"));
echo transliterator_get_error_message($t), "\n";
echo $t->getErrorMessage(), "\n";
var_dump($t->transliterate(""));
echo $t->getErrorMessage(), "\n";
echo "Done.\n";
--EXPECTF--
Warning: Transliterator::transliterate(): String conversion of string to UTF-16 failed in %s on line %d
bool(false)
String conversion of string to UTF-16 failed: U_INVALID_CHAR_FOUND
String conversion of string to UTF-16 failed: U_INVALID_CHAR_FOUND
string(0) ""
U_ZERO_ERROR
Done.

24
ext/intl/tests/transliterator_get_error_message_error.phpt

@ -0,0 +1,24 @@
--TEST--
Transliterator::getErrorMessage (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$t = Transliterator::create("[\p{Bidi_Mirrored}] Hex");
echo transliterator_get_error_message(), "\n";
echo $t->getErrorMessage(null), "\n";
echo transliterator_get_error_message(array()), "\n";
--EXPECTF--
Warning: transliterator_get_error_message() expects exactly 1 parameter, 0 given in %s on line %d
Warning: transliterator_get_error_message(): transliterator_get_error_message: unable to parse input params in %s on line %d
Warning: Transliterator::getErrorMessage() expects exactly 0 parameters, 1 given in %s on line %d
Warning: Transliterator::getErrorMessage(): transliterator_get_error_message: unable to parse input params in %s on line %d
Catchable fatal error: Argument 1 passed to transliterator_get_error_message() must be an instance of Transliterator, array given in %s on line %d

16
ext/intl/tests/transliterator_list_ids_basic.phpt

@ -0,0 +1,16 @@
--TEST--
Transliterator::listIDs (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
var_dump(count(transliterator_list_ids()) > 100);
var_dump(count(Transliterator::listIDs()) > 100);
echo "Done.\n";
--EXPECT--
bool(true)
bool(true)
Done.

18
ext/intl/tests/transliterator_list_ids_error.phpt

@ -0,0 +1,18 @@
--TEST--
Transliterator::listIDs (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
var_dump(transliterator_list_ids(array()));
echo "Done.\n";
--EXPECTF--
Warning: transliterator_list_ids() expects exactly 0 parameters, 1 given in %s on line %d
Warning: transliterator_list_ids(): transliterator_list_ids: bad arguments in %s on line %d
bool(false)
Done.

21
ext/intl/tests/transliterator_property_id.phpt

@ -0,0 +1,21 @@
--TEST--
Transliterator - "id" property
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
$tr = Transliterator::create("Katakana-Latin");
echo $tr->id, "\n";
$revtr = $tr->createInverse();
echo $revtr->id, "\n";
var_dump($revtr);
echo "Done.\n";
--EXPECTF--
Katakana-Latin
Latin-Katakana
object(Transliterator)#%d (%d) {
["id"]=>
string(%d) "Latin-Katakana"
}
Done.

20
ext/intl/tests/transliterator_transliterate_basic.phpt

@ -0,0 +1,20 @@
--TEST--
Transliterator::transliterate (basic)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
$t = transliterator_create("Latin; Title");
$s = "Κοντογιαννάτος, Βασίλης";
echo $t->transliterate($s),"\n";
echo transliterator_transliterate($t, $s),"\n";
echo $t->transliterate($s, 3),"\n";
echo $t->transliterate($s, 3, 4),"\n";
echo "Done.\n";
--EXPECT--
Kontogiannátos, Basílēs
Kontogiannátos, Basílēs
ΚονTogiannátos, Basílēs
ΚονTογιαννάτος, Βασίλης
Done.

60
ext/intl/tests/transliterator_transliterate_error.phpt

@ -0,0 +1,60 @@
--TEST--
Transliterator::transliterate (error)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
$tr = Transliterator::create("latin");
//Arguments
var_dump(transliterator_transliterate());
var_dump(transliterator_transliterate($tr,array()));
var_dump(transliterator_transliterate($tr,"str",7));
var_dump(transliterator_transliterate($tr,"str",7,6));
var_dump(transliterator_transliterate($tr,"str",2,-1,"extra"));
//Arguments
var_dump($tr->transliterate());
var_dump($tr->transliterate(array()));
//bad UTF-8
transliterator_transliterate($tr, "\x80\x03");
echo "Done.\n";
--EXPECTF--
Warning: transliterator_transliterate() expects at least 2 parameters, 0 given in %s on line %d
Warning: transliterator_transliterate(): transliterator_transliterate: bad arguments in %s on line %d
bool(false)
Warning: transliterator_transliterate() expects parameter 2 to be string, array given in %s on line %d
Warning: transliterator_transliterate(): transliterator_transliterate: bad arguments in %s on line %d
bool(false)
Warning: transliterator_transliterate(): transliterator_transliterate: Neither "start" nor the "end" arguments can exceed the number of UTF-16 code units (in this case, 3) in %s on line %d
bool(false)
Warning: transliterator_transliterate(): transliterator_transliterate: "start" argument should be non-negative and not bigger than "end" (if defined) in %s on line %d
bool(false)
Warning: transliterator_transliterate() expects at most 4 parameters, 5 given in %s on line %d
Warning: transliterator_transliterate(): transliterator_transliterate: bad arguments in %s on line %d
bool(false)
Warning: Transliterator::transliterate() expects at least 1 parameter, 0 given in %s on line %d
Warning: Transliterator::transliterate(): transliterator_transliterate: bad arguments in %s on line %d
bool(false)
Warning: Transliterator::transliterate() expects parameter 1 to be string, array given in %s on line %d
Warning: Transliterator::transliterate(): transliterator_transliterate: bad arguments in %s on line %d
bool(false)
Warning: transliterator_transliterate(): String conversion of string to UTF-16 failed in %s on line %d
Done.

37
ext/intl/tests/transliterator_transliterate_variant1.phpt

@ -0,0 +1,37 @@
--TEST--
transliterator_transliterate (variant 1, non-transliterator 1st arg)
--SKIPIF--
<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
--FILE--
<?php
ini_set("intl.error_level", E_WARNING);
//exec('pause');
$str = " o";
echo transliterator_transliterate("[\p{White_Space}] hex", $str), "\n";
echo transliterator_transliterate("\x8F", $str), "\n";
echo intl_get_error_message(), "\n";
class A {
function __toString() { return "inexistant id"; }
}
echo transliterator_transliterate(new A(), $str), "\n";
echo intl_get_error_message(), "\n";
echo "Done.\n";
--EXPECTF--
\u0020o
Warning: transliterator_transliterate(): String conversion of id to UTF-16 failed in %s on line %d
Warning: transliterator_transliterate(): Could not create transliterator with ID %s
String conversion of id to UTF-16 failed: U_INVALID_CHAR_FOUND
Warning: transliterator_transliterate(): transliterator_create: unable to open ICU transliterator with id "inexistant id" in %s on line %d
Warning: transliterator_transliterate(): Could not create transliterator with ID "inexistant id" (transliterator_create: unable to open ICU transliterator with id "inexistant id": U_INVALID_ID) in %s on line %d
transliterator_create: unable to open ICU transliterator with id "inexistant id": U_INVALID_ID
Done.

138
ext/intl/transliterator/transliterator.c

@ -0,0 +1,138 @@
/*
+----------------------------------------------------------------------+
| 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> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "transliterator_class.h"
#include "transliterator.h"
#include "intl_convert.h"
#include <unicode/ustring.h>
/* {{{ transliterator_register_constants
* Register constants common for both (OO and procedural) APIs.
*/
void transliterator_register_constants( INIT_FUNC_ARGS )
{
if( !Transliterator_ce_ptr )
{
zend_error( E_ERROR, "Transliterator class not defined" );
return;
}
#define TRANSLITERATOR_EXPOSE_CONST( x ) REGISTER_LONG_CONSTANT( #x, x, CONST_CS )
#define TRANSLITERATOR_EXPOSE_CLASS_CONST( x ) zend_declare_class_constant_long( Transliterator_ce_ptr, ZEND_STRS( #x ) - 1, TRANSLITERATOR_##x TSRMLS_CC );
#define TRANSLITERATOR_EXPOSE_CUSTOM_CLASS_CONST( name, value ) zend_declare_class_constant_long( Transliterator_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );*/
/* Normalization form constants */
TRANSLITERATOR_EXPOSE_CLASS_CONST( FORWARD );
TRANSLITERATOR_EXPOSE_CLASS_CONST( REVERSE );
#undef NORMALIZER_EXPOSE_CUSTOM_CLASS_CONST
#undef NORMALIZER_EXPOSE_CLASS_CONST
#undef NORMALIZER_EXPOSE_CONST
}
/* }}} */
/* {{{ transliterator_parse_error_to_string
* Transforms parse errors in strings.
*/
smart_str transliterator_parse_error_to_string( UParseError* pe )
{
smart_str ret = {0};
char *buf;
int u8len;
UErrorCode status;
int any = 0;
assert( pe != NULL );
smart_str_appends( &ret, "parse error " );
if( pe->line > 0 )
{
smart_str_appends( &ret, "on line " );
smart_str_append_long( &ret, (long ) pe->line );
any = 1;
}
if( pe->offset >= 0 ) {
if( any )
smart_str_appends( &ret, ", " );
else
smart_str_appends( &ret, "at " );
smart_str_appends( &ret, "offset " );
smart_str_append_long( &ret, (long ) pe->offset );
any = 1;
}
if (pe->preContext[0] != 0 ) {
if( any )
smart_str_appends( &ret, ", " );
smart_str_appends( &ret, "after \"" );
intl_convert_utf16_to_utf8( &buf, &u8len, pe->preContext, -1, &status );
if( U_FAILURE( status ) )
{
smart_str_appends( &ret, "(could not convert parser error pre-context to UTF-8)" );
}
else {
smart_str_appendl( &ret, buf, u8len );
efree( buf );
}
smart_str_appends( &ret, "\"" );
any = 1;
}
if( pe->postContext[0] != 0 )
{
if( any )
smart_str_appends( &ret, ", " );
smart_str_appends( &ret, "before or at \"" );
intl_convert_utf16_to_utf8( &buf, &u8len, pe->postContext, -1, &status );
if( U_FAILURE( status ) )
{
smart_str_appends( &ret, "(could not convert parser error post-context to UTF-8)" );
}
else
{
smart_str_appendl( &ret, buf, u8len );
efree( buf );
}
smart_str_appends( &ret, "\"" );
any = 1;
}
if( !any )
{
smart_str_free( &ret );
smart_str_appends( &ret, "no parse error" );
}
smart_str_0( &ret );
return ret;
}
/*
* 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/transliterator/transliterator.h

@ -0,0 +1,29 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gustavo Lopes <cataphract@netcabo.ot> |
+----------------------------------------------------------------------+
*/
#ifndef TRANSLITERATOR_TRANSLITERATOR_H
#define TRANSLITERATOR_TRANSLITERATOR_H
#include <php.h>
#include <unicode/utypes.h>
#include <unicode/utrans.h>
#include "ext/standard/php_smart_str.h"
void transliterator_register_constants( INIT_FUNC_ARGS );
smart_str transliterator_parse_error_to_string( UParseError* pe );
#endif /* #ifndef TRANSLITERATOR_TRANSLITERATOR_H */

434
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
*/

65
ext/intl/transliterator/transliterator_class.h

@ -0,0 +1,65 @@
/*
+----------------------------------------------------------------------+
| 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@netcabo.pt> |
+----------------------------------------------------------------------+
*/
#ifndef TRANSLITERATOR_CLASS_H
#define TRANSLITERATOR_CLASS_H
#include <php.h>
#include "intl_common.h"
#include "intl_error.h"
#include <unicode/utrans.h>
typedef struct {
zend_object zo;
// error handling
intl_error err;
// ICU transliterator
UTransliterator* utrans;
} Transliterator_object;
#define TRANSLITERATOR_FORWARD UTRANS_FORWARD
#define TRANSLITERATOR_REVERSE UTRANS_REVERSE
#define TRANSLITERATOR_ERROR( co ) (co)->err
#define TRANSLITERATOR_ERROR_P( co ) &(TRANSLITERATOR_ERROR( co ))
#define TRANSLITERATOR_ERROR_CODE( co ) INTL_ERROR_CODE(TRANSLITERATOR_ERROR( co ))
#define TRANSLITERATOR_ERROR_CODE_P( co ) &(INTL_ERROR_CODE(TRANSLITERATOR_ERROR( co )))
#define TRANSLITERATOR_METHOD_INIT_VARS INTL_METHOD_INIT_VARS( Transliterator, to )
#define TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK INTL_METHOD_FETCH_OBJECT( Transliterator, to )
#define TRANSLITERATOR_METHOD_FETCH_OBJECT\
TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; \
if( to->utrans == NULL ) \
{ \
intl_errors_set( &to->err, U_ILLEGAL_ARGUMENT_ERROR, "Found unconstructed transliterator", 0 TSRMLS_CC ); \
RETURN_FALSE; \
}
int transliterator_object_construct( zval *object,
UTransliterator *utrans,
UErrorCode *status TSRMLS_DC );
void transliterator_register_Transliterator_class( TSRMLS_D );
extern zend_class_entry *Transliterator_ce_ptr;
extern zend_object_handlers Transliterator_handlers;
#endif /* #ifndef TRANSLITERATOR_CLASS_H */

538
ext/intl/transliterator/transliterator_methods.c

@ -0,0 +1,538 @@
/*
+----------------------------------------------------------------------+
| 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> |
+----------------------------------------------------------------------+
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php_intl.h"
#include "transliterator.h"
#include "transliterator_class.h"
#include "transliterator_methods.h"
#include "intl_data.h"
#include "intl_convert.h"
#include <zend_exceptions.h>
static int create_transliterator( char *str_id, int str_id_len, long direction, zval *object TSRMLS_DC )
{
Transliterator_object *to;
UChar *ustr_id = NULL;
int32_t ustr_id_len = 0;
UTransliterator *utrans;
UParseError parse_error = {0, -1};
intl_error_reset( NULL TSRMLS_CC );
if( ( direction != TRANSLITERATOR_FORWARD ) && (direction != TRANSLITERATOR_REVERSE ) )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_create: invalid direction", 0 TSRMLS_CC );
return FAILURE;
}
object_init_ex( object, Transliterator_ce_ptr );
TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; /* fetch zend object from zval "object" into "to" */
/* Convert transliterator id to UTF-16 */
intl_convert_utf8_to_utf16( &ustr_id, &ustr_id_len, str_id, str_id_len, TRANSLITERATOR_ERROR_CODE_P( to ) );
if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to ) ) )
{
intl_error_set_code( NULL, TRANSLITERATOR_ERROR_CODE( to ) TSRMLS_CC );
intl_error_set_custom_msg( NULL, "String conversion of id to UTF-16 failed", 0 TSRMLS_CC );
zval_dtor( object );
return FAILURE;
}
/* Open ICU Transliterator. */
utrans = utrans_openU( ustr_id, ustr_id_len, (UTransDirection ) direction,
NULL, -1, &parse_error, TRANSLITERATOR_ERROR_CODE_P( to ) );
efree( ustr_id );
if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to ) ) )
{
char *buf = NULL;
intl_error_set_code( NULL, TRANSLITERATOR_ERROR_CODE( to ) TSRMLS_CC );
spprintf( &buf, 0, "transliterator_create: unable to open ICU transliterator"
" with id \"%s\"", str_id );
if( buf == NULL ) {
intl_error_set_custom_msg( NULL,
"transliterator_create: unable to open ICU transliterator", 0 TSRMLS_CC );
}
else
{
intl_error_set_custom_msg( NULL, buf, /* copy message */ 1 TSRMLS_CC );
efree( buf );
}
zval_dtor( object );
return FAILURE;
}
transliterator_object_construct( object, utrans, TRANSLITERATOR_ERROR_CODE_P( to ) TSRMLS_CC );
/* no need to close the transliterator manually on construction error */
if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to ) ) )
{
intl_error_set_code( NULL, TRANSLITERATOR_ERROR_CODE( to ) TSRMLS_CC );
intl_error_set_custom_msg( NULL,
"transliterator_create: internal constructor call failed", 0 TSRMLS_CC );
zval_dtor( object );
return FAILURE;
}
return SUCCESS;
}
/* {{{ proto Transliterator transliterator_create( string id [, int direction ] )
* proto Transliterator Transliterator::create( string id [, int direction ] )
* Opens a transliterator by id.
*/
PHP_FUNCTION( transliterator_create )
{
char *str_id;
int str_id_len;
long direction = TRANSLITERATOR_FORWARD;
int res;
TRANSLITERATOR_METHOD_INIT_VARS;
(void) to; /* unused */
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
&str_id, &str_id_len, &direction ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_create: bad arguments", 0 TSRMLS_CC );
RETURN_NULL();
}
object = return_value;
res = create_transliterator( str_id, str_id_len, direction, object TSRMLS_CC );
if( res == FAILURE )
RETURN_NULL();
/* success, leave return_value as it is (set by create_transliterator) */
}
/* }}} */
/* {{{ proto Transliterator transliterator_create_from_rules( string rules [, int direction ] )
* proto Transliterator Transliterator::createFromRules( string rules [, int direction ] )
* Opens a transliterator by id.
*/
PHP_FUNCTION( transliterator_create_from_rules )
{
char *str_rules;
int str_rules_len;
UChar *ustr_rules = NULL;
int32_t ustr_rules_len = 0;
long direction = TRANSLITERATOR_FORWARD;
UParseError parse_error = {0, -1};
UTransliterator *utrans;
UChar id[] = {0x52, 0x75, 0x6C, 0x65, 0x73, 0x54, 0x72,
0x61, 0x6E, 0x73, 0x50, 0x48, 0x50, 0}; /* RulesTransPHP */
TRANSLITERATOR_METHOD_INIT_VARS;
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
&str_rules, &str_rules_len, &direction ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_create_from_rules: bad arguments", 0 TSRMLS_CC );
RETURN_NULL();
}
if( ( direction != TRANSLITERATOR_FORWARD ) && (direction != TRANSLITERATOR_REVERSE ) )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_create_from_rules: invalid direction", 0 TSRMLS_CC );
RETURN_NULL();
}
object = return_value;
object_init_ex( object, Transliterator_ce_ptr );
TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
intl_convert_utf8_to_utf16( &ustr_rules, &ustr_rules_len,
str_rules, str_rules_len, TRANSLITERATOR_ERROR_CODE_P( to ) );
/* (I'm not a big fan of non-obvious flow control macros ).
* This one checks the error value, destroys object and returns false */
INTL_CTOR_CHECK_STATUS( to, "String conversion of rules to UTF-16 failed" );
/* Open ICU Transliterator. */
utrans = utrans_openU( id, ( sizeof( id ) - 1 ) / ( sizeof( *id ) ), (UTransDirection ) direction,
ustr_rules, ustr_rules_len, &parse_error, TRANSLITERATOR_ERROR_CODE_P( to ) );
efree( ustr_rules );
intl_error_set_code( NULL, INTL_DATA_ERROR_CODE( to ) TSRMLS_CC );
if( U_FAILURE( INTL_DATA_ERROR_CODE( to ) ) )
{
char *msg = NULL;
smart_str parse_error_str;
parse_error_str = transliterator_parse_error_to_string( &parse_error );
spprintf( &msg, 0, "transliterator_create_from_rules: unable to "
"create ICU transliterator from rules (%s)", parse_error_str.c );
smart_str_free( &parse_error_str );
if( msg != NULL )
{
intl_errors_set_custom_msg( INTL_DATA_ERROR_P( to ), msg, 1 TSRMLS_CC );
efree( msg );
}
zval_dtor( return_value );
RETURN_NULL();
}
transliterator_object_construct( object, utrans, TRANSLITERATOR_ERROR_CODE_P( to ) TSRMLS_CC );
/* no need to close the transliterator manually on construction error */
INTL_CTOR_CHECK_STATUS( to, "transliterator_create_from_rules: internal constructor call failed" );
}
/* }}} */
/* {{{ proto Transliterator transliterator_create_inverse( Transliterator orig_trans )
* proto Transliterator Transliterator::createInverse()
* Opens the inverse transliterator transliterator.
*/
PHP_FUNCTION( transliterator_create_inverse )
{
Transliterator_object *to_orig;
UTransliterator *utrans;
TRANSLITERATOR_METHOD_INIT_VARS;
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, Transliterator_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_create_inverse: bad arguments", 0 TSRMLS_CC );
RETURN_NULL();
}
TRANSLITERATOR_METHOD_FETCH_OBJECT;
to_orig = to;
object = return_value;
object_init_ex( object, Transliterator_ce_ptr );
TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK; /* change "to" into new object (from "object" ) */
utrans = utrans_openInverse( to_orig->utrans, TRANSLITERATOR_ERROR_CODE_P( to ) );
INTL_CTOR_CHECK_STATUS( to, "transliterator_create_inverse: could not create "
"inverse ICU transliterator" );
transliterator_object_construct( object, utrans, TRANSLITERATOR_ERROR_CODE_P( to ) TSRMLS_CC );
/* no need to close the transliterator manually on construction error */
INTL_CTOR_CHECK_STATUS( to, "transliterator_create: internal constructor call failed" );
}
/* }}} */
/* {{{ proto array transliterator_list_ids()
* proto array Transliterator::listIDs()
* Return an array with the registered transliterator IDs.
*/
PHP_FUNCTION( transliterator_list_ids )
{
UEnumeration *en;
const UChar *elem;
int32_t elem_len;
UErrorCode status = U_ZERO_ERROR;
intl_error_reset( NULL TSRMLS_CC );
if( zend_parse_parameters_none() == FAILURE )
{
/* seems to be the convention in this lib to return false instead of
* null on bad parameter types, except on constructors and factory
* methods */
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_list_ids: bad arguments", 0 TSRMLS_CC );
RETURN_FALSE;
}
en = utrans_openIDs( &status );
INTL_CHECK_STATUS( status,
"transliterator_list_ids: Failed to obtain registered transliterators" );
array_init( return_value );
while( elem = uenum_unext( en, &elem_len, &status ) )
{
char *el_char = NULL;
int el_len = 0;
intl_convert_utf16_to_utf8( &el_char, &el_len, elem, elem_len, &status );
if( U_FAILURE( status ) )
{
efree( el_char );
break;
}
else
{
add_next_index_stringl( return_value, el_char, el_len, 0 );
}
}
uenum_close( en );
intl_error_set_code( NULL, status TSRMLS_CC );
if( U_FAILURE( status ) )
{
zval_dtor( return_value );
RETVAL_FALSE;
intl_error_set_custom_msg( NULL, "transliterator_list_ids: "
"Failed to build array of registered transliterators", 0 TSRMLS_CC );
}
}
/* }}} */
/* {{{ proto string transliterator_transliterate( Transliterator trans, string subject [, int start = 0 [, int end = -1 ]] )
* proto string Transliterator::transliterate( string subject [, int start = 0 [, int end = -1 ]] )
* Transliterate a string. */
PHP_FUNCTION( transliterator_transliterate )
{
char *str;
UChar *ustr = NULL,
*uresult = NULL;
int str_len;
int32_t ustr_len = 0,
capacity,
uresult_len;
long start = 0,
limit = -1;
int success = 0,
temp_trans = 0;
TRANSLITERATOR_METHOD_INIT_VARS;
object = getThis();
if( object == NULL )
{
/* in non-OOP version, accept both a transliterator and a string */
zval **arg1;
if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Zs|ll",
&arg1, &str, &str_len, &start, &limit ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_transliterate: bad arguments", 0 TSRMLS_CC );
RETURN_FALSE;
}
if( Z_TYPE_PP( arg1 ) == IS_OBJECT &&
instanceof_function( Z_OBJCE_PP( arg1 ), Transliterator_ce_ptr TSRMLS_CC ) )
{
object = *arg1;
}
else
{ /* not a transliterator object as first argument */
int res;
if(Z_TYPE_PP( arg1 ) != IS_STRING )
{
SEPARATE_ZVAL( arg1 );
convert_to_string( *arg1 );
}
ALLOC_INIT_ZVAL( object );
temp_trans = 1;
res = create_transliterator( Z_STRVAL_PP( arg1 ), Z_STRLEN_PP( arg1 ),
TRANSLITERATOR_FORWARD, object TSRMLS_CC );
if( res == FAILURE )
{
char *message = intl_error_get_message( NULL TSRMLS_CC );
php_error_docref0( NULL TSRMLS_CC, E_WARNING, "Could not create "
"transliterator with ID \"%s\" (%s)", Z_STRVAL_PP( arg1 ), message );
efree( message );
/* don't set U_ILLEGAL_ARGUMENT_ERROR to allow fetching of inner error */
goto cleanup;
}
}
}
else if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|ll",
&str, &str_len, &start, &limit ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_transliterate: bad arguments", 0 TSRMLS_CC );
RETURN_FALSE;
}
if( limit < -1 )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_transliterate: \"end\" argument should be "
"either non-negative or -1", 0 TSRMLS_CC );
RETURN_FALSE;
}
if( start < 0 || (limit != -1 ) && (start > limit ) )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_transliterate: \"start\" argument should be "
"non-negative and not bigger than \"end\" (if defined)", 0 TSRMLS_CC );
RETURN_FALSE;
}
/* end argument parsing/validation */
TRANSLITERATOR_METHOD_FETCH_OBJECT;
intl_convert_utf8_to_utf16( &ustr, &ustr_len, str, str_len,
TRANSLITERATOR_ERROR_CODE_P( to ) );
INTL_METHOD_CHECK_STATUS( to, "String conversion of string to UTF-16 failed" );
/* we've started allocating resources, goto from now on */
if( ( start > ustr_len ) || (( limit != -1 ) && (limit > ustr_len ) ) )
{
char *msg;
spprintf( &msg, 0,
"transliterator_transliterate: Neither \"start\" nor the \"end\" "
"arguments can exceed the number of UTF-16 code units "
"(in this case, %d)", (int) ustr_len );
if(msg != NULL )
{
intl_errors_set( TRANSLITERATOR_ERROR_P( to ), U_ILLEGAL_ARGUMENT_ERROR,
msg, 1 TSRMLS_CC );
efree( msg );
}
RETVAL_FALSE;
goto cleanup;
}
uresult = safe_emalloc( ustr_len, sizeof( UChar ), 1 * sizeof( UChar ) );
capacity = ustr_len + 1;
while( 1 )
{
int32_t temp_limit = ( limit == -1 ? ustr_len : (int32_t) limit );
memcpy( uresult, ustr, ustr_len * sizeof( UChar ) );
uresult_len = ustr_len;
utrans_transUChars( to->utrans, uresult, &uresult_len, capacity, (int32_t) start,
&temp_limit, TRANSLITERATOR_ERROR_CODE_P( to ) );
if( TRANSLITERATOR_ERROR_CODE( to ) == U_BUFFER_OVERFLOW_ERROR )
{
efree( uresult );
uresult = safe_emalloc( uresult_len, sizeof( UChar ), 1 * sizeof( UChar ) );
capacity = uresult_len + 1;
intl_error_reset( TRANSLITERATOR_ERROR_P( to ) TSRMLS_CC );
}
else if(TRANSLITERATOR_ERROR_CODE( to ) == U_STRING_NOT_TERMINATED_WARNING )
{
uresult = safe_erealloc( uresult, uresult_len, sizeof( UChar ), 1 * sizeof( UChar ) );
intl_error_reset( TRANSLITERATOR_ERROR_P( to ) TSRMLS_CC );
break;
}
else if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to ) ) )
{
intl_error_set_code( NULL, TRANSLITERATOR_ERROR_CODE( to ) TSRMLS_CC );
intl_errors_set_custom_msg( TRANSLITERATOR_ERROR_P( to ),
"transliterator_transliterate: transliteration failed", 0 TSRMLS_CC );
goto cleanup;
}
else
break;
}
uresult[uresult_len] = (UChar) 0;
success = 1;
cleanup:
if( ustr )
efree( ustr );
if( success ) {
/* frees uresult even on error */
INTL_METHOD_RETVAL_UTF8( to, uresult, uresult_len, 1 );
}
else
{
if( uresult )
efree( uresult );
RETVAL_FALSE;
}
if (temp_trans )
zval_ptr_dtor( &object );
}
/* }}} */
PHP_METHOD( Transliterator, __construct )
{
/* this constructor shouldn't be called as it's private */
zend_throw_exception( NULL,
"An object of this type cannot be created with the new operator.",
0 TSRMLS_CC );
}
/* {{{ proto int transliterator_get_error_code( Transliterator trans )
* proto int Transliterator::getErrorCode()
* Get the last error code for this transliterator.
*/
PHP_FUNCTION( transliterator_get_error_code )
{
TRANSLITERATOR_METHOD_INIT_VARS
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, Transliterator_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_get_error_code: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
/* Fetch the object (without resetting its last error code ). */
to = zend_object_store_get_object( object TSRMLS_CC );
if (to == NULL )
RETURN_FALSE;
RETURN_LONG( (long) TRANSLITERATOR_ERROR_CODE( to ) );
}
/* }}} */
/* {{{ proto string transliterator_get_error_message( Transliterator trans )
* proto string Transliterator::getErrorMessage()
* Get the last error message for this transliterator.
*/
PHP_FUNCTION( transliterator_get_error_message )
{
const char* message = NULL;
TRANSLITERATOR_METHOD_INIT_VARS
if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&object, Transliterator_ce_ptr ) == FAILURE )
{
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
"transliterator_get_error_message: unable to parse input params", 0 TSRMLS_CC );
RETURN_FALSE;
}
/* Fetch the object (without resetting its last error code ). */
to = zend_object_store_get_object( object TSRMLS_CC );
if (to == NULL )
RETURN_FALSE;
/* Return last error message. */
message = intl_error_get_message( TRANSLITERATOR_ERROR_P( to ) 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
*/

38
ext/intl/transliterator/transliterator_methods.h

@ -0,0 +1,38 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Gustavo Lopes <cataphract@php.net> |
+----------------------------------------------------------------------+
*/
#ifndef TRANSLITERATOR_METHODS_H
#define TRANSLITERATOR_METHODS_H
#include <php.h>
PHP_FUNCTION( transliterator_create );
PHP_FUNCTION( transliterator_create_from_rules );
PHP_FUNCTION( transliterator_list_ids );
PHP_FUNCTION( transliterator_create_inverse );
PHP_FUNCTION( transliterator_transliterate );
PHP_METHOD( Transliterator, __construct );
PHP_FUNCTION( transliterator_get_error_code );
PHP_FUNCTION( transliterator_get_error_message );
#endif /* #ifndef TRANSLITERATOR_METHODS_H */
Loading…
Cancel
Save