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 <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)
36{
37    int count;
38    UChar* formatted = NULL;
39    int formatted_len = 0;
40    HashTable *args_copy;
41
42    count = zend_hash_num_elements(Z_ARRVAL_P(args));
43
44    ALLOC_HASHTABLE(args_copy);
45    zend_hash_init(args_copy, count, NULL, ZVAL_PTR_DTOR, 0);
46    zend_hash_copy(args_copy, Z_ARRVAL_P(args), (copy_ctor_func_t)zval_add_ref);
47
48    umsg_format_helper(mfo, args_copy, &formatted, &formatted_len);
49
50    zend_hash_destroy(args_copy);
51    efree(args_copy);
52
53    if (formatted && U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) {
54            efree(formatted);
55    }
56
57    if (U_FAILURE(INTL_DATA_ERROR_CODE(mfo))) {
58        RETURN_FALSE;
59    } else {
60        INTL_METHOD_RETVAL_UTF8(mfo, formatted, formatted_len, 1);
61    }
62}
63/* }}} */
64
65/* {{{ proto mixed MessageFormatter::format( array $args )
66 * Format a message. }}} */
67/* {{{ proto mixed msgfmt_format( MessageFormatter $nf, array $args )
68 * Format a message.
69 */
70PHP_FUNCTION( msgfmt_format )
71{
72    zval *args;
73    MSG_FORMAT_METHOD_INIT_VARS;
74
75
76    /* Parse parameters. */
77    if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Oa",
78        &object, MessageFormatter_ce_ptr,  &args ) == FAILURE )
79    {
80        intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
81            "msgfmt_format: unable to parse input params", 0 );
82
83        RETURN_FALSE;
84    }
85
86    /* Fetch the object. */
87    MSG_FORMAT_METHOD_FETCH_OBJECT;
88
89    msgfmt_do_format(mfo, args, return_value);
90}
91/* }}} */
92
93/* {{{ proto mixed MessageFormatter::formatMessage( string $locale, string $pattern, array $args )
94 * Format a message. }}} */
95/* {{{ proto mixed msgfmt_format_message( string $locale, string $pattern, array $args )
96 * Format a message.
97 */
98PHP_FUNCTION( msgfmt_format_message )
99{
100    zval       *args;
101    UChar      *spattern = NULL;
102    int         spattern_len = 0;
103    char       *pattern = NULL;
104    size_t         pattern_len = 0;
105    const char *slocale = NULL;
106    size_t         slocale_len = 0;
107    MessageFormatter_object mf = {0};
108    MessageFormatter_object *mfo = &mf;
109
110    /* Parse parameters. */
111    if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "ssa",
112          &slocale, &slocale_len, &pattern, &pattern_len, &args ) == FAILURE )
113    {
114        intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
115            "msgfmt_format_message: unable to parse input params", 0 );
116
117        RETURN_FALSE;
118    }
119
120    msgformat_data_init(&mfo->mf_data);
121
122    if(pattern && pattern_len) {
123        intl_convert_utf8_to_utf16(&spattern, &spattern_len, pattern, pattern_len, &INTL_DATA_ERROR_CODE(mfo));
124        if( U_FAILURE(INTL_DATA_ERROR_CODE((mfo))) )
125        {
126            intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
127                "msgfmt_format_message: error converting pattern to UTF-16", 0 );
128            RETURN_FALSE;
129        }
130    } else {
131        spattern_len = 0;
132        spattern = NULL;
133    }
134
135    if(slocale_len == 0) {
136        slocale = intl_locale_get_default();
137    }
138
139#ifdef MSG_FORMAT_QUOTE_APOS
140    if(msgformat_fix_quotes(&spattern, &spattern_len, &INTL_DATA_ERROR_CODE(mfo)) != SUCCESS) {
141        intl_error_set( NULL, U_INVALID_FORMAT_ERROR,
142            "msgfmt_format_message: error converting pattern to quote-friendly format", 0 );
143        RETURN_FALSE;
144    }
145#endif
146
147    /* Create an ICU message formatter. */
148    MSG_FORMAT_OBJECT(mfo) = umsg_open(spattern, spattern_len, slocale, NULL, &INTL_DATA_ERROR_CODE(mfo));
149    if(spattern && spattern_len) {
150        efree(spattern);
151    }
152    INTL_METHOD_CHECK_STATUS(mfo, "Creating message formatter failed");
153
154    msgfmt_do_format(mfo, args, return_value);
155
156    /* drop the temporary formatter */
157    msgformat_data_free(&mfo->mf_data);
158}
159/* }}} */
160
161/*
162 * Local variables:
163 * tab-width: 4
164 * c-basic-offset: 4
165 * End:
166 * vim600: noet sw=4 ts=4 fdm=marker
167 * vim<600: noet sw=4 ts=4
168 */
169