xref: /PHP-5.3/ext/intl/dateformat/dateformat.c (revision a5d0c1e2)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
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: Kirti Velankar <kirtig@yahoo-inc.com>                       |
14    +----------------------------------------------------------------------+
15 */
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19 
20 #include <unicode/ustring.h>
21 #include <unicode/udat.h>
22 #include <unicode/ucal.h>
23 
24 #include "php_intl.h"
25 #include "intl_convert.h"
26 #include "dateformat_class.h"
27 #include "dateformat.h"
28 
29 /* {{{ dateformat_register_constants
30  * Register constants common for the both (OO and procedural)
31  * APIs.
32  */
dateformat_register_constants(INIT_FUNC_ARGS)33 void dateformat_register_constants( INIT_FUNC_ARGS )
34 {
35 	if( IntlDateFormatter_ce_ptr == NULL) {
36 		zend_error(E_ERROR, "DateFormat class not defined");
37 		return;
38 	}
39 
40 	#define DATEFORMATTER_EXPOSE_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS)
41 	#define DATEFORMATTER_EXPOSE_CLASS_CONST(x) zend_declare_class_constant_long( IntlDateFormatter_ce_ptr, ZEND_STRS( #x ) - 1, UDAT_##x TSRMLS_CC );
42 	#define DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST(name, value) zend_declare_class_constant_long( IntlDateFormatter_ce_ptr, ZEND_STRS( name ) - 1, value TSRMLS_CC );
43 
44 	#define DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST(x) zend_declare_class_constant_long( IntlDateFormatter_ce_ptr, ZEND_STRS( #x ) - 1, UCAL_##x TSRMLS_CC );
45 
46 	/* UDateFormatStyle constants */
47 	DATEFORMATTER_EXPOSE_CLASS_CONST( FULL );
48 	DATEFORMATTER_EXPOSE_CLASS_CONST( LONG );
49 	DATEFORMATTER_EXPOSE_CLASS_CONST( MEDIUM );
50 	DATEFORMATTER_EXPOSE_CLASS_CONST( SHORT );
51 	DATEFORMATTER_EXPOSE_CLASS_CONST( NONE );
52 
53 /*
54 	DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "GREGORIAN", DATEF_GREGORIAN );
55 	DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "CUSTOMARY", DATEF_CUSTOMARY );
56 	DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "BUDDHIST", DATEF_BUDDHIST );
57 	DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST( "JAPANESE_IMPERIAL", DATEF_JAPANESE_IMPERIAL );
58 */
59 
60 	DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST( GREGORIAN );
61 	DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST( TRADITIONAL );
62 
63 	#undef DATEFORMATTER_EXPOSE_UCAL_CLASS_CONST
64 	#undef DATEFORMATTER_EXPOSE_CUSTOM_CLASS_CONST
65 	#undef DATEFORMATTER_EXPOSE_CLASS_CONST
66 	#undef DATEFORMATTER_EXPOSE_CONST
67 }
68 /* }}} */
69 
70 /* {{{ */
datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS)71 static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS)
72 {
73     char*       locale;
74 	int         locale_len = 0;
75 	zval*       object;
76     long        date_type = 0;
77     long        time_type = 0;
78     long        calendar = UCAL_GREGORIAN;
79     char*       timezone_str = NULL;
80     int         timezone_str_len = 0;
81     char*       pattern_str = NULL;
82     int         pattern_str_len = 0;
83     UChar*      svalue = NULL;		/* UTF-16 pattern_str */
84     int         slength = 0;
85     UChar*      timezone_utf16 = NULL;		/* UTF-16 timezone_str */
86     int         timezone_utf16_len = 0;
87 	UCalendar   ucal_obj = NULL;
88 	IntlDateFormatter_object* dfo;
89 
90 	intl_error_reset( NULL TSRMLS_CC );
91 	object = return_value;
92 	/* Parse parameters. */
93     if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "sll|sls",
94 		&locale, &locale_len, &date_type, &time_type, &timezone_str, &timezone_str_len, &calendar,&pattern_str, &pattern_str_len ) == FAILURE )
95     {
96 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,	"datefmt_create: unable to parse input parameters", 0 TSRMLS_CC );
97 		zval_dtor(return_value);
98 		RETURN_NULL();
99     }
100 
101 	INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value);
102 
103 	if (calendar != UCAL_TRADITIONAL && calendar != UCAL_GREGORIAN) {
104 		intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: "
105 				"invalid value for calendar type; it must be one of "
106 				"IntlDateFormatter::TRADITIONAL (locale's default calendar) "
107 				"or IntlDateFormatter::GREGORIAN", 0 TSRMLS_CC);
108 		goto error;
109 	}
110 
111 	DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK;
112 
113 	if (DATE_FORMAT_OBJECT(dfo) != NULL) {
114 		intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR,
115 				"datefmt_create: cannot call constructor twice", 0 TSRMLS_CC);
116 		return;
117 	}
118 
119 	/* Convert pattern (if specified) to UTF-16. */
120 	if( pattern_str && pattern_str_len>0 ){
121 		intl_convert_utf8_to_utf16(&svalue, &slength,
122 				pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo));
123 		if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
124 			/* object construction -> only set global error */
125 			intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: "
126 					"error converting pattern to UTF-16", 0 TSRMLS_CC);
127 			goto error;
128 		}
129 	}
130 
131 	/* resources allocated from now on */
132 
133 	/* Convert pattern (if specified) to UTF-16. */
134 	if( timezone_str && timezone_str_len >0 ){
135 		intl_convert_utf8_to_utf16(&timezone_utf16, &timezone_utf16_len,
136 				timezone_str, timezone_str_len, &INTL_DATA_ERROR_CODE(dfo));
137 		if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
138 			intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: "
139 					"error converting timezone_str to UTF-16", 0 TSRMLS_CC);
140 			goto error;
141 		}
142 	}
143 
144 	if(locale_len == 0) {
145 		locale = INTL_G(default_locale);
146 	}
147 
148 	if( pattern_str && pattern_str_len>0 ){
149 		DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo));
150 	} else {
151 		DATE_FORMAT_OBJECT(dfo) = udat_open(time_type, date_type, locale, timezone_utf16, timezone_utf16_len, svalue, slength, &INTL_DATA_ERROR_CODE(dfo));
152 	}
153 
154     if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
155 		if (calendar != UCAL_TRADITIONAL) {
156 			ucal_obj = ucal_open(timezone_utf16, timezone_utf16_len, locale,
157 					calendar, &INTL_DATA_ERROR_CODE(dfo));
158 			if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) {
159 				udat_setCalendar(DATE_FORMAT_OBJECT(dfo), ucal_obj);
160 				ucal_close(ucal_obj);
161 			} else {
162 				intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create"
163 						": error opening calendar", 0 TSRMLS_CC);
164 				goto error;
165 			}
166 		}
167     } else {
168 		intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo),	"datefmt_create: date "
169 				"formatter creation failed", 0 TSRMLS_CC);
170 		goto error;
171 	}
172 
173 	/* Set the class variables */
174 	dfo->date_type = date_type;
175 	dfo->time_type = time_type;
176 	dfo->calendar  = calendar;
177 	if( timezone_str && timezone_str_len > 0){
178 		dfo->timezone_id = estrndup( timezone_str, timezone_str_len);
179 	}
180 
181 error:
182 	if (svalue) {
183 		efree(svalue);
184 	}
185 	if (timezone_utf16) {
186 		efree(timezone_utf16);
187 	}
188 	if (U_FAILURE(intl_error_get_code(NULL TSRMLS_CC))) {
189 		/* free_object handles partially constructed instances fine */
190 		zval_dtor(return_value);
191 		RETVAL_NULL();
192 	}
193 }
194 /* }}} */
195 
196 /* {{{ proto IntlDateFormatter IntlDateFormatter::create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] )
197  * Create formatter. }}} */
198 /* {{{ proto IntlDateFormatter datefmt_create(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern] )
199 
200  * Create formatter.
201  */
PHP_FUNCTION(datefmt_create)202 PHP_FUNCTION( datefmt_create )
203 {
204     object_init_ex( return_value, IntlDateFormatter_ce_ptr );
205 	datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
206 }
207 /* }}} */
208 
209 /* {{{ proto void IntlDateFormatter::__construct(string $locale, long date_type, long time_type[, string $timezone_str, long $calendar, string $pattern])
210  * IntlDateFormatter object constructor.
211  */
PHP_METHOD(IntlDateFormatter,__construct)212 PHP_METHOD( IntlDateFormatter, __construct )
213 {
214 	/* return_value param is being changed, therefore we will always return
215 	 * NULL here */
216 	return_value = getThis();
217 	datefmt_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU);
218 }
219 /* }}} */
220 
221 /* {{{ proto int IntlDateFormatter::getErrorCode()
222  * Get formatter's last error code. }}} */
223 /* {{{ proto int datefmt_get_error_code( IntlDateFormatter $nf )
224  * Get formatter's last error code.
225  */
PHP_FUNCTION(datefmt_get_error_code)226 PHP_FUNCTION( datefmt_get_error_code )
227 {
228 	DATE_FORMAT_METHOD_INIT_VARS;
229 
230 	/* Parse parameters. */
231 	if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
232 		&object, IntlDateFormatter_ce_ptr ) == FAILURE )
233 	{
234 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
235 			"datefmt_get_error_code: unable to parse input params", 0 TSRMLS_CC );
236 		RETURN_FALSE;
237 	}
238 
239 	dfo = (IntlDateFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
240 
241 	/* Return formatter's last error code. */
242 	RETURN_LONG( INTL_DATA_ERROR_CODE(dfo) );
243 }
244 /* }}} */
245 
246 /* {{{ proto string IntlDateFormatter::getErrorMessage( )
247  * Get text description for formatter's last error code. }}} */
248 /* {{{ proto string datefmt_get_error_message( IntlDateFormatter $coll )
249  * Get text description for formatter's last error code.
250  */
PHP_FUNCTION(datefmt_get_error_message)251 PHP_FUNCTION( datefmt_get_error_message )
252 {
253 	char*                    message = NULL;
254 	DATE_FORMAT_METHOD_INIT_VARS;
255 
256 	/* Parse parameters. */
257 	if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
258 		&object, IntlDateFormatter_ce_ptr ) == FAILURE )
259 	{
260 		intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
261 			"datefmt_get_error_message: unable to parse input params", 0 TSRMLS_CC );
262 
263 		RETURN_FALSE;
264 	}
265 
266 	dfo = (IntlDateFormatter_object *) zend_object_store_get_object( object TSRMLS_CC );
267 
268 	/* Return last error message. */
269 	message = intl_error_get_message( INTL_DATA_ERROR_P(dfo) TSRMLS_CC );
270 	RETURN_STRING( message, 0);
271 }
272 /* }}} */
273