1 /*
2 +----------------------------------------------------------------------+
3 | This source file is subject to version 3.01 of the PHP license, |
4 | that is bundled with this package in the file LICENSE, and is |
5 | available through the world-wide-web at the following url: |
6 | https://www.php.net/license/3_01.txt |
7 | If you did not receive a copy of the PHP license and are unable to |
8 | obtain it through the world-wide-web, please send a note to |
9 | license@php.net so we can mail you a copy immediately. |
10 +----------------------------------------------------------------------+
11 | Authors: Stanislav Malyshev <stas@zend.com> |
12 +----------------------------------------------------------------------+
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #include "php_intl.h"
20 #include "formatter_class.h"
21 #include "intl_convert.h"
22
23 #include <unicode/ustring.h>
24
25 /* {{{ Get formatter attribute value. */
PHP_FUNCTION(numfmt_get_attribute)26 PHP_FUNCTION( numfmt_get_attribute )
27 {
28 zend_long attribute, value;
29 FORMATTER_METHOD_INIT_VARS;
30
31 /* Parse parameters. */
32 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
33 &object, NumberFormatter_ce_ptr, &attribute ) == FAILURE )
34 {
35 RETURN_THROWS();
36 }
37
38 /* Fetch the object. */
39 FORMATTER_METHOD_FETCH_OBJECT;
40
41 switch(attribute) {
42 case UNUM_PARSE_INT_ONLY:
43 case UNUM_GROUPING_USED:
44 case UNUM_DECIMAL_ALWAYS_SHOWN:
45 case UNUM_MAX_INTEGER_DIGITS:
46 case UNUM_MIN_INTEGER_DIGITS:
47 case UNUM_INTEGER_DIGITS:
48 case UNUM_MAX_FRACTION_DIGITS:
49 case UNUM_MIN_FRACTION_DIGITS:
50 case UNUM_FRACTION_DIGITS:
51 case UNUM_MULTIPLIER:
52 case UNUM_GROUPING_SIZE:
53 case UNUM_ROUNDING_MODE:
54 case UNUM_FORMAT_WIDTH:
55 case UNUM_PADDING_POSITION:
56 case UNUM_SECONDARY_GROUPING_SIZE:
57 case UNUM_SIGNIFICANT_DIGITS_USED:
58 case UNUM_MIN_SIGNIFICANT_DIGITS:
59 case UNUM_MAX_SIGNIFICANT_DIGITS:
60 case UNUM_LENIENT_PARSE:
61 value = unum_getAttribute(FORMATTER_OBJECT(nfo), attribute);
62 if(value == -1) {
63 INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
64 } else {
65 RETVAL_LONG(value);
66 }
67 break;
68 case UNUM_ROUNDING_INCREMENT:
69 {
70 double value_double = unum_getDoubleAttribute(FORMATTER_OBJECT(nfo), attribute);
71 if(value_double == -1) {
72 INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
73 } else {
74 RETVAL_DOUBLE(value_double);
75 }
76 }
77 break;
78 default:
79 INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
80 break;
81 }
82
83 INTL_METHOD_CHECK_STATUS( nfo, "Error getting attribute value" );
84 }
85 /* }}} */
86
87 /* {{{ Get formatter attribute value. */
PHP_FUNCTION(numfmt_get_text_attribute)88 PHP_FUNCTION( numfmt_get_text_attribute )
89 {
90 zend_long attribute;
91 UChar value_buf[64];
92 int32_t value_buf_size = USIZE( value_buf );
93 UChar* value = value_buf;
94 int32_t length = 0;
95 FORMATTER_METHOD_INIT_VARS;
96
97 /* Parse parameters. */
98 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
99 &object, NumberFormatter_ce_ptr, &attribute ) == FAILURE )
100 {
101 RETURN_THROWS();
102 }
103
104 /* Fetch the object. */
105 FORMATTER_METHOD_FETCH_OBJECT;
106
107 length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, value_buf_size, &INTL_DATA_ERROR_CODE(nfo) );
108 if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= value_buf_size) {
109 ++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
110 INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
111 value = eumalloc(length);
112 length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, length, &INTL_DATA_ERROR_CODE(nfo) );
113 if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
114 efree(value);
115 value = value_buf;
116 }
117 }
118 INTL_METHOD_CHECK_STATUS( nfo, "Error getting attribute value" );
119
120 INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
121 }
122 /* }}} */
123
124 /* {{{ Get formatter attribute value. */
PHP_FUNCTION(numfmt_set_attribute)125 PHP_FUNCTION( numfmt_set_attribute )
126 {
127 zend_long attribute;
128 zval *value;
129 FORMATTER_METHOD_INIT_VARS;
130
131 /* Parse parameters. */
132 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oln",
133 &object, NumberFormatter_ce_ptr, &attribute, &value ) == FAILURE)
134 {
135 RETURN_THROWS();
136 }
137
138 /* Fetch the object. */
139 FORMATTER_METHOD_FETCH_OBJECT;
140
141 switch(attribute) {
142 case UNUM_PARSE_INT_ONLY:
143 case UNUM_GROUPING_USED:
144 case UNUM_DECIMAL_ALWAYS_SHOWN:
145 case UNUM_MAX_INTEGER_DIGITS:
146 case UNUM_MIN_INTEGER_DIGITS:
147 case UNUM_INTEGER_DIGITS:
148 case UNUM_MAX_FRACTION_DIGITS:
149 case UNUM_MIN_FRACTION_DIGITS:
150 case UNUM_FRACTION_DIGITS:
151 case UNUM_MULTIPLIER:
152 case UNUM_GROUPING_SIZE:
153 case UNUM_ROUNDING_MODE:
154 case UNUM_FORMAT_WIDTH:
155 case UNUM_PADDING_POSITION:
156 case UNUM_SECONDARY_GROUPING_SIZE:
157 case UNUM_SIGNIFICANT_DIGITS_USED:
158 case UNUM_MIN_SIGNIFICANT_DIGITS:
159 case UNUM_MAX_SIGNIFICANT_DIGITS:
160 case UNUM_LENIENT_PARSE:
161 unum_setAttribute(FORMATTER_OBJECT(nfo), attribute, zval_get_long(value));
162 break;
163 case UNUM_ROUNDING_INCREMENT:
164 unum_setDoubleAttribute(FORMATTER_OBJECT(nfo), attribute, zval_get_double(value));
165 break;
166 default:
167 INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
168 break;
169 }
170
171 INTL_METHOD_CHECK_STATUS( nfo, "Error setting attribute value" );
172
173 RETURN_TRUE;
174 }
175 /* }}} */
176
177 /* {{{ Get formatter attribute value. */
PHP_FUNCTION(numfmt_set_text_attribute)178 PHP_FUNCTION( numfmt_set_text_attribute )
179 {
180 int32_t slength = 0;
181 UChar *svalue = NULL;
182 zend_long attribute;
183 char *value;
184 size_t len;
185 FORMATTER_METHOD_INIT_VARS;
186
187 /* Parse parameters. */
188 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ols",
189 &object, NumberFormatter_ce_ptr, &attribute, &value, &len ) == FAILURE)
190 {
191 RETURN_THROWS();
192 }
193
194 /* Fetch the object. */
195 FORMATTER_METHOD_FETCH_OBJECT;
196
197 /* Convert given attribute value to UTF-16. */
198 intl_convert_utf8_to_utf16(&svalue, &slength, value, len, &INTL_DATA_ERROR_CODE(nfo));
199 INTL_METHOD_CHECK_STATUS( nfo, "Error converting attribute value to UTF-16" );
200
201 /* Actually set new attribute value. */
202 unum_setTextAttribute(FORMATTER_OBJECT(nfo), attribute, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
203 if (svalue) {
204 efree(svalue);
205 }
206 INTL_METHOD_CHECK_STATUS( nfo, "Error setting text attribute" );
207
208 RETURN_TRUE;
209 }
210 /* }}} */
211
212 /* {{{ Get formatter symbol value. */
PHP_FUNCTION(numfmt_get_symbol)213 PHP_FUNCTION( numfmt_get_symbol )
214 {
215 zend_long symbol;
216 UChar value_buf[4];
217 UChar *value = value_buf;
218 uint32_t length = USIZE(value_buf);
219 FORMATTER_METHOD_INIT_VARS;
220
221 /* Parse parameters. */
222 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
223 &object, NumberFormatter_ce_ptr, &symbol ) == FAILURE )
224 {
225 RETURN_THROWS();
226 }
227
228 if(symbol >= UNUM_FORMAT_SYMBOL_COUNT || symbol < 0) {
229 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "numfmt_get_symbol: invalid symbol value", 0 );
230 RETURN_FALSE;
231 }
232
233 /* Fetch the object. */
234 FORMATTER_METHOD_FETCH_OBJECT;
235
236 length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value_buf, length, &INTL_DATA_ERROR_CODE(nfo));
237 if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
238 ++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
239 INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
240 value = eumalloc(length);
241 length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value, length, &INTL_DATA_ERROR_CODE(nfo));
242 if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
243 efree(value);
244 value = value_buf;
245 }
246 }
247 INTL_METHOD_CHECK_STATUS( nfo, "Error getting symbol value" );
248
249 INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value_buf != value ) );
250 }
251 /* }}} */
252
253 /* {{{ Set formatter symbol value. */
PHP_FUNCTION(numfmt_set_symbol)254 PHP_FUNCTION( numfmt_set_symbol )
255 {
256 zend_long symbol;
257 char* value = NULL;
258 size_t value_len = 0;
259 UChar* svalue = 0;
260 int32_t slength = 0;
261 FORMATTER_METHOD_INIT_VARS;
262
263 /* Parse parameters. */
264 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ols",
265 &object, NumberFormatter_ce_ptr, &symbol, &value, &value_len ) == FAILURE )
266 {
267 RETURN_THROWS();
268 }
269
270 if (symbol >= UNUM_FORMAT_SYMBOL_COUNT || symbol < 0) {
271 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "numfmt_set_symbol: invalid symbol value", 0 );
272 RETURN_FALSE;
273 }
274
275 /* Fetch the object. */
276 FORMATTER_METHOD_FETCH_OBJECT;
277
278 /* Convert given symbol to UTF-16. */
279 intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
280 INTL_METHOD_CHECK_STATUS( nfo, "Error converting symbol value to UTF-16" );
281
282 /* Actually set the symbol. */
283 unum_setSymbol(FORMATTER_OBJECT(nfo), symbol, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
284 if (svalue) {
285 efree(svalue);
286 }
287 INTL_METHOD_CHECK_STATUS( nfo, "Error setting symbol value" );
288
289 RETURN_TRUE;
290 }
291 /* }}} */
292
293 /* {{{ Get formatter pattern. */
PHP_FUNCTION(numfmt_get_pattern)294 PHP_FUNCTION( numfmt_get_pattern )
295 {
296 UChar value_buf[64];
297 uint32_t length = USIZE( value_buf );
298 UChar* value = value_buf;
299 FORMATTER_METHOD_INIT_VARS;
300
301 /* Parse parameters. */
302 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O",
303 &object, NumberFormatter_ce_ptr ) == FAILURE )
304 {
305 RETURN_THROWS();
306 }
307
308 /* Fetch the object. */
309 FORMATTER_METHOD_FETCH_OBJECT;
310
311 length = unum_toPattern(FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo));
312 if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
313 ++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
314 INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
315 value = eumalloc(length);
316 length = unum_toPattern( FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo) );
317 if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
318 efree(value);
319 value = value_buf;
320 }
321 }
322 INTL_METHOD_CHECK_STATUS( nfo, "Error getting formatter pattern" );
323
324 INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
325 }
326 /* }}} */
327
328 /* {{{ Set formatter pattern. */
PHP_FUNCTION(numfmt_set_pattern)329 PHP_FUNCTION( numfmt_set_pattern )
330 {
331 char* value = NULL;
332 size_t value_len = 0;
333 int32_t slength = 0;
334 UChar* svalue = NULL;
335 UParseError spattern_error = {0};
336 FORMATTER_METHOD_INIT_VARS;
337
338 /* Parse parameters. */
339 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os",
340 &object, NumberFormatter_ce_ptr, &value, &value_len ) == FAILURE )
341 {
342 RETURN_THROWS();
343 }
344
345 FORMATTER_METHOD_FETCH_OBJECT;
346
347 /* Convert given pattern to UTF-16. */
348 intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
349 INTL_METHOD_CHECK_STATUS( nfo, "Error converting pattern to UTF-16" );
350
351 unum_applyPattern(FORMATTER_OBJECT(nfo), 0, svalue, slength, &spattern_error, &INTL_DATA_ERROR_CODE(nfo));
352 if (svalue) {
353 efree(svalue);
354 }
355 if (U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
356 char *msg;
357 spprintf(&msg, 0, "Error setting pattern value at line %d, offset %d", spattern_error.line, spattern_error.offset);
358 intl_errors_set_custom_msg(INTL_DATA_ERROR_P(nfo), msg, 1);
359 efree(msg);
360 RETURN_FALSE;
361 }
362
363 RETURN_TRUE;
364 }
365 /* }}} */
366
367 /* {{{ Get formatter locale. */
PHP_FUNCTION(numfmt_get_locale)368 PHP_FUNCTION( numfmt_get_locale )
369 {
370 zend_long type = ULOC_ACTUAL_LOCALE;
371 char* loc;
372 FORMATTER_METHOD_INIT_VARS;
373
374 /* Parse parameters. */
375 if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O|l",
376 &object, NumberFormatter_ce_ptr, &type ) == FAILURE )
377 {
378 RETURN_THROWS();
379 }
380
381 /* Fetch the object. */
382 FORMATTER_METHOD_FETCH_OBJECT;
383
384 loc = (char *)unum_getLocaleByType(FORMATTER_OBJECT(nfo), type, &INTL_DATA_ERROR_CODE(nfo));
385 INTL_METHOD_CHECK_STATUS( nfo, "Error getting locale" );
386 RETURN_STRING(loc);
387 }
388 /* }}} */
389