xref: /PHP-7.4/ext/intl/formatter/formatter_attr.c (revision 92ac598a)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
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 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php_intl.h"
22 #include "formatter_class.h"
23 #include "formatter_attr.h"
24 #include "intl_convert.h"
25 
26 #include <unicode/ustring.h>
27 
28 /* {{{ proto mixed NumberFormatter::getAttribute( int $attr )
29  * Get formatter attribute value. }}} */
30 /* {{{ proto mixed numfmt_get_attribute( NumberFormatter $nf, int $attr )
31  * Get formatter attribute value.
32  */
PHP_FUNCTION(numfmt_get_attribute)33 PHP_FUNCTION( numfmt_get_attribute )
34 {
35 	zend_long attribute, value;
36 	FORMATTER_METHOD_INIT_VARS;
37 
38 	/* Parse parameters. */
39 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
40 		&object, NumberFormatter_ce_ptr, &attribute ) == FAILURE )
41 	{
42 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
43 			"numfmt_get_attribute: unable to parse input params", 0 );
44 
45 		RETURN_FALSE;
46 	}
47 
48 	/* Fetch the object. */
49 	FORMATTER_METHOD_FETCH_OBJECT;
50 
51 	switch(attribute) {
52 		case UNUM_PARSE_INT_ONLY:
53 		case UNUM_GROUPING_USED:
54 		case UNUM_DECIMAL_ALWAYS_SHOWN:
55 		case UNUM_MAX_INTEGER_DIGITS:
56 		case UNUM_MIN_INTEGER_DIGITS:
57 		case UNUM_INTEGER_DIGITS:
58 		case UNUM_MAX_FRACTION_DIGITS:
59 		case UNUM_MIN_FRACTION_DIGITS:
60 		case UNUM_FRACTION_DIGITS:
61 		case UNUM_MULTIPLIER:
62 		case UNUM_GROUPING_SIZE:
63 		case UNUM_ROUNDING_MODE:
64 		case UNUM_FORMAT_WIDTH:
65 		case UNUM_PADDING_POSITION:
66 		case UNUM_SECONDARY_GROUPING_SIZE:
67 		case UNUM_SIGNIFICANT_DIGITS_USED:
68 		case UNUM_MIN_SIGNIFICANT_DIGITS:
69 		case UNUM_MAX_SIGNIFICANT_DIGITS:
70 		case UNUM_LENIENT_PARSE:
71 			value = unum_getAttribute(FORMATTER_OBJECT(nfo), attribute);
72 			if(value == -1) {
73 				INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
74 			} else {
75 				RETVAL_LONG(value);
76 			}
77 			break;
78 		case UNUM_ROUNDING_INCREMENT:
79 		{
80 			double value_double = unum_getDoubleAttribute(FORMATTER_OBJECT(nfo), attribute);
81 			if(value_double == -1) {
82 				INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
83 			} else {
84 				RETVAL_DOUBLE(value_double);
85 			}
86 		}
87 			break;
88 		default:
89 			INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
90 			break;
91 	}
92 
93 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting attribute value" );
94 }
95 /* }}} */
96 
97 /* {{{ proto string NumberFormatter::getTextAttribute( int $attr )
98  * Get formatter attribute value. }}} */
99 /* {{{ proto string numfmt_get_text_attribute( NumberFormatter $nf, int $attr )
100  * Get formatter attribute value.
101  */
PHP_FUNCTION(numfmt_get_text_attribute)102 PHP_FUNCTION( numfmt_get_text_attribute )
103 {
104 	zend_long   attribute;
105 	UChar   value_buf[64];
106 	int32_t value_buf_size = USIZE( value_buf );
107 	UChar*  value  = value_buf;
108 	int32_t length = 0;
109 	FORMATTER_METHOD_INIT_VARS;
110 
111 	/* Parse parameters. */
112 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
113 		&object, NumberFormatter_ce_ptr, &attribute ) == FAILURE )
114 	{
115 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
116 			"numfmt_get_text_attribute: unable to parse input params", 0 );
117 
118 		RETURN_FALSE;
119 	}
120 
121 	/* Fetch the object. */
122 	FORMATTER_METHOD_FETCH_OBJECT;
123 
124 	length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, value_buf_size, &INTL_DATA_ERROR_CODE(nfo) );
125 	if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= value_buf_size) {
126 		++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
127 		INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
128 		value = eumalloc(length);
129 		length = unum_getTextAttribute( FORMATTER_OBJECT(nfo), attribute, value, length, &INTL_DATA_ERROR_CODE(nfo) );
130 		if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
131 			efree(value);
132 			value = value_buf;
133 		}
134 	}
135 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting attribute value" );
136 
137 	INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
138 }
139 /* }}} */
140 
141 /* {{{ proto bool NumberFormatter::setAttribute( int $attr, mixed $value )
142  * Get formatter attribute value. }}} */
143 /* {{{ proto bool numfmt_set_attribute( NumberFormatter $nf, int $attr, mixed $value )
144  * Get formatter attribute value.
145  */
PHP_FUNCTION(numfmt_set_attribute)146 PHP_FUNCTION( numfmt_set_attribute )
147 {
148 	zend_long attribute;
149 	zval *value;
150 	FORMATTER_METHOD_INIT_VARS;
151 
152 	/* Parse parameters. */
153 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Olz",
154 		&object, NumberFormatter_ce_ptr, &attribute, &value ) == FAILURE)
155 	{
156 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
157 			"numfmt_set_attribute: unable to parse input params", 0 );
158 
159 		RETURN_FALSE;
160 	}
161 
162 	/* Fetch the object. */
163 	FORMATTER_METHOD_FETCH_OBJECT;
164 
165 	switch(attribute) {
166 		case UNUM_PARSE_INT_ONLY:
167 		case UNUM_GROUPING_USED:
168 		case UNUM_DECIMAL_ALWAYS_SHOWN:
169 		case UNUM_MAX_INTEGER_DIGITS:
170 		case UNUM_MIN_INTEGER_DIGITS:
171 		case UNUM_INTEGER_DIGITS:
172 		case UNUM_MAX_FRACTION_DIGITS:
173 		case UNUM_MIN_FRACTION_DIGITS:
174 		case UNUM_FRACTION_DIGITS:
175 		case UNUM_MULTIPLIER:
176 		case UNUM_GROUPING_SIZE:
177 		case UNUM_ROUNDING_MODE:
178 		case UNUM_FORMAT_WIDTH:
179 		case UNUM_PADDING_POSITION:
180 		case UNUM_SECONDARY_GROUPING_SIZE:
181 		case UNUM_SIGNIFICANT_DIGITS_USED:
182 		case UNUM_MIN_SIGNIFICANT_DIGITS:
183 		case UNUM_MAX_SIGNIFICANT_DIGITS:
184 		case UNUM_LENIENT_PARSE:
185 			unum_setAttribute(FORMATTER_OBJECT(nfo), attribute, zval_get_long(value));
186 			break;
187 		case UNUM_ROUNDING_INCREMENT:
188 			unum_setDoubleAttribute(FORMATTER_OBJECT(nfo), attribute, zval_get_double(value));
189 			break;
190 		default:
191 			INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
192 			break;
193 	}
194 
195 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting attribute value" );
196 
197 	RETURN_TRUE;
198 }
199 /* }}} */
200 
201 /* {{{ proto bool NumberFormatter::setTextAttribute( int $attr, string $value )
202  * Get formatter attribute value. }}} */
203 /* {{{ proto bool numfmt_set_text_attribute( NumberFormatter $nf, int $attr, string $value )
204  * Get formatter attribute value.
205  */
PHP_FUNCTION(numfmt_set_text_attribute)206 PHP_FUNCTION( numfmt_set_text_attribute )
207 {
208 	int32_t slength = 0;
209 	UChar *svalue = NULL;
210 	zend_long attribute;
211 	char *value;
212 	size_t len;
213 	FORMATTER_METHOD_INIT_VARS;
214 
215 	/* Parse parameters. */
216 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ols",
217 		&object, NumberFormatter_ce_ptr, &attribute, &value, &len ) == FAILURE)
218 	{
219 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
220 			"numfmt_set_text_attribute: unable to parse input params", 0 );
221 
222 		RETURN_FALSE;
223 	}
224 
225 	/* Fetch the object. */
226 	FORMATTER_METHOD_FETCH_OBJECT;
227 
228 	/* Convert given attribute value to UTF-16. */
229 	intl_convert_utf8_to_utf16(&svalue, &slength, value, len, &INTL_DATA_ERROR_CODE(nfo));
230 	INTL_METHOD_CHECK_STATUS( nfo, "Error converting attribute value to UTF-16" );
231 
232 	/* Actually set new attribute value. */
233 	unum_setTextAttribute(FORMATTER_OBJECT(nfo), attribute, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
234 	if (svalue) {
235 		efree(svalue);
236 	}
237 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting text attribute" );
238 
239 	RETURN_TRUE;
240 }
241 /* }}} */
242 
243 /* {{{ proto string NumberFormatter::getSymbol( int $attr )
244  * Get formatter symbol value. }}} */
245 /* {{{ proto string numfmt_get_symbol( NumberFormatter $nf, int $attr )
246  * Get formatter symbol value.
247  */
PHP_FUNCTION(numfmt_get_symbol)248 PHP_FUNCTION( numfmt_get_symbol )
249 {
250 	zend_long symbol;
251 	UChar value_buf[4];
252 	UChar *value = value_buf;
253 	uint32_t length = USIZE(value_buf);
254 	FORMATTER_METHOD_INIT_VARS;
255 
256 	/* Parse parameters. */
257 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
258 		&object, NumberFormatter_ce_ptr, &symbol ) == FAILURE )
259 	{
260 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
261 			"numfmt_get_symbol: unable to parse input params", 0 );
262 
263 		RETURN_FALSE;
264 	}
265 
266 	if(symbol >= UNUM_FORMAT_SYMBOL_COUNT || symbol < 0) {
267 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,	"numfmt_get_symbol: invalid symbol value", 0 );
268 		RETURN_FALSE;
269 	}
270 
271 	/* Fetch the object. */
272 	FORMATTER_METHOD_FETCH_OBJECT;
273 
274 	length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value_buf, length, &INTL_DATA_ERROR_CODE(nfo));
275 	if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
276 		++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
277 		INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
278 		value = eumalloc(length);
279 		length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value, length, &INTL_DATA_ERROR_CODE(nfo));
280 		if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
281 			efree(value);
282 			value = value_buf;
283 		}
284 	}
285 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting symbol value" );
286 
287 	INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value_buf != value ) );
288 }
289 /* }}} */
290 
291 /* {{{ proto bool NumberFormatter::setSymbol( int $attr, string $symbol )
292  * Set formatter symbol value. }}} */
293 /* {{{ proto bool numfmt_set_symbol( NumberFormatter $nf, int $attr, string $symbol )
294  * Set formatter symbol value.
295  */
PHP_FUNCTION(numfmt_set_symbol)296 PHP_FUNCTION( numfmt_set_symbol )
297 {
298 	zend_long  symbol;
299 	char*      value     = NULL;
300 	size_t     value_len = 0;
301 	UChar*     svalue  = 0;
302 	int32_t    slength = 0;
303 	FORMATTER_METHOD_INIT_VARS;
304 
305 	/* Parse parameters. */
306 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ols",
307 		&object, NumberFormatter_ce_ptr, &symbol, &value, &value_len ) == FAILURE )
308 	{
309 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
310 			"numfmt_set_symbol: unable to parse input params", 0 );
311 
312 		RETURN_FALSE;
313 	}
314 
315 	if (symbol >= UNUM_FORMAT_SYMBOL_COUNT || symbol < 0) {
316 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,	"numfmt_set_symbol: invalid symbol value", 0 );
317 		RETURN_FALSE;
318 	}
319 
320 	/* Fetch the object. */
321 	FORMATTER_METHOD_FETCH_OBJECT;
322 
323 	/* Convert given symbol to UTF-16. */
324 	intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
325 	INTL_METHOD_CHECK_STATUS( nfo, "Error converting symbol value to UTF-16" );
326 
327 	/* Actually set the symbol. */
328 	unum_setSymbol(FORMATTER_OBJECT(nfo), symbol, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
329 	if (svalue) {
330 		efree(svalue);
331 	}
332 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting symbol value" );
333 
334 	RETURN_TRUE;
335 }
336 /* }}} */
337 
338 /* {{{ proto string NumberFormatter::getPattern( )
339  * Get formatter pattern. }}} */
340 /* {{{ proto string numfmt_get_pattern( NumberFormatter $nf )
341  * Get formatter pattern.
342  */
PHP_FUNCTION(numfmt_get_pattern)343 PHP_FUNCTION( numfmt_get_pattern )
344 {
345 	UChar   value_buf[64];
346 	uint32_t length = USIZE( value_buf );
347 	UChar*  value  = value_buf;
348 	FORMATTER_METHOD_INIT_VARS;
349 
350 	/* Parse parameters. */
351 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O",
352 		&object, NumberFormatter_ce_ptr ) == FAILURE )
353 	{
354 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
355 			"numfmt_get_pattern: unable to parse input params", 0 );
356 
357 		RETURN_FALSE;
358 	}
359 
360 	/* Fetch the object. */
361 	FORMATTER_METHOD_FETCH_OBJECT;
362 
363 	length = unum_toPattern(FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo));
364 	if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
365 		++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
366 		INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
367 		value = eumalloc(length);
368 		length = unum_toPattern( FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo) );
369 		if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
370 			efree(value);
371 			value = value_buf;
372 		}
373 	}
374 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting formatter pattern" );
375 
376 	INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
377 }
378 /* }}} */
379 
380 /* {{{ proto bool NumberFormatter::setPattern( string $pattern )
381  * Set formatter pattern. }}} */
382 /* {{{ proto bool numfmt_set_pattern( NumberFormatter $nf, string $pattern )
383  * Set formatter pattern.
384  */
PHP_FUNCTION(numfmt_set_pattern)385 PHP_FUNCTION( numfmt_set_pattern )
386 {
387 	char*       value = NULL;
388 	size_t      value_len = 0;
389 	int32_t     slength = 0;
390 	UChar*	    svalue  = NULL;
391 	FORMATTER_METHOD_INIT_VARS;
392 
393 	/* Parse parameters. */
394 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os",
395 		&object, NumberFormatter_ce_ptr, &value, &value_len ) == FAILURE )
396 	{
397 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
398 			"numfmt_set_pattern: unable to parse input params", 0 );
399 
400 		RETURN_FALSE;
401 	}
402 
403 	FORMATTER_METHOD_FETCH_OBJECT;
404 
405 	/* Convert given pattern to UTF-16. */
406 	intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
407 	INTL_METHOD_CHECK_STATUS( nfo, "Error converting pattern to UTF-16" );
408 
409 	/* TODO: add parse error information */
410 	unum_applyPattern(FORMATTER_OBJECT(nfo), 0, svalue, slength, NULL, &INTL_DATA_ERROR_CODE(nfo));
411 	if (svalue) {
412 		efree(svalue);
413 	}
414 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting pattern value" );
415 
416 	RETURN_TRUE;
417 }
418 /* }}} */
419 
420 /* {{{ proto string NumberFormatter::getLocale([int type])
421  * Get formatter locale. }}} */
422 /* {{{ proto string numfmt_get_locale( NumberFormatter $nf[, int type] )
423  * Get formatter locale.
424  */
PHP_FUNCTION(numfmt_get_locale)425 PHP_FUNCTION( numfmt_get_locale )
426 {
427 	zend_long type = ULOC_ACTUAL_LOCALE;
428 	char* loc;
429 	FORMATTER_METHOD_INIT_VARS;
430 
431 	/* Parse parameters. */
432 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O|l",
433 		&object, NumberFormatter_ce_ptr, &type ) == FAILURE )
434 	{
435 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
436 			"numfmt_get_locale: unable to parse input params", 0 );
437 
438 		RETURN_FALSE;
439 	}
440 
441 	/* Fetch the object. */
442 	FORMATTER_METHOD_FETCH_OBJECT;
443 
444 	loc = (char *)unum_getLocaleByType(FORMATTER_OBJECT(nfo), type, &INTL_DATA_ERROR_CODE(nfo));
445 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting locale" );
446 	RETURN_STRING(loc);
447 }
448 /* }}} */
449