Patch intl-named-arguments for intl Bug #61871
Patch version 2012-04-27 19:03 UTC
Return to Bug #61871 |
Download this patch
Patch Revisions:
Developer: web-php-bugs@sklar.com
diff -uBbr intl-2.0.0.orig/msgformat/msgformat_format.c intl-2.0.0/msgformat/msgformat_format.c
--- intl-2.0.0.orig/msgformat/msgformat_format.c 2012-04-07 15:47:35.000000000 -0400
+++ intl-2.0.0/msgformat/msgformat_format.c 2012-04-27 14:51:49.000000000 -0400
@@ -37,6 +37,7 @@
zval **fargs;
int count;
UChar* formatted = NULL;
+ char **farg_names = NULL;
int formatted_len = 0;
HashPosition pos;
int i;
@@ -40,9 +41,10 @@
int formatted_len = 0;
HashPosition pos;
int i;
-
count = zend_hash_num_elements(Z_ARRVAL_P(args));
+ /* umsg_format_arg_count() always returns 0 for named argument patterns,
+ * so this check is ignored and {name} pattern strings are returned unmodified */
if(count < umsg_format_arg_count(MSG_FORMAT_OBJECT(mfo))) {
/* Not enough aguments for format! */
intl_error_set( INTL_DATA_ERROR_P(mfo), U_ILLEGAL_ARGUMENT_ERROR,
@@ -51,19 +53,41 @@
return;
}
+ zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
+
fargs = safe_emalloc(count, sizeof(zval *), 0);
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
+ /* If the first key is a string, then treat everything as a named argument */
+ if (HASH_KEY_IS_STRING == zend_hash_get_current_key_type_ex(Z_ARRVAL_P(args), &pos)) {
+ farg_names = safe_emalloc(count, sizeof(char *), 0);
+ }
+
for(i=0;i<count;i++) {
zval **val;
zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **)&val, &pos);
fargs[i] = *val;
Z_ADDREF_P(fargs[i]);
/* TODO: needs refcount increase here? */
+ if (NULL != farg_names) {
+ char *key;
+ uint key_len;
+ ulong index;
+ int key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(args), &key, &key_len, &index, 0, &pos);
+ if (HASH_KEY_IS_STRING == key_type) {
+ farg_names[i] = estrndup(key, key_len);
+ }
+ else if (HASH_KEY_IS_LONG == key_type) {
+ farg_names[i] = emalloc(sizeof("18446744073709551616")); // 2^64
+ snprintf(farg_names[i], sizeof("18446744073709551616"), "%lu", (unsigned long) index);
+ }
+ else {
+ farg_names[i] = estrndup("", 0);
+ }
+ }
zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos);
}
- umsg_format_helper(MSG_FORMAT_OBJECT(mfo), count, fargs, &formatted, &formatted_len, &INTL_DATA_ERROR_CODE(mfo) TSRMLS_CC);
+ umsg_format_helper(MSG_FORMAT_OBJECT(mfo), count, fargs, farg_names, &formatted, &formatted_len, &INTL_DATA_ERROR_CODE(mfo) TSRMLS_CC);
for(i=0;i<count;i++) {
zval_ptr_dtor(&fargs[i]);
@@ -71,6 +95,13 @@
efree(fargs);
+ if (farg_names) {
+ for (i = 0; i < count; i++) {
+ efree(farg_names[i]);
+ }
+ efree(farg_names);
+ }
+
if (formatted && U_FAILURE( INTL_DATA_ERROR_CODE(mfo) ) ) {
efree(formatted);
}
diff -uBbr intl-2.0.0.orig/msgformat/msgformat_helpers.cpp intl-2.0.0/msgformat/msgformat_helpers.cpp
--- intl-2.0.0.orig/msgformat/msgformat_helpers.cpp 2012-04-07 15:47:35.000000000 -0400
+++ intl-2.0.0/msgformat/msgformat_helpers.cpp 2012-04-27 14:53:21.000000000 -0400
@@ -28,6 +28,7 @@
#include "msgformat_format.h"
#include "msgformat_helpers.h"
#include "intl_convert.h"
+#include "ext/date/php_date.h"
}
U_NAMESPACE_BEGIN
@@ -55,12 +56,118 @@
return fmt_count;
}
-U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC)
+U_CFUNC void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, char **arg_names, UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC)
{
- int fmt_count = 0;
+ int fmt_count;
+ Formattable* fargs;
+ UnicodeString *farg_names;
+
+ /** If the format uses named arguments, then:
+ * - populate fargs and farg_names without asking the MessageFormat how
+ * many args it has
+ * - use the type in the zval (and perhaps the object type) to determine
+ * how to format it
+ */
+ if (((const MessageFormat*)fmt)->usesNamedArguments()) {
+ fmt_count = arg_count;
+ fargs = new Formattable[fmt_count];
+ farg_names = new UnicodeString[fmt_count];
+ for (int32_t i = 0; i < fmt_count; ++i) {
+ UChar* text = NULL;
+ int textLen = 0;
+ intl_convert_utf8_to_utf16(&text, &textLen, arg_names[i], strlen(arg_names[i]), status);
+ if (U_FAILURE(*status)) {
+ delete[] fargs;
+ delete[] farg_names;
+ return;
+ }
+ farg_names[i].setTo(text, textLen);
+ efree(text);
+ text = NULL; textLen = 0;
+
+ /* Figure out what type to use for each
+ * argument based on its PHP type:
+ * float -> Formattable::kDouble
+ * long -> Formattable::kInt64
+ * string -> Formattable::kString
+ * bool -> Formattable::kInt64 0/1
+ * null -> Formattable::kString empty string
+ * object:
+ * - datetime -> Formattable::kDate
+ * - otherwise, an error
+ * array -> error
+ */
+ switch (Z_TYPE_P(args[i])) {
+ case IS_DOUBLE:
+ fargs[i].setDouble(Z_DVAL_P(args[i]));
+ break;
+ case IS_LONG:
+ case IS_BOOL:
+ fargs[i].setInt64((int64_t) Z_LVAL_P(args[i]));
+ break;
+ case IS_STRING:
+ intl_convert_utf8_to_utf16(&text, &textLen, Z_STRVAL_P(args[i]), Z_STRLEN_P(args[i]), status);
+ if (U_FAILURE(*status)) {
+ delete[] fargs;
+ delete[] farg_names;
+ return;
+ }
+ fargs[i].setString(text);
+ efree(text);
+ text = NULL; textLen = 0;
+ break;
+ case IS_NULL:
+ intl_convert_utf8_to_utf16(&text, &textLen, "", 0, status);
+ if (U_FAILURE(*status)) {
+ delete[] fargs;
+ delete[] farg_names;
+ return;
+ }
+ fargs[i].setString(text);
+ efree(text);
+ text = NULL; textLen = 0;
+ break;
+ case IS_OBJECT:
+ /* Borrowed from datefmt_format() in intl/dateformat/dateformat_format.c */
+ if (instanceof_function(Z_OBJCE_P(args[i]), php_date_get_date_ce() TSRMLS_CC)) {
+ zval retval;
+ zval *zfuncname;
+ INIT_ZVAL(retval);
+ MAKE_STD_ZVAL(zfuncname);
+ ZVAL_STRING(zfuncname, "getTimestamp", 1);
+ if (call_user_function(NULL, &(args[i]), zfuncname, &retval, 0, NULL TSRMLS_CC) != SUCCESS || Z_TYPE(retval) != IS_LONG) {
+ *status = U_RESOURCE_TYPE_MISMATCH;
+ delete[] fargs;
+ delete[] farg_names;
+ return;
+ }
+ zval_ptr_dtor(&zfuncname);
+ fargs[i].setDate(U_MILLIS_PER_SECOND * (double) Z_LVAL(retval));
+ }
+ else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ delete[] fargs;
+ delete[] farg_names;
+ return;
+ }
+ break;
+ case IS_ARRAY:
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ delete[] fargs;
+ delete[] farg_names;
+ return;
+ }
+ }
+ }
+ /* Otherwise, ask the MessageFormat how many args there are and format
+ * based on those arg types */
+ else {
const Formattable::Type* argTypes =
MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, fmt_count);
- Formattable* fargs = new Formattable[fmt_count ? fmt_count : 1];
+
+ fargs = new Formattable[fmt_count ? fmt_count : 1];
+
for(int32_t i = 0; i < fmt_count; ++i) {
UChar *stringVal = NULL;
@@ -114,13 +221,18 @@
return;
}
}
+ }
UnicodeString resultStr;
FieldPosition fieldPosition(0);
/* format the message */
+ if (((const MessageFormat*)fmt)->usesNamedArguments()) {
+ ((const MessageFormat*)fmt)->format(farg_names, fargs, fmt_count, resultStr, *status);
+ delete[] farg_names;
+ } else {
((const MessageFormat*)fmt)->format(fargs, fmt_count, resultStr, fieldPosition, *status);
-
+ }
delete[] fargs;
if(U_FAILURE(*status)){
diff -uBbr intl-2.0.0.orig/msgformat/msgformat_helpers.h intl-2.0.0/msgformat/msgformat_helpers.h
--- intl-2.0.0.orig/msgformat/msgformat_helpers.h 2012-04-07 15:47:35.000000000 -0400
+++ intl-2.0.0/msgformat/msgformat_helpers.h 2012-04-26 11:30:01.000000000 -0400
@@ -18,7 +18,7 @@
#define MSG_FORMAT_HELPERS_H
int32_t umsg_format_arg_count(UMessageFormat *fmt);
-void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args,
+void umsg_format_helper(UMessageFormat *fmt, int arg_count, zval **args, char **arg_names,
UChar **formatted, int *formatted_len, UErrorCode *status TSRMLS_DC);
void umsg_parse_helper(UMessageFormat *fmt, int *count, zval ***args,
UChar *source, int source_len, UErrorCode *status);
|