]> granicus.if.org Git - php/commitdiff
add ICU resource bundle support, contributed by Hans-Peter Oeri
authorStanislav Malyshev <stas@php.net>
Mon, 4 Jan 2010 21:44:45 +0000 (21:44 +0000)
committerStanislav Malyshev <stas@php.net>
Mon, 4 Jan 2010 21:44:45 +0000 (21:44 +0000)
24 files changed:
ext/intl/config.m4
ext/intl/config.w32
ext/intl/php_intl.c
ext/intl/resourcebundle/TODO [new file with mode: 0755]
ext/intl/resourcebundle/resourcebundle.c [new file with mode: 0644]
ext/intl/resourcebundle/resourcebundle.h [new file with mode: 0644]
ext/intl/resourcebundle/resourcebundle_class.c [new file with mode: 0644]
ext/intl/resourcebundle/resourcebundle_class.h [new file with mode: 0644]
ext/intl/resourcebundle/resourcebundle_iterator.c [new file with mode: 0644]
ext/intl/resourcebundle/resourcebundle_iterator.h [new file with mode: 0644]
ext/intl/tests/_files/es-bundle.txt [new file with mode: 0755]
ext/intl/tests/_files/res_index.txt [new file with mode: 0755]
ext/intl/tests/_files/resourcebundle.txt [new file with mode: 0755]
ext/intl/tests/_files/resourcebundle/es.res [new file with mode: 0755]
ext/intl/tests/_files/resourcebundle/res_index.res [new file with mode: 0755]
ext/intl/tests/_files/resourcebundle/root.res [new file with mode: 0755]
ext/intl/tests/rb_build.php [new file with mode: 0755]
ext/intl/tests/resourcebundle.inc [new file with mode: 0644]
ext/intl/tests/resourcebundle_arrayaccess.phpt [new file with mode: 0644]
ext/intl/tests/resourcebundle_create.phpt [new file with mode: 0644]
ext/intl/tests/resourcebundle_individual.phpt [new file with mode: 0644]
ext/intl/tests/resourcebundle_iterator.phpt [new file with mode: 0644]
ext/intl/tests/resourcebundle_locales.phpt [new file with mode: 0755]
ext/intl/tests/ut_common.inc

index 9735b4450cf660e8e1b6588aac440d71e5189eb9..dc235db08c81fb2728d142b41b5b1f6dc52708b4 100755 (executable)
@@ -52,6 +52,9 @@ if test "$PHP_INTL" != "no"; then
     msgformat/msgformat_parse.c \
     grapheme/grapheme_string.c \
     grapheme/grapheme_util.c \
+    resourcebundle/resourcebundle.c \
+    resourcebundle/resourcebundle_class.c \
+    resourcebundle/resourcebundle_iterator.c \
     idn/idn.c, $ext_shared,,$ICU_INCS)
 
   PHP_ADD_BUILD_DIR($ext_builddir/collator)
@@ -62,5 +65,6 @@ if test "$PHP_INTL" != "no"; then
   PHP_ADD_BUILD_DIR($ext_builddir/locale)
   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/idn)
 fi
index 9184f8dfcd741df86e3129df86c707a4bb6d0093..68ccadf2d837af7c0d78dba87f44601caf53b3da 100755 (executable)
@@ -66,6 +66,11 @@ if (PHP_INTL != "no") {
                ADD_SOURCES(configure_module_dirname + "/idn", "\
                                idn.c",
                                "intl");
+               ADD_SOURCES(configure_module_dirname + "/resourcebundle", "\
+                               resourcebundle.c \
+                               resourcebundle_class.c \
+                               resourcebundle_iterator.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 {
index f4d1dcc525e76a36828e9782f8b5233f499eca35..a9bfefd14ca1f52014ad38ed3b9f57c4a8175d19 100755 (executable)
@@ -62,6 +62,8 @@
 #include "dateformat/dateformat_parse.h"
 #include "dateformat/dateformat_data.h"
 
+#include "resourcebundle/resourcebundle_class.h"
+
 #include "idn/idn.h"
 
 #include "msgformat/msgformat.h"
 #define INTL_MODULE_VERSION PHP_INTL_VERSION
 
 /*
- * locale_get_default has a conflict since ICU also has 
+ * 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 
+ * Same true for the locale_set_default function
 */
 #undef locale_get_default
 #undef locale_set_default
@@ -330,6 +332,36 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_idn_to_utf8, 0, 0, 1)
        ZEND_ARG_INFO(0, option)
        ZEND_ARG_INFO(0, status)
 ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_create_proc, 0, 0, 2 )
+       ZEND_ARG_INFO( 0, locale )
+       ZEND_ARG_INFO( 0, bundlename )
+       ZEND_ARG_INFO( 0, fallback )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_proc, 0, 0, 2 )
+    ZEND_ARG_INFO( 0, bundle )
+       ZEND_ARG_INFO( 0, index )
+       ZEND_ARG_INFO( 0, fallback )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_count_proc, 0, 0, 1 )
+  ZEND_ARG_INFO( 0, bundle )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_locales_proc, 0, 0, 1 )
+       ZEND_ARG_INFO( 0, bundlename )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_code_proc, 0, 0, 1 )
+  ZEND_ARG_INFO( 0, bundle )
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_message_proc, 0, 0, 1 )
+  ZEND_ARG_INFO( 0, bundle )
+ZEND_END_ARG_INFO()
+
+
 /* }}} */
 
 /* {{{ intl_functions
@@ -422,7 +454,7 @@ zend_function_entry intl_functions[] = {
        PHP_FE( datefmt_set_lenient, arginfo_msgfmt_get_locale )
        PHP_FE( datefmt_format, arginfo_datefmt_format )
        PHP_FE( datefmt_parse, datefmt_parse_args )
-    PHP_FE( datefmt_localtime , datefmt_parse_args )
+       PHP_FE( datefmt_localtime , datefmt_parse_args )
        PHP_FE( datefmt_get_error_code, arginfo_msgfmt_get_error_code )
        PHP_FE( datefmt_get_error_message, arginfo_msgfmt_get_error_message )
 
@@ -438,8 +470,16 @@ zend_function_entry intl_functions[] = {
        PHP_FE( grapheme_extract, grapheme_extract_args )
 
        /* IDN functions */
-       PHP_FE(idn_to_ascii, arginfo_idn_to_ascii)
-       PHP_FE(idn_to_utf8, arginfo_idn_to_ascii)
+       PHP_FE( idn_to_ascii, arginfo_idn_to_ascii)
+       PHP_FE( idn_to_utf8, arginfo_idn_to_ascii)
+
+       /* ResourceBundle functions */
+       PHP_FE( resourcebundle_create, arginfo_resourcebundle_create_proc )
+       PHP_FE( resourcebundle_get, arginfo_resourcebundle_get_proc )
+       PHP_FE( resourcebundle_count, arginfo_resourcebundle_count_proc )
+       PHP_FE( resourcebundle_locales, arginfo_resourcebundle_locales_proc )
+       PHP_FE( resourcebundle_get_error_code, arginfo_resourcebundle_get_error_code_proc )
+       PHP_FE( resourcebundle_get_error_message, arginfo_resourcebundle_get_error_message_proc )
 
        /* common functions */
        PHP_FE( intl_get_error_code, intl_0_args )
@@ -521,7 +561,7 @@ PHP_MINIT_FUNCTION( intl )
 
        /* Expose Normalizer constants to PHP scripts */
        normalizer_register_constants( INIT_FUNC_ARGS_PASSTHRU );
-       
+
        /* Register 'Locale' PHP class */
        locale_register_Locale_class( TSRMLS_C );
 
@@ -538,6 +578,9 @@ PHP_MINIT_FUNCTION( intl )
        /* Expose DateFormat constants to PHP scripts */
        dateformat_register_constants( INIT_FUNC_ARGS_PASSTHRU );
 
+       /* Register 'ResourceBundle' PHP class */
+       resourcebundle_register_class( TSRMLS_C);
+
        /* Expose ICU error codes to PHP scripts. */
        intl_expose_icu_error_codes( INIT_FUNC_ARGS_PASSTHRU );
 
diff --git a/ext/intl/resourcebundle/TODO b/ext/intl/resourcebundle/TODO
new file mode 100755 (executable)
index 0000000..ace4ceb
--- /dev/null
@@ -0,0 +1 @@
+- var_dump support\r
diff --git a/ext/intl/resourcebundle/resourcebundle.c b/ext/intl/resourcebundle/resourcebundle.c
new file mode 100644 (file)
index 0000000..3d881a2
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+   +----------------------------------------------------------------------+
+   | 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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
+   +----------------------------------------------------------------------+
+ */
+
+#include <unicode/ures.h>
+
+#include <zend.h>
+#include <zend_API.h>
+
+#include "intl_convert.h"
+#include "intl_data.h"
+#include "resourcebundle/resourcebundle_class.h"
+
+/* {{{ ResourceBundle_extract_value */
+void resourcebundle_extract_value( zval *return_value, ResourceBundle_object *source TSRMLS_DC ) 
+{
+       UResType               restype;
+       const UChar*           ufield;
+       const uint8_t*         bfield;
+       char *                 cfield;
+       const int32_t*         vfield;
+       int32_t                ilen;
+       int                    i;
+       long                   lfield;
+       ResourceBundle_object* newrb;
+
+       restype = ures_getType( source->child );
+       switch (restype)
+       {
+               case URES_STRING:
+                       ufield = ures_getString( source->child, &ilen, &INTL_DATA_ERROR_CODE(source) );
+                       INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve string value");
+                       INTL_METHOD_RETVAL_UTF8(source, ufield, ilen, 0);
+                       break;
+
+               case URES_BINARY:
+                       bfield = ures_getBinary( source->child, &ilen, &INTL_DATA_ERROR_CODE(source) );
+                       INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve binary value");
+                       ZVAL_STRINGL( return_value, (char *) bfield, ilen, 1 );
+                       break;
+
+               case URES_INT:
+                       lfield = ures_getInt( source->child, &INTL_DATA_ERROR_CODE(source) );
+                       INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve integer value");
+                       ZVAL_LONG( return_value, lfield );
+                       break;
+
+               case URES_INT_VECTOR:
+                       vfield = ures_getIntVector( source->child, &ilen, &INTL_DATA_ERROR_CODE(source) );
+                       INTL_METHOD_CHECK_STATUS(source, "Failed to retrieve vector value");
+                       array_init( return_value );
+                       for (i=0; i<ilen; i++) {
+                               add_next_index_long( return_value, vfield[i] );
+                       }
+                       break;
+
+               case URES_ARRAY:
+               case URES_TABLE:
+                       object_init_ex( return_value, ResourceBundle_ce_ptr );
+                       newrb = (ResourceBundle_object *) zend_object_store_get_object( return_value TSRMLS_CC );
+                       newrb->me = source->child;
+                       source->child = NULL;
+                       intl_errors_reset(INTL_DATA_ERROR_P(source) TSRMLS_CC);
+                       break;
+
+               default:
+                       intl_errors_set(INTL_DATA_ERROR_P(source), U_ILLEGAL_ARGUMENT_ERROR, "Unknown resource type", 0 TSRMLS_CC);
+                       RETURN_FALSE;
+                       break;
+       }
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/resourcebundle/resourcebundle.h b/ext/intl/resourcebundle/resourcebundle.h
new file mode 100644 (file)
index 0000000..607ece9
--- /dev/null
@@ -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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef RESOURCEBUNDLE_H
+#define RESOURCEBUNDLE_H
+
+#include <unicode/ures.h>
+
+#include <zend.h>
+
+#include "resourcebundle/resourcebundle_class.h"
+
+void resourcebundle_extract_value( zval *target, ResourceBundle_object *source TSRMLS_DC);
+
+#endif // #ifndef RESOURCEBUNDLE_CLASS_H
diff --git a/ext/intl/resourcebundle/resourcebundle_class.c b/ext/intl/resourcebundle/resourcebundle_class.c
new file mode 100644 (file)
index 0000000..9d51feb
--- /dev/null
@@ -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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
+   +----------------------------------------------------------------------+
+ */
+
+#include <stdlib.h>
+#include <unicode/ures.h>
+#include <unicode/uenum.h>
+
+#include <zend.h>
+#include <Zend/zend_exceptions.h>
+#include <Zend/zend_interfaces.h>
+#include <php.h>
+
+#include "php_intl.h"
+#include "intl_data.h"
+
+#include "resourcebundle/resourcebundle.h"
+#include "resourcebundle/resourcebundle_iterator.h"
+#include "resourcebundle/resourcebundle_class.h"
+
+zend_class_entry *ResourceBundle_ce_ptr = NULL;
+
+static zend_object_handlers ResourceBundle_object_handlers;
+
+/* {{{ ResourceBundle_object_dtor */
+static void ResourceBundle_object_destroy( void *object, zend_object_handle handle TSRMLS_DC )
+{
+       ResourceBundle_object *rb = (ResourceBundle_object *) object;
+
+       // only free local errors
+       intl_error_reset( INTL_DATA_ERROR_P(rb) TSRMLS_CC );
+
+       if (rb->me) {
+               ures_close( rb->me );
+       }
+       if (rb->child) {
+               ures_close( rb->child );
+       }
+
+       zend_object_std_dtor( object TSRMLS_CC );
+       efree(object);
+}
+/* }}} */
+
+/* {{{ ResourceBundle_object_create */
+static zend_object_value ResourceBundle_object_create( zend_class_entry *ce TSRMLS_DC )
+{
+       zend_object_value     retval;
+       ResourceBundle_object *rb;
+
+       rb = ecalloc( 1, sizeof(ResourceBundle_object) );
+
+       zend_object_std_init( (zend_object *) rb, ce TSRMLS_CC );
+
+       intl_error_init( INTL_DATA_ERROR_P(rb) TSRMLS_CC );
+       rb->me = NULL;
+       rb->child = NULL;
+
+       retval.handlers = &ResourceBundle_object_handlers;
+       retval.handle = zend_objects_store_put( rb, ResourceBundle_object_destroy, NULL, NULL TSRMLS_CC );
+
+       return retval;
+}
+/* }}} */
+
+/* {{{ ResourceBundle_ctor */
+static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS) 
+{
+       char *    bundlename;
+       int       bundlename_len = 0;
+       char *    locale;
+       int       locale_len = 0;
+       zend_bool fallback = 1;
+
+       char *    pbuf;
+
+       zval                  *object = return_value;
+       ResourceBundle_object *rb = (ResourceBundle_object *) zend_object_store_get_object( object );
+
+       intl_error_reset( NULL TSRMLS_CC );
+
+       if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", 
+               &locale, &locale_len, &bundlename, &bundlename_len, &fallback ) == FAILURE )
+       {
+               intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+                       "resourcebundle_ctor: unable to parse input parameters", 0 TSRMLS_CC );
+               zval_dtor( return_value );
+               RETURN_NULL();
+       }
+
+       INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
+
+       rb->me = ures_open(bundlename, locale, &INTL_DATA_ERROR_CODE(rb));
+
+       INTL_CTOR_CHECK_STATUS(rb, "resourcebundle_ctor: Cannot load libICU resource bundle");
+
+       if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
+               intl_errors_set_code( NULL, INTL_DATA_ERROR_CODE(rb) TSRMLS_CC );
+               spprintf( &pbuf, 0, "resourcebundle_ctor: Cannot load libICU resource '%s' without fallback from %s to %s",
+                               bundlename, locale, ures_getLocale( rb->me, &INTL_DATA_ERROR_CODE(rb)) );
+               intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 TSRMLS_CC );
+               efree(pbuf);
+               zval_dtor( return_value );
+               RETURN_NULL();
+       }
+}
+/* }}} */
+
+/* {{{ arginfo_resourcebundle__construct */
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle___construct, 0, 0, 2 )
+       ZEND_ARG_INFO( 0, locale )
+       ZEND_ARG_INFO( 0, bundlename )
+       ZEND_ARG_INFO( 0, fallback )
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ proto void ResourceBundle::__construct( string $bundlename [, string $locale [, bool $fallback = true ]] )
+ * ResourceBundle object constructor
+ */
+PHP_METHOD( ResourceBundle, __construct )
+{
+       return_value = getThis();
+       resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto ResourceBundle ResourceBundle::create( string $bundlename [, string $locale [, bool $fallback = true ]] )
+proto ResourceBundle resourcebundle_create( string $bundlename [, string $locale [, bool $fallback = true ]] ) */
+PHP_FUNCTION( resourcebundle_create ) 
+{
+       object_init_ex( return_value, ResourceBundle_ce_ptr );
+       resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ resourcebundle_array_fetch */
+static void resourcebundle_array_fetch(zval *object, zval *offset, zval *return_value, int fallback TSRMLS_DC) 
+{
+       int32_t     meindex;
+       char *      mekey;
+       long        mekeylen;
+    zend_bool    is_numeric = 0;
+       char         *pbuf;
+       ResourceBundle_object *rb;
+
+       intl_error_reset( NULL TSRMLS_CC );     
+       RESOURCEBUNDLE_METHOD_FETCH_OBJECT;
+
+       if(Z_TYPE_P(offset) == IS_LONG) {
+               is_numeric = 1;
+               meindex = Z_LVAL_P(offset);
+               rb->child = ures_getByIndex( rb->me, meindex, rb->child, &INTL_DATA_ERROR_CODE(rb) );
+       } else if(Z_TYPE_P(offset) == IS_STRING) {
+               mekey = Z_STRVAL_P(offset);
+               mekeylen = Z_STRLEN_P(offset);
+               rb->child = ures_getByKey(rb->me, mekey, rb->child, &INTL_DATA_ERROR_CODE(rb) );
+       } else {
+               intl_errors_set(INTL_DATA_ERROR_P(rb), U_ILLEGAL_ARGUMENT_ERROR,        
+                       "resourcebundle_get: index should be integer or string", 0 TSRMLS_CC);
+               RETURN_NULL();
+       }
+
+       intl_error_set_code( NULL, INTL_DATA_ERROR_CODE(rb) TSRMLS_CC );        
+       if (U_FAILURE(INTL_DATA_ERROR_CODE(rb))) {
+               if (is_numeric) {
+                       spprintf( &pbuf, 0, "Cannot load resource element %d", meindex );
+               } else {
+                       spprintf( &pbuf, 0, "Cannot load resource element '%s'", mekey );
+               }
+               intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 TSRMLS_CC );
+               efree(pbuf);
+               RETURN_NULL();
+       }
+
+       if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
+               UErrorCode icuerror;
+               const char * locale = ures_getLocale( rb->me, &icuerror );
+               if (is_numeric) {
+                       spprintf( &pbuf, 0, "Cannot load element %d without fallback from to %s", meindex, locale );
+               } else {
+                       spprintf( &pbuf, 0, "Cannot load element '%s' without fallback from to %s", mekey, locale );
+               }
+               intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 TSRMLS_CC );
+               efree(pbuf);
+               RETURN_NULL();
+       }
+
+       resourcebundle_extract_value( return_value, rb TSRMLS_CC );
+}
+/* }}} */
+
+/* {{{ resourcebundle_array_get */
+zval *resourcebundle_array_get(zval *object, zval *offset, int type TSRMLS_DC) 
+{
+       zval *retval;
+
+       if(offset == NULL) {
+               php_error( E_ERROR, "Cannot apply [] to ResourceBundle object" );
+       }
+       MAKE_STD_ZVAL(retval);
+
+       resourcebundle_array_fetch(object, offset, retval, 1 TSRMLS_CC);
+       Z_DELREF_P(retval);
+       return retval;
+}
+/* }}} */
+
+/* {{{ arginfo_resourcebundle_get */
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get, 0, 0, 1 )
+       ZEND_ARG_INFO( 0, index )
+       ZEND_ARG_INFO( 0, fallback )
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ proto mixed ResourceBundle::get( integer|string $resindex [, bool $fallback = true ] )
+ * proto mixed resourcebundle_get( ResourceBundle $rb, integer|string $resindex [, bool $fallback = true ] )
+ * Get resource identified by numerical index or key name.
+ */
+PHP_FUNCTION( resourcebundle_get )
+{
+       zend_bool   fallback = 1;
+       zval *          offset;
+       zval *      object;
+
+       if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz|b",  &object, ResourceBundle_ce_ptr, &offset, &fallback ) == FAILURE) {
+               intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,  
+                       "resourcebundle_get: unable to parse input params", 0 TSRMLS_CC);
+               RETURN_FALSE;
+       }
+
+       resourcebundle_array_fetch(object, offset, return_value, fallback TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ resourcebundle_array_count */
+int resourcebundle_array_count(zval *object, long *count TSRMLS_DC) 
+{
+       ResourceBundle_object *rb = (ResourceBundle_object *) zend_object_store_get_object( object );
+
+       *count = ures_getSize( rb->me );
+
+       return SUCCESS;
+}
+/* }}} */
+
+/* {{{ arginfo_resourcebundle_count */
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_count, 0, 0, 0 )
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ proto int ResourceBundle::count()
+ * proto int resourcebundle_count( ResourceBundle $bundle )
+ * Get resources count
+ */
+PHP_FUNCTION( resourcebundle_count )
+{
+       int32_t                len;
+       RESOURCEBUNDLE_METHOD_INIT_VARS;
+
+       if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, ResourceBundle_ce_ptr ) == FAILURE ) {
+               intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,  
+                       "resourcebundle_count: unable to parse input params", 0 TSRMLS_CC);
+               RETURN_FALSE;
+       }
+
+       RESOURCEBUNDLE_METHOD_FETCH_OBJECT;
+
+       len = ures_getSize( rb->me );
+       RETURN_LONG( len );
+}
+
+/* {{{ arginfo_resourcebundle_getlocales */
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_getlocales, 0, 0, 1 )
+       ZEND_ARG_INFO( 0, bundlename )
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ proto array ResourceBundle::getLocales( string $bundlename )
+ * proto array resourcebundle_locales( string $bundlename )
+ * Get available locales from ResourceBundle name
+ */
+PHP_FUNCTION( resourcebundle_locales )
+{
+       char * bundlename;
+       int    bundlename_len = 0;
+       const char * entry;
+       int entry_len;
+       UEnumeration *icuenum;
+       UErrorCode   icuerror = U_ZERO_ERROR;
+
+       intl_errors_reset( NULL TSRMLS_CC );
+
+       if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &bundlename, &bundlename_len ) == FAILURE )
+       {
+               intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,  
+                       "resourcebundle_locales: unable to parse input params", 0 TSRMLS_CC);
+               RETURN_FALSE;
+       }
+
+       if(bundlename_len == 0) {
+               // fetch default locales list
+               bundlename = NULL;
+       }
+
+       icuenum = ures_openAvailableLocales( bundlename, &icuerror );
+       INTL_CHECK_STATUS(icuerror, "Cannot fetch locales list");               
+
+       uenum_reset( icuenum, &icuerror );
+       INTL_CHECK_STATUS(icuerror, "Cannot iterate locales list");             
+
+       array_init( return_value );
+       while ((entry = uenum_next( icuenum, &entry_len, &icuerror ))) {
+               add_next_index_stringl( return_value, (char *) entry, entry_len, 1 );
+       }
+       uenum_close( icuenum );
+}
+/* }}} */
+
+/* {{{ arginfo_resourcebundle_get_error_code */
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_code, 0, 0, 0 )
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ proto string ResourceBundle::getErrorCode( )
+ * proto string resourcebundle_get_error_code( ResourceBundle $bundle )
+ * Get text description for ResourceBundle's last error code.
+ */
+PHP_FUNCTION( resourcebundle_get_error_code )
+{
+       RESOURCEBUNDLE_METHOD_INIT_VARS;
+
+       if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+               &object, ResourceBundle_ce_ptr ) == FAILURE )
+       {
+               intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+                       "resourcebundle_get_error_code: unable to parse input params", 0 TSRMLS_CC );
+               RETURN_FALSE;
+       }
+
+       rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
+
+       RETURN_LONG(INTL_DATA_ERROR_CODE(rb));
+}
+/* }}} */
+
+/* {{{ arginfo_resourcebundle_get_error_message */
+ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_message, 0, 0, 0 )
+ZEND_END_ARG_INFO()
+/* }}} */
+
+/* {{{ proto string ResourceBundle::getErrorMessage( )
+ * proto string resourcebundle_get_error_message( ResourceBundle $bundle )
+ * Get text description for ResourceBundle's last error.
+ */
+PHP_FUNCTION( resourcebundle_get_error_message )
+{
+       char* message = NULL;
+       RESOURCEBUNDLE_METHOD_INIT_VARS;
+
+       if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
+               &object, ResourceBundle_ce_ptr ) == FAILURE )
+       {
+               intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
+                       "resourcebundle_get_error_message: unable to parse input params", 0 TSRMLS_CC );
+               RETURN_FALSE;
+       }
+
+       rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
+       message = (char *)intl_error_get_message(INTL_DATA_ERROR_P(rb) TSRMLS_CC);
+       RETURN_STRING(message, 0);
+}
+/* }}} */
+
+/* {{{ ResourceBundle_class_functions
+ * Every 'ResourceBundle' class method has an entry in this table
+ */
+static function_entry ResourceBundle_class_functions[] = {
+       PHP_ME( ResourceBundle, __construct, arginfo_resourcebundle___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
+       ZEND_NAMED_ME( create, ZEND_FN( resourcebundle_create ), arginfo_resourcebundle___construct, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
+       ZEND_NAMED_ME( get, ZEND_FN(resourcebundle_get), arginfo_resourcebundle_get, ZEND_ACC_PUBLIC )
+       ZEND_NAMED_ME( count, ZEND_FN(resourcebundle_count), arginfo_resourcebundle_count, ZEND_ACC_PUBLIC )
+       ZEND_NAMED_ME( getLocales, ZEND_FN(resourcebundle_locales), arginfo_resourcebundle_getlocales, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC )
+       ZEND_NAMED_ME( getErrorCode, ZEND_FN(resourcebundle_get_error_code), arginfo_resourcebundle_get_error_code, ZEND_ACC_PUBLIC )
+       ZEND_NAMED_ME( getErrorMessage, ZEND_FN(resourcebundle_get_error_message), arginfo_resourcebundle_get_error_message, ZEND_ACC_PUBLIC )
+       { NULL, NULL, NULL }
+};
+/* }}} */
+
+/* {{{ resourcebundle_register_class
+ * Initialize 'ResourceBundle' class
+ */
+void resourcebundle_register_class( TSRMLS_D )
+{
+       zend_class_entry ce;
+
+       INIT_CLASS_ENTRY( ce, "ResourceBundle", ResourceBundle_class_functions );
+
+       ce.create_object = ResourceBundle_object_create;
+       ce.get_iterator = resourcebundle_get_iterator;
+
+       ResourceBundle_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
+
+       if( !ResourceBundle_ce_ptr )
+       {
+               zend_error(E_ERROR, "Failed to register ResourceBundle class");
+               return;
+       }
+
+       ResourceBundle_object_handlers = std_object_handlers;
+       ResourceBundle_object_handlers.read_dimension = resourcebundle_array_get;
+       ResourceBundle_object_handlers.count_elements = resourcebundle_array_count;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/resourcebundle/resourcebundle_class.h b/ext/intl/resourcebundle/resourcebundle_class.h
new file mode 100644 (file)
index 0000000..65330dd
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+   +----------------------------------------------------------------------+
+   | 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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef RESOURCEBUNDLE_CLASS_H
+#define RESOURCEBUNDLE_CLASS_H
+
+#include <unicode/ures.h>
+
+#include <zend.h>
+
+#include "intl_error.h"
+
+typedef struct {
+       zend_object     zend;
+       intl_error      error;
+
+       UResourceBundle *me;
+       UResourceBundle *child;
+} ResourceBundle_object;
+
+#define RESOURCEBUNDLE_METHOD_INIT_VARS                INTL_METHOD_INIT_VARS(ResourceBundle, rb)
+#define RESOURCEBUNDLE_METHOD_FETCH_OBJECT     INTL_METHOD_FETCH_OBJECT(ResourceBundle, rb)
+#define RESOURCEBUNDLE_OBJECT(rb)                      (rb)->me
+
+void resourcebundle_register_class( TSRMLS_D );
+extern zend_class_entry *ResourceBundle_ce_ptr;
+
+PHP_FUNCTION( resourcebundle_create );
+PHP_FUNCTION( resourcebundle_get );
+PHP_FUNCTION( resourcebundle_count );
+PHP_FUNCTION( resourcebundle_locales );
+PHP_FUNCTION( resourcebundle_get_error_code );
+PHP_FUNCTION( resourcebundle_get_error_message );
+
+#endif // #ifndef RESOURCEBUNDLE_CLASS_H
diff --git a/ext/intl/resourcebundle/resourcebundle_iterator.c b/ext/intl/resourcebundle/resourcebundle_iterator.c
new file mode 100644 (file)
index 0000000..d90ab71
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+   +----------------------------------------------------------------------+
+   | 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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
+   +----------------------------------------------------------------------+
+ */
+
+#include <php.h>
+#include <zend.h>
+#include <zend_API.h>
+
+#include "resourcebundle/resourcebundle.h"
+#include "resourcebundle/resourcebundle_class.h"
+#include "resourcebundle/resourcebundle_iterator.h"
+
+/*
+ * Although libicu offers iterator functions, they are not used here: libicu does iterate
+ * irrespective of array indices. Those cannot be recreated afterwards. Arrays as well as tables
+ * can however be accessed by numerical index, with table keys readable ex post.
+ */
+
+/* {{{ resourcebundle_iterator_read */
+static void resourcebundle_iterator_read( ResourceBundle_iterator *iterator TSRMLS_DC ) 
+{
+       UErrorCode icuerror = U_ZERO_ERROR;
+       ResourceBundle_object *rb = iterator->subject;
+
+       rb->child = ures_getByIndex( rb->me, iterator->i, rb->child, &icuerror );
+
+       if (U_SUCCESS(icuerror)) {
+               /* ATTN: key extraction must be the first thing to do... rb->child might be reset in read! */
+               if (iterator->is_table) {
+                       iterator->currentkey = estrdup( ures_getKey( rb->child ) );
+               }
+               MAKE_STD_ZVAL( iterator->current );
+               resourcebundle_extract_value( iterator->current, rb TSRMLS_CC );
+       }
+       else {
+               // zend_throw_exception( spl_ce_OutOfRangeException, "Running past end of ResourceBundle", 0 TSRMLS_CC);
+               iterator->current = NULL;
+       }
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_invalidate */
+static void resourcebundle_iterator_invalidate( zend_object_iterator *iter TSRMLS_DC ) 
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+
+       if (iterator->current) {
+               zval_ptr_dtor( &iterator->current );
+               iterator->current = NULL;
+       }
+       if (iterator->currentkey) {
+               efree( iterator->currentkey );
+               iterator->currentkey = NULL;
+       }
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_dtor */
+static void resourcebundle_iterator_dtor( zend_object_iterator *iter TSRMLS_DC )
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+       zval                    *object = (zval *)iterator->intern.data;
+
+       resourcebundle_iterator_invalidate( iter TSRMLS_CC );
+
+       Z_DELREF_P(object);
+
+       efree(iterator);
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_has_more */
+static int resourcebundle_iterator_has_more( zend_object_iterator *iter TSRMLS_DC )
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+       return (iterator->i < iterator->length) ? SUCCESS : FAILURE;
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_current */
+static void resourcebundle_iterator_current( zend_object_iterator *iter, zval ***data TSRMLS_DC )
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+       if (!iterator->current) {
+               resourcebundle_iterator_read( iterator );
+       }
+       *data = &iterator->current;
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_key */
+static int resourcebundle_iterator_key( zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC )
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+
+       if (!iterator->current) {
+               resourcebundle_iterator_read( iterator );
+       }
+       if (iterator->is_table) {
+               *str_key = estrdup( iterator->currentkey );
+               *str_key_len = strlen( iterator->currentkey ) + 1;
+               return HASH_KEY_IS_STRING;
+       }
+       else {
+               *int_key = iterator->i;
+               return HASH_KEY_IS_LONG;
+       }
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_has_more */
+static void resourcebundle_iterator_step( zend_object_iterator *iter TSRMLS_DC )
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+
+       iterator->i++;
+       resourcebundle_iterator_invalidate( iter TSRMLS_CC );
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_has_reset */
+static void resourcebundle_iterator_reset( zend_object_iterator *iter TSRMLS_DC )
+{
+       ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
+
+       iterator->i = 0;
+       resourcebundle_iterator_invalidate( iter TSRMLS_CC );
+}
+/* }}} */
+
+/* {{{ resourcebundle_iterator_funcs */
+static zend_object_iterator_funcs resourcebundle_iterator_funcs = {
+       resourcebundle_iterator_dtor,
+       resourcebundle_iterator_has_more,
+       resourcebundle_iterator_current,
+       resourcebundle_iterator_key,
+       resourcebundle_iterator_step,
+       resourcebundle_iterator_reset,
+       resourcebundle_iterator_invalidate
+};
+/* }}} */
+
+/* {{{ resourcebundle_get_iterator */
+zend_object_iterator *resourcebundle_get_iterator( zend_class_entry *ce, zval *object, int byref TSRMLS_DC )
+{
+       ResourceBundle_object   *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
+       ResourceBundle_iterator *iterator = emalloc( sizeof( ResourceBundle_iterator ) );
+
+       if (byref) {
+            php_error( E_ERROR, "ResourceBundle does not support writable iterators" );
+       }
+
+       Z_ADDREF_P(object);
+       iterator->intern.data = (void *) object;
+       iterator->intern.funcs = &resourcebundle_iterator_funcs;
+
+       iterator->subject = rb;
+
+       /* The iterated rb can only be either URES_TABLE or URES_ARRAY
+        * All other types are returned as php primitives!
+        */
+       iterator->is_table = (ures_getType( rb->me ) == URES_TABLE);
+       iterator->length = ures_getSize( rb->me );
+
+       iterator->current = NULL;
+       iterator->currentkey = NULL;
+       iterator->i = 0;
+
+       return (zend_object_iterator *) iterator;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/intl/resourcebundle/resourcebundle_iterator.h b/ext/intl/resourcebundle/resourcebundle_iterator.h
new file mode 100644 (file)
index 0000000..90dba86
--- /dev/null
@@ -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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
+   +----------------------------------------------------------------------+
+ */
+
+#ifndef RESOURCEBUNDLE_ITERATOR_H
+#define RESOURCEBUNDLE_ITERATOR_H
+
+#include <zend.h>
+
+#include "resourcebundle/resourcebundle_class.h"
+
+typedef struct {
+       zend_object_iterator  intern;
+       ResourceBundle_object *subject;
+       zend_bool             is_table;
+       long                  length;
+       zval                  *current;
+       char                  *currentkey;
+       long                  i;
+} ResourceBundle_iterator;
+
+zend_object_iterator *resourcebundle_get_iterator( zend_class_entry *ce, zval *object, int byref TSRMLS_DC );
+
+#endif // #ifndef RESOURCEBUNDLE_ITERATOR_H
diff --git a/ext/intl/tests/_files/es-bundle.txt b/ext/intl/tests/_files/es-bundle.txt
new file mode 100755 (executable)
index 0000000..46399a7
--- /dev/null
@@ -0,0 +1,21 @@
+es {
+    teststring:string { "Hola Mundo!" }
+
+    testint:int { 2 }
+
+    testvector:intvector { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }
+
+    testbin:bin { a1b2c3d4e5f67890 }
+
+    testtable:table {
+        major:int { 3 }
+        minor:int { 4 }
+        patch:int { 7 }
+    }
+
+    testarray:array {
+        "cadena 1",
+        "cadena 2",
+        "cadena 3"
+    }
+}
diff --git a/ext/intl/tests/_files/res_index.txt b/ext/intl/tests/_files/res_index.txt
new file mode 100755 (executable)
index 0000000..a39bea5
--- /dev/null
@@ -0,0 +1,6 @@
+res_index:table(nofallback) {\r
+    InstalledLocales {\r
+es {""}
+root {""}\r
+    }\r
+}
\ No newline at end of file
diff --git a/ext/intl/tests/_files/resourcebundle.txt b/ext/intl/tests/_files/resourcebundle.txt
new file mode 100755 (executable)
index 0000000..5b081da
--- /dev/null
@@ -0,0 +1,21 @@
+root {
+    teststring:string { "Hello World!" }
+
+    testint:int { 2 }
+
+    testvector:intvector { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }
+
+    testbin:bin { a1b2c3d4e5f67890 }
+
+    testtable:table {
+        major:int { 3 }
+        minor:int { 4 }
+        patch:int { 7 }
+    }
+
+    testarray:array {
+        "string 1",
+        "string 2",
+        "string 3"
+    }
+}
diff --git a/ext/intl/tests/_files/resourcebundle/es.res b/ext/intl/tests/_files/resourcebundle/es.res
new file mode 100755 (executable)
index 0000000..f9d891d
Binary files /dev/null and b/ext/intl/tests/_files/resourcebundle/es.res differ
diff --git a/ext/intl/tests/_files/resourcebundle/res_index.res b/ext/intl/tests/_files/resourcebundle/res_index.res
new file mode 100755 (executable)
index 0000000..9dd3df2
Binary files /dev/null and b/ext/intl/tests/_files/resourcebundle/res_index.res differ
diff --git a/ext/intl/tests/_files/resourcebundle/root.res b/ext/intl/tests/_files/resourcebundle/root.res
new file mode 100755 (executable)
index 0000000..62cb48c
Binary files /dev/null and b/ext/intl/tests/_files/resourcebundle/root.res differ
diff --git a/ext/intl/tests/rb_build.php b/ext/intl/tests/rb_build.php
new file mode 100755 (executable)
index 0000000..6a7eeae
--- /dev/null
@@ -0,0 +1,33 @@
+<?php\r
+// THIS SCRIPT WILL REBUILD ResourceBundle bundles from source files\r
+\r
+// DEFINE YOUR ICU TOOLS PATH HERE\r
+define("ICU_DIR", "C:/PROJECTS/ICU40/BIN/");\r
+\r
+$here = dirname(__FILE__);\r
+\r
+$dir = new GlobIterator("$here/_files/*.txt", FilesystemIterator::KEY_AS_FILENAME);\r
+\r
+foreach($dir as $file) {\r
+  passthru( ICU_DIR."genrb -s $here/_files/ -d $here/_files/resourcebundle ".$file->getFileName());\r
+}\r
+\r
+$dir = new GlobIterator("$here/_files/resourcebundle/*.res", FilesystemIterator::KEY_AS_FILENAME);\r
+foreach($dir as $file) {\r
+  if($file->getFileName() == "res_index.res") continue;\r
+  $list[] = str_replace(".res", "", $file->getFileName());\r
+}\r
+\r
+$filelist = join(" {\"\"}\n", $list);\r
+$res_index = <<<END\r
+res_index:table(nofallback) {\r
+    InstalledLocales {\r
+$filelist {""}\r
+    }\r
+}\r
+END;\r
+file_put_contents("$here/_files/res_index.txt", $res_index);\r
+\r
+passthru( ICU_DIR."genrb -s $here/_files/ -d $here/_files/resourcebundle res_index.txt");\r
+\r
+// passthru(ICU_DIR."icupkg -tl -a $here/rb.txt -s $here/_files -d $here/_files new $here/_files/resourcebundle.dat");
\ No newline at end of file
diff --git a/ext/intl/tests/resourcebundle.inc b/ext/intl/tests/resourcebundle.inc
new file mode 100644 (file)
index 0000000..2ec138b
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+define('BUNDLE', dirname(__FILE__)."/_files/resourcebundle");
+
+function debug( $res ) {
+       if (is_null( $res )) {
+               $ret = "NULL\n";
+       }
+       else {
+               $ret = print_r( $res, true ). "\n";
+       }
+       return $ret . sprintf( "%5d: %s\n", intl_get_error_code(), intl_get_error_message() );
+}
+
diff --git a/ext/intl/tests/resourcebundle_arrayaccess.phpt b/ext/intl/tests/resourcebundle_arrayaccess.phpt
new file mode 100644 (file)
index 0000000..ef2c0a8
--- /dev/null
@@ -0,0 +1,48 @@
+--TEST--
+Test ResourceBundle array access and count - existing/missing keys
+--FILE--
+<?php
+       include "resourcebundle.inc";
+
+       // fall back
+       $r = new ResourceBundle( 'en_US', BUNDLE );
+
+       printf( "length: %d\n", count($r) );
+       printf( "teststring: %s\n", $r['teststring'] );
+       printf( "testint: %d\n", $r['testint'] );
+
+       print_r( $r['testvector'] );
+
+       printf( "testbin: %s\n", bin2hex($r['testbin']) );
+
+       $r2 = $r['testtable'];
+       printf( "testtable: %d\n", $r2['major'] );
+
+       $r2 = $r['testarray'];
+       printf( "testarray: %s\n", $r2[2] );
+
+       $t = $r['nonexisting'];
+       echo debug( $t );
+?>
+--EXPECT--
+length: 6
+teststring: Hello World!
+testint: 2
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+    [3] => 4
+    [4] => 5
+    [5] => 6
+    [6] => 7
+    [7] => 8
+    [8] => 9
+    [9] => 0
+)
+testbin: a1b2c3d4e5f67890
+testtable: 3
+testarray: string 3
+NULL
+    2: Cannot load resource element 'nonexisting': U_MISSING_RESOURCE_ERROR
diff --git a/ext/intl/tests/resourcebundle_create.phpt b/ext/intl/tests/resourcebundle_create.phpt
new file mode 100644 (file)
index 0000000..4d96d3e
--- /dev/null
@@ -0,0 +1,62 @@
+--TEST--
+Test ResourceBundle::__construct() - existing/missing bundles/locales
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+       
+include "resourcebundle.inc";
+
+function ut_main() {
+       $str_res = '';
+       // all fine
+       $r1 = ut_resourcebundle_create( 'root', BUNDLE );
+       $str_res .= debug( $r1 );
+       $str_res .= print_r( $r1['teststring'], true)."\n";
+
+       // non-root one
+       $r1 = ut_resourcebundle_create( 'es', BUNDLE );
+       $str_res .= debug( $r1 );
+       $str_res .= print_r( $r1['teststring'], true)."\n";
+
+       // fall back
+       $r1 = ut_resourcebundle_create( 'en_US', BUNDLE );
+        $str_res .= debug( $r1 );
+       $str_res .= print_r( $r1['testsring'], true);
+
+       // fall out
+       $r2 = ut_resourcebundle_create( 'en_US', BUNDLE, false );
+        $str_res .= debug( $r2 );
+
+       // missing
+       $r3 = ut_resourcebundle_create( 'en_US', 'nonexisting' );
+        $str_res .= debug( $r3 );
+       
+       return $str_res;
+}
+
+       include_once( 'ut_common.inc' );
+       ut_run();
+?>
+--EXPECTF--
+ResourceBundle Object
+(
+)
+
+    0: U_ZERO_ERROR
+Hello World!
+ResourceBundle Object
+(
+)
+
+    0: U_ZERO_ERROR
+Hola Mundo!
+ResourceBundle Object
+(
+)
+
+ -127: U_USING_DEFAULT_WARNING
+NULL
+ -127: resourcebundle_ctor: Cannot load libICU resource '%s/resourcebundle' without fallback from en_US to root: U_USING_DEFAULT_WARNING
+NULL
+    2: resourcebundle_ctor: Cannot load libICU resource bundle: U_MISSING_RESOURCE_ERROR
diff --git a/ext/intl/tests/resourcebundle_individual.phpt b/ext/intl/tests/resourcebundle_individual.phpt
new file mode 100644 (file)
index 0000000..182cbf3
--- /dev/null
@@ -0,0 +1,55 @@
+--TEST--
+Test ResourceBundle::get() and length() - existing/missing keys
+--FILE--
+<?php
+       include "resourcebundle.inc";
+
+function ut_main() {
+       $str_res = '';
+       // fall back
+       $r = ut_resourcebundle_create( 'en_US', BUNDLE );
+
+       $str_res .= sprintf( "length: %d\n", ut_resourcebundle_count($r) );
+       $str_res .= sprintf( "teststring: %s\n", ut_resourcebundle_get($r,  'teststring' ) );
+       $str_res .= sprintf( "testint: %d\n", ut_resourcebundle_get($r, 'testint' ) );
+
+       $str_res .= print_r( ut_resourcebundle_get($r, 'testvector' ), true );
+
+       $str_res .= sprintf( "testbin: %s\n", bin2hex(ut_resourcebundle_get( $r,'testbin' )) );
+
+       $r2 = ut_resourcebundle_get($r, 'testtable' );
+       $str_res .= sprintf( "testtable: %d\n", ut_resourcebundle_get($r2, 'major' ) );
+
+       $r2 = ut_resourcebundle_get($r,'testarray' );
+       $str_res .= sprintf( "testarray: %s\n", ut_resourcebundle_get($r2, 2 ) );
+
+       $t = ut_resourcebundle_get( $r, 'nonexisting' );
+       $str_res .= debug( $t );
+       
+       return $str_res;
+}
+       include_once( 'ut_common.inc' );
+       ut_run();
+?>
+--EXPECT--
+length: 6
+teststring: Hello World!
+testint: 2
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+    [3] => 4
+    [4] => 5
+    [5] => 6
+    [6] => 7
+    [7] => 8
+    [8] => 9
+    [9] => 0
+)
+testbin: a1b2c3d4e5f67890
+testtable: 3
+testarray: string 3
+NULL
+    2: Cannot load resource element 'nonexisting': U_MISSING_RESOURCE_ERROR
diff --git a/ext/intl/tests/resourcebundle_iterator.phpt b/ext/intl/tests/resourcebundle_iterator.phpt
new file mode 100644 (file)
index 0000000..31b0768
--- /dev/null
@@ -0,0 +1,71 @@
+--TEST--
+Test ResourceBundle iterator
+--FILE--
+<?php
+       include "resourcebundle.inc";
+
+       // fall back
+       $r = new ResourceBundle( 'en_US', BUNDLE );
+
+       foreach ($r as $onekey => $oneval) {
+               echo "Here comes $onekey:\n";
+               switch (gettype($oneval)) {
+                 case 'string':
+                   echo bin2hex( $oneval ) . "\n";
+                   break;
+
+                 case 'integer':
+                   echo "$oneval\n";
+                   break;
+
+                 default:
+                   print_r( $oneval );
+               }
+               echo "\n";
+       }
+
+       echo "Testarray Contents:\n";
+       $r = $r->get( 'testarray' );
+       foreach ($r as $onekey => $oneval) {
+          echo "$onekey => $oneval\n";
+       }
+?>
+--EXPECTF--
+Here comes testarray:
+ResourceBundle Object
+(
+)
+
+Here comes testbin:
+a1b2c3d4e5f67890
+
+Here comes testint:
+2
+
+Here comes teststring:
+48656c6c6f20576f726c6421
+
+Here comes testtable:
+ResourceBundle Object
+(
+)
+
+Here comes testvector:
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+    [3] => 4
+    [4] => 5
+    [5] => 6
+    [6] => 7
+    [7] => 8
+    [8] => 9
+    [9] => 0
+)
+
+Testarray Contents:
+0 => string 1
+1 => string 2
+2 => string 3
diff --git a/ext/intl/tests/resourcebundle_locales.phpt b/ext/intl/tests/resourcebundle_locales.phpt
new file mode 100755 (executable)
index 0000000..e14a7e5
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+Test ResourceBundle::getLocales
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+       
+include "resourcebundle.inc";
+
+function ut_main() {
+       $str_res = '';
+
+       $str_res .= join("\n", ut_resourcebundle_locales(BUNDLE));
+       
+       return $str_res;
+}
+
+       include_once( 'ut_common.inc' );
+       ut_run();
+?>
+--EXPECT--
+es
+root
index c59d1770eeb3b77bf3f4c3950f96c8d9632f75a3..09be22bf5a63317c35248eec3537ec97c3982b71 100755 (executable)
@@ -389,4 +389,28 @@ function ut_datefmt_localtime( $fmt , $value , &$parse_pos=0 )
 {
     return $GLOBALS['oo-mode'] ? $fmt->localtime(  $value , $parse_pos ) : datefmt_localtime( $fmt ,  $value , $parse_pos );
 }
-?>
+
+function ut_resourcebundle_create( $locale, $bundle, $fallback=true )
+{
+    return $GLOBALS['oo-mode'] ? new ResourceBundle($locale, $bundle, $fallback): resourcebundle_create($locale, $bundle, $fallback);
+}
+function ut_resourcebundle_count($bundle )
+{
+    return $GLOBALS['oo-mode'] ? $bundle->count():resourcebundle_count($bundle);
+}
+function ut_resourcebundle_locales($bundle )
+{
+    return $GLOBALS['oo-mode'] ? ResourceBundle::getLocales($bundle):resourcebundle_locales($bundle);
+}
+function ut_resourcebundle_get($bundle, $idx )
+{
+    return $GLOBALS['oo-mode'] ? $bundle->get($idx):resourcebundle_get($bundle, $idx);
+}
+function ut_resourcebundle_get_error_code($bundle )
+{
+    return $GLOBALS['oo-mode'] ? $bundle->getErrorCode():resourcebundle_get_error_code($bundle);
+}
+function ut_resourcebundle_get_error_message($bundle )
+{
+    return $GLOBALS['oo-mode'] ? $bundle->getErrorMessage():resourcebundle_get_error_message($bundle);
+}