Browse Source

Improved setlocale(). Eliminated locale comparison in ext/pcre if it's not necessary.

pull/954/merge
Dmitry Stogov 11 years ago
parent
commit
4514ba016f
  1. 44
      ext/pcre/php_pcre.c
  2. 2
      ext/pcre/php_pcre.h
  3. 4
      ext/standard/basic_functions.c
  4. 2
      ext/standard/basic_functions.h
  5. 67
      ext/standard/string.c

44
ext/pcre/php_pcre.c

@ -23,6 +23,7 @@
#include "php_globals.h"
#include "php_pcre.h"
#include "ext/standard/info.h"
#include "ext/standard/basic_functions.h"
#include "zend_smart_str.h"
#if HAVE_PCRE || HAVE_BUNDLED_PCRE
@ -96,7 +97,9 @@ static void php_free_pcre_cache(zval *data) /* {{{ */
}
#if HAVE_SETLOCALE
if ((void*)pce->tables) pefree((void*)pce->tables, 1);
pefree(pce->locale, 1);
if (pce->locale) {
zend_string_release(pce->locale);
}
#endif
pefree(pce, 1);
}
@ -238,41 +241,24 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
int do_study = 0;
int poptions = 0;
unsigned const char *tables = NULL;
#if HAVE_SETLOCALE
char *locale;
#endif
pcre_cache_entry *pce;
pcre_cache_entry new_entry;
int rc;
#if HAVE_SETLOCALE
# if defined(PHP_WIN32) && defined(ZTS)
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
# endif
locale = setlocale(LC_CTYPE, NULL);
#endif
/* Try to lookup the cached regex entry, and if successful, just pass
back the compiled pattern, otherwise go on and compile it. */
pce = zend_hash_find_ptr(&PCRE_G(pcre_cache), regex);
if (pce) {
/*
* We use a quick pcre_fullinfo() check to see whether cache is corrupted, and if it
* is, we flush it and compile the pattern from scratch.
*/
//??? int count = 0;
//???
//??? if (pcre_fullinfo(pce->re, NULL, PCRE_INFO_CAPTURECOUNT, &count) == PCRE_ERROR_BADMAGIC) {
//??? zend_hash_clean(&PCRE_G(pcre_cache));
//??? } else {
#if HAVE_SETLOCALE
if (!strcmp(pce->locale, locale)) {
#endif
return pce;
#if HAVE_SETLOCALE
}
if (pce->locale == BG(locale_string) ||
(pce->locale && BG(locale_string) &&
pce->locale->len == BG(locale_string)->len &&
!memcmp(pce->locale->val, BG(locale_string)->val, pce->locale->len))) {
return pce;
}
#else
return pce;
#endif
//??? }
}
p = regex->val;
@ -389,8 +375,10 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
}
#if HAVE_SETLOCALE
if (strcmp(locale, "C"))
if (BG(locale_string) &&
(!BG(locale_string)->len != 1 || !BG(locale_string)->val[0] != 'C')) {
tables = pcre_maketables();
}
#endif
/* Compile pattern and display a warning if compilation failed. */
@ -451,7 +439,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex)
new_entry.preg_options = poptions;
new_entry.compile_options = coptions;
#if HAVE_SETLOCALE
new_entry.locale = pestrdup(locale, 1);
new_entry.locale = BG(locale_string) ? zend_string_dup(BG(locale_string), 1) : NULL;
new_entry.tables = tables;
#endif

2
ext/pcre/php_pcre.h

@ -47,7 +47,7 @@ typedef struct {
int capture_count;
int name_count;
#if HAVE_SETLOCALE
char *locale;
zend_string *locale;
unsigned const char *tables;
#endif
int compile_options;

4
ext/standard/basic_functions.c

@ -3760,9 +3760,7 @@ PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */
setlocale(LC_ALL, "C");
setlocale(LC_CTYPE, "");
zend_update_current_locale();
}
if (BG(locale_string)) {
efree(BG(locale_string));
zend_string_release(BG(locale_string));
BG(locale_string) = NULL;
}

2
ext/standard/basic_functions.h

@ -168,7 +168,7 @@ typedef struct _php_basic_globals {
HashTable putenv_ht;
zval strtok_zval;
char *strtok_string;
char *locale_string;
zend_string *locale_string;
char *strtok_last;
char strtok_table[256];
zend_ulong strtok_len;

67
ext/standard/string.c

@ -4184,8 +4184,9 @@ PHP_FUNCTION(setlocale)
{
zval *args = NULL;
zval *pcategory, *plocale;
zend_string *loc;
char *retval;
int num_args, cat, i = 0;
char *loc, *retval;
HashPosition pos;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z+", &pcategory, &args, &num_args) == FAILURE) {
@ -4197,38 +4198,32 @@ PHP_FUNCTION(setlocale)
cat = (int)Z_LVAL_P(pcategory);
} else {
/* FIXME: The following behaviour should be removed. */
char *category;
zval tmp;
zend_string *category = zval_get_string(pcategory);
php_error_docref(NULL, E_DEPRECATED, "Passing locale category name as string is deprecated. Use the LC_* -constants instead");
ZVAL_DUP(&tmp, pcategory);
convert_to_string_ex(&tmp);
category = Z_STRVAL(tmp);
if (!strcasecmp("LC_ALL", category)) {
if (!strcasecmp("LC_ALL", category->val)) {
cat = LC_ALL;
} else if (!strcasecmp("LC_COLLATE", category)) {
} else if (!strcasecmp("LC_COLLATE", category->val)) {
cat = LC_COLLATE;
} else if (!strcasecmp("LC_CTYPE", category)) {
} else if (!strcasecmp("LC_CTYPE", category->val)) {
cat = LC_CTYPE;
#ifdef LC_MESSAGES
} else if (!strcasecmp("LC_MESSAGES", category)) {
} else if (!strcasecmp("LC_MESSAGES", category->val)) {
cat = LC_MESSAGES;
#endif
} else if (!strcasecmp("LC_MONETARY", category)) {
} else if (!strcasecmp("LC_MONETARY", category->val)) {
cat = LC_MONETARY;
} else if (!strcasecmp("LC_NUMERIC", category)) {
} else if (!strcasecmp("LC_NUMERIC", category->val)) {
cat = LC_NUMERIC;
} else if (!strcasecmp("LC_TIME", category)) {
} else if (!strcasecmp("LC_TIME", category->val)) {
cat = LC_TIME;
} else {
php_error_docref(NULL, E_WARNING, "Invalid locale category name %s, must be one of LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, or LC_TIME", category);
php_error_docref(NULL, E_WARNING, "Invalid locale category name %s, must be one of LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, or LC_TIME", category->val);
zval_dtor(&tmp);
zend_string_release(category);
RETURN_FALSE;
}
zval_dtor(&tmp);
zend_string_release(category);
}
if (Z_TYPE(args[0]) == IS_ARRAY) {
@ -4236,7 +4231,6 @@ PHP_FUNCTION(setlocale)
}
while (1) {
zval tmp;
if (Z_TYPE(args[0]) == IS_ARRAY) {
if (!zend_hash_num_elements(Z_ARRVAL(args[0]))) {
break;
@ -4248,36 +4242,41 @@ PHP_FUNCTION(setlocale)
plocale = &args[i];
}
ZVAL_DUP(&tmp, plocale);
convert_to_string(&tmp);
loc = zval_get_string(plocale);
if (!strcmp ("0", Z_STRVAL(tmp))) {
if (!strcmp("0", loc->val)) {
zend_string_release(loc);
loc = NULL;
} else {
loc = Z_STRVAL(tmp);
if (Z_STRLEN(tmp) >= 255) {
if (loc->len >= 255) {
php_error_docref(NULL, E_WARNING, "Specified locale name is too long");
zval_dtor(&tmp);
zend_string_release(loc);
break;
}
}
retval = php_my_setlocale(cat, loc);
retval = php_my_setlocale(cat, loc ? loc->val : NULL);
zend_update_current_locale();
if (retval) {
/* Remember if locale was changed */
if (loc) {
//??? zend_string_free(BG(locale_string));
/* Remember if locale was changed */
size_t len;
if (BG(locale_string)) {
efree(BG(locale_string));
zend_string_release(BG(locale_string));
}
len = strlen(retval);
if (len == loc->len && !memcmp(loc->val, retval, len)) {
BG(locale_string) = zend_string_copy(loc);
} else {
BG(locale_string) = zend_string_init(retval, len, 0);
}
BG(locale_string) = estrdup(retval);
}
zval_dtor(&tmp);
RETURN_STRING(retval);
zend_string_release(loc);
}
RETURN_STR(zend_string_copy(BG(locale_string)));
}
zval_dtor(&tmp);
zend_string_release(loc);
if (Z_TYPE(args[0]) == IS_ARRAY) {
if (zend_hash_move_forward_ex(Z_ARRVAL(args[0]), &pos) == FAILURE) break;

Loading…
Cancel
Save