Skip to content

Commit 507078f

Browse files
committed
ext/intl: Migrate formatter, listformatter, and rangeformatter from ICU C API to C++ API.
- formatter: Replace intl_convert_utf8_to_utf16/uloc_getISO3Language with intl_stringFromChar/icu::Locale, use UnicodeString for pattern handling - listformatter: Replace ulistfmt_open/ulistfmt_openForType/ulistfmt_close/ ulistfmt_format with ListFormatter C++ equivalents, use UnicodeString array and intl_stringFromChar/intl_charFromString for string conversions - rangeformatter: Replace uloc_getISO3Language with icu::Locale::getISO3Language
1 parent 58acc67 commit 507078f

4 files changed

Lines changed: 52 additions & 81 deletions

File tree

ext/intl/formatter/formatter_main.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616
#include <config.h>
1717
#endif
1818

19-
#include <unicode/ustring.h>
20-
#include <unicode/uloc.h>
19+
#include <unicode/locid.h>
20+
#include "../intl_convertcpp.h"
2121

2222
extern "C" {
2323
#include "php_intl.h"
24-
#include "intl_convert.h"
2524
}
2625
#include "formatter_class.h"
2726

@@ -32,8 +31,7 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
3231
char* pattern = NULL;
3332
size_t locale_len = 0, pattern_len = 0;
3433
zend_long style;
35-
UChar* spattern = NULL;
36-
int32_t spattern_len = 0;
34+
UnicodeString upattern;
3735
FORMATTER_METHOD_INIT_VARS;
3836

3937
ZEND_PARSE_PARAMETERS_START(2, 3)
@@ -53,15 +51,15 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
5351

5452
/* Convert pattern (if specified) to UTF-16. */
5553
if(pattern && pattern_len) {
56-
intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo));
54+
intl_stringFromChar(upattern, pattern, pattern_len, &INTL_DATA_ERROR_CODE(nfo));
5755
INTL_CTOR_CHECK_STATUS(nfo, "error converting pattern to UTF-16");
5856
}
5957

6058
if(locale_len == 0) {
6159
locale = (char *)intl_locale_get_default();
6260
}
6361

64-
if (strlen(uloc_getISO3Language(locale)) == 0) {
62+
if (icu::Locale(locale).getISO3Language()[0] == '\0') {
6563
zend_argument_value_error(1, "\"%s\" is invalid", locale);
6664
return FAILURE;
6765
}
@@ -70,12 +68,10 @@ static int numfmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
7068
const char* final_locale = canonicalized_locale ? canonicalized_locale : locale;
7169

7270
/* Create an ICU number formatter. */
73-
FORMATTER_OBJECT(nfo) = unum_open(static_cast<UNumberFormatStyle>(style), spattern, spattern_len, final_locale, nullptr, &INTL_DATA_ERROR_CODE(nfo));
71+
FORMATTER_OBJECT(nfo) = unum_open(static_cast<UNumberFormatStyle>(style),
72+
upattern.isEmpty() ? nullptr : upattern.getBuffer(), upattern.length(),
73+
final_locale, nullptr, &INTL_DATA_ERROR_CODE(nfo));
7474

75-
if (spattern) {
76-
efree(spattern);
77-
}
78-
7975
if (canonicalized_locale) {
8076
efree(canonicalized_locale);
8177
}

ext/intl/listformatter/listformatter_class.cpp

Lines changed: 34 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@
1414

1515
extern "C" {
1616
#include "php.h"
17+
}
18+
19+
#include <unicode/listformatter.h>
20+
#include <unicode/locid.h>
21+
#include "../intl_convertcpp.h"
22+
23+
extern "C" {
1724
#include "php_intl.h"
18-
#include "intl_convert.h"
1925
}
20-
#include <unicode/ulistformatter.h>
2126
#include "listformatter_class.h"
2227
#include "listformatter_arginfo.h"
2328

@@ -27,9 +32,7 @@ static void listformatter_free_obj(zend_object *object)
2732
{
2833
ListFormatter_object *obj = php_intl_listformatter_fetch_object(object);
2934

30-
if( obj->lf_data.ulistfmt )
31-
ulistfmt_close( obj->lf_data.ulistfmt );
32-
35+
delete obj->lf_data.ulistfmt;
3336
obj->lf_data.ulistfmt = nullptr;
3437
intl_error_reset( &obj->lf_data.error );
3538

@@ -78,7 +81,7 @@ PHP_METHOD(IntlListFormatter, __construct)
7881
RETURN_THROWS();
7982
}
8083

81-
if (strlen(uloc_getISO3Language(locale)) == 0) {
84+
if (icu::Locale(locale).getISO3Language()[0] == '\0') {
8285
zend_argument_value_error(1, "\"%s\" is invalid", locale);
8386
RETURN_THROWS();
8487
}
@@ -89,13 +92,13 @@ PHP_METHOD(IntlListFormatter, __construct)
8992
zend_argument_value_error(2, "must be one of IntlListFormatter::TYPE_AND, IntlListFormatter::TYPE_OR, or IntlListFormatter::TYPE_UNITS");
9093
RETURN_THROWS();
9194
}
92-
95+
9396
if (width != ULISTFMT_WIDTH_WIDE && width != ULISTFMT_WIDTH_SHORT && width != ULISTFMT_WIDTH_NARROW) {
9497
zend_argument_value_error(3, "must be one of IntlListFormatter::WIDTH_WIDE, IntlListFormatter::WIDTH_SHORT, or IntlListFormatter::WIDTH_NARROW");
9598
RETURN_THROWS();
9699
}
97100

98-
LISTFORMATTER_OBJECT(obj) = ulistfmt_openForType(locale, static_cast<UListFormatterType>(type), static_cast<UListFormatterWidth>(width), &status);
101+
LISTFORMATTER_OBJECT(obj) = ListFormatter::createInstance(icu::Locale(locale), static_cast<UListFormatterType>(type), static_cast<UListFormatterWidth>(width), status);
99102
#else
100103
if (type != INTL_LISTFORMATTER_FALLBACK_TYPE_AND) {
101104
zend_argument_value_error(2, "contains an unsupported type. ICU 66 and below only support IntlListFormatter::TYPE_AND");
@@ -107,7 +110,7 @@ PHP_METHOD(IntlListFormatter, __construct)
107110
RETURN_THROWS();
108111
}
109112

110-
LISTFORMATTER_OBJECT(obj) = ulistfmt_open(locale, &status);
113+
LISTFORMATTER_OBJECT(obj) = ListFormatter::createInstance(icu::Locale(locale), status);
111114
#endif
112115

113116
if (U_FAILURE(status)) {
@@ -131,84 +134,50 @@ PHP_METHOD(IntlListFormatter, format)
131134
RETURN_EMPTY_STRING();
132135
}
133136

134-
const UChar **items = (const UChar **)safe_emalloc(count, sizeof(const UChar *), 0);
135-
int32_t *itemLengths = (int32_t *)safe_emalloc(count, sizeof(int32_t), 0);
137+
UnicodeString *items = new UnicodeString[count];
136138
uint32_t i = 0;
137139
zval *val;
138140

139141
ZEND_HASH_FOREACH_VAL(ht, val) {
140142
zend_string *str_val, *tmp_str;
141-
142-
str_val = zval_get_tmp_string(val, &tmp_str);
143-
144-
// Convert PHP string to UTF-16
145-
UChar *ustr = nullptr;
146-
int32_t ustr_len = 0;
147-
UErrorCode status = U_ZERO_ERROR;
148-
149-
intl_convert_utf8_to_utf16(&ustr, &ustr_len, ZSTR_VAL(str_val), ZSTR_LEN(str_val), &status);
143+
UErrorCode conv_status = U_ZERO_ERROR;
144+
145+
str_val = zval_try_get_tmp_string(val, &tmp_str);
146+
if (UNEXPECTED(!str_val)) {
147+
delete[] items;
148+
RETURN_THROWS();
149+
}
150+
intl_stringFromChar(items[i], ZSTR_VAL(str_val), ZSTR_LEN(str_val), &conv_status);
150151
zend_tmp_string_release(tmp_str);
151152

152-
if (U_FAILURE(status)) {
153-
// We can't use goto cleanup because items and itemLengths are incompletely allocated
154-
for (uint32_t j = 0; j < i; j++) {
155-
efree((void *)items[j]);
156-
}
157-
efree(items);
158-
efree(itemLengths);
159-
intl_error_set(nullptr, status, "Failed to convert string to UTF-16");
153+
if (U_FAILURE(conv_status)) {
154+
delete[] items;
155+
intl_error_set(nullptr, conv_status, "Failed to convert string to UTF-16");
160156
RETURN_FALSE;
161157
}
162-
163-
items[i] = ustr;
164-
itemLengths[i] = ustr_len;
158+
165159
i++;
166160
} ZEND_HASH_FOREACH_END();
167161

168162
UErrorCode status = U_ZERO_ERROR;
169-
int32_t resultLength;
170-
UChar *result = nullptr;
171-
zend_string *ret = nullptr;
172-
173-
resultLength = ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, nullptr, 0, &status);
174-
175-
if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
176-
intl_error_set(nullptr, status, "Failed to format list");
177-
RETVAL_FALSE;
178-
goto cleanup;
179-
}
163+
UnicodeString result;
180164

181-
// Allocate buffer and try again
182-
status = U_ZERO_ERROR;
183-
result = (UChar *)safe_emalloc(resultLength + 1, sizeof(UChar), 0);
184-
ulistfmt_format(LISTFORMATTER_OBJECT(obj), items, itemLengths, count, result, resultLength, &status);
165+
LISTFORMATTER_OBJECT(obj)->format(items, count, result, status);
166+
delete[] items;
185167

186168
if (U_FAILURE(status)) {
187-
if (result) {
188-
efree(result);
189-
}
190169
intl_error_set(nullptr, status, "Failed to format list");
191-
RETVAL_FALSE;
192-
goto cleanup;
170+
RETURN_FALSE;
193171
}
194172

195-
// Convert result back to UTF-8
196-
ret = intl_convert_utf16_to_utf8(result, resultLength, &status);
197-
efree(result);
198-
173+
zend_string *ret = intl_charFromString(result, &status);
174+
199175
if (!ret) {
200176
intl_error_set(nullptr, status, "Failed to convert result to UTF-8");
201-
RETVAL_FALSE;
202-
} else {
203-
RETVAL_NEW_STR(ret);
177+
RETURN_FALSE;
204178
}
205179

206-
cleanup:
207-
for (i = 0; i < count; i++) {
208-
efree((void *)items[i]);
209-
}
210-
efree(items);
211-
efree(itemLengths);
180+
RETVAL_STR(ret);
212181
}
213182

214183
PHP_METHOD(IntlListFormatter, getErrorCode)
@@ -236,7 +205,7 @@ void listformatter_register_class(void)
236205
{
237206
zend_class_entry *class_entry = register_class_IntlListFormatter();
238207
class_entry->create_object = listformatter_create_object;
239-
208+
240209
memcpy(&listformatter_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
241210
listformatter_handlers.offset = XtOffsetOf(ListFormatter_object, zo);
242211
listformatter_handlers.free_obj = listformatter_free_obj;

ext/intl/listformatter/listformatter_class.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,20 @@
2121
#include "intl_error.h"
2222
#include "intl_data.h"
2323

24-
#include <unicode/ulistformatter.h>
24+
#include <unicode/listformatter.h>
25+
26+
#ifdef __cplusplus
27+
using icu::ListFormatter;
28+
#else
29+
typedef void ListFormatter;
30+
#endif
2531

2632
typedef struct {
2733
// error handling
2834
intl_error error;
2935

3036
// formatter handling
31-
UListFormatter* ulistfmt;
37+
ListFormatter* ulistfmt;
3238
} listformatter_data;
3339

3440
typedef struct {

ext/intl/rangeformatter/rangeformatter_class.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern "C" {
2222
#include <unicode/numberrangeformatter.h>
2323
#include <unicode/numberformatter.h>
2424
#include <unicode/unistr.h>
25+
#include <unicode/locid.h>
2526
#include "../intl_convertcpp.h"
2627

2728
extern "C" {
@@ -30,7 +31,6 @@ extern "C" {
3031
#include "../intl_data.h"
3132
#include "rangeformatter_arginfo.h"
3233
#include "rangeformatter_class.h"
33-
#include "intl_convert.h"
3434
}
3535

3636
using icu::number::NumberRangeFormatter;
@@ -91,7 +91,7 @@ U_CFUNC PHP_METHOD(IntlNumberRangeFormatter, createFromSkeleton)
9191
RETURN_THROWS();
9292
}
9393

94-
if (strlen(uloc_getISO3Language(locale)) == 0) {
94+
if (icu::Locale(locale).getISO3Language()[0] == '\0') {
9595
zend_argument_value_error(2, "\"%s\" is invalid", locale);
9696
RETURN_THROWS();
9797
}

0 commit comments

Comments
 (0)