xref: /PHP-7.1/ext/intl/formatter/formatter_attr.c (revision 323b2733)
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 			convert_to_long_ex(value);
186 			unum_setAttribute(FORMATTER_OBJECT(nfo), attribute, Z_LVAL_P(value));
187 			break;
188 		case UNUM_ROUNDING_INCREMENT:
189 			convert_to_double_ex(value);
190 			unum_setDoubleAttribute(FORMATTER_OBJECT(nfo), attribute, Z_DVAL_P(value));
191 			break;
192 		default:
193 			INTL_DATA_ERROR_CODE(nfo) = U_UNSUPPORTED_ERROR;
194 			break;
195 	}
196 
197 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting attribute value" );
198 
199 	RETURN_TRUE;
200 }
201 /* }}} */
202 
203 /* {{{ proto bool NumberFormatter::setTextAttribute( int $attr, string $value )
204  * Get formatter attribute value. }}} */
205 /* {{{ proto bool numfmt_set_text_attribute( NumberFormatter $nf, int $attr, string $value )
206  * Get formatter attribute value.
207  */
PHP_FUNCTION(numfmt_set_text_attribute)208 PHP_FUNCTION( numfmt_set_text_attribute )
209 {
210 	int32_t slength = 0;
211 	UChar *svalue = NULL;
212 	zend_long attribute;
213 	char *value;
214 	size_t len;
215 	FORMATTER_METHOD_INIT_VARS;
216 
217 	/* Parse parameters. */
218 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ols",
219 		&object, NumberFormatter_ce_ptr, &attribute, &value, &len ) == FAILURE)
220 	{
221 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
222 			"numfmt_set_text_attribute: unable to parse input params", 0 );
223 
224 		RETURN_FALSE;
225 	}
226 
227 	/* Fetch the object. */
228 	FORMATTER_METHOD_FETCH_OBJECT;
229 
230 	/* Convert given attribute value to UTF-16. */
231 	intl_convert_utf8_to_utf16(&svalue, &slength, value, len, &INTL_DATA_ERROR_CODE(nfo));
232 	INTL_METHOD_CHECK_STATUS( nfo, "Error converting attribute value to UTF-16" );
233 
234 	/* Actually set new attribute value. */
235 	unum_setTextAttribute(FORMATTER_OBJECT(nfo), attribute, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
236 	if (svalue) {
237 		efree(svalue);
238 	}
239 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting text attribute" );
240 
241 	RETURN_TRUE;
242 }
243 /* }}} */
244 
245 /* {{{ proto string NumberFormatter::getSymbol( int $attr )
246  * Get formatter symbol value. }}} */
247 /* {{{ proto string numfmt_get_symbol( NumberFormatter $nf, int $attr )
248  * Get formatter symbol value.
249  */
PHP_FUNCTION(numfmt_get_symbol)250 PHP_FUNCTION( numfmt_get_symbol )
251 {
252 	zend_long symbol;
253 	UChar value_buf[4];
254 	UChar *value = value_buf;
255 	uint32_t length = USIZE(value_buf);
256 	FORMATTER_METHOD_INIT_VARS;
257 
258 	/* Parse parameters. */
259 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ol",
260 		&object, NumberFormatter_ce_ptr, &symbol ) == FAILURE )
261 	{
262 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
263 			"numfmt_get_symbol: unable to parse input params", 0 );
264 
265 		RETURN_FALSE;
266 	}
267 
268 	if(symbol >= UNUM_FORMAT_SYMBOL_COUNT || symbol < 0) {
269 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,	"numfmt_get_symbol: invalid symbol value", 0 );
270 		RETURN_FALSE;
271 	}
272 
273 	/* Fetch the object. */
274 	FORMATTER_METHOD_FETCH_OBJECT;
275 
276 	length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value_buf, length, &INTL_DATA_ERROR_CODE(nfo));
277 	if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
278 		++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
279 		INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
280 		value = eumalloc(length);
281 		length = unum_getSymbol(FORMATTER_OBJECT(nfo), symbol, value, length, &INTL_DATA_ERROR_CODE(nfo));
282 		if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
283 			efree(value);
284 			value = value_buf;
285 		}
286 	}
287 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting symbol value" );
288 
289 	INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value_buf != value ) );
290 }
291 /* }}} */
292 
293 /* {{{ proto bool NumberFormatter::setSymbol( int $attr, string $symbol )
294  * Set formatter symbol value. }}} */
295 /* {{{ proto bool numfmt_set_symbol( NumberFormatter $nf, int $attr, string $symbol )
296  * Set formatter symbol value.
297  */
PHP_FUNCTION(numfmt_set_symbol)298 PHP_FUNCTION( numfmt_set_symbol )
299 {
300 	zend_long  symbol;
301 	char*      value     = NULL;
302 	size_t     value_len = 0;
303 	UChar*     svalue  = 0;
304 	int32_t    slength = 0;
305 	FORMATTER_METHOD_INIT_VARS;
306 
307 	/* Parse parameters. */
308 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Ols",
309 		&object, NumberFormatter_ce_ptr, &symbol, &value, &value_len ) == FAILURE )
310 	{
311 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
312 			"numfmt_set_symbol: unable to parse input params", 0 );
313 
314 		RETURN_FALSE;
315 	}
316 
317 	if (symbol >= UNUM_FORMAT_SYMBOL_COUNT || symbol < 0) {
318 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,	"numfmt_set_symbol: invalid symbol value", 0 );
319 		RETURN_FALSE;
320 	}
321 
322 	/* Fetch the object. */
323 	FORMATTER_METHOD_FETCH_OBJECT;
324 
325 	/* Convert given symbol to UTF-16. */
326 	intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
327 	INTL_METHOD_CHECK_STATUS( nfo, "Error converting symbol value to UTF-16" );
328 
329 	/* Actually set the symbol. */
330 	unum_setSymbol(FORMATTER_OBJECT(nfo), symbol, svalue, slength, &INTL_DATA_ERROR_CODE(nfo));
331 	if (svalue) {
332 		efree(svalue);
333 	}
334 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting symbol value" );
335 
336 	RETURN_TRUE;
337 }
338 /* }}} */
339 
340 /* {{{ proto string NumberFormatter::getPattern( )
341  * Get formatter pattern. }}} */
342 /* {{{ proto string numfmt_get_pattern( NumberFormatter $nf )
343  * Get formatter pattern.
344  */
PHP_FUNCTION(numfmt_get_pattern)345 PHP_FUNCTION( numfmt_get_pattern )
346 {
347 	UChar   value_buf[64];
348 	uint32_t length = USIZE( value_buf );
349 	UChar*  value  = value_buf;
350 	FORMATTER_METHOD_INIT_VARS;
351 
352 	/* Parse parameters. */
353 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O",
354 		&object, NumberFormatter_ce_ptr ) == FAILURE )
355 	{
356 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
357 			"numfmt_get_pattern: unable to parse input params", 0 );
358 
359 		RETURN_FALSE;
360 	}
361 
362 	/* Fetch the object. */
363 	FORMATTER_METHOD_FETCH_OBJECT;
364 
365 	length = unum_toPattern(FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo));
366 	if(INTL_DATA_ERROR_CODE(nfo) == U_BUFFER_OVERFLOW_ERROR && length >= USIZE( value_buf )) {
367 		++length; /* to avoid U_STRING_NOT_TERMINATED_WARNING */
368 		INTL_DATA_ERROR_CODE(nfo) = U_ZERO_ERROR;
369 		value = eumalloc(length);
370 		length = unum_toPattern( FORMATTER_OBJECT(nfo), 0, value, length, &INTL_DATA_ERROR_CODE(nfo) );
371 		if(U_FAILURE(INTL_DATA_ERROR_CODE(nfo))) {
372 			efree(value);
373 			value = value_buf;
374 		}
375 	}
376 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting formatter pattern" );
377 
378 	INTL_METHOD_RETVAL_UTF8( nfo, value, length, ( value != value_buf ) );
379 }
380 /* }}} */
381 
382 /* {{{ proto bool NumberFormatter::setPattern( string $pattern )
383  * Set formatter pattern. }}} */
384 /* {{{ proto bool numfmt_set_pattern( NumberFormatter $nf, string $pattern )
385  * Set formatter pattern.
386  */
PHP_FUNCTION(numfmt_set_pattern)387 PHP_FUNCTION( numfmt_set_pattern )
388 {
389 	char*       value = NULL;
390 	size_t      value_len = 0;
391 	int32_t     slength = 0;
392 	UChar*	    svalue  = NULL;
393 	FORMATTER_METHOD_INIT_VARS;
394 
395 	/* Parse parameters. */
396 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os",
397 		&object, NumberFormatter_ce_ptr, &value, &value_len ) == FAILURE )
398 	{
399 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
400 			"numfmt_set_pattern: unable to parse input params", 0 );
401 
402 		RETURN_FALSE;
403 	}
404 
405 	FORMATTER_METHOD_FETCH_OBJECT;
406 
407 	/* Convert given pattern to UTF-16. */
408 	intl_convert_utf8_to_utf16(&svalue, &slength, value, value_len, &INTL_DATA_ERROR_CODE(nfo));
409 	INTL_METHOD_CHECK_STATUS( nfo, "Error converting pattern to UTF-16" );
410 
411 	/* TODO: add parse error information */
412 	unum_applyPattern(FORMATTER_OBJECT(nfo), 0, svalue, slength, NULL, &INTL_DATA_ERROR_CODE(nfo));
413 	if (svalue) {
414 		efree(svalue);
415 	}
416 	INTL_METHOD_CHECK_STATUS( nfo, "Error setting pattern value" );
417 
418 	RETURN_TRUE;
419 }
420 /* }}} */
421 
422 /* {{{ proto string NumberFormatter::getLocale([int type])
423  * Get formatter locale. }}} */
424 /* {{{ proto string numfmt_get_locale( NumberFormatter $nf[, int type] )
425  * Get formatter locale.
426  */
PHP_FUNCTION(numfmt_get_locale)427 PHP_FUNCTION( numfmt_get_locale )
428 {
429 	zend_long type = ULOC_ACTUAL_LOCALE;
430 	char* loc;
431 	FORMATTER_METHOD_INIT_VARS;
432 
433 	/* Parse parameters. */
434 	if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "O|l",
435 		&object, NumberFormatter_ce_ptr, &type ) == FAILURE )
436 	{
437 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
438 			"numfmt_get_locale: unable to parse input params", 0 );
439 
440 		RETURN_FALSE;
441 	}
442 
443 	/* Fetch the object. */
444 	FORMATTER_METHOD_FETCH_OBJECT;
445 
446 	loc = (char *)unum_getLocaleByType(FORMATTER_OBJECT(nfo), type, &INTL_DATA_ERROR_CODE(nfo));
447 	INTL_METHOD_CHECK_STATUS( nfo, "Error getting locale" );
448 	RETURN_STRING(loc);
449 }
450 /* }}} */
451 
452 /*
453  * Local variables:
454  * tab-width: 4
455  * c-basic-offset: 4
456  * End:
457  * vim600: noet sw=4 ts=4 fdm=marker
458  * vim<600: noet sw=4 ts=4
459  */
460