You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

463 lines
14 KiB

11 years ago
12 years ago
16 years ago
16 years ago
12 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  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 "intl_common.h"
  26. #include "resourcebundle/resourcebundle.h"
  27. #include "resourcebundle/resourcebundle_iterator.h"
  28. #include "resourcebundle/resourcebundle_class.h"
  29. zend_class_entry *ResourceBundle_ce_ptr = NULL;
  30. static zend_object_handlers ResourceBundle_object_handlers;
  31. /* {{{ ResourceBundle_object_dtor */
  32. static void ResourceBundle_object_destroy( zend_object *object )
  33. {
  34. ResourceBundle_object *rb = php_intl_resourcebundle_fetch_object(object);
  35. // only free local errors
  36. intl_error_reset( INTL_DATA_ERROR_P(rb) );
  37. if (rb->me) {
  38. ures_close( rb->me );
  39. }
  40. if (rb->child) {
  41. ures_close( rb->child );
  42. }
  43. //???zend_object_std_dtor( object );
  44. }
  45. /* }}} */
  46. /* {{{ ResourceBundle_object_create */
  47. static zend_object *ResourceBundle_object_create( zend_class_entry *ce )
  48. {
  49. ResourceBundle_object *rb;
  50. rb = ecalloc( 1, sizeof(ResourceBundle_object) + zend_object_properties_size(ce));
  51. zend_object_std_init( &rb->zend, ce );
  52. object_properties_init( &rb->zend, ce);
  53. intl_error_init( INTL_DATA_ERROR_P(rb) );
  54. rb->me = NULL;
  55. rb->child = NULL;
  56. rb->zend.handlers = &ResourceBundle_object_handlers;
  57. return &rb->zend;
  58. }
  59. /* }}} */
  60. /* {{{ ResourceBundle_ctor */
  61. static void resourcebundle_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_constructor)
  62. {
  63. const char *bundlename;
  64. size_t bundlename_len = 0;
  65. const char *locale;
  66. size_t locale_len = 0;
  67. zend_bool fallback = 1;
  68. int zpp_flags = is_constructor ? ZEND_PARSE_PARAMS_THROW : 0;
  69. zval *object = return_value;
  70. ResourceBundle_object *rb = Z_INTL_RESOURCEBUNDLE_P( object );
  71. intl_error_reset( NULL );
  72. if( zend_parse_parameters_ex( zpp_flags, ZEND_NUM_ARGS(), "s!s!|b",
  73. &locale, &locale_len, &bundlename, &bundlename_len, &fallback ) == FAILURE )
  74. {
  75. intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
  76. "resourcebundle_ctor: unable to parse input parameters", 0 );
  77. Z_OBJ_P(return_value) = NULL;
  78. return;
  79. }
  80. INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
  81. if (locale == NULL) {
  82. locale = intl_locale_get_default();
  83. }
  84. if (fallback) {
  85. rb->me = ures_open(bundlename, locale, &INTL_DATA_ERROR_CODE(rb));
  86. } else {
  87. rb->me = ures_openDirect(bundlename, locale, &INTL_DATA_ERROR_CODE(rb));
  88. }
  89. INTL_CTOR_CHECK_STATUS(rb, "resourcebundle_ctor: Cannot load libICU resource bundle");
  90. if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING ||
  91. INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
  92. char *pbuf;
  93. intl_errors_set_code(NULL, INTL_DATA_ERROR_CODE(rb));
  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);
  100. efree(pbuf);
  101. Z_OBJ_P(return_value) = NULL;
  102. }
  103. }
  104. /* }}} */
  105. /* {{{ arginfo_resourcebundle__construct */
  106. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle___construct, 0, 0, 2 )
  107. ZEND_ARG_INFO( 0, locale )
  108. ZEND_ARG_INFO( 0, bundlename )
  109. ZEND_ARG_INFO( 0, fallback )
  110. ZEND_END_ARG_INFO()
  111. /* }}} */
  112. /* {{{ proto void ResourceBundle::__construct( string $locale [, string $bundlename [, bool $fallback = true ]] )
  113. * ResourceBundle object constructor
  114. */
  115. PHP_METHOD( ResourceBundle, __construct )
  116. {
  117. zend_error_handling error_handling;
  118. zend_replace_error_handling(EH_THROW, IntlException_ce_ptr, &error_handling);
  119. return_value = getThis();
  120. resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  121. if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
  122. if (!EG(exception)) {
  123. zend_throw_exception(IntlException_ce_ptr, "Constructor failed", 0);
  124. }
  125. }
  126. zend_restore_error_handling(&error_handling);
  127. }
  128. /* }}} */
  129. /* {{{ proto ResourceBundle ResourceBundle::create( string $locale [, string $bundlename [, bool $fallback = true ]] )
  130. proto ResourceBundle resourcebundle_create( string $locale [, string $bundlename [, bool $fallback = true ]] )
  131. */
  132. PHP_FUNCTION( resourcebundle_create )
  133. {
  134. object_init_ex( return_value, ResourceBundle_ce_ptr );
  135. resourcebundle_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  136. if (Z_TYPE_P(return_value) == IS_OBJECT && Z_OBJ_P(return_value) == NULL) {
  137. RETURN_NULL();
  138. }
  139. }
  140. /* }}} */
  141. /* {{{ resourcebundle_array_fetch */
  142. static void resourcebundle_array_fetch(zval *object, zval *offset, zval *return_value, int fallback)
  143. {
  144. int32_t meindex = 0;
  145. char * mekey = NULL;
  146. zend_bool is_numeric = 0;
  147. char *pbuf;
  148. ResourceBundle_object *rb;
  149. intl_error_reset( NULL );
  150. RESOURCEBUNDLE_METHOD_FETCH_OBJECT;
  151. if(Z_TYPE_P(offset) == IS_LONG) {
  152. is_numeric = 1;
  153. meindex = (int32_t)Z_LVAL_P(offset);
  154. rb->child = ures_getByIndex( rb->me, meindex, rb->child, &INTL_DATA_ERROR_CODE(rb) );
  155. } else if(Z_TYPE_P(offset) == IS_STRING) {
  156. mekey = Z_STRVAL_P(offset);
  157. rb->child = ures_getByKey(rb->me, mekey, rb->child, &INTL_DATA_ERROR_CODE(rb) );
  158. } else {
  159. intl_errors_set(INTL_DATA_ERROR_P(rb), U_ILLEGAL_ARGUMENT_ERROR,
  160. "resourcebundle_get: index should be integer or string", 0);
  161. RETURN_NULL();
  162. }
  163. intl_error_set_code( NULL, INTL_DATA_ERROR_CODE(rb) );
  164. if (U_FAILURE(INTL_DATA_ERROR_CODE(rb))) {
  165. if (is_numeric) {
  166. spprintf( &pbuf, 0, "Cannot load resource element %d", meindex );
  167. } else {
  168. spprintf( &pbuf, 0, "Cannot load resource element '%s'", mekey );
  169. }
  170. intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 );
  171. efree(pbuf);
  172. RETURN_NULL();
  173. }
  174. if (!fallback && (INTL_DATA_ERROR_CODE(rb) == U_USING_FALLBACK_WARNING || INTL_DATA_ERROR_CODE(rb) == U_USING_DEFAULT_WARNING)) {
  175. UErrorCode icuerror;
  176. const char * locale = ures_getLocaleByType( rb->me, ULOC_ACTUAL_LOCALE, &icuerror );
  177. if (is_numeric) {
  178. spprintf( &pbuf, 0, "Cannot load element %d without fallback from to %s", meindex, locale );
  179. } else {
  180. spprintf( &pbuf, 0, "Cannot load element '%s' without fallback from to %s", mekey, locale );
  181. }
  182. intl_errors_set_custom_msg( INTL_DATA_ERROR_P(rb), pbuf, 1 );
  183. efree(pbuf);
  184. RETURN_NULL();
  185. }
  186. resourcebundle_extract_value( return_value, rb );
  187. }
  188. /* }}} */
  189. /* {{{ resourcebundle_array_get */
  190. zval *resourcebundle_array_get(zval *object, zval *offset, int type, zval *rv)
  191. {
  192. if(offset == NULL) {
  193. php_error( E_ERROR, "Cannot apply [] to ResourceBundle object" );
  194. }
  195. ZVAL_NULL(rv);
  196. resourcebundle_array_fetch(object, offset, rv, 1);
  197. return rv;
  198. }
  199. /* }}} */
  200. /* {{{ arginfo_resourcebundle_get */
  201. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get, 0, 0, 1 )
  202. ZEND_ARG_INFO( 0, index )
  203. ZEND_ARG_INFO( 0, fallback )
  204. ZEND_END_ARG_INFO()
  205. /* }}} */
  206. /* {{{ proto mixed ResourceBundle::get( integer|string $resindex [, bool $fallback = true ] )
  207. * proto mixed resourcebundle_get( ResourceBundle $rb, integer|string $resindex [, bool $fallback = true ] )
  208. * Get resource identified by numerical index or key name.
  209. */
  210. PHP_FUNCTION( resourcebundle_get )
  211. {
  212. zend_bool fallback = 1;
  213. zval * offset;
  214. zval * object;
  215. if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oz|b", &object, ResourceBundle_ce_ptr, &offset, &fallback ) == FAILURE) {
  216. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  217. "resourcebundle_get: unable to parse input params", 0);
  218. RETURN_FALSE;
  219. }
  220. resourcebundle_array_fetch(object, offset, return_value, fallback);
  221. }
  222. /* }}} */
  223. /* {{{ resourcebundle_array_count */
  224. int resourcebundle_array_count(zval *object, zend_long *count)
  225. {
  226. ResourceBundle_object *rb;
  227. RESOURCEBUNDLE_METHOD_FETCH_OBJECT_NO_CHECK;
  228. if (rb->me == NULL) {
  229. intl_errors_set(&rb->error, U_ILLEGAL_ARGUMENT_ERROR,
  230. "Found unconstructed ResourceBundle", 0);
  231. return 0;
  232. }
  233. *count = ures_getSize( rb->me );
  234. return SUCCESS;
  235. }
  236. /* }}} */
  237. /* {{{ arginfo_resourcebundle_count */
  238. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_count, 0, 0, 0 )
  239. ZEND_END_ARG_INFO()
  240. /* }}} */
  241. /* {{{ proto int ResourceBundle::count()
  242. * proto int resourcebundle_count( ResourceBundle $bundle )
  243. * Get resources count
  244. */
  245. PHP_FUNCTION( resourcebundle_count )
  246. {
  247. int32_t len;
  248. RESOURCEBUNDLE_METHOD_INIT_VARS;
  249. if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O", &object, ResourceBundle_ce_ptr ) == FAILURE ) {
  250. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  251. "resourcebundle_count: unable to parse input params", 0);
  252. RETURN_FALSE;
  253. }
  254. RESOURCEBUNDLE_METHOD_FETCH_OBJECT;
  255. len = ures_getSize( rb->me );
  256. RETURN_LONG( len );
  257. }
  258. /* {{{ arginfo_resourcebundle_getlocales */
  259. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_getlocales, 0, 0, 1 )
  260. ZEND_ARG_INFO( 0, bundlename )
  261. ZEND_END_ARG_INFO()
  262. /* }}} */
  263. /* {{{ proto array ResourceBundle::getLocales( string $bundlename )
  264. * proto array resourcebundle_locales( string $bundlename )
  265. * Get available locales from ResourceBundle name
  266. */
  267. PHP_FUNCTION( resourcebundle_locales )
  268. {
  269. char * bundlename;
  270. size_t bundlename_len = 0;
  271. const char * entry;
  272. int entry_len;
  273. UEnumeration *icuenum;
  274. UErrorCode icuerror = U_ZERO_ERROR;
  275. intl_errors_reset( NULL );
  276. if( zend_parse_parameters(ZEND_NUM_ARGS(), "s", &bundlename, &bundlename_len ) == FAILURE )
  277. {
  278. intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
  279. "resourcebundle_locales: unable to parse input params", 0);
  280. RETURN_FALSE;
  281. }
  282. if(bundlename_len == 0) {
  283. // fetch default locales list
  284. bundlename = NULL;
  285. }
  286. icuenum = ures_openAvailableLocales( bundlename, &icuerror );
  287. INTL_CHECK_STATUS(icuerror, "Cannot fetch locales list");
  288. uenum_reset( icuenum, &icuerror );
  289. INTL_CHECK_STATUS(icuerror, "Cannot iterate locales list");
  290. array_init( return_value );
  291. while ((entry = uenum_next( icuenum, &entry_len, &icuerror ))) {
  292. add_next_index_stringl( return_value, (char *) entry, entry_len);
  293. }
  294. uenum_close( icuenum );
  295. }
  296. /* }}} */
  297. /* {{{ arginfo_resourcebundle_get_error_code */
  298. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_code, 0, 0, 0 )
  299. ZEND_END_ARG_INFO()
  300. /* }}} */
  301. /* {{{ proto string ResourceBundle::getErrorCode( )
  302. * proto string resourcebundle_get_error_code( ResourceBundle $bundle )
  303. * Get text description for ResourceBundle's last error code.
  304. */
  305. PHP_FUNCTION( resourcebundle_get_error_code )
  306. {
  307. RESOURCEBUNDLE_METHOD_INIT_VARS;
  308. if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O",
  309. &object, ResourceBundle_ce_ptr ) == FAILURE )
  310. {
  311. intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
  312. "resourcebundle_get_error_code: unable to parse input params", 0 );
  313. RETURN_FALSE;
  314. }
  315. rb = Z_INTL_RESOURCEBUNDLE_P( object );
  316. RETURN_LONG(INTL_DATA_ERROR_CODE(rb));
  317. }
  318. /* }}} */
  319. /* {{{ arginfo_resourcebundle_get_error_message */
  320. ZEND_BEGIN_ARG_INFO_EX( arginfo_resourcebundle_get_error_message, 0, 0, 0 )
  321. ZEND_END_ARG_INFO()
  322. /* }}} */
  323. /* {{{ proto string ResourceBundle::getErrorMessage( )
  324. * proto string resourcebundle_get_error_message( ResourceBundle $bundle )
  325. * Get text description for ResourceBundle's last error.
  326. */
  327. PHP_FUNCTION( resourcebundle_get_error_message )
  328. {
  329. zend_string* message = NULL;
  330. RESOURCEBUNDLE_METHOD_INIT_VARS;
  331. if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O",
  332. &object, ResourceBundle_ce_ptr ) == FAILURE )
  333. {
  334. intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
  335. "resourcebundle_get_error_message: unable to parse input params", 0 );
  336. RETURN_FALSE;
  337. }
  338. rb = Z_INTL_RESOURCEBUNDLE_P( object );
  339. message = intl_error_get_message(INTL_DATA_ERROR_P(rb));
  340. RETURN_STR(message);
  341. }
  342. /* }}} */
  343. /* {{{ ResourceBundle_class_functions
  344. * Every 'ResourceBundle' class method has an entry in this table
  345. */
  346. static zend_function_entry ResourceBundle_class_functions[] = {
  347. PHP_ME( ResourceBundle, __construct, arginfo_resourcebundle___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR )
  348. ZEND_NAMED_ME( create, ZEND_FN( resourcebundle_create ), arginfo_resourcebundle___construct, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC )
  349. ZEND_NAMED_ME( get, ZEND_FN(resourcebundle_get), arginfo_resourcebundle_get, ZEND_ACC_PUBLIC )
  350. ZEND_NAMED_ME( count, ZEND_FN(resourcebundle_count), arginfo_resourcebundle_count, ZEND_ACC_PUBLIC )
  351. ZEND_NAMED_ME( getLocales, ZEND_FN(resourcebundle_locales), arginfo_resourcebundle_getlocales, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC )
  352. ZEND_NAMED_ME( getErrorCode, ZEND_FN(resourcebundle_get_error_code), arginfo_resourcebundle_get_error_code, ZEND_ACC_PUBLIC )
  353. ZEND_NAMED_ME( getErrorMessage, ZEND_FN(resourcebundle_get_error_message), arginfo_resourcebundle_get_error_message, ZEND_ACC_PUBLIC )
  354. PHP_FE_END
  355. };
  356. /* }}} */
  357. /* {{{ resourcebundle_register_class
  358. * Initialize 'ResourceBundle' class
  359. */
  360. void resourcebundle_register_class( void )
  361. {
  362. zend_class_entry ce;
  363. INIT_CLASS_ENTRY( ce, "ResourceBundle", ResourceBundle_class_functions );
  364. ce.create_object = ResourceBundle_object_create;
  365. ce.get_iterator = resourcebundle_get_iterator;
  366. ResourceBundle_ce_ptr = zend_register_internal_class( &ce );
  367. if( !ResourceBundle_ce_ptr )
  368. {
  369. zend_error(E_ERROR, "Failed to register ResourceBundle class");
  370. return;
  371. }
  372. ResourceBundle_object_handlers = std_object_handlers;
  373. ResourceBundle_object_handlers.offset = XtOffsetOf(ResourceBundle_object, zend);
  374. ResourceBundle_object_handlers.clone_obj = NULL; /* ICU ResourceBundle has no clone implementation */
  375. ResourceBundle_object_handlers.dtor_obj = ResourceBundle_object_destroy;
  376. ResourceBundle_object_handlers.read_dimension = resourcebundle_array_get;
  377. ResourceBundle_object_handlers.count_elements = resourcebundle_array_count;
  378. zend_class_implements(ResourceBundle_ce_ptr, 1, zend_ce_traversable);
  379. }
  380. /* }}} */
  381. /*
  382. * Local variables:
  383. * tab-width: 4
  384. * c-basic-offset: 4
  385. * End:
  386. * vim600: noet sw=4 ts=4 fdm=marker
  387. * vim<600: noet sw=4 ts=4
  388. */