ext/gettext: update arguments handling.

using zend_string whenever relevant too.

Close GH-13582.
This commit is contained in:
David Carlier 2024-03-03 11:53:49 +00:00
parent 782af7a963
commit 5823a96f1e
No known key found for this signature in database
GPG key ID: CEF290BB40D2086B
4 changed files with 99 additions and 68 deletions

View file

@ -81,18 +81,20 @@ PHP_MINFO_FUNCTION(php_gettext)
/* {{{ Set the textdomain to "domain". Returns the current domain */ /* {{{ Set the textdomain to "domain". Returns the current domain */
PHP_FUNCTION(textdomain) PHP_FUNCTION(textdomain)
{ {
char *domain_name = NULL, *retval; char *domain_name = NULL, *retval = NULL;
zend_string *domain = NULL; zend_string *domain = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S!", &domain) == FAILURE) { ZEND_PARSE_PARAMETERS_START(0, 1)
RETURN_THROWS(); Z_PARAM_OPTIONAL
} Z_PARAM_STR_OR_NULL(domain)
ZEND_PARSE_PARAMETERS_END();
if (domain != NULL) { if (domain != NULL) {
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain)) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
} if (zend_string_equals_literal(domain, "0")) {
zend_argument_value_error(1, "cannot be zero");
if (domain != NULL && !zend_string_equals_literal(domain, "0")) { RETURN_THROWS();
}
domain_name = ZSTR_VAL(domain); domain_name = ZSTR_VAL(domain);
} }
@ -105,7 +107,7 @@ PHP_FUNCTION(textdomain)
/* {{{ Return the translation of msgid for the current domain, or msgid unaltered if a translation does not exist */ /* {{{ Return the translation of msgid for the current domain, or msgid unaltered if a translation does not exist */
PHP_FUNCTION(gettext) PHP_FUNCTION(gettext)
{ {
char *msgstr; char *msgstr = NULL;
zend_string *msgid; zend_string *msgid;
ZEND_PARSE_PARAMETERS_START(1, 1) ZEND_PARSE_PARAMETERS_START(1, 1)
@ -126,12 +128,13 @@ PHP_FUNCTION(gettext)
/* {{{ Return the translation of msgid for domain_name, or msgid unaltered if a translation does not exist */ /* {{{ Return the translation of msgid for domain_name, or msgid unaltered if a translation does not exist */
PHP_FUNCTION(dgettext) PHP_FUNCTION(dgettext)
{ {
char *msgstr; char *msgstr = NULL;
zend_string *domain, *msgid; zend_string *domain, *msgid;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &domain, &msgid) == FAILURE) { ZEND_PARSE_PARAMETERS_START(2, 2)
RETURN_THROWS(); Z_PARAM_STR(domain)
} Z_PARAM_STR(msgid)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain)) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid)) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid))
@ -149,13 +152,15 @@ PHP_FUNCTION(dgettext)
/* {{{ Return the translation of msgid for domain_name and category, or msgid unaltered if a translation does not exist */ /* {{{ Return the translation of msgid for domain_name and category, or msgid unaltered if a translation does not exist */
PHP_FUNCTION(dcgettext) PHP_FUNCTION(dcgettext)
{ {
char *msgstr; char *msgstr = NULL;
zend_string *domain, *msgid; zend_string *domain, *msgid;
zend_long category; zend_long category;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSl", &domain, &msgid, &category) == FAILURE) { ZEND_PARSE_PARAMETERS_START(3, 3)
RETURN_THROWS(); Z_PARAM_STR(domain)
} Z_PARAM_STR(msgid)
Z_PARAM_LONG(category)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain)) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid)) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid))
@ -174,19 +179,24 @@ PHP_FUNCTION(dcgettext)
/* {{{ Bind to the text domain domain_name, looking for translations in dir. Returns the current domain */ /* {{{ Bind to the text domain domain_name, looking for translations in dir. Returns the current domain */
PHP_FUNCTION(bindtextdomain) PHP_FUNCTION(bindtextdomain)
{ {
char *domain; zend_string *domain, *dir = NULL;
size_t domain_len;
zend_string *dir = NULL;
char *retval, dir_name[MAXPATHLEN]; char *retval, dir_name[MAXPATHLEN];
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sS!", &domain, &domain_len, &dir) == FAILURE) { ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(domain)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(dir)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
if (!ZSTR_LEN(domain)) {
zend_argument_value_error(1, "cannot be empty");
RETURN_THROWS(); RETURN_THROWS();
} }
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, domain_len)
if (dir == NULL) { if (dir == NULL) {
RETURN_STRING(bindtextdomain(domain, NULL)); RETURN_STRING(bindtextdomain(ZSTR_VAL(domain), NULL));
} }
if (ZSTR_LEN(dir) != 0 && !zend_string_equals_literal(dir, "0")) { if (ZSTR_LEN(dir) != 0 && !zend_string_equals_literal(dir, "0")) {
@ -197,7 +207,7 @@ PHP_FUNCTION(bindtextdomain)
RETURN_FALSE; RETURN_FALSE;
} }
retval = bindtextdomain(domain, dir_name); retval = bindtextdomain(ZSTR_VAL(domain), dir_name);
RETURN_STRING(retval); RETURN_STRING(retval);
} }
@ -207,18 +217,20 @@ PHP_FUNCTION(bindtextdomain)
/* {{{ Plural version of gettext() */ /* {{{ Plural version of gettext() */
PHP_FUNCTION(ngettext) PHP_FUNCTION(ngettext)
{ {
char *msgid1, *msgid2, *msgstr; char *msgstr = NULL;
size_t msgid1_len, msgid2_len; zend_string *msgid1, *msgid2;
zend_long count; zend_long count;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssl", &msgid1, &msgid1_len, &msgid2, &msgid2_len, &count) == FAILURE) { ZEND_PARSE_PARAMETERS_START(3, 3)
RETURN_THROWS(); Z_PARAM_STR(msgid1)
} Z_PARAM_STR(msgid2)
Z_PARAM_LONG(count)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_LENGTH_CHECK(1, msgid1_len) PHP_GETTEXT_LENGTH_CHECK(1, ZSTR_LEN(msgid1))
PHP_GETTEXT_LENGTH_CHECK(2, msgid2_len) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid2))
msgstr = ngettext(msgid1, msgid2, count); msgstr = ngettext(ZSTR_VAL(msgid1), ZSTR_VAL(msgid2), count);
ZEND_ASSERT(msgstr); ZEND_ASSERT(msgstr);
RETURN_STRING(msgstr); RETURN_STRING(msgstr);
@ -230,20 +242,22 @@ PHP_FUNCTION(ngettext)
/* {{{ Plural version of dgettext() */ /* {{{ Plural version of dgettext() */
PHP_FUNCTION(dngettext) PHP_FUNCTION(dngettext)
{ {
char *domain, *msgid1, *msgid2, *msgstr = NULL; char *msgstr = NULL;
size_t domain_len, msgid1_len, msgid2_len; zend_string *domain, *msgid1, *msgid2;
zend_long count; zend_long count;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sssl", &domain, &domain_len, ZEND_PARSE_PARAMETERS_START(4, 4)
&msgid1, &msgid1_len, &msgid2, &msgid2_len, &count) == FAILURE) { Z_PARAM_STR(domain)
RETURN_THROWS(); Z_PARAM_STR(msgid1)
} Z_PARAM_STR(msgid2)
Z_PARAM_LONG(count)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, domain_len) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
PHP_GETTEXT_LENGTH_CHECK(2, msgid1_len) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid1))
PHP_GETTEXT_LENGTH_CHECK(3, msgid2_len) PHP_GETTEXT_LENGTH_CHECK(3, ZSTR_LEN(msgid2))
msgstr = dngettext(domain, msgid1, msgid2, count); msgstr = dngettext(ZSTR_VAL(domain), ZSTR_VAL(msgid1), ZSTR_VAL(msgid2), count);
ZEND_ASSERT(msgstr); ZEND_ASSERT(msgstr);
RETURN_STRING(msgstr); RETURN_STRING(msgstr);
@ -255,23 +269,26 @@ PHP_FUNCTION(dngettext)
/* {{{ Plural version of dcgettext() */ /* {{{ Plural version of dcgettext() */
PHP_FUNCTION(dcngettext) PHP_FUNCTION(dcngettext)
{ {
char *domain, *msgid1, *msgid2, *msgstr = NULL; char *msgstr = NULL;
size_t domain_len, msgid1_len, msgid2_len; zend_string *domain, *msgid1, *msgid2;
zend_long count, category; zend_long count, category;
RETVAL_FALSE; RETVAL_FALSE;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sssll", &domain, &domain_len, ZEND_PARSE_PARAMETERS_START(5, 5)
&msgid1, &msgid1_len, &msgid2, &msgid2_len, &count, &category) == FAILURE) { Z_PARAM_STR(domain)
RETURN_THROWS(); Z_PARAM_STR(msgid1)
} Z_PARAM_STR(msgid2)
Z_PARAM_LONG(count)
Z_PARAM_LONG(category)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, domain_len) PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
PHP_GETTEXT_LENGTH_CHECK(2, msgid1_len) PHP_GETTEXT_LENGTH_CHECK(2, ZSTR_LEN(msgid1))
PHP_GETTEXT_LENGTH_CHECK(3, msgid2_len) PHP_GETTEXT_LENGTH_CHECK(3, ZSTR_LEN(msgid2))
PHP_DCGETTEXT_CATEGORY_CHECK(5, category) PHP_DCGETTEXT_CATEGORY_CHECK(5, category)
msgstr = dcngettext(domain, msgid1, msgid2, count, category); msgstr = dcngettext(ZSTR_VAL(domain), ZSTR_VAL(msgid1), ZSTR_VAL(msgid2), count, category);
ZEND_ASSERT(msgstr); ZEND_ASSERT(msgstr);
RETURN_STRING(msgstr); RETURN_STRING(msgstr);
@ -284,16 +301,23 @@ PHP_FUNCTION(dcngettext)
/* {{{ Specify the character encoding in which the messages from the DOMAIN message catalog will be returned. */ /* {{{ Specify the character encoding in which the messages from the DOMAIN message catalog will be returned. */
PHP_FUNCTION(bind_textdomain_codeset) PHP_FUNCTION(bind_textdomain_codeset)
{ {
char *domain, *codeset = NULL, *retval = NULL; char *retval = NULL;
size_t domain_len, codeset_len; zend_string *domain, *codeset = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss!", &domain, &domain_len, &codeset, &codeset_len) == FAILURE) { ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(domain)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_NULL(codeset)
ZEND_PARSE_PARAMETERS_END();
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, ZSTR_LEN(domain))
if (!ZSTR_LEN(domain)) {
zend_argument_value_error(1, "cannot be empty");
RETURN_THROWS(); RETURN_THROWS();
} }
PHP_GETTEXT_DOMAIN_LENGTH_CHECK(1, domain_len) retval = bind_textdomain_codeset(ZSTR_VAL(domain), codeset ? ZSTR_VAL(codeset) : NULL);
retval = bind_textdomain_codeset(domain, codeset);
if (!retval) { if (!retval) {
RETURN_FALSE; RETURN_FALSE;

View file

@ -3,7 +3,7 @@
/** @generate-class-entries */ /** @generate-class-entries */
/** @refcount 1 */ /** @refcount 1 */
function textdomain(?string $domain): string {} function textdomain(?string $domain = null): string {}
/** @refcount 1 */ /** @refcount 1 */
function gettext(string $message): string {} function gettext(string $message): string {}
@ -18,7 +18,7 @@ function dgettext(string $domain, string $message): string {}
function dcgettext(string $domain, string $message, int $category): string {} function dcgettext(string $domain, string $message, int $category): string {}
/** @refcount 1 */ /** @refcount 1 */
function bindtextdomain(string $domain, ?string $directory): string|false {} function bindtextdomain(string $domain, ?string $directory = null): string|false {}
#ifdef HAVE_NGETTEXT #ifdef HAVE_NGETTEXT
/** @refcount 1 */ /** @refcount 1 */
@ -37,5 +37,5 @@ function dcngettext(string $domain, string $singular, string $plural, int $count
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
/** @refcount 1 */ /** @refcount 1 */
function bind_textdomain_codeset(string $domain, ?string $codeset): string|false {} function bind_textdomain_codeset(string $domain, ?string $codeset = null): string|false {}
#endif #endif

View file

@ -1,8 +1,8 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 864b3389d4f99b0d7302ae399544e6fb9fb80b7e */ * Stub hash: c675dc9492943bbac106c5906b75c31436964423 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_textdomain, 0, 1, IS_STRING, 0) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_textdomain, 0, 0, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, domain, IS_STRING, 1, "null")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gettext, 0, 1, IS_STRING, 0) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gettext, 0, 1, IS_STRING, 0)
@ -22,9 +22,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_dcgettext, 0, 3, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, category, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, category, IS_LONG, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_bindtextdomain, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_bindtextdomain, 0, 1, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, directory, IS_STRING, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, directory, IS_STRING, 1, "null")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#if defined(HAVE_NGETTEXT) #if defined(HAVE_NGETTEXT)
@ -55,9 +55,9 @@ ZEND_END_ARG_INFO()
#endif #endif
#if defined(HAVE_BIND_TEXTDOMAIN_CODESET) #if defined(HAVE_BIND_TEXTDOMAIN_CODESET)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_bind_textdomain_codeset, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_bind_textdomain_codeset, 0, 1, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, domain, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, codeset, IS_STRING, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, codeset, IS_STRING, 1, "null")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
#endif #endif

View file

@ -19,6 +19,12 @@ echo textdomain('test'), "\n";
echo textdomain(null), "\n"; echo textdomain(null), "\n";
echo textdomain('foo'), "\n"; echo textdomain('foo'), "\n";
try {
textdomain('0');
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try { try {
textdomain(''); textdomain('');
} catch (\ValueError $e) { } catch (\ValueError $e) {
@ -29,6 +35,7 @@ try {
test test
test test
foo foo
textdomain(): Argument #1 ($domain) cannot be zero
textdomain(): Argument #1 ($domain) cannot be empty textdomain(): Argument #1 ($domain) cannot be empty
--CREDITS-- --CREDITS--
Christian Weiske, cweiske@php.net Christian Weiske, cweiske@php.net