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.

211 lines
6.2 KiB

  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: Stanislav Malyshev <stas@zend.com> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include <math.h>
  20. #include <unicode/msgfmt.h>
  21. extern "C" {
  22. #include "php_intl.h"
  23. #include "msgformat_class.h"
  24. #include "msgformat_format.h"
  25. #include "msgformat_helpers.h"
  26. #include "intl_convert.h"
  27. }
  28. U_NAMESPACE_BEGIN
  29. /**
  30. * This class isolates our access to private internal methods of
  31. * MessageFormat. It is never instantiated; it exists only for C++
  32. * access management.
  33. */
  34. class MessageFormatAdapter {
  35. public:
  36. static const Formattable::Type* getArgTypeList(const MessageFormat& m,
  37. int32_t& count);
  38. };
  39. const Formattable::Type*
  40. MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
  41. int32_t& count) {
  42. return m.getArgTypeList(count);
  43. }
  44. U_NAMESPACE_END
  45. U_CFUNC int32_t umsg_format_arg_count(UMessageFormat *fmt)
  46. {
  47. int32_t fmt_count = 0;
  48. MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
  49. return fmt_count;
  50. }
  51. U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC)
  52. {
  53. int fmt_count = 0;
  54. const Formattable::Type* argTypes =
  55. MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
  56. Formattable* fargs = new Formattable[fmt_count ? fmt_count : 1];
  57. for(int32_t i = 0; i < fmt_count; ++i) {
  58. UChar *stringVal = NULL;
  59. int stringLen = 0;
  60. int64_t tInt64 = 0;
  61. switch(argTypes[i]) {
  62. case Formattable::kDate:
  63. convert_to_long_ex(&args[i]);
  64. fargs[i].setDate(U_MILLIS_PER_SECOND * (double)Z_LVAL_P(args[i]));
  65. break;
  66. case Formattable::kDouble:
  67. convert_to_double_ex(&args[i]);
  68. fargs[i].setDouble(Z_DVAL_P(args[i]));
  69. break;
  70. case Formattable::kLong:
  71. convert_to_long_ex(&args[i]);
  72. fargs[i].setLong(Z_LVAL_P(args[i]));
  73. break;
  74. case Formattable::kInt64:
  75. if(Z_TYPE_P(args[i]) == IS_DOUBLE) {
  76. tInt64 = (int64_t)Z_DVAL_P(args[i]);
  77. } else if(Z_TYPE_P(args[i]) == IS_LONG) {
  78. tInt64 = (int64_t)Z_LVAL_P(args[i]);
  79. } else {
  80. SEPARATE_ZVAL_IF_NOT_REF(&args[i]);
  81. convert_scalar_to_number( args[i] TSRMLS_CC );
  82. tInt64 = (Z_TYPE_P(args[i]) == IS_DOUBLE)?(int64_t)Z_DVAL_P(args[i]):Z_LVAL_P(args[i]);
  83. }
  84. fargs[i].setInt64(tInt64);
  85. break;
  86. case Formattable::kString:
  87. convert_to_string_ex(&args[i]);
  88. intl_convert_utf8_to_utf16(&stringVal, &stringLen, Z_STRVAL_P(args[i]), Z_STRLEN_P(args[i]), status);
  89. if(U_FAILURE(*status)){
  90. delete[] fargs;
  91. return;
  92. }
  93. fargs[i].setString(stringVal);
  94. efree(stringVal);
  95. break;
  96. case Formattable::kArray:
  97. case Formattable::kObject:
  98. *status = U_UNSUPPORTED_ERROR;
  99. delete[] fargs;
  100. return;
  101. }
  102. }
  103. UnicodeString resultStr;
  104. FieldPosition fieldPosition(0);
  105. /* format the message */
  106. ((const MessageFormat*)fmt)->format(fargs, fmt_count, resultStr, fieldPosition, *status);
  107. delete[] fargs;
  108. if(U_FAILURE(*status)){
  109. return;
  110. }
  111. *formatted_len = resultStr.length();
  112. *formatted = eumalloc(*formatted_len+1);
  113. resultStr.extract(*formatted, *formatted_len+1, *status);
  114. }
  115. #define cleanup_zvals() for(int j=i;j>=0;j--) { zval_ptr_dtor((*args)+i); }
  116. U_CFUNC void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args, UChar *source, int source_len, UErrorCode *status)
  117. {
  118. UnicodeString srcString(source, source_len);
  119. Formattable *fargs = ((const MessageFormat*)fmt)->parse(srcString, *count, *status);
  120. if(U_FAILURE(*status)) {
  121. return;
  122. }
  123. *args = (zval **)safe_emalloc(*count, sizeof(zval *), 0);
  124. // assign formattables to varargs
  125. for(int32_t i = 0; i < *count; i++) {
  126. int64_t aInt64;
  127. double aDate;
  128. UnicodeString temp;
  129. char *stmp;
  130. int stmp_len;
  131. ALLOC_INIT_ZVAL((*args)[i]);
  132. switch(fargs[i].getType()) {
  133. case Formattable::kDate:
  134. aDate = ((double)fargs[i].getDate())/U_MILLIS_PER_SECOND;
  135. if(aDate > LONG_MAX || aDate < -LONG_MAX) {
  136. ZVAL_DOUBLE((*args)[i], aDate<0?ceil(aDate):floor(aDate));
  137. } else {
  138. ZVAL_LONG((*args)[i], (long)aDate);
  139. }
  140. break;
  141. case Formattable::kDouble:
  142. ZVAL_DOUBLE((*args)[i], (double)fargs[i].getDouble());
  143. break;
  144. case Formattable::kLong:
  145. ZVAL_LONG((*args)[i], fargs[i].getLong());
  146. break;
  147. case Formattable::kInt64:
  148. aInt64 = fargs[i].getInt64();
  149. if(aInt64 > LONG_MAX || aInt64 < -LONG_MAX) {
  150. ZVAL_DOUBLE((*args)[i], (double)aInt64);
  151. } else {
  152. ZVAL_LONG((*args)[i], (long)aInt64);
  153. }
  154. break;
  155. case Formattable::kString:
  156. fargs[i].getString(temp);
  157. intl_convert_utf16_to_utf8(&stmp, &stmp_len, temp.getBuffer(), temp.length(), status);
  158. if(U_FAILURE(*status)) {
  159. cleanup_zvals();
  160. return;
  161. }
  162. ZVAL_STRINGL((*args)[i], stmp, stmp_len, 0);
  163. break;
  164. case Formattable::kObject:
  165. case Formattable::kArray:
  166. *status = U_ILLEGAL_ARGUMENT_ERROR;
  167. cleanup_zvals();
  168. break;
  169. }
  170. }
  171. delete[] fargs;
  172. }
  173. /*
  174. * Local variables:
  175. * tab-width: 4
  176. * c-basic-offset: 4
  177. * End:
  178. * vim600: noet sw=4 ts=4 fdm=marker
  179. * vim<600: noet sw=4 ts=4
  180. */