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: Stanislav Malyshev <stas@zend.com>                          |
14   +----------------------------------------------------------------------+
15 */
16
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <unicode/ustring.h>
22
23#include "php_intl.h"
24#include "msgformat_class.h"
25#include "msgformat_format.h"
26#include "msgformat_data.h"
27#include "msgformat_helpers.h"
28#include "intl_convert.h"
29
30#ifndef Z_ADDREF_P
31#define Z_ADDREF_P(z) ((z)->refcount++)
32#endif
33
34/* {{{ */
35static void msgfmt_do_format(MessageFormatter_object *mfo, zval *args, zval *return_value TSRMLS_DC)
36{
37    zval **fargs;
38    int count;
39    UChar* formatted = NULL;
40    int formatted_len = 0;
41    HashPosition pos;
42    int i;
43
44    count = zend_hash_num_elements(Z_ARRVAL_P(args));
45
46    if(count < umsg_format_arg_count(MSG_FORMAT_OBJECT(mfo))) {
47        /* Not enough aguments for format! */
48        intl_error_set( INTL_DATA_ERROR_P(mfo), U_ILLEGAL_ARGUMENT_ERROR,
49            "msgfmt_format: not enough parameters", 0 TSRMLS_CC );
50        RETVAL_FALSE;
51        return;
52    }
53
54    fargs = safe_emalloc(count, sizeof(zval *), 0);
55
56    zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos);
57    for(i=0;i<count;i++) {
58        zval **val;
59        zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **)&val, &pos);
60        fargs[i] = *val;
61        Z_ADDREF_P(fargs[i]);
62        /* TODO: needs refcount increase here? */
63        zend_hash_move_forward_ex(Z_ARRVAL_P(args), &pos);
64    }
65
66    umsg_format_helper(MSG_FORMAT_OBJECT(mfo), count, fargs, &formatted, &formatted_len, &INTL_DATA_ERROR_CODE(mfo) TSRMLS_CC);
67
68    for(i=0;i<count;i++) {
69        zval_ptr_dtor(&fargs[i]);
70    }
71
72    efree(fargs);
73
74    if (formatted && U_FAILURE( INTL_DATA_ERROR_CODE(mfo) ) ) {
75            efree(formatted);
76    }
77
78    INTL_METHOD_CHECK_STATUS( mfo, "Number formatting failed" );
79    INTL_METHOD_RETVAL_UTF8( mfo, formatted, formatted_len, 1 );
80}
81/* }}} */
82
83/* {{{ proto mixed MessageFormatter::format( array $args )
84 * Format a message. }}} */
85/* {{{ proto mixed msgfmt_format( MessageFormatter $nf, array $args )
86 * Format a message.
87 */
88PHP_FUNCTION( msgfmt_format )
89{
90    zval *args;
91    MSG_FORMAT_METHOD_INIT_VARS;
92
93
94    /* Parse parameters. */
95    if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
96        &object, MessageFormatter_ce_ptr,  &args ) == FAILURE )
97    {
98        intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
99            "msgfmt_format: unable to parse input params", 0 TSRMLS_CC );
100
101        RETURN_FALSE;
102    }
103
104    /* Fetch the object. */
105    MSG_FORMAT_METHOD_FETCH_OBJECT;
106
107    msgfmt_do_format(mfo, args, return_value TSRMLS_CC);
108}
109/* }}} */
110
111/* {{{ proto mixed MessageFormatter::formatMessage( string $locale, string $pattern, array $args )
112 * Format a message. }}} */
113/* {{{ proto mixed msgfmt_format_message( string $locale, string $pattern, array $args )
114 * Format a message.
115 */
116PHP_FUNCTION( msgfmt_format_message )
117{
118    zval       *args;
119    UChar      *spattern = NULL;
120    int         spattern_len = 0;
121    char       *pattern = NULL;
122    int         pattern_len = 0;
123    char       *slocale = NULL;
124    int         slocale_len = 0;
125    MessageFormatter_object mf = {0};
126    MessageFormatter_object *mfo = &mf;
127
128    /* Parse parameters. */
129    if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "ssa",
130          &slocale, &slocale_len, &pattern, &pattern_len, &args ) == FAILURE )
131    {
132        intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
133            "msgfmt_format_message: unable to parse input params", 0 TSRMLS_CC );
134
135        RETURN_FALSE;
136    }
137
138    msgformat_data_init(&mfo->mf_data TSRMLS_CC);
139
140    if(pattern && pattern_len) {
141        intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo));
142        if( U_FAILURE(INTL_DATA_ERROR_CODE((mfo))) )
143        {
144            intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
145                "msgfmt_format_message: error converting pattern to UTF-16", 0 TSRMLS_CC );
146            RETURN_FALSE;
147        }
148    } else {
149        spattern_len = 0;
150        spattern = NULL;
151    }
152
153    if(slocale_len == 0) {
154        slocale = INTL_G(default_locale);
155    }
156
157#ifdef MSG_FORMAT_QUOTE_APOS
158    if(msgformat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
159        intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
160            "msgfmt_format_message: error converting pattern to quote-friendly format", 0 TSRMLS_CC );
161        RETURN_FALSE;
162    }
163#endif
164
165    /* Create an ICU message formatter. */
166    MSG_FORMAT_OBJECT(mfo) = umsg_open(spattern, spattern_len, slocale, NULL, &INTL_DATA_ERROR_CODE(mfo));
167    if(spattern && spattern_len) {
168        efree(spattern);
169    }
170    INTL_METHOD_CHECK_STATUS(mfo, "Creating message formatter failed");
171
172    msgfmt_do_format(mfo, args, return_value TSRMLS_CC);
173
174    /* drop the temporary formatter */
175    msgformat_data_free(&mfo->mf_data TSRMLS_CC);
176}
177/* }}} */
178
179/*
180 * Local variables:
181 * tab-width: 4
182 * c-basic-offset: 4
183 * End:
184 * vim600: noet sw=4 ts=4 fdm=marker
185 * vim<600: noet sw=4 ts=4
186 */
187