1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Alex Plotnick <alex@wgate.com> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: gettext.c 277841 2009-03-26 20:02:53Z felipe $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 :
27 : #if HAVE_LIBINTL
28 :
29 : #include <stdio.h>
30 : #include "ext/standard/info.h"
31 : #include "php_gettext.h"
32 :
33 : /* {{{ arginfo */
34 : ZEND_BEGIN_ARG_INFO(arginfo_textdomain, 0)
35 : ZEND_ARG_INFO(0, domain)
36 : ZEND_END_ARG_INFO()
37 :
38 : ZEND_BEGIN_ARG_INFO(arginfo_gettext, 0)
39 : ZEND_ARG_INFO(0, msgid)
40 : ZEND_END_ARG_INFO()
41 :
42 : ZEND_BEGIN_ARG_INFO(arginfo_dgettext, 0)
43 : ZEND_ARG_INFO(0, domain_name)
44 : ZEND_ARG_INFO(0, msgid)
45 : ZEND_END_ARG_INFO()
46 :
47 : ZEND_BEGIN_ARG_INFO(arginfo_dcgettext, 0)
48 : ZEND_ARG_INFO(0, domain_name)
49 : ZEND_ARG_INFO(0, msgid)
50 : ZEND_ARG_INFO(0, category)
51 : ZEND_END_ARG_INFO()
52 :
53 : ZEND_BEGIN_ARG_INFO(arginfo_bindtextdomain, 0)
54 : ZEND_ARG_INFO(0, domain_name)
55 : ZEND_ARG_INFO(0, dir)
56 : ZEND_END_ARG_INFO()
57 :
58 : #if HAVE_NGETTEXT
59 : ZEND_BEGIN_ARG_INFO(arginfo_ngettext, 0)
60 : ZEND_ARG_INFO(0, msgid1)
61 : ZEND_ARG_INFO(0, msgid2)
62 : ZEND_ARG_INFO(0, count)
63 : ZEND_END_ARG_INFO()
64 : #endif
65 :
66 : #if HAVE_DNGETTEXT
67 : ZEND_BEGIN_ARG_INFO(arginfo_dngettext, 0)
68 : ZEND_ARG_INFO(0, domain)
69 : ZEND_ARG_INFO(0, msgid1)
70 : ZEND_ARG_INFO(0, msgid2)
71 : ZEND_ARG_INFO(0, count)
72 : ZEND_END_ARG_INFO()
73 : #endif
74 :
75 : #if HAVE_DCNGETTEXT
76 : ZEND_BEGIN_ARG_INFO(arginfo_dcngettext, 0)
77 : ZEND_ARG_INFO(0, domain)
78 : ZEND_ARG_INFO(0, msgid1)
79 : ZEND_ARG_INFO(0, msgid2)
80 : ZEND_ARG_INFO(0, count)
81 : ZEND_ARG_INFO(0, category)
82 : ZEND_END_ARG_INFO()
83 : #endif
84 :
85 : #if HAVE_BIND_TEXTDOMAIN_CODESET
86 : ZEND_BEGIN_ARG_INFO(arginfo_bind_textdomain_codeset, 0)
87 : ZEND_ARG_INFO(0, domain)
88 : ZEND_ARG_INFO(0, codeset)
89 : ZEND_END_ARG_INFO()
90 : #endif
91 : /* }}} */
92 :
93 : /* {{{ php_gettext_functions[]
94 : */
95 : const zend_function_entry php_gettext_functions[] = {
96 : PHP_NAMED_FE(textdomain, zif_textdomain, arginfo_textdomain)
97 : PHP_NAMED_FE(gettext, zif_gettext, arginfo_gettext)
98 : /* Alias for gettext() */
99 : PHP_NAMED_FE(_, zif_gettext, arginfo_gettext)
100 : PHP_NAMED_FE(dgettext, zif_dgettext, arginfo_dgettext)
101 : PHP_NAMED_FE(dcgettext, zif_dcgettext, arginfo_dcgettext)
102 : PHP_NAMED_FE(bindtextdomain, zif_bindtextdomain, arginfo_bindtextdomain)
103 : #if HAVE_NGETTEXT
104 : PHP_NAMED_FE(ngettext, zif_ngettext, arginfo_ngettext)
105 : #endif
106 : #if HAVE_DNGETTEXT
107 : PHP_NAMED_FE(dngettext, zif_dngettext, arginfo_dngettext)
108 : #endif
109 : #if HAVE_DCNGETTEXT
110 : PHP_NAMED_FE(dcngettext, zif_dcngettext, arginfo_dcngettext)
111 : #endif
112 : #if HAVE_BIND_TEXTDOMAIN_CODESET
113 : PHP_NAMED_FE(bind_textdomain_codeset, zif_bind_textdomain_codeset, arginfo_bind_textdomain_codeset)
114 : #endif
115 : {NULL, NULL, NULL}
116 : };
117 : /* }}} */
118 :
119 : #include <libintl.h>
120 :
121 : zend_module_entry php_gettext_module_entry = {
122 : STANDARD_MODULE_HEADER,
123 : "gettext",
124 : php_gettext_functions,
125 : NULL,
126 : NULL,
127 : NULL,
128 : NULL,
129 : PHP_MINFO(php_gettext),
130 : NO_VERSION_YET,
131 : STANDARD_MODULE_PROPERTIES
132 : };
133 :
134 : #ifdef COMPILE_DL_GETTEXT
135 : ZEND_GET_MODULE(php_gettext)
136 : #endif
137 :
138 : #define PHP_GETTEXT_MAX_DOMAIN_LENGTH 1024
139 : #define PHP_GETTEXT_MAX_MSGID_LENGTH 4096
140 :
141 : #define PHP_GETTEXT_DOMAIN_LENGTH_CHECK \
142 : if (domain_len > PHP_GETTEXT_MAX_DOMAIN_LENGTH) { \
143 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "domain passed too long"); \
144 : RETURN_FALSE; \
145 : }
146 :
147 : #define PHP_GETTEXT_LENGTH_CHECK(check_name, check_len) \
148 : if (check_len > PHP_GETTEXT_MAX_MSGID_LENGTH) { \
149 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s passed too long", check_name); \
150 : RETURN_FALSE; \
151 : }
152 :
153 : PHP_MINFO_FUNCTION(php_gettext)
154 43 : {
155 43 : php_info_print_table_start();
156 43 : php_info_print_table_row(2, "GetText Support", "enabled");
157 43 : php_info_print_table_end();
158 43 : }
159 :
160 : #define RETVAL_FS_STRING(s, f) \
161 : RETVAL_STRING((s), (f)); \
162 : zval_string_to_unicode_ex(return_value, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)) TSRMLS_CC);
163 :
164 : #define RETURN_FS_STRING(s, f) \
165 : RETVAL_FS_STRING((s), (f)); \
166 : return;
167 :
168 : /* {{{ proto string textdomain(string domain) U
169 : Set the textdomain to "domain". Returns the current domain */
170 : PHP_NAMED_FUNCTION(zif_textdomain)
171 12 : {
172 : char *domain_str;
173 : int domain_len;
174 :
175 12 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)))) {
176 1 : return;
177 : }
178 :
179 11 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
180 :
181 10 : if (!domain_len || (domain_len == 1 && *domain_str == '0')) {
182 3 : domain_str = NULL;
183 : }
184 10 : RETURN_FS_STRING(textdomain(domain_str), ZSTR_DUPLICATE);
185 : }
186 : /* }}} */
187 :
188 : /* {{{ proto binary gettext(string msgid) U
189 : Return the translation of msgid for the current domain, or msgid unaltered if a translation does not exist */
190 : PHP_NAMED_FUNCTION(zif_gettext)
191 12 : {
192 : char *msgid_str;
193 : int msgid_len;
194 :
195 12 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&", &msgid_str, &msgid_len, UG(ascii_conv))) {
196 1 : return;
197 : }
198 :
199 11 : PHP_GETTEXT_LENGTH_CHECK("msgid", msgid_len)
200 :
201 10 : RETURN_STRING(gettext(msgid_str), ZSTR_DUPLICATE);
202 : }
203 : /* }}} */
204 :
205 : /* {{{ proto binary dgettext(string domain_name, string msgid) U
206 : Return the translation of msgid for domain_name, or msgid unaltered if a translation does not exist */
207 : PHP_NAMED_FUNCTION(zif_dgettext)
208 7 : {
209 : char *domain_str, *msgid_str;
210 : int domain_len, msgid_len;
211 :
212 7 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)), &msgid_str, &msgid_len, UG(ascii_conv))) {
213 4 : return;
214 : }
215 :
216 3 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
217 2 : PHP_GETTEXT_LENGTH_CHECK("msgid", msgid_len)
218 :
219 1 : RETURN_STRING(dgettext(domain_str, msgid_str), ZSTR_DUPLICATE);
220 : }
221 : /* }}} */
222 :
223 : /* {{{ proto binary dcgettext(string domain_name, string msgid, int category) U
224 : Return the translation of msgid for domain_name and category, or msgid unaltered if a translation does not exist */
225 : PHP_NAMED_FUNCTION(zif_dcgettext)
226 5 : {
227 : char *domain_str, *msgid_str;
228 : int domain_len, msgid_len;
229 : long category;
230 :
231 5 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&l", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)), &msgid_str, &msgid_len, UG(ascii_conv), &category)) {
232 1 : return;
233 : }
234 :
235 4 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
236 3 : PHP_GETTEXT_LENGTH_CHECK("msgid", msgid_len)
237 :
238 2 : RETURN_STRING(dcgettext(domain_str, msgid_str, category), ZSTR_DUPLICATE);
239 : }
240 : /* }}} */
241 :
242 : /* {{{ proto string bindtextdomain(string domain_name, string dir) U
243 : Bind to the text domain domain_name, looking for translations in dir. Returns the current domain */
244 : PHP_NAMED_FUNCTION(zif_bindtextdomain)
245 18 : {
246 18 : char *domain_str, *dir_str, dir_tmp[MAXPATHLEN] = {0};
247 : int domain_len, dir_len;
248 :
249 18 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)), &dir_str, &dir_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)))) {
250 2 : return;
251 : }
252 :
253 16 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
254 :
255 15 : if (!domain_len || !*domain_str) {
256 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "the first parameter must not be empty");
257 1 : RETURN_FALSE;
258 : }
259 15 : if (!dir_len || (dir_len == 1 && *dir_str == '0')) {
260 1 : if (!VCWD_GETCWD(dir_tmp, sizeof(dir_tmp))) {
261 0 : RETURN_FALSE;
262 : }
263 13 : } else if (!VCWD_REALPATH(dir_str, dir_tmp)) {
264 1 : RETURN_FALSE;
265 : }
266 13 : RETURN_FS_STRING(bindtextdomain(domain_str, dir_tmp), ZSTR_DUPLICATE);
267 : }
268 : /* }}} */
269 :
270 : #if HAVE_NGETTEXT
271 : /* {{{ proto binary ngettext(string msgid1, string msgid2, int count) U
272 : Plural version of gettext() */
273 : PHP_NAMED_FUNCTION(zif_ngettext)
274 10 : {
275 : char *msgid_str1, *msgid_str2, *msgstr;
276 : int msgid1_len, msgid2_len;
277 : long count;
278 :
279 10 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&l", &msgid_str1, &msgid1_len, UG(ascii_conv), &msgid_str2, &msgid2_len, UG(ascii_conv), &count)) {
280 6 : RETURN_FALSE;
281 : }
282 :
283 4 : PHP_GETTEXT_LENGTH_CHECK("msgid1", msgid1_len)
284 3 : PHP_GETTEXT_LENGTH_CHECK("msgid2", msgid2_len)
285 :
286 2 : if ((msgstr = ngettext(msgid_str1, msgid_str2, count))) {
287 2 : RETURN_STRING(msgstr, ZSTR_DUPLICATE);
288 : } else {
289 0 : RETURN_FALSE;
290 : }
291 : }
292 : /* }}} */
293 : #endif
294 :
295 : #if HAVE_DNGETTEXT
296 : /* {{{ proto binary dngettext (string domain, string msgid1, string msgid2, int count) U
297 : Plural version of dgettext() */
298 : PHP_NAMED_FUNCTION(zif_dngettext)
299 6 : {
300 : char *domain_str, *msgid_str1, *msgid_str2, *msgstr;
301 : int domain_len, msgid1_len, msgid2_len;
302 : long count;
303 :
304 6 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&s&l", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)), &msgid_str1, &msgid1_len, UG(ascii_conv), &msgid_str2, &msgid2_len, UG(ascii_conv), &count)) {
305 1 : RETURN_FALSE;
306 : }
307 :
308 5 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
309 4 : PHP_GETTEXT_LENGTH_CHECK("msgid1", msgid1_len)
310 3 : PHP_GETTEXT_LENGTH_CHECK("msgid2", msgid2_len)
311 :
312 2 : if ((msgstr = dngettext(domain_str, msgid_str1, msgid_str2, count))) {
313 2 : RETURN_STRING(msgstr, ZSTR_DUPLICATE);
314 : } else {
315 0 : RETURN_FALSE;
316 : }
317 : }
318 : /* }}} */
319 : #endif
320 :
321 : #if HAVE_DCNGETTEXT
322 : /* {{{ proto binary dcngettext (string domain, string msgid1, string msgid2, int count, int category) U
323 : Plural version of dcgettext() */
324 : PHP_NAMED_FUNCTION(zif_dcngettext)
325 10 : {
326 : char *domain_str, *msgid_str1, *msgid_str2, *msgstr;
327 : int domain_len, msgid1_len, msgid2_len;
328 : long count, category;
329 :
330 10 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&s&ll", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)), &msgid_str1, &msgid1_len, UG(ascii_conv), &msgid_str2, &msgid2_len, UG(ascii_conv), &count, &category)) {
331 1 : RETURN_FALSE;
332 : }
333 :
334 9 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
335 8 : PHP_GETTEXT_LENGTH_CHECK("msgid1", msgid1_len)
336 7 : PHP_GETTEXT_LENGTH_CHECK("msgid2", msgid2_len)
337 :
338 6 : if ((msgstr = dcngettext(domain_str, msgid_str1, msgid_str2, count, category))) {
339 6 : RETURN_STRING(msgstr, ZSTR_DUPLICATE);
340 : } else {
341 0 : RETURN_FALSE;
342 : }
343 : }
344 : /* }}} */
345 : #endif
346 :
347 : #if HAVE_BIND_TEXTDOMAIN_CODESET
348 : /* {{{ proto string bind_textdomain_codeset (string domain, string codeset) U
349 : Specify the character encoding in which the messages from the DOMAIN message catalog will be returned. */
350 : PHP_NAMED_FUNCTION(zif_bind_textdomain_codeset)
351 4 : {
352 : char *domain_str, *codeset_str, *codeset_ret;
353 : int domain_len, codeset_len;
354 :
355 4 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s&s&", &domain_str, &domain_len, ZEND_U_CONVERTER(UG(filesystem_encoding_conv)), &codeset_str, &codeset_len, UG(ascii_conv))) {
356 2 : return;
357 : }
358 :
359 2 : PHP_GETTEXT_DOMAIN_LENGTH_CHECK
360 :
361 2 : if (!codeset_len) {
362 1 : codeset_str = NULL;
363 : }
364 2 : if ((codeset_ret = bind_textdomain_codeset(domain_str, codeset_str))) {
365 1 : RETURN_ASCII_STRING(codeset_ret, ZSTR_DUPLICATE);
366 : } else {
367 1 : RETURN_FALSE;
368 : }
369 : }
370 : /* }}} */
371 : #endif
372 :
373 :
374 : #endif /* HAVE_LIBINTL */
375 :
376 : /*
377 : * Local variables:
378 : * tab-width: 4
379 : * c-basic-offset: 4
380 : * End:
381 : * vim600: sw=4 ts=4 fdm=marker
382 : * vim<600: sw=4 ts=4
383 : */
384 :
|