PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/intl/resourcebundle/resourcebundle_class.c

https://bitbucket.org/luobailiang/php-src
C | 450 lines | 285 code | 76 blank | 89 comment | 44 complexity | 7119604d731c0915b33f9bd52863dbb9 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include <stdlib.h>
  17. #include <unicode/ures.h>
  18. #include <unicode/uenum.h>
  19. #include <zend.h>
  20. #include <Zend/zend_exceptions.h>
  21. #include <Zend/zend_interfaces.h>
  22. #include <php.h>
  23. #include "php_intl.h"
  24. #include "intl_data.h"
  25. #include "resourcebundle/resourcebundle.h"
  26. #include "resourcebundle/resourcebundle_iterator.h"
  27. #include "resourcebundle/resourcebundle_class.h"
  28. zend_class_entry *ResourceBundle_ce_ptr = NULL;
  29. static zend_object_handlers ResourceBundle_object_handlers;
  30. /* {{{ ResourceBundle_object_dtor */
  31. static void ResourceBundle_object_destroy( void *object, zend_object_handle handle TSRMLS_DC )
  32. {
  33. ResourceBundle_object *rb = (ResourceBundle_object *) object;
  34. // only free local errors
  35. intl_error_reset( INTL_DATA_ERROR_P(rb) TSRMLS_CC );
  36. if (rb->me) {
  37. ures_close( rb->me );
  38. }
  39. if (rb->child) {
  40. ures_close( rb->child );
  41. }
  42. zend_object_std_dtor( object TSRMLS_CC );
  43. efree(object);
  44. }
  45. /* }}} */
  46. /* {{{ ResourceBundle_object_create */
  47. static zend_object_value ResourceBundle_object_create( zend_class_entry *ce TSRMLS_DC )
  48. {
  49. zend_object_value retval;
  50. ResourceBundle_object *rb;
  51. rb = ecalloc( 1, sizeof(ResourceBundle_object) );
  52. zend_object_std_init( (zend_object *) rb, ce TSRMLS_CC );
  53. intl_error_init( INTL_DATA_ERROR_P(rb) TSRMLS_CC );
  54. rb->me = NULL;
  55. rb->child = NULL;
  56. retval.handlers = &ResourceBundle_object_handlers;
  57. retval.handle = zend_objects_store_put( rb, ResourceBundle_object_destroy, NULL, NULL TSRMLS_CC );
  58. return retval;
  59. }
  60. /* }}} */
  61. /* {{{ ResourceBundle_ctor */
  62. static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS)
  63. {
  64. char * bundlename;
  65. int bundlename_len = 0;
  66. char * locale;
  67. int locale_len = 0;
  68. zend_bool fallback = 1;
  69. char * pbuf;
  70. zval *object = return_value;
  71. ResourceBundle_object *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC);
  72. intl_error_reset( NULL TSRMLS_CC );
  73. if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s!s!|b",
  74. &locale, &locale_len, &bundlename, &bundlename_len, &fallback ) == FAILURE )
  75. {
  76. intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
  77. "resourcebundle_ctor: unable to parse input parameters", 0 TSRMLS_CC );
  78. zval_dtor( return_value );
  79. RETURN_NULL();
  80. }
  81. INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
  82. if (locale == NULL) {
  83. locale = intl_locale_get_default(TSRMLS_C);
  84. }
  85. if (fallback) {
  86. rb->me = ures_open(bundlename, locale, &INTL_DATA_ERROR_CODE(rb));
  87. } else {
  88. rb->me = ures_openDirect(bundlename, locale, &INTL_DATA_ERROR_CODE(rb));
  89. }
  90. INTL_CTOR_CHECK_STATUS(rb, "resourcebundle_ctor: Cannot load libICU resource bundle");
  91. if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING ||
  92. INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
  93. intl_errors_set_code(NULL, INTL_DATA_ERROR_CODE(rb) TSRMLS_CC);
  94. spprintf(&pbuf, 0, "resourcebundle_ctor: Cannot load libICU resource "
  95. "'%s' without fallback from %s to %s",
  96. bundlename ? bundlename : "(default data)", locale,
  97. ures_getLocaleByType(
  98. rb->me, ULOC_ACTUAL_LOCALE, &INTL_DATA_ERROR_CODE(rb)));
  99. intl_errors_set_custom_msg(INTL_DATA_ERROR_P(rb), pbuf, 1 TSRMLS_CC);
  100. efree(pbuf);
  101. zval_dtor(return_value);
  102. RETURN_NULL();
  103. }
  104. }
  105. /* }}} */
  106. /* {{{ arginfo_resourcebundle__construct */
  107. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle___construct, 0, 0, 2 )
  108. ZEND_ARG_INFO( 0, locale )
  109. ZEND_ARG_INFO( 0, bundlename )
  110. ZEND_ARG_INFO( 0, fallback )
  111. ZEND_END_ARG_INFO()
  112. /* }}} */
  113. /* {{{ proto void ResourceBundle::__construct( string $locale [, string $bundlename [, bool $fallback = true ]] )
  114. * ResourceBundle object constructor
  115. */
  116. PHP_METHOD( ResourceBundle, __construct )
  117. {
  118. return_value = getThis();
  119. resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  120. }
  121. /* }}} */
  122. /* {{{ proto ResourceBundle ResourceBundle::create( string $locale [, string $bundlename [, bool $fallback = true ]] )
  123. proto ResourceBundle resourcebundle_create( string $locale [, string $bundlename [, bool $fallback = true ]] )
  124. */
  125. PHP_FUNCTION( resourcebundle_create )
  126. {
  127. object_init_ex( return_value, ResourceBundle_ce_ptr );
  128. resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  129. }
  130. /* }}} */
  131. /* {{{ resourcebundle_array_fetch */
  132. static void resourcebundle_array_fetch(zval *object, zval *offset, zval *return_value, int fallback TSRMLS_DC)
  133. {
  134. int32_t meindex;
  135. char * mekey;
  136. long mekeylen;
  137. zend_bool is_numeric = 0;
  138. char *pbuf;
  139. ResourceBundle_object *rb;
  140. intl_error_reset( NULL TSRMLS_CC );
  141. RESOURCEBUNDLE_METHOD_FETCH_OBJECT;
  142. if(Z_TYPE_P(offset) == IS_LONG) {
  143. is_numeric = 1;
  144. meindex = Z_LVAL_P(offset);
  145. rb->child = ures_getByIndex( rb->me, meindex, rb->child, &INTL_DATA_ERROR_CODE(rb) );
  146. } else if(Z_TYPE_P(offset) == IS_STRING) {
  147. mekey = Z_STRVAL_P(offset);
  148. mekeylen = Z_STRLEN_P(offset);
  149. rb->child = ures_getByKey(rb->me, mekey, rb->child, &INTL_DATA_ERROR_CODE(rb) );
  150. } else {
  151. intl_errors_set(INTL_DATA_ERROR_P(rb), U_ILLEGAL_ARGUMENT_ERROR,
  152. "resourcebundle_get: index should be integer or string", 0 TSRMLS_CC);
  153. RETURN_NULL();
  154. }
  155. intl_error_set_code( NULL, INTL_DATA_ERROR_CODE(rb) TSRMLS_CC );
  156. if (U_FAILURE(INTL_DATA_ERROR_CODE(rb))) {
  157. if (is_numeric) {
  158. spprintf( &pbuf, 0, "Cannot load resource element %d", meindex );
  159. } else {
  160. spprintf( &pbuf, 0, "Cannot load resource element '%s'", mekey );
  161. }
  162. intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 TSRMLS_CC );
  163. efree(pbuf);
  164. RETURN_NULL();
  165. }
  166. if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
  167. UErrorCode icuerror;
  168. const char * locale = ures_getLocaleByType( rb->me, ULOC_ACTUAL_LOCALE, &icuerror );
  169. if (is_numeric) {
  170. spprintf( &pbuf, 0, "Cannot load element %d without fallback from to %s", meindex, locale );
  171. } else {
  172. spprintf( &pbuf, 0, "Cannot load element '%s' without fallback from to %s", mekey, locale );
  173. }
  174. intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 TSRMLS_CC );
  175. efree(pbuf);
  176. RETURN_NULL();
  177. }
  178. resourcebundle_extract_value( return_value, rb TSRMLS_CC );
  179. }
  180. /* }}} */
  181. /* {{{ resourcebundle_array_get */
  182. zval *resourcebundle_array_get(zval *object, zval *offset, int type TSRMLS_DC)
  183. {
  184. zval *retval;
  185. if(offset == NULL) {
  186. php_error( E_ERROR, "Cannot apply [] to ResourceBundle object" );
  187. }
  188. MAKE_STD_ZVAL(retval);
  189. resourcebundle_array_fetch(object, offset, retval, 1 TSRMLS_CC);
  190. Z_DELREF_P(retval);
  191. return retval;
  192. }
  193. /* }}} */
  194. /* {{{ arginfo_resourcebundle_get */
  195. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get, 0, 0, 1 )
  196. ZEND_ARG_INFO( 0, index )
  197. ZEND_ARG_INFO( 0, fallback )
  198. ZEND_END_ARG_INFO()
  199. /* }}} */
  200. /* {{{ proto mixed ResourceBundle::get( integer|string $resindex [, bool $fallback = true ] )
  201. * proto mixed resourcebundle_get( ResourceBundle $rb, integer|string $resindex [, bool $fallback = true ] )
  202. * Get resource identified by numerical index or key name.
  203. */
  204. PHP_FUNCTION( resourcebundle_get )
  205. {
  206. zend_bool fallback = 1;
  207. zval * offset;
  208. zval * object;
  209. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz|b", &object, ResourceBundle_ce_ptr, &offset, &fallback ) == FAILURE) {
  210. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  211. "resourcebundle_get: unable to parse input params", 0 TSRMLS_CC);
  212. RETURN_FALSE;
  213. }
  214. resourcebundle_array_fetch(object, offset, return_value, fallback TSRMLS_CC);
  215. }
  216. /* }}} */
  217. /* {{{ resourcebundle_array_count */
  218. int resourcebundle_array_count(zval *object, long *count TSRMLS_DC)
  219. {
  220. ResourceBundle_object *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC);
  221. *count = ures_getSize( rb->me );
  222. return SUCCESS;
  223. }
  224. /* }}} */
  225. /* {{{ arginfo_resourcebundle_count */
  226. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_count, 0, 0, 0 )
  227. ZEND_END_ARG_INFO()
  228. /* }}} */
  229. /* {{{ proto int ResourceBundle::count()
  230. * proto int resourcebundle_count( ResourceBundle $bundle )
  231. * Get resources count
  232. */
  233. PHP_FUNCTION( resourcebundle_count )
  234. {
  235. int32_t len;
  236. RESOURCEBUNDLE_METHOD_INIT_VARS;
  237. if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, ResourceBundle_ce_ptr ) == FAILURE ) {
  238. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  239. "resourcebundle_count: unable to parse input params", 0 TSRMLS_CC);
  240. RETURN_FALSE;
  241. }
  242. RESOURCEBUNDLE_METHOD_FETCH_OBJECT;
  243. len = ures_getSize( rb->me );
  244. RETURN_LONG( len );
  245. }
  246. /* {{{ arginfo_resourcebundle_getlocales */
  247. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_getlocales, 0, 0, 1 )
  248. ZEND_ARG_INFO( 0, bundlename )
  249. ZEND_END_ARG_INFO()
  250. /* }}} */
  251. /* {{{ proto array ResourceBundle::getLocales( string $bundlename )
  252. * proto array resourcebundle_locales( string $bundlename )
  253. * Get available locales from ResourceBundle name
  254. */
  255. PHP_FUNCTION( resourcebundle_locales )
  256. {
  257. char * bundlename;
  258. int bundlename_len = 0;
  259. const char * entry;
  260. int entry_len;
  261. UEnumeration *icuenum;
  262. UErrorCode icuerror = U_ZERO_ERROR;
  263. intl_errors_reset( NULL TSRMLS_CC );
  264. if( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &bundlename, &bundlename_len ) == FAILURE )
  265. {
  266. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  267. "resourcebundle_locales: unable to parse input params", 0 TSRMLS_CC);
  268. RETURN_FALSE;
  269. }
  270. if(bundlename_len == 0) {
  271. // fetch default locales list
  272. bundlename = NULL;
  273. }
  274. icuenum = ures_openAvailableLocales( bundlename, &icuerror );
  275. INTL_CHECK_STATUS(icuerror, "Cannot fetch locales list");
  276. uenum_reset( icuenum, &icuerror );
  277. INTL_CHECK_STATUS(icuerror, "Cannot iterate locales list");
  278. array_init( return_value );
  279. while ((entry = uenum_next( icuenum, &entry_len, &icuerror ))) {
  280. add_next_index_stringl( return_value, (char *) entry, entry_len, 1 );
  281. }
  282. uenum_close( icuenum );
  283. }
  284. /* }}} */
  285. /* {{{ arginfo_resourcebundle_get_error_code */
  286. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_code, 0, 0, 0 )
  287. ZEND_END_ARG_INFO()
  288. /* }}} */
  289. /* {{{ proto string ResourceBundle::getErrorCode( )
  290. * proto string resourcebundle_get_error_code( ResourceBundle $bundle )
  291. * Get text description for ResourceBundle's last error code.
  292. */
  293. PHP_FUNCTION( resourcebundle_get_error_code )
  294. {
  295. RESOURCEBUNDLE_METHOD_INIT_VARS;
  296. if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
  297. &object, ResourceBundle_ce_ptr ) == FAILURE )
  298. {
  299. intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
  300. "resourcebundle_get_error_code: unable to parse input params", 0 TSRMLS_CC );
  301. RETURN_FALSE;
  302. }
  303. rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
  304. RETURN_LONG(INTL_DATA_ERROR_CODE(rb));
  305. }
  306. /* }}} */
  307. /* {{{ arginfo_resourcebundle_get_error_message */
  308. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_message, 0, 0, 0 )
  309. ZEND_END_ARG_INFO()
  310. /* }}} */
  311. /* {{{ proto string ResourceBundle::getErrorMessage( )
  312. * proto string resourcebundle_get_error_message( ResourceBundle $bundle )
  313. * Get text description for ResourceBundle's last error.
  314. */
  315. PHP_FUNCTION( resourcebundle_get_error_message )
  316. {
  317. char* message = NULL;
  318. RESOURCEBUNDLE_METHOD_INIT_VARS;
  319. if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
  320. &object, ResourceBundle_ce_ptr ) == FAILURE )
  321. {
  322. intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
  323. "resourcebundle_get_error_message: unable to parse input params", 0 TSRMLS_CC );
  324. RETURN_FALSE;
  325. }
  326. rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
  327. message = (char *)intl_error_get_message(INTL_DATA_ERROR_P(rb) TSRMLS_CC);
  328. RETURN_STRING(message, 0);
  329. }
  330. /* }}} */
  331. /* {{{ ResourceBundle_class_functions
  332. * Every 'ResourceBundle' class method has an entry in this table
  333. */
  334. static zend_function_entry ResourceBundle_class_functions[] = {
  335. PHP_ME( ResourceBundle, __construct, arginfo_resourcebundle___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
  336. ZEND_NAMED_ME( create, ZEND_FN( resourcebundle_create ), arginfo_resourcebundle___construct, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
  337. ZEND_NAMED_ME( get, ZEND_FN(resourcebundle_get), arginfo_resourcebundle_get, ZEND_ACC_PUBLIC )
  338. ZEND_NAMED_ME( count, ZEND_FN(resourcebundle_count), arginfo_resourcebundle_count, ZEND_ACC_PUBLIC )
  339. ZEND_NAMED_ME( getLocales, ZEND_FN(resourcebundle_locales), arginfo_resourcebundle_getlocales, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC )
  340. ZEND_NAMED_ME( getErrorCode, ZEND_FN(resourcebundle_get_error_code), arginfo_resourcebundle_get_error_code, ZEND_ACC_PUBLIC )
  341. ZEND_NAMED_ME( getErrorMessage, ZEND_FN(resourcebundle_get_error_message), arginfo_resourcebundle_get_error_message, ZEND_ACC_PUBLIC )
  342. PHP_FE_END
  343. };
  344. /* }}} */
  345. /* {{{ resourcebundle_register_class
  346. * Initialize 'ResourceBundle' class
  347. */
  348. void resourcebundle_register_class( TSRMLS_D )
  349. {
  350. zend_class_entry ce;
  351. INIT_CLASS_ENTRY( ce, "ResourceBundle", ResourceBundle_class_functions );
  352. ce.create_object = ResourceBundle_object_create;
  353. ce.get_iterator = resourcebundle_get_iterator;
  354. ResourceBundle_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
  355. if( !ResourceBundle_ce_ptr )
  356. {
  357. zend_error(E_ERROR, "Failed to register ResourceBundle class");
  358. return;
  359. }
  360. ResourceBundle_object_handlers = std_object_handlers;
  361. ResourceBundle_object_handlers.clone_obj = NULL; /* ICU ResourceBundle has no clone implementation */
  362. ResourceBundle_object_handlers.read_dimension = resourcebundle_array_get;
  363. ResourceBundle_object_handlers.count_elements = resourcebundle_array_count;
  364. zend_class_implements(ResourceBundle_ce_ptr TSRMLS_CC, 1, zend_ce_traversable);
  365. }
  366. /* }}} */
  367. /*
  368. * Local variables:
  369. * tab-width: 4
  370. * c-basic-offset: 4
  371. * End:
  372. * vim600: noet sw=4 ts=4 fdm=marker
  373. * vim<600: noet sw=4 ts=4
  374. */