php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #61871
Patch intl-named-arguments-2.diff revision 2012-05-03 18:06 UTC by web-php-bugs at sklar dot com
Patch intl-named-arguments revision 2012-04-27 19:03 UTC by web-php-bugs at sklar dot com

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);
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 30 03:01:31 2024 UTC