2008-07-07 22:51:04 +00:00
|
|
|
|
/*
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
| PHP Version 5 |
|
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
|
|
|
| available through the world-wide-web at the following url: |
|
|
|
|
|
| http://www.php.net/license/3_01.txt |
|
|
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
|
|
|
+----------------------------------------------------------------------+
|
2008-08-03 11:33:45 +00:00
|
|
|
|
| Authors: Kirti Velankar <kirtig@yahoo-inc.com> |
|
2008-07-07 22:51:04 +00:00
|
|
|
|
+----------------------------------------------------------------------+
|
2008-08-03 11:33:45 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* $Id$ */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <unicode/ustring.h>
|
|
|
|
|
#include <unicode/udata.h>
|
|
|
|
|
#include <unicode/putil.h>
|
2008-07-23 01:15:33 +00:00
|
|
|
|
#include <unicode/ures.h>
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
#include "php_intl.h"
|
|
|
|
|
#include "locale.h"
|
|
|
|
|
#include "locale_class.h"
|
|
|
|
|
#include "locale_methods.h"
|
|
|
|
|
#include "intl_convert.h"
|
2008-07-23 01:15:33 +00:00
|
|
|
|
#include "intl_data.h"
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
#include <zend_API.h>
|
|
|
|
|
#include <zend.h>
|
|
|
|
|
#include <php.h>
|
|
|
|
|
#include "main/php_ini.h"
|
2008-07-23 19:44:51 +00:00
|
|
|
|
#include "ext/standard/php_smart_str.h"
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
ZEND_EXTERN_MODULE_GLOBALS( intl )
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Sizes required for the strings "variant15" , "extlang11", "private12" etc. */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
#define SEPARATOR "_"
|
|
|
|
|
#define SEPARATOR1 "-"
|
|
|
|
|
#define DELIMITER "-_"
|
|
|
|
|
#define EXTLANG_PREFIX "a"
|
|
|
|
|
#define PRIVATE_PREFIX "x"
|
|
|
|
|
#define DISP_NAME "name"
|
|
|
|
|
|
|
|
|
|
#define MAX_NO_VARIANT 15
|
|
|
|
|
#define MAX_NO_EXTLANG 3
|
|
|
|
|
#define MAX_NO_PRIVATE 15
|
|
|
|
|
#define MAX_NO_LOOKUP_LANG_TAG 100
|
|
|
|
|
|
2008-07-23 19:44:51 +00:00
|
|
|
|
#define LOC_NOT_FOUND 1
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Sizes required for the strings "variant15" , "extlang3", "private12" etc. */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
#define VARIANT_KEYNAME_LEN 11
|
|
|
|
|
#define EXTLANG_KEYNAME_LEN 10
|
|
|
|
|
#define PRIVATE_KEYNAME_LEN 11
|
|
|
|
|
|
|
|
|
|
/* Based on IANA registry at the time of writing this code
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static const char * const LOC_GRANDFATHERED[] = {
|
|
|
|
|
"art-lojban", "i-klingon", "i-lux", "i-navajo", "no-bok", "no-nyn",
|
|
|
|
|
"cel-gaulish", "en-GB-oed", "i-ami",
|
|
|
|
|
"i-bnn", "i-default", "i-enochian",
|
|
|
|
|
"i-mingo", "i-pwn", "i-tao",
|
|
|
|
|
"i-tay", "i-tsu", "sgn-BE-fr",
|
|
|
|
|
"sgn-BE-nl", "sgn-CH-de", "zh-cmn",
|
|
|
|
|
"zh-cmn-Hans", "zh-cmn-Hant", "zh-gan" ,
|
|
|
|
|
"zh-guoyu", "zh-hakka", "zh-min",
|
|
|
|
|
"zh-min-nan", "zh-wuu", "zh-xiang",
|
|
|
|
|
"zh-yue", NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Based on IANA registry at the time of writing this code
|
|
|
|
|
* This array lists the preferred values for the grandfathered tags if applicable
|
|
|
|
|
* This is in sync with the array LOC_GRANDFATHERED
|
|
|
|
|
* e.g. the offsets of the grandfathered tags match the offset of the preferred value
|
|
|
|
|
*/
|
|
|
|
|
static const int LOC_PREFERRED_GRANDFATHERED_LEN = 6;
|
|
|
|
|
static const char * const LOC_PREFERRED_GRANDFATHERED[] = {
|
|
|
|
|
"jbo", "tlh", "lb",
|
|
|
|
|
"nv", "nb", "nn",
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*returns TRUE if a is an ID separator FALSE otherwise*/
|
|
|
|
|
#define isIDSeparator(a) (a == '_' || a == '-')
|
|
|
|
|
#define isKeywordSeparator(a) (a == '@' )
|
|
|
|
|
#define isEndOfTag(a) (a == '\0' )
|
|
|
|
|
|
|
|
|
|
#define isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
|
|
|
|
|
|
|
|
|
|
/*returns TRUE if one of the special prefixes is here (s=string)
|
|
|
|
|
'x-' or 'i-' */
|
|
|
|
|
#define isIDPrefix(s) (isPrefixLetter(s[0])&&isIDSeparator(s[1]))
|
|
|
|
|
#define isKeywordPrefix(s) ( isKeywordSeparator(s[0]) )
|
|
|
|
|
|
|
|
|
|
/* Dot terminates it because of POSIX form where dot precedes the codepage
|
2008-08-03 11:33:45 +00:00
|
|
|
|
* except for variant */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
#define isTerminator(a) ((a==0)||(a=='.')||(a=='@'))
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* {{{ return the offset of 'key' in the array 'list'.
|
|
|
|
|
* returns -1 if not present */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
static int16_t findOffset(const char* const* list, const char* key)
|
|
|
|
|
{
|
2008-08-03 11:33:45 +00:00
|
|
|
|
const char* const* anchor = list;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
while (*list != NULL) {
|
|
|
|
|
if (strcmp(key, *list) == 0) {
|
|
|
|
|
return (int16_t)(list - anchor);
|
|
|
|
|
}
|
|
|
|
|
list++;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
return -1;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
|
|
static char* getPreferredTag(char* gf_tag)
|
|
|
|
|
{
|
|
|
|
|
char* result = NULL;
|
|
|
|
|
int grOffset = 0;
|
|
|
|
|
|
|
|
|
|
grOffset = findOffset( LOC_GRANDFATHERED ,gf_tag);
|
|
|
|
|
if( grOffset < LOC_PREFERRED_GRANDFATHERED_LEN ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* return preferred tag */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result = estrdup( LOC_PREFERRED_GRANDFATHERED[grOffset] );
|
|
|
|
|
} else {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Return correct grandfathered language tag */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result = estrdup( LOC_GRANDFATHERED[grOffset] );
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* {{{
|
|
|
|
|
* returns the position of next token for lookup
|
|
|
|
|
* or -1 if no token
|
|
|
|
|
* strtokr equivalent search for token in reverse direction
|
|
|
|
|
*/
|
|
|
|
|
static int getStrrtokenPos(char* str, int savedPos)
|
|
|
|
|
{
|
|
|
|
|
int result =-1;
|
2009-07-02 00:43:26 +00:00
|
|
|
|
int i;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 22:36:16 +00:00
|
|
|
|
for(i=savedPos-1; i>=0; i--) {
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(isIDSeparator(*(str+i)) ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* delimiter found; check for singleton */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(i>=2 && isIDSeparator(*(str+i-2)) ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* a singleton; so send the position of token before the singleton */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
result = i-2;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
} else {
|
2009-07-02 00:43:26 +00:00
|
|
|
|
result = i;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(result < 1){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Just in case inavlid locale e.g. '-x-xyz' or '-sl_Latn' */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result =-1;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{
|
|
|
|
|
* returns the position of a singleton if present
|
|
|
|
|
* returns -1 if no singleton
|
|
|
|
|
* strtok equivalent search for singleton
|
|
|
|
|
*/
|
|
|
|
|
static int getSingletonPos(char* str)
|
|
|
|
|
{
|
|
|
|
|
int result =-1;
|
|
|
|
|
int i=0;
|
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
|
|
if( str && ((len=strlen(str))>0) ){
|
|
|
|
|
for( i=0; i<len ; i++){
|
|
|
|
|
if( isIDSeparator(*(str+i)) ){
|
|
|
|
|
if( i==1){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* string is of the form x-avy or a-prv1 */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result =0;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* delimiter found; check for singleton */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( isIDSeparator(*(str+i+2)) ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* a singleton; so send the position of separator before singleton */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result = i+1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
}/* end of for */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ proto static string Locale::getDefault( )
|
2008-08-03 11:33:45 +00:00
|
|
|
|
Get default locale */
|
|
|
|
|
/* }}} */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
/* {{{ proto static string locale_get_default( )
|
2008-08-03 11:33:45 +00:00
|
|
|
|
Get default locale */
|
|
|
|
|
PHP_NAMED_FUNCTION(zif_locale_get_default)
|
|
|
|
|
{
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( INTL_G(default_locale) == NULL ) {
|
|
|
|
|
INTL_G(default_locale) = pestrdup( uloc_getDefault(), 1);
|
|
|
|
|
}
|
|
|
|
|
RETURN_STRING( INTL_G(default_locale), TRUE );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ proto static string Locale::setDefault( string $locale )
|
2008-08-03 11:33:45 +00:00
|
|
|
|
Set default locale */
|
|
|
|
|
/* }}} */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
/* {{{ proto static string locale_set_default( string $locale )
|
2008-08-03 11:33:45 +00:00
|
|
|
|
Set default locale */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
PHP_NAMED_FUNCTION(zif_locale_set_default)
|
|
|
|
|
{
|
|
|
|
|
char* locale_name = NULL;
|
|
|
|
|
int len=0;
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
|
|
|
|
|
&locale_name ,&len ) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_set_default: unable to parse input params", 0 TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(len == 0) {
|
|
|
|
|
locale_name = (char *)uloc_getDefault() ;
|
|
|
|
|
len = strlen(locale_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zend_alter_ini_entry(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME), locale_name, len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
|
|
|
|
|
|
|
|
|
|
RETURN_TRUE;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{
|
|
|
|
|
* Gets the value from ICU
|
|
|
|
|
* common code shared by get_primary_language,get_script or get_region or get_variant
|
|
|
|
|
* result = 0 if error, 1 if successful , -1 if no value
|
|
|
|
|
*/
|
|
|
|
|
static char* get_icu_value_internal( char* loc_name , char* tag_name, int* result , int fromParseLocale)
|
|
|
|
|
{
|
|
|
|
|
char* tag_value = NULL;
|
|
|
|
|
int32_t tag_value_len = 512;
|
|
|
|
|
|
|
|
|
|
int singletonPos = 0;
|
|
|
|
|
char* mod_loc_name = NULL;
|
|
|
|
|
int grOffset = 0;
|
|
|
|
|
|
|
|
|
|
int32_t buflen = 512;
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( tag_name != LOC_CANONICALIZE_TAG ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Handle grandfathered languages */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
|
|
|
|
|
if( grOffset >= 0 ){
|
|
|
|
|
if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
|
|
|
|
|
tag_value = estrdup(loc_name);
|
|
|
|
|
return tag_value;
|
|
|
|
|
} else {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Since Grandfathered , no value , do nothing , retutn NULL */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( fromParseLocale==1 ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Handle singletons */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
|
|
|
|
|
if( strlen(loc_name)>1 && (isIDPrefix(loc_name) ==1 ) ){
|
|
|
|
|
return loc_name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
singletonPos = getSingletonPos( loc_name );
|
|
|
|
|
if( singletonPos == 0){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* singleton at start of script, region , variant etc.
|
|
|
|
|
* or invalid singleton at start of language */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
} else if( singletonPos > 0 ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* singleton at some position except at start
|
|
|
|
|
* strip off the singleton and rest of the loc_name */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
mod_loc_name = estrndup ( loc_name , singletonPos-1);
|
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of if fromParse */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of if != LOC_CANONICAL_TAG */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
if( mod_loc_name == NULL){
|
|
|
|
|
mod_loc_name = estrdup(loc_name );
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Proceed to ICU */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
do{
|
2008-08-03 11:33:45 +00:00
|
|
|
|
tag_value = erealloc( tag_value , buflen );
|
|
|
|
|
tag_value_len = buflen;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getScript ( mod_loc_name ,tag_value , tag_value_len , &status);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
if( strcmp(tag_name , LOC_LANG_TAG )==0 ){
|
|
|
|
|
buflen = uloc_getLanguage ( mod_loc_name ,tag_value , tag_value_len , &status);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getCountry ( mod_loc_name ,tag_value , tag_value_len , &status);
|
|
|
|
|
}
|
|
|
|
|
if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getVariant ( mod_loc_name ,tag_value , tag_value_len , &status);
|
|
|
|
|
}
|
|
|
|
|
if( strcmp(tag_name , LOC_CANONICALIZE_TAG)==0 ){
|
|
|
|
|
buflen = uloc_canonicalize ( mod_loc_name ,tag_value , tag_value_len , &status);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
if( U_FAILURE( status ) ) {
|
|
|
|
|
if( status == U_BUFFER_OVERFLOW_ERROR ) {
|
|
|
|
|
status = U_ZERO_ERROR;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Error in retriving data */
|
|
|
|
|
*result = 0;
|
|
|
|
|
if( tag_value ){
|
|
|
|
|
efree( tag_value );
|
|
|
|
|
}
|
|
|
|
|
if( mod_loc_name ){
|
|
|
|
|
efree( mod_loc_name);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} while( buflen > tag_value_len );
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
if( buflen ==0 ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* No value found */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
*result = -1;
|
|
|
|
|
if( tag_value ){
|
|
|
|
|
efree( tag_value );
|
|
|
|
|
}
|
|
|
|
|
if( mod_loc_name ){
|
|
|
|
|
efree( mod_loc_name);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
} else {
|
|
|
|
|
*result = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( mod_loc_name ){
|
|
|
|
|
efree( mod_loc_name);
|
|
|
|
|
}
|
|
|
|
|
return tag_value;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{
|
|
|
|
|
* Gets the value from ICU , called when PHP userspace function is called
|
|
|
|
|
* common code shared by get_primary_language,get_script or get_region or get_variant
|
|
|
|
|
*/
|
|
|
|
|
static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
char* loc_name = NULL;
|
|
|
|
|
int loc_name_len = 0;
|
|
|
|
|
|
|
|
|
|
char* tag_value = NULL;
|
|
|
|
|
char* empty_result = "";
|
|
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
char* msg = NULL;
|
|
|
|
|
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
|
|
|
|
|
&loc_name ,&loc_name_len ) == FAILURE) {
|
|
|
|
|
spprintf(&msg , 0, "locale_get_%s : unable to parse input params", tag_name );
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, msg , 1 TSRMLS_CC );
|
|
|
|
|
efree(msg);
|
|
|
|
|
|
|
|
|
|
RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_name_len == 0) {
|
|
|
|
|
loc_name = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Call ICU get */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
tag_value = get_icu_value_internal( loc_name , tag_name , &result ,0);
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* No value found */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( result == -1 ) {
|
|
|
|
|
if( tag_value){
|
|
|
|
|
efree( tag_value);
|
|
|
|
|
}
|
|
|
|
|
RETURN_STRING( empty_result , TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* value found */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( tag_value){
|
|
|
|
|
RETURN_STRING( tag_value , FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Error encountered while fetching the value */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( result ==0) {
|
|
|
|
|
spprintf(&msg , 0, "locale_get_%s : unable to get locale %s", tag_name , tag_name );
|
|
|
|
|
intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
|
|
|
|
|
efree(msg);
|
|
|
|
|
RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getScript($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the script for the $locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string locale_get_script($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the script for the $locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION( locale_get_script )
|
|
|
|
|
{
|
|
|
|
|
get_icu_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getRegion($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the region for the $locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string locale_get_region($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the region for the $locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION( locale_get_region )
|
|
|
|
|
{
|
|
|
|
|
get_icu_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getPrimaryLanguage($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the primary language for the $locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string locale_get_primary_language($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the primary language for the $locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_primary_language )
|
|
|
|
|
{
|
|
|
|
|
get_icu_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* {{{
|
|
|
|
|
* common code shared by display_xyz functions to get the value from ICU
|
|
|
|
|
}}} */
|
|
|
|
|
static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS)
|
|
|
|
|
{
|
|
|
|
|
char* loc_name = NULL;
|
|
|
|
|
int loc_name_len = 0;
|
|
|
|
|
|
|
|
|
|
char* disp_loc_name = NULL;
|
|
|
|
|
int disp_loc_name_len = 0;
|
|
|
|
|
|
|
|
|
|
UChar* disp_name = NULL;
|
|
|
|
|
int32_t disp_name_len = 0;
|
|
|
|
|
|
|
|
|
|
char* mod_loc_name = NULL;
|
|
|
|
|
|
|
|
|
|
int32_t buflen = 512;
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
|
|
char* utf8value = NULL;
|
|
|
|
|
int utf8value_len = 0;
|
|
|
|
|
|
|
|
|
|
char* msg = NULL;
|
|
|
|
|
int grOffset = 0;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
|
|
|
|
|
&loc_name, &loc_name_len ,
|
|
|
|
|
&disp_loc_name ,&disp_loc_name_len ) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
spprintf(&msg , 0, "locale_get_display_%s : unable to parse input params", tag_name );
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, msg , 1 TSRMLS_CC );
|
|
|
|
|
efree(msg);
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_name_len == 0) {
|
|
|
|
|
loc_name = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( tag_name != DISP_NAME ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Handle grandfathered languages */
|
|
|
|
|
grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( grOffset >= 0 ){
|
|
|
|
|
if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
|
|
|
|
|
mod_loc_name = getPreferredTag( loc_name );
|
|
|
|
|
} else {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Since Grandfathered, no value, do nothing, retutn NULL */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of if != LOC_CANONICAL_TAG */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
if( mod_loc_name==NULL ){
|
|
|
|
|
mod_loc_name = estrdup( loc_name );
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Get the disp_value for the given locale */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
do{
|
|
|
|
|
disp_name = erealloc( disp_name , buflen );
|
|
|
|
|
disp_name_len = buflen;
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Check if disp_loc_name passed , if not use default locale */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( !disp_loc_name){
|
|
|
|
|
disp_loc_name = estrdup(INTL_G(default_locale));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getDisplayLanguage ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
|
|
|
|
|
} else if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getDisplayScript ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
|
|
|
|
|
} else if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getDisplayCountry ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
|
|
|
|
|
} else if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
|
|
|
|
|
buflen = uloc_getDisplayVariant ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
|
|
|
|
|
} else if( strcmp(tag_name , DISP_NAME)==0 ){
|
|
|
|
|
buflen = uloc_getDisplayName ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( U_FAILURE( status ) )
|
|
|
|
|
{
|
|
|
|
|
if( status == U_BUFFER_OVERFLOW_ERROR )
|
|
|
|
|
{
|
|
|
|
|
status = U_ZERO_ERROR;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spprintf(&msg, 0, "locale_get_display_%s : unable to get locale %s", tag_name , tag_name );
|
|
|
|
|
intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
|
|
|
|
|
efree(msg);
|
|
|
|
|
if( disp_name){
|
|
|
|
|
efree( disp_name );
|
|
|
|
|
}
|
|
|
|
|
if( mod_loc_name){
|
|
|
|
|
efree( mod_loc_name );
|
|
|
|
|
}
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
} while( buflen > disp_name_len );
|
|
|
|
|
|
|
|
|
|
if( mod_loc_name){
|
|
|
|
|
efree( mod_loc_name );
|
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Convert display locale name from UTF-16 to UTF-8. */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
intl_convert_utf16_to_utf8( &utf8value, &utf8value_len, disp_name, buflen, &status );
|
|
|
|
|
efree( disp_name );
|
|
|
|
|
if( U_FAILURE( status ) )
|
|
|
|
|
{
|
|
|
|
|
spprintf(&msg, 0, "locale_get_display_%s :error converting display name for %s to UTF-8", tag_name , tag_name );
|
|
|
|
|
intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
|
|
|
|
|
efree(msg);
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RETVAL_STRINGL( utf8value, utf8value_len , FALSE);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getDisplayName($locale[, $in_locale = null])
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the name for the $locale in $in_locale or default_locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string get_display_name($locale[, $in_locale = null])
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the name for the $locale in $in_locale or default_locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_display_name)
|
|
|
|
|
{
|
|
|
|
|
get_icu_disp_value_src_php( DISP_NAME , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getDisplayLanguage($locale[, $in_locale = null])
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the language for the $locale in $in_locale or default_locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string get_display_language($locale[, $in_locale = null])
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the language for the $locale in $in_locale or default_locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_display_language)
|
|
|
|
|
{
|
|
|
|
|
get_icu_disp_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getDisplayScript($locale, $in_locale = null)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the script for the $locale in $in_locale or default_locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string get_display_script($locale, $in_locale = null)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the script for the $locale in $in_locale or default_locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_display_script)
|
|
|
|
|
{
|
|
|
|
|
get_icu_disp_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::getDisplayRegion($locale, $in_locale = null)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the region for the $locale in $in_locale or default_locale
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string get_display_region($locale, $in_locale = null)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the region for the $locale in $in_locale or default_locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_display_region)
|
|
|
|
|
{
|
|
|
|
|
get_icu_disp_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{
|
2008-07-23 01:15:33 +00:00
|
|
|
|
* proto static string Locale::getDisplayVariant($locale, $in_locale = null)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the variant for the $locale in $in_locale or default_locale
|
|
|
|
|
}}} */
|
|
|
|
|
/* {{{
|
2008-07-23 01:15:33 +00:00
|
|
|
|
* proto static string get_display_variant($locale, $in_locale = null)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* gets the variant for the $locale in $in_locale or default_locale
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_display_variant)
|
|
|
|
|
{
|
|
|
|
|
get_icu_disp_value_src_php( LOC_VARIANT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static array getKeywords(string $locale) {
|
|
|
|
|
* return an associative array containing keyword-value
|
|
|
|
|
* pairs for this locale. The keys are keys to the array (doh!)
|
|
|
|
|
* }}}*/
|
|
|
|
|
/* {{{ proto static array locale_get_keywords(string $locale) {
|
|
|
|
|
* return an associative array containing keyword-value
|
|
|
|
|
* pairs for this locale. The keys are keys to the array (doh!)
|
|
|
|
|
*/
|
2008-07-07 22:51:04 +00:00
|
|
|
|
PHP_FUNCTION( locale_get_keywords )
|
|
|
|
|
{
|
|
|
|
|
UEnumeration* e = NULL;
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
|
|
const char* kw_key = NULL;
|
|
|
|
|
int32_t kw_key_len = 0;
|
|
|
|
|
|
|
|
|
|
char* loc_name = NULL;
|
|
|
|
|
int loc_name_len = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
ICU expects the buffer to be allocated before calling the function
|
|
|
|
|
and so the buffer size has been explicitly specified
|
|
|
|
|
ICU uloc.h #define ULOC_KEYWORD_AND_VALUES_CAPACITY 100
|
|
|
|
|
hence the kw_value buffer size is 100
|
|
|
|
|
*/
|
|
|
|
|
char* kw_value = NULL;
|
|
|
|
|
int32_t kw_value_len = 100;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
|
|
|
|
|
&loc_name, &loc_name_len ) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_get_keywords: unable to parse input params", 0 TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_name_len == 0) {
|
|
|
|
|
loc_name = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Get the keywords */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
e = uloc_openKeywords( loc_name, &status );
|
|
|
|
|
if( e != NULL )
|
|
|
|
|
{
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Traverse it, filling the return array. */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
array_init( return_value );
|
|
|
|
|
|
|
|
|
|
while( ( kw_key = uenum_next( e, &kw_key_len, &status ) ) != NULL ){
|
|
|
|
|
kw_value = ecalloc( 1 , kw_value_len );
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Get the keyword value for each keyword */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len , &status );
|
|
|
|
|
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
|
|
|
|
status = U_ZERO_ERROR;
|
|
|
|
|
kw_value = erealloc( kw_value , kw_value_len+1);
|
|
|
|
|
kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len+1 , &status );
|
|
|
|
|
} else if(!U_FAILURE(status)) {
|
|
|
|
|
kw_value = erealloc( kw_value , kw_value_len+1);
|
|
|
|
|
}
|
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
|
intl_error_set( NULL, FAILURE, "locale_get_keywords: Error encountered while getting the keyword value for the keyword", 0 TSRMLS_CC );
|
|
|
|
|
if( kw_value){
|
|
|
|
|
efree( kw_value );
|
|
|
|
|
}
|
|
|
|
|
zval_dtor(return_value);
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add_assoc_stringl( return_value, (char *)kw_key, kw_value , kw_value_len, 0);
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of while */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of if e!=NULL */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
uenum_close( e );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::canonicalize($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* @return string the canonicalized locale
|
|
|
|
|
* }}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string locale_canonicalize(Locale $loc, string $locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* @param string $locale The locale string to canonicalize
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_canonicalize)
|
|
|
|
|
{
|
|
|
|
|
get_icu_value_src_php( LOC_CANONICALIZE_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ append_key_value
|
|
|
|
|
* Internal function which is called from locale_compose
|
|
|
|
|
* gets the value for the key_name and appends to the loc_name
|
|
|
|
|
* returns 1 if successful , -1 if not found ,
|
|
|
|
|
* 0 if array element is not a string , -2 if buffer-overflow
|
|
|
|
|
*/
|
2008-07-23 19:44:51 +00:00
|
|
|
|
static int append_key_value(smart_str* loc_name, HashTable* hash_arr, char* key_name)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
{
|
|
|
|
|
zval** ele_value = NULL;
|
|
|
|
|
|
2008-07-23 19:44:51 +00:00
|
|
|
|
if(zend_hash_find(hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
|
|
|
|
|
if(Z_TYPE_PP(ele_value)!= IS_STRING ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* element value is not a string */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
return FAILURE;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-07-23 19:44:51 +00:00
|
|
|
|
if(strcmp(key_name, LOC_LANG_TAG) != 0 &&
|
|
|
|
|
strcmp(key_name, LOC_GRANDFATHERED_LANG_TAG)!=0 ) {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* not lang or grandfathered tag */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-07-23 19:44:51 +00:00
|
|
|
|
smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
|
|
|
|
|
return SUCCESS;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-23 19:44:51 +00:00
|
|
|
|
return LOC_NOT_FOUND;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ append_prefix , appends the prefix needed
|
|
|
|
|
* e.g. private adds 'x'
|
|
|
|
|
*/
|
2008-07-23 19:44:51 +00:00
|
|
|
|
static void add_prefix(smart_str* loc_name, char* key_name)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
{
|
|
|
|
|
if( strncmp(key_name , LOC_PRIVATE_TAG , 7) == 0 ){
|
2008-07-23 19:44:51 +00:00
|
|
|
|
smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
|
|
|
|
|
smart_str_appendl(loc_name, PRIVATE_PREFIX , sizeof(PRIVATE_PREFIX)-1);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ append_multiple_key_values
|
|
|
|
|
* Internal function which is called from locale_compose
|
|
|
|
|
* gets the multiple values for the key_name and appends to the loc_name
|
|
|
|
|
* used for 'variant','extlang','private'
|
|
|
|
|
* returns 1 if successful , -1 if not found ,
|
|
|
|
|
* 0 if array element is not a string , -2 if buffer-overflow
|
|
|
|
|
*/
|
2008-07-25 12:41:57 +00:00
|
|
|
|
static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, char* key_name TSRMLS_DC)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
{
|
|
|
|
|
zval** ele_value = NULL;
|
|
|
|
|
int i = 0;
|
|
|
|
|
int isFirstSubtag = 0;
|
|
|
|
|
int max_value = 0;
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Variant/ Extlang/Private etc. */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
if( zend_hash_find( hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
|
|
|
|
|
if( Z_TYPE_PP(ele_value) == IS_STRING ){
|
|
|
|
|
add_prefix( loc_name , key_name);
|
|
|
|
|
|
|
|
|
|
smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
|
|
|
|
|
smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
|
|
|
|
|
return SUCCESS;
|
|
|
|
|
} else if(Z_TYPE_PP(ele_value) == IS_ARRAY ) {
|
|
|
|
|
HashPosition pos;
|
|
|
|
|
HashTable *arr = HASH_OF(*ele_value);
|
|
|
|
|
zval **data = NULL;
|
|
|
|
|
|
|
|
|
|
zend_hash_internal_pointer_reset_ex(arr, &pos);
|
|
|
|
|
while(zend_hash_get_current_data_ex(arr, (void **)&data, &pos) != FAILURE) {
|
|
|
|
|
if(Z_TYPE_PP(data) != IS_STRING) {
|
|
|
|
|
return FAILURE;
|
|
|
|
|
}
|
|
|
|
|
if (isFirstSubtag++ == 0){
|
|
|
|
|
add_prefix(loc_name , key_name);
|
|
|
|
|
}
|
|
|
|
|
smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
|
|
|
|
|
smart_str_appendl(loc_name, Z_STRVAL_PP(data) , Z_STRLEN_PP(data));
|
|
|
|
|
zend_hash_move_forward_ex(arr, &pos);
|
|
|
|
|
}
|
|
|
|
|
return SUCCESS;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
} else {
|
2008-07-23 19:44:51 +00:00
|
|
|
|
return FAILURE;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2008-07-23 19:44:51 +00:00
|
|
|
|
char cur_key_name[31];
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Decide the max_value: the max. no. of elements allowed */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( strcmp(key_name , LOC_VARIANT_TAG) ==0 ){
|
|
|
|
|
max_value = MAX_NO_VARIANT;
|
|
|
|
|
}
|
|
|
|
|
if( strcmp(key_name , LOC_EXTLANG_TAG) ==0 ){
|
|
|
|
|
max_value = MAX_NO_EXTLANG;
|
|
|
|
|
}
|
|
|
|
|
if( strcmp(key_name , LOC_PRIVATE_TAG) ==0 ){
|
|
|
|
|
max_value = MAX_NO_PRIVATE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Multiple variant values as variant0, variant1 ,variant2 */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
isFirstSubtag = 0;
|
|
|
|
|
for( i=0 ; i< max_value; i++ ){
|
2008-07-23 19:44:51 +00:00
|
|
|
|
snprintf( cur_key_name , 30, "%s%d", key_name , i);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( zend_hash_find( hash_arr , cur_key_name , strlen(cur_key_name) + 1,(void **)&ele_value ) == SUCCESS ){
|
|
|
|
|
if( Z_TYPE_PP(ele_value)!= IS_STRING ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* variant is not a string */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
return FAILURE;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Add the contents */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if (isFirstSubtag++ == 0){
|
2008-07-23 19:44:51 +00:00
|
|
|
|
add_prefix(loc_name , cur_key_name);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-07-23 19:44:51 +00:00
|
|
|
|
smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
|
|
|
|
|
smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of for */
|
|
|
|
|
} /* end of else */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-07-23 19:44:51 +00:00
|
|
|
|
return SUCCESS;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/*{{{
|
|
|
|
|
* If applicable sets error message and aborts locale_compose gracefully
|
|
|
|
|
* returns 0 if locale_compose needs to be aborted
|
|
|
|
|
* otherwise returns 1
|
|
|
|
|
*/
|
2008-07-23 19:44:51 +00:00
|
|
|
|
static int handleAppendResult( int result, smart_str* loc_name TSRMLS_DC)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
{
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
2008-07-23 19:44:51 +00:00
|
|
|
|
if( result == FAILURE) {
|
2008-07-07 22:51:04 +00:00
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
2008-07-23 19:44:51 +00:00
|
|
|
|
"locale_compose: parameter array element is not a string", 0 TSRMLS_CC );
|
|
|
|
|
smart_str_free(loc_name);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2008-07-23 19:44:51 +00:00
|
|
|
|
#define RETURN_SMART_STR(s) smart_str_0((s)); RETURN_STRINGL((s)->c, (s)->len, 0)
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string Locale::composeLocale($array)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* Creates a locale by combining the parts of locale-ID passed
|
|
|
|
|
* }}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static string compose_locale($array)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* Creates a locale by combining the parts of locale-ID passed
|
|
|
|
|
* }}} */
|
|
|
|
|
PHP_FUNCTION(locale_compose)
|
|
|
|
|
{
|
2008-07-23 19:44:51 +00:00
|
|
|
|
smart_str loc_name_s = {0};
|
|
|
|
|
smart_str *loc_name = &loc_name_s;
|
|
|
|
|
zval* arr = NULL;
|
|
|
|
|
HashTable* hash_arr = NULL;
|
|
|
|
|
int result = 0;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
2008-08-03 11:33:45 +00:00
|
|
|
|
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "a",
|
|
|
|
|
&arr) == FAILURE)
|
|
|
|
|
{
|
2008-07-23 19:44:51 +00:00
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_compose: unable to parse input params", 0 TSRMLS_CC );
|
|
|
|
|
RETURN_FALSE;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hash_arr = HASH_OF( arr );
|
|
|
|
|
|
|
|
|
|
if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Check for grandfathered first */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
result = append_key_value(loc_name, hash_arr, LOC_GRANDFATHERED_LANG_TAG);
|
|
|
|
|
if( result == SUCCESS){
|
|
|
|
|
RETURN_SMART_STR(loc_name);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Not grandfathered */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);
|
|
|
|
|
if( result == LOC_NOT_FOUND ){
|
2008-07-07 22:51:04 +00:00
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_compose: parameter array does not contain 'language' tag.", 0 TSRMLS_CC );
|
2008-07-23 19:44:51 +00:00
|
|
|
|
smart_str_free(loc_name);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Extlang */
|
2008-07-25 12:41:57 +00:00
|
|
|
|
result = append_multiple_key_values(loc_name, hash_arr , LOC_EXTLANG_TAG TSRMLS_CC);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Script */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Region */
|
2008-07-23 19:44:51 +00:00
|
|
|
|
result = append_key_value( loc_name, hash_arr , LOC_REGION_TAG);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Variant */
|
2008-07-25 12:41:57 +00:00
|
|
|
|
result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Private */
|
2008-07-25 12:41:57 +00:00
|
|
|
|
result = append_multiple_key_values( loc_name, hash_arr , LOC_PRIVATE_TAG TSRMLS_CC);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( !handleAppendResult( result, loc_name TSRMLS_CC)){
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-23 19:44:51 +00:00
|
|
|
|
RETURN_SMART_STR(loc_name);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*{{{
|
|
|
|
|
* Parses the locale and returns private subtags if existing
|
|
|
|
|
* else returns NULL
|
|
|
|
|
* e.g. for locale='en_US-x-prv1-prv2-prv3'
|
|
|
|
|
* returns a pointer to the string 'prv1-prv2-prv3'
|
|
|
|
|
*/
|
|
|
|
|
static char* get_private_subtags(char* loc_name)
|
|
|
|
|
{
|
|
|
|
|
char* result =NULL;
|
|
|
|
|
int singletonPos = 0;
|
|
|
|
|
int len =0;
|
|
|
|
|
char* mod_loc_name =NULL;
|
|
|
|
|
|
|
|
|
|
if( loc_name && (len = strlen(loc_name)>0 ) ){
|
|
|
|
|
mod_loc_name = loc_name ;
|
|
|
|
|
len = strlen(mod_loc_name);
|
|
|
|
|
while( (singletonPos = getSingletonPos(mod_loc_name))!= -1){
|
|
|
|
|
|
|
|
|
|
if( singletonPos!=-1){
|
|
|
|
|
if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* private subtag start found */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( singletonPos + 2 == len){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* loc_name ends with '-x-' ; return NULL */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
else{
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* result = mod_loc_name + singletonPos +2; */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result = estrndup(mod_loc_name + singletonPos+2 , (len -( singletonPos +2) ) );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
if( singletonPos + 1 >= len){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* String end */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
break;
|
|
|
|
|
} else {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* singleton found but not a private subtag , hence check further in the string for the private subtag */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
mod_loc_name = mod_loc_name + singletonPos +1;
|
|
|
|
|
len = strlen(mod_loc_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of while */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ code used by locale_parse
|
|
|
|
|
*/
|
|
|
|
|
static int add_array_entry(char* loc_name, zval* hash_arr, char* key_name TSRMLS_DC)
|
|
|
|
|
{
|
|
|
|
|
char* key_value = NULL;
|
|
|
|
|
char* cur_key_name = NULL;
|
|
|
|
|
char* token = NULL;
|
|
|
|
|
char* last_ptr = NULL;
|
|
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
int cur_result = 0;
|
|
|
|
|
int cnt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( strcmp(key_name , LOC_PRIVATE_TAG)==0 ){
|
|
|
|
|
key_value = get_private_subtags( loc_name );
|
|
|
|
|
result = 1;
|
|
|
|
|
} else {
|
|
|
|
|
key_value = get_icu_value_internal( loc_name , key_name , &result,1 );
|
|
|
|
|
}
|
|
|
|
|
if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) ||
|
|
|
|
|
( strcmp(key_name , LOC_VARIANT_TAG)==0) ){
|
|
|
|
|
if( result > 0 && key_value){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Tokenize on the "_" or "-" */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
token = php_strtok_r( key_value , DELIMITER ,&last_ptr);
|
|
|
|
|
if( cur_key_name ){
|
|
|
|
|
efree( cur_key_name);
|
|
|
|
|
}
|
|
|
|
|
cur_key_name = (char*)ecalloc( 25, 25);
|
|
|
|
|
sprintf( cur_key_name , "%s%d", key_name , cnt++);
|
|
|
|
|
add_assoc_string( hash_arr, cur_key_name , token ,TRUE );
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* tokenize on the "_" or "-" and stop at singleton if any */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
while( (token = php_strtok_r(NULL , DELIMITER , &last_ptr)) && (strlen(token)>1) ){
|
|
|
|
|
sprintf( cur_key_name , "%s%d", key_name , cnt++);
|
|
|
|
|
add_assoc_string( hash_arr, cur_key_name , token , TRUE );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( key_name == LOC_PRIVATE_TAG ){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if( result == 1 ){
|
|
|
|
|
add_assoc_string( hash_arr, key_name , key_value , TRUE );
|
|
|
|
|
cur_result = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( cur_key_name ){
|
|
|
|
|
efree( cur_key_name);
|
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/*if( key_name != LOC_PRIVATE_TAG && key_value){*/
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( key_value){
|
|
|
|
|
efree(key_value);
|
|
|
|
|
}
|
|
|
|
|
return cur_result;
|
|
|
|
|
}
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* }}} */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static array Locale::parseLocale($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* parses a locale-id into an array the different parts of it
|
|
|
|
|
}}} */
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto static array parse_locale($locale)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* parses a locale-id into an array the different parts of it
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_parse)
|
|
|
|
|
{
|
|
|
|
|
char* loc_name = NULL;
|
|
|
|
|
int loc_name_len = 0;
|
|
|
|
|
int grOffset = 0;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
|
|
|
|
|
&loc_name, &loc_name_len ) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_parse: unable to parse input params", 0 TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_name_len == 0) {
|
|
|
|
|
loc_name = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array_init( return_value );
|
|
|
|
|
|
|
|
|
|
grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
|
|
|
|
|
if( grOffset >= 0 ){
|
|
|
|
|
add_assoc_string( return_value , LOC_GRANDFATHERED_LANG_TAG , estrdup(loc_name) ,FALSE );
|
|
|
|
|
}
|
|
|
|
|
else{
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Not grandfathered */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
add_array_entry( loc_name , return_value , LOC_LANG_TAG TSRMLS_CC);
|
|
|
|
|
add_array_entry( loc_name , return_value , LOC_SCRIPT_TAG TSRMLS_CC);
|
|
|
|
|
add_array_entry( loc_name , return_value , LOC_REGION_TAG TSRMLS_CC);
|
|
|
|
|
add_array_entry( loc_name , return_value , LOC_VARIANT_TAG TSRMLS_CC);
|
|
|
|
|
add_array_entry( loc_name , return_value , LOC_PRIVATE_TAG TSRMLS_CC);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/* {{{ proto static array Locale::getAllVariants($locale)
|
|
|
|
|
* gets an array containing the list of variants, or null
|
|
|
|
|
}}} */
|
|
|
|
|
/* {{{ proto static array locale_get_all_variants($locale)
|
|
|
|
|
* gets an array containing the list of variants, or null
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_get_all_variants)
|
|
|
|
|
{
|
|
|
|
|
char* loc_name = NULL;
|
|
|
|
|
int loc_name_len = 0;
|
|
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
char* token = NULL;
|
|
|
|
|
char* variant = NULL;
|
|
|
|
|
char* saved_ptr = NULL;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
|
|
|
|
|
&loc_name, &loc_name_len ) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_parse: unable to parse input params", 0 TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_name_len == 0) {
|
|
|
|
|
loc_name = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
array_init( return_value );
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* If the locale is grandfathered, stop, no variants */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( findOffset( LOC_GRANDFATHERED , loc_name ) >= 0 ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* ("Grandfathered Tag. No variants."); */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Call ICU variant */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0);
|
|
|
|
|
if( result > 0 && variant){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Tokenize on the "_" or "-" */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
token = php_strtok_r( variant , DELIMITER , &saved_ptr);
|
|
|
|
|
add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* tokenize on the "_" or "-" and stop at singleton if any */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
|
|
|
|
|
add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( variant ){
|
|
|
|
|
efree( variant );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
|
|
/*{{{
|
2009-07-02 00:43:26 +00:00
|
|
|
|
* Converts to lower case and also replaces all hyphens with the underscore
|
2008-07-07 22:51:04 +00:00
|
|
|
|
*/
|
|
|
|
|
static int strToMatch(char* str ,char *retstr)
|
|
|
|
|
{
|
|
|
|
|
char* anchor = NULL;
|
|
|
|
|
char* anchor1 = NULL;
|
|
|
|
|
int result = 0;
|
|
|
|
|
int len = 0;
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if( (!str) || str[0] == '\0'){
|
2008-07-07 22:51:04 +00:00
|
|
|
|
return result;
|
|
|
|
|
} else {
|
|
|
|
|
anchor = retstr;
|
|
|
|
|
anchor1 = str;
|
|
|
|
|
len = strlen(str);
|
|
|
|
|
while( (*str)!='\0' ){
|
|
|
|
|
if( *str == '-' ){
|
|
|
|
|
*retstr = '_';
|
|
|
|
|
} else {
|
|
|
|
|
*retstr = tolower(*str);
|
|
|
|
|
}
|
|
|
|
|
str++;
|
|
|
|
|
retstr++;
|
|
|
|
|
}
|
|
|
|
|
*retstr = '\0';
|
|
|
|
|
retstr= anchor;
|
|
|
|
|
str= anchor1;
|
|
|
|
|
result = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
/* {{{ proto static boolean Locale::filterMatches(string $langtag, string $locale[, bool $canonicalize])
|
2008-07-23 01:15:33 +00:00
|
|
|
|
* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm
|
|
|
|
|
*/
|
|
|
|
|
/* }}} */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
/* {{{ proto boolean locale_filter_matches(string $langtag, string $locale[, bool $canonicalize])
|
2008-07-23 01:15:33 +00:00
|
|
|
|
* Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm
|
2008-07-07 22:51:04 +00:00
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_filter_matches)
|
|
|
|
|
{
|
|
|
|
|
char* lang_tag = NULL;
|
|
|
|
|
int lang_tag_len = 0;
|
|
|
|
|
char* loc_range = NULL;
|
|
|
|
|
int loc_range_len = 0;
|
|
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
|
char* token = 0;
|
|
|
|
|
char* chrcheck = NULL;
|
|
|
|
|
|
|
|
|
|
char* can_lang_tag = NULL;
|
|
|
|
|
char* can_loc_range = NULL;
|
|
|
|
|
|
|
|
|
|
char* cur_lang_tag = NULL;
|
|
|
|
|
char* cur_loc_range = NULL;
|
|
|
|
|
|
|
|
|
|
zend_bool boolCanonical = 0;
|
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss|b",
|
2008-07-07 22:51:04 +00:00
|
|
|
|
&lang_tag, &lang_tag_len , &loc_range , &loc_range_len ,
|
|
|
|
|
&boolCanonical) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_filter_matches: unable to parse input params", 0 TSRMLS_CC );
|
|
|
|
|
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_range_len == 0) {
|
|
|
|
|
loc_range = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( strcmp(loc_range,"*")==0){
|
|
|
|
|
RETURN_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( boolCanonical ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* canonicalize loc_range */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
can_loc_range=get_icu_value_internal( loc_range , LOC_CANONICALIZE_TAG , &result , 0);
|
|
|
|
|
if( result ==0) {
|
|
|
|
|
intl_error_set( NULL, status,
|
|
|
|
|
"locale_filter_matches : unable to canonicalize loc_range" , 0 TSRMLS_CC );
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* canonicalize lang_tag */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
can_lang_tag = get_icu_value_internal( lang_tag , LOC_CANONICALIZE_TAG , &result , 0);
|
|
|
|
|
if( result ==0) {
|
|
|
|
|
intl_error_set( NULL, status,
|
|
|
|
|
"locale_filter_matches : unable to canonicalize lang_tag" , 0 TSRMLS_CC );
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Convert to lower case for case-insensitive comparison */
|
2008-07-30 19:34:23 +00:00
|
|
|
|
cur_lang_tag = ecalloc( 1, strlen(can_lang_tag) + 1);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Convert to lower case for case-insensitive comparison */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result = strToMatch( can_lang_tag , cur_lang_tag);
|
|
|
|
|
if( result == 0) {
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
efree( can_lang_tag );
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 19:34:23 +00:00
|
|
|
|
cur_loc_range = ecalloc( 1, strlen(can_loc_range) + 1);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
result = strToMatch( can_loc_range , cur_loc_range );
|
|
|
|
|
if( result == 0) {
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
efree( can_lang_tag );
|
|
|
|
|
efree( cur_loc_range );
|
|
|
|
|
efree( can_loc_range );
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* check if prefix */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
token = strstr( cur_lang_tag , cur_loc_range );
|
|
|
|
|
|
|
|
|
|
if( token && (token==cur_lang_tag) ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* check if the char. after match is SEPARATOR */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
chrcheck = token + (strlen(cur_loc_range));
|
|
|
|
|
if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
|
|
|
|
|
if( cur_lang_tag){
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
}
|
|
|
|
|
if( cur_loc_range){
|
|
|
|
|
efree( cur_loc_range );
|
|
|
|
|
}
|
|
|
|
|
if( can_lang_tag){
|
|
|
|
|
efree( can_lang_tag );
|
|
|
|
|
}
|
|
|
|
|
if( can_loc_range){
|
|
|
|
|
efree( can_loc_range );
|
|
|
|
|
}
|
|
|
|
|
RETURN_TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* No prefix as loc_range */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( cur_lang_tag){
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
}
|
|
|
|
|
if( cur_loc_range){
|
|
|
|
|
efree( cur_loc_range );
|
|
|
|
|
}
|
|
|
|
|
if( can_lang_tag){
|
|
|
|
|
efree( can_lang_tag );
|
|
|
|
|
}
|
|
|
|
|
if( can_loc_range){
|
|
|
|
|
efree( can_loc_range );
|
|
|
|
|
}
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of if isCanonical */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
else{
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Convert to lower case for case-insensitive comparison */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
cur_lang_tag = ecalloc( 1, strlen(lang_tag ) + 1);
|
|
|
|
|
|
|
|
|
|
result = strToMatch( lang_tag , cur_lang_tag);
|
|
|
|
|
if( result == 0) {
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
cur_loc_range = ecalloc( 1, strlen(loc_range ) + 1);
|
|
|
|
|
result = strToMatch( loc_range , cur_loc_range );
|
|
|
|
|
if( result == 0) {
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
efree( cur_loc_range );
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* check if prefix */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
token = strstr( cur_lang_tag , cur_loc_range );
|
|
|
|
|
|
|
|
|
|
if( token && (token==cur_lang_tag) ){
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* check if the char. after match is SEPARATOR */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
chrcheck = token + (strlen(cur_loc_range));
|
|
|
|
|
if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){
|
|
|
|
|
if( cur_lang_tag){
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
}
|
|
|
|
|
if( cur_loc_range){
|
|
|
|
|
efree( cur_loc_range );
|
|
|
|
|
}
|
|
|
|
|
RETURN_TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* No prefix as loc_range */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if( cur_lang_tag){
|
|
|
|
|
efree( cur_lang_tag );
|
|
|
|
|
}
|
|
|
|
|
if( cur_loc_range){
|
|
|
|
|
efree( cur_loc_range );
|
|
|
|
|
}
|
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* }}} */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
static void array_cleanup( char* arr[] , int arr_size)
|
|
|
|
|
{
|
|
|
|
|
int i=0;
|
|
|
|
|
for( i=0; i< arr_size; i++ ){
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if( arr[i*2] ){
|
|
|
|
|
efree( arr[i*2]);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
efree(arr);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
#define LOOKUP_CLEAN_RETURN(value) array_cleanup(cur_arr, cur_arr_len); return (value)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
/* {{{
|
|
|
|
|
* returns the lookup result to lookup_loc_range_src_php
|
|
|
|
|
* internal function
|
|
|
|
|
*/
|
2009-07-02 00:43:26 +00:00
|
|
|
|
static char* lookup_loc_range(char* loc_range, HashTable* hash_arr, int canonicalize TSRMLS_DC)
|
2008-07-07 22:51:04 +00:00
|
|
|
|
{
|
2009-07-02 00:43:26 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
int cur_arr_len = 0;
|
|
|
|
|
int result = 0;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
char* lang_tag = NULL;
|
|
|
|
|
zval** ele_value = NULL;
|
|
|
|
|
char** cur_arr = NULL;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
char* cur_loc_range = NULL;
|
|
|
|
|
char* can_loc_range = NULL;
|
|
|
|
|
int saved_pos = 0;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
char* return_value = NULL;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
cur_arr = ecalloc(zend_hash_num_elements(hash_arr)*2, sizeof(char *));
|
|
|
|
|
/* convert the array to lowercase , also replace hyphens with the underscore and store it in cur_arr */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
for(zend_hash_internal_pointer_reset(hash_arr);
|
|
|
|
|
zend_hash_has_more_elements(hash_arr) == SUCCESS;
|
|
|
|
|
zend_hash_move_forward(hash_arr)) {
|
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
if (zend_hash_get_current_data(hash_arr, (void**)&ele_value) == FAILURE) {
|
|
|
|
|
/* Should never actually fail since the key is known to exist.*/
|
|
|
|
|
continue;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(Z_TYPE_PP(ele_value)!= IS_STRING) {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* element value is not a string */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: locale array element is not a string", 0 TSRMLS_CC);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
|
|
|
|
}
|
|
|
|
|
cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_PP(ele_value), Z_STRLEN_PP(ele_value));
|
|
|
|
|
result = strToMatch(Z_STRVAL_PP(ele_value), cur_arr[cur_arr_len*2]);
|
|
|
|
|
if(result == 0) {
|
|
|
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag", 0 TSRMLS_CC);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
cur_arr[cur_arr_len*2+1] = Z_STRVAL_PP(ele_value);
|
|
|
|
|
cur_arr_len++ ;
|
2008-08-03 11:33:45 +00:00
|
|
|
|
} /* end of for */
|
|
|
|
|
|
|
|
|
|
/* Canonicalize array elements */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(canonicalize) {
|
|
|
|
|
for(i=0; i<cur_arr_len; i++) {
|
|
|
|
|
lang_tag = get_icu_value_internal(cur_arr[i*2], LOC_CANONICALIZE_TAG, &result, 0);
|
|
|
|
|
if(result != 1 || lang_tag == NULL || !lang_tag[0]) {
|
|
|
|
|
if(lang_tag) {
|
|
|
|
|
efree(lang_tag);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
|
|
|
|
}
|
|
|
|
|
cur_arr[i*2] = erealloc(cur_arr[i*2], strlen(lang_tag)+1);
|
|
|
|
|
result = strToMatch(lang_tag, cur_arr[i*2]);
|
|
|
|
|
efree(lang_tag);
|
|
|
|
|
if(result == 0) {
|
|
|
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(canonicalize) {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Canonicalize the loc_range */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
can_loc_range = get_icu_value_internal(loc_range, LOC_CANONICALIZE_TAG, &result , 0);
|
|
|
|
|
if( result != 1 || can_loc_range == NULL || !can_loc_range[0]) {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Error */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize loc_range" , 0 TSRMLS_CC );
|
|
|
|
|
if(can_loc_range) {
|
|
|
|
|
efree(can_loc_range);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
} else {
|
2009-07-02 00:43:26 +00:00
|
|
|
|
loc_range = can_loc_range;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
}
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
cur_loc_range = ecalloc(1, strlen(loc_range)+1);
|
|
|
|
|
/* convert to lower and replace hyphens */
|
|
|
|
|
result = strToMatch(loc_range, cur_loc_range);
|
|
|
|
|
if(can_loc_range) {
|
|
|
|
|
efree(can_loc_range);
|
|
|
|
|
}
|
|
|
|
|
if(result == 0) {
|
|
|
|
|
intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
|
|
|
|
}
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Lookup for the lang_tag match */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
saved_pos = strlen(cur_loc_range);
|
2009-07-02 00:43:26 +00:00
|
|
|
|
while(saved_pos > 0) {
|
|
|
|
|
for(i=0; i< cur_arr_len; i++){
|
|
|
|
|
if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {
|
2008-08-03 11:33:45 +00:00
|
|
|
|
/* Match found */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
return_value = estrdup(canonicalize?cur_arr[i*2]:cur_arr[i*2+1]);
|
|
|
|
|
efree(cur_loc_range);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(return_value);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-02 00:43:26 +00:00
|
|
|
|
saved_pos = getStrrtokenPos(cur_loc_range, saved_pos);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-08-03 11:33:45 +00:00
|
|
|
|
|
|
|
|
|
/* Match not found */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
efree(cur_loc_range);
|
|
|
|
|
LOOKUP_CLEAN_RETURN(NULL);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
/* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* Searchs the items in $langtag for the best match to the language
|
|
|
|
|
* range
|
|
|
|
|
*/
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* }}} */
|
2009-07-02 00:43:26 +00:00
|
|
|
|
/* {{{ proto string locale_lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
|
2008-07-07 22:51:04 +00:00
|
|
|
|
* Searchs the items in $langtag for the best match to the language
|
|
|
|
|
* range
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_lookup)
|
|
|
|
|
{
|
2009-07-02 00:43:26 +00:00
|
|
|
|
char* fallback_loc = NULL;
|
|
|
|
|
int fallback_loc_len = 0;
|
|
|
|
|
char* loc_range = NULL;
|
|
|
|
|
int loc_range_len = 0;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
zval* arr = NULL;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
HashTable* hash_arr = NULL;
|
2009-07-02 00:43:26 +00:00
|
|
|
|
zend_bool boolCanonical = 0;
|
2008-07-07 22:51:04 +00:00
|
|
|
|
char* result =NULL;
|
|
|
|
|
|
|
|
|
|
intl_error_reset( NULL TSRMLS_CC );
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "as|bs", &arr, &loc_range, &loc_range_len,
|
|
|
|
|
&boolCanonical, &fallback_loc, &fallback_loc_len) == FAILURE) {
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "locale_lookup: unable to parse input params", 0 TSRMLS_CC );
|
2008-07-07 22:51:04 +00:00
|
|
|
|
RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(loc_range_len == 0) {
|
|
|
|
|
loc_range = INTL_G(default_locale);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
hash_arr = HASH_OF(arr);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) {
|
2008-07-07 22:51:04 +00:00
|
|
|
|
RETURN_EMPTY_STRING();
|
2009-07-02 00:43:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = lookup_loc_range(loc_range, hash_arr, boolCanonical TSRMLS_CC);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
if(result == NULL || result[0] == '\0') {
|
|
|
|
|
if( fallback_loc ) {
|
2009-07-02 00:43:26 +00:00
|
|
|
|
result = estrndup(fallback_loc, fallback_loc_len);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
} else {
|
|
|
|
|
RETURN_EMPTY_STRING();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-02 00:43:26 +00:00
|
|
|
|
RETVAL_STRINGL(result, strlen(result), 0);
|
2008-07-07 22:51:04 +00:00
|
|
|
|
}
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* }}} */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
2008-07-23 01:15:33 +00:00
|
|
|
|
/* {{{ proto string Locale::acceptFromHttp(string $http_accept)
|
|
|
|
|
* Tries to find out best available locale based on HTTP <EFBFBD>Accept-Language<EFBFBD> header
|
|
|
|
|
*/
|
|
|
|
|
/* }}} */
|
|
|
|
|
/* {{{ proto string locale_accept_from_http(string $http_accept)
|
|
|
|
|
* Tries to find out best available locale based on HTTP <EFBFBD>Accept-Language<EFBFBD> header
|
|
|
|
|
*/
|
|
|
|
|
PHP_FUNCTION(locale_accept_from_http)
|
|
|
|
|
{
|
|
|
|
|
UEnumeration *available;
|
|
|
|
|
char *http_accept = NULL;
|
|
|
|
|
int http_accept_len;
|
|
|
|
|
UErrorCode status = 0;
|
|
|
|
|
int len;
|
|
|
|
|
char resultLocale[INTL_MAX_LOCALE_LEN+1];
|
|
|
|
|
UAcceptResult outResult;
|
|
|
|
|
|
|
|
|
|
if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &http_accept, &http_accept_len) == FAILURE)
|
|
|
|
|
{
|
|
|
|
|
intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
|
|
|
|
|
"locale_accept_from_http: unable to parse input parameters", 0 TSRMLS_CC );
|
|
|
|
|
RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
available = ures_openAvailableLocales(NULL, &status);
|
|
|
|
|
INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list");
|
|
|
|
|
len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN,
|
|
|
|
|
&outResult, http_accept, available, &status);
|
|
|
|
|
uenum_close(available);
|
|
|
|
|
INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to find acceptable locale");
|
2008-07-30 16:43:11 +00:00
|
|
|
|
if (len < 0 || outResult == ULOC_ACCEPT_FAILED) {
|
2008-07-23 01:15:33 +00:00
|
|
|
|
RETURN_FALSE;
|
|
|
|
|
}
|
|
|
|
|
RETURN_STRINGL(resultLocale, len, 1);
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
2008-07-07 22:51:04 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Local variables:
|
|
|
|
|
* tab-width: 4
|
|
|
|
|
* c-basic-offset: 4
|
|
|
|
|
* End:
|
|
|
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
|
|
|
* vim<600: noet sw=4 ts=4
|
|
|
|
|
*can_loc_len
|
|
|
|
|
*/
|