PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - intl/locale - locale_methods.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 693
Code covered: 82.3 % Executed lines: 570
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | This source file is subject to version 3.01 of the PHP license,      |
       6                 :    | that is bundled with this package in the file LICENSE, and is        |
       7                 :    | available through the world-wide-web at the following url:           |
       8                 :    | http://www.php.net/license/3_01.txt                                  |
       9                 :    | If you did not receive a copy of the PHP license and are unable to   |
      10                 :    | obtain it through the world-wide-web, please send a note to          |
      11                 :    | license@php.net so we can mail you a copy immediately.               |
      12                 :    +----------------------------------------------------------------------+
      13                 :    | Authors: Kirti Velankar <kirtig@yahoo-inc.com>                       |
      14                 :    +----------------------------------------------------------------------+
      15                 : */
      16                 : 
      17                 : /* $Id: locale_methods.c 283367 2009-07-02 22:36:16Z stas $ */
      18                 : 
      19                 : #ifdef HAVE_CONFIG_H
      20                 : #include "config.h"
      21                 : #endif
      22                 : 
      23                 : #include <unicode/ustring.h>
      24                 : #include <unicode/udata.h>
      25                 : #include <unicode/putil.h>
      26                 : #include <unicode/ures.h>
      27                 : 
      28                 : #include "php_intl.h"
      29                 : #include "locale.h"
      30                 : #include "locale_class.h"
      31                 : #include "locale_methods.h"
      32                 : #include "intl_convert.h"
      33                 : #include "intl_data.h"
      34                 : 
      35                 : #include <zend_API.h>
      36                 : #include <zend.h>
      37                 : #include <php.h>
      38                 : #include "main/php_ini.h"
      39                 : #include "ext/standard/php_smart_str.h"
      40                 : 
      41                 : ZEND_EXTERN_MODULE_GLOBALS( intl )
      42                 : 
      43                 : /* Sizes required for the strings "variant15" , "extlang11", "private12" etc. */
      44                 : #define SEPARATOR "_"
      45                 : #define SEPARATOR1 "-"
      46                 : #define DELIMITER "-_"
      47                 : #define EXTLANG_PREFIX "a"
      48                 : #define PRIVATE_PREFIX "x"
      49                 : #define DISP_NAME "name"
      50                 : 
      51                 : #define MAX_NO_VARIANT  15
      52                 : #define MAX_NO_EXTLANG  3
      53                 : #define MAX_NO_PRIVATE  15
      54                 : #define MAX_NO_LOOKUP_LANG_TAG  100
      55                 : 
      56                 : #define LOC_NOT_FOUND 1
      57                 : 
      58                 : /* Sizes required for the strings "variant15" , "extlang3", "private12" etc. */
      59                 : #define VARIANT_KEYNAME_LEN  11
      60                 : #define EXTLANG_KEYNAME_LEN  10
      61                 : #define PRIVATE_KEYNAME_LEN  11
      62                 : 
      63                 : /* Based on IANA registry at the time of writing this code
      64                 : *
      65                 : */
      66                 : static const char * const LOC_GRANDFATHERED[] = {
      67                 :         "art-lojban",         "i-klingon",          "i-lux",                      "i-navajo",           "no-bok",             "no-nyn",
      68                 :         "cel-gaulish",                "en-GB-oed",          "i-ami",              
      69                 :         "i-bnn",              "i-default",          "i-enochian", 
      70                 :         "i-mingo",            "i-pwn",              "i-tao", 
      71                 :         "i-tay",              "i-tsu",              "sgn-BE-fr",
      72                 :         "sgn-BE-nl",          "sgn-CH-de",          "zh-cmn",
      73                 :         "zh-cmn-Hans",                "zh-cmn-Hant",                "zh-gan" ,
      74                 :         "zh-guoyu",           "zh-hakka",           "zh-min",
      75                 :         "zh-min-nan",                 "zh-wuu",             "zh-xiang",   
      76                 :         "zh-yue",             NULL
      77                 : };
      78                 : 
      79                 : /* Based on IANA registry at the time of writing this code
      80                 : *  This array lists the preferred values for the grandfathered tags if applicable
      81                 : *  This is in sync with the array LOC_GRANDFATHERED      
      82                 : *  e.g. the offsets of the grandfathered tags match the offset of the preferred  value
      83                 : */
      84                 : static const int                LOC_PREFERRED_GRANDFATHERED_LEN = 6;
      85                 : static const char * const       LOC_PREFERRED_GRANDFATHERED[]  = {
      86                 :         "jbo",                        "tlh",                        "lb",
      87                 :         "nv",                         "nb",                 "nn",                 
      88                 :         NULL
      89                 : };
      90                 : 
      91                 : /*returns TRUE if a is an ID separator FALSE otherwise*/
      92                 : #define isIDSeparator(a) (a == '_' || a == '-')
      93                 : #define isKeywordSeparator(a) (a == '@' )
      94                 : #define isEndOfTag(a) (a == '\0' )
      95                 : 
      96                 : #define isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
      97                 : 
      98                 : /*returns TRUE if one of the special prefixes is here (s=string)
      99                 :   'x-' or 'i-' */
     100                 : #define isIDPrefix(s) (isPrefixLetter(s[0])&&isIDSeparator(s[1]))
     101                 : #define isKeywordPrefix(s) ( isKeywordSeparator(s[0]) )
     102                 : 
     103                 : /* Dot terminates it because of POSIX form  where dot precedes the codepage
     104                 :  * except for variant */
     105                 : #define isTerminator(a)  ((a==0)||(a=='.')||(a=='@'))
     106                 : 
     107                 : /* {{{ return the offset of 'key' in the array 'list'.
     108                 :  * returns -1 if not present */
     109                 : static int16_t findOffset(const char* const* list, const char* key)
     110            1468 : {
     111            1468 :         const char* const* anchor = list;
     112           46982 :         while (*list != NULL) {
     113           44146 :                 if (strcmp(key, *list) == 0) {
     114             100 :                         return (int16_t)(list - anchor);
     115                 :                 }
     116           44046 :                 list++;
     117                 :         }
     118                 : 
     119            1368 :         return -1;
     120                 : 
     121                 : }
     122                 : /*}}}*/
     123                 : 
     124                 : static char* getPreferredTag(char* gf_tag)
     125              18 : { 
     126              18 :         char* result = NULL;
     127              18 :         int grOffset = 0;
     128                 : 
     129              18 :         grOffset = findOffset( LOC_GRANDFATHERED ,gf_tag);
     130              18 :         if( grOffset < LOC_PREFERRED_GRANDFATHERED_LEN ){
     131                 :                 /* return preferred tag */
     132               6 :                 result = estrdup( LOC_PREFERRED_GRANDFATHERED[grOffset] );
     133                 :         } else {
     134                 :                 /* Return correct grandfathered language tag */
     135              12 :                 result = estrdup( LOC_GRANDFATHERED[grOffset] );
     136                 :         }
     137              18 :         return result;
     138                 : }
     139                 : 
     140                 : /* {{{
     141                 : * returns the position of next token for lookup 
     142                 : * or -1 if no token
     143                 : * strtokr equivalent search for token in reverse direction 
     144                 : */
     145                 : static int getStrrtokenPos(char* str, int savedPos)
     146               4 : {
     147               4 :         int result =-1;
     148                 :         int i;
     149                 :         
     150              24 :         for(i=savedPos-1; i>=0; i--) {
     151              24 :                 if(isIDSeparator(*(str+i)) ){
     152                 :                         /* delimiter found; check for singleton */
     153               4 :                         if(i>=2 && isIDSeparator(*(str+i-2)) ){
     154                 :                                 /* a singleton; so send the position of token before the singleton */
     155               0 :                                 result = i-2;
     156                 :                         } else {
     157               4 :                                 result = i;
     158                 :                         }
     159               4 :                         break;
     160                 :                 }
     161                 :         }
     162               4 :         if(result < 1){
     163                 :                 /* Just in case inavlid locale e.g. '-x-xyz' or '-sl_Latn' */
     164               0 :                 result =-1;
     165                 :         }
     166               4 :         return result;
     167                 : }
     168                 : /* }}} */
     169                 : 
     170                 : /* {{{
     171                 : * returns the position of a singleton if present 
     172                 : * returns -1 if no singleton
     173                 : * strtok equivalent search for singleton
     174                 : */
     175                 : static int getSingletonPos(char* str)
     176             346 : {
     177             346 :         int result =-1;
     178             346 :         int i=0;
     179             346 :         int len = 0;
     180                 :         
     181             346 :         if( str && ((len=strlen(str))>0) ){
     182            3154 :                 for( i=0; i<len ; i++){
     183            2896 :                         if( isIDSeparator(*(str+i)) ){
     184             484 :                                 if( i==1){
     185                 :                                         /* string is of the form x-avy or a-prv1 */
     186              10 :                                         result =0;
     187              10 :                                         break;
     188                 :                                 } else {
     189                 :                                         /* delimiter found; check for singleton */
     190             474 :                                         if( isIDSeparator(*(str+i+2)) ){
     191                 :                                                 /* a singleton; so send the position of separator before singleton */
     192              78 :                                                 result = i+1;
     193              78 :                                                 break;
     194                 :                                         }
     195                 :                                 }
     196                 :                         }
     197                 :                 }/* end of for */
     198                 :                 
     199                 :         }
     200             346 :         return result;
     201                 : }
     202                 : /* }}} */
     203                 : 
     204                 : /* {{{ proto static string Locale::getDefault(  )
     205                 :    Get default locale */
     206                 : /* }}} */
     207                 : /* {{{ proto static string locale_get_default( )
     208                 :    Get default locale */
     209                 : PHP_NAMED_FUNCTION(zif_locale_get_default)
     210              78 : {
     211              78 :         if( INTL_G(default_locale) == NULL ) {
     212               0 :                 INTL_G(default_locale) = pestrdup( uloc_getDefault(), 1);
     213                 :         }
     214              78 :         RETURN_STRING( INTL_G(default_locale), TRUE );
     215                 : }
     216                 : 
     217                 : /* }}} */
     218                 : 
     219                 : /* {{{ proto static string Locale::setDefault( string $locale )
     220                 :    Set default locale */
     221                 : /* }}} */
     222                 : /* {{{ proto static string locale_set_default( string $locale )
     223                 :    Set default locale */
     224                 : PHP_NAMED_FUNCTION(zif_locale_set_default)
     225              74 : {
     226              74 :         char* locale_name = NULL;
     227              74 :         int   len=0;    
     228                 : 
     229              74 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC,  "s",
     230                 :                 &locale_name ,&len ) == FAILURE)
     231                 :         {
     232               0 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     233                 :                                 "locale_set_default: unable to parse input params", 0 TSRMLS_CC );
     234                 : 
     235               0 :                 RETURN_FALSE;
     236                 :         }
     237                 : 
     238              74 :         if(len == 0) {
     239               0 :                 locale_name =  (char *)uloc_getDefault() ;
     240               0 :                 len = strlen(locale_name);
     241                 :         }
     242                 : 
     243              74 :         zend_alter_ini_entry(LOCALE_INI_NAME, sizeof(LOCALE_INI_NAME), locale_name, len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);  
     244                 : 
     245              74 :         RETURN_TRUE;
     246                 : }
     247                 : /* }}} */
     248                 : 
     249                 : /* {{{
     250                 : * Gets the value from ICU 
     251                 : * common code shared by get_primary_language,get_script or get_region or get_variant
     252                 : * result = 0 if error, 1 if successful , -1 if no value
     253                 : */
     254                 : static char* get_icu_value_internal( char* loc_name , char* tag_name, int* result , int fromParseLocale)
     255            1446 : {
     256            1446 :         char*           tag_value       = NULL;
     257            1446 :         int32_t         tag_value_len   = 512;
     258                 : 
     259            1446 :         int             singletonPos    = 0;
     260            1446 :         char*           mod_loc_name    = NULL;
     261            1446 :         int             grOffset        = 0;
     262                 : 
     263            1446 :         int32_t         buflen          = 512;
     264            1446 :         UErrorCode      status          = U_ZERO_ERROR;
     265                 : 
     266                 : 
     267            1446 :         if( tag_name != LOC_CANONICALIZE_TAG ){
     268                 :                 /* Handle  grandfathered languages */
     269             488 :                 grOffset =  findOffset( LOC_GRANDFATHERED , loc_name );
     270             488 :                 if( grOffset >= 0 ){
     271              12 :                         if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
     272               4 :                                 tag_value = estrdup(loc_name);
     273               4 :                                 return tag_value;
     274                 :                         } else {
     275                 :                                 /* Since Grandfathered , no value , do nothing , retutn NULL */
     276               8 :                                 return NULL;
     277                 :                         }
     278                 :                 }
     279                 : 
     280             476 :         if( fromParseLocale==1 ){
     281                 :                 /* Handle singletons */
     282             264 :                 if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
     283              66 :                         if( strlen(loc_name)>1 && (isIDPrefix(loc_name) ==1 ) ){
     284               0 :                                 return loc_name;
     285                 :                         }
     286                 :                 }
     287                 : 
     288             264 :                 singletonPos = getSingletonPos( loc_name );     
     289             264 :                 if( singletonPos == 0){
     290                 :                         /* singleton at start of script, region , variant etc.
     291                 :                          * or invalid singleton at start of language */
     292               8 :                         return NULL;
     293             256 :                 } else if( singletonPos > 0 ){
     294                 :                         /* singleton at some position except at start
     295                 :                          * strip off the singleton and rest of the loc_name */
     296              56 :                         mod_loc_name = estrndup ( loc_name , singletonPos-1);
     297                 :                 }
     298                 :         } /* end of if fromParse */
     299                 : 
     300                 :         } /* end of if != LOC_CANONICAL_TAG */
     301                 : 
     302            1426 :         if( mod_loc_name == NULL){
     303            1370 :                 mod_loc_name = estrdup(loc_name );      
     304                 :         }
     305                 : 
     306                 :         /* Proceed to ICU */
     307                 :     do{
     308            1426 :                 tag_value = erealloc( tag_value , buflen  );
     309            1426 :                 tag_value_len = buflen;
     310                 : 
     311            1426 :                 if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
     312             132 :                         buflen = uloc_getScript ( mod_loc_name ,tag_value , tag_value_len , &status);
     313                 :                 }
     314            1426 :                 if( strcmp(tag_name , LOC_LANG_TAG )==0 ){
     315             130 :                         buflen = uloc_getLanguage ( mod_loc_name ,tag_value , tag_value_len , &status);
     316                 :                 }
     317            1426 :                 if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
     318             132 :                         buflen = uloc_getCountry ( mod_loc_name ,tag_value , tag_value_len , &status);
     319                 :                 }
     320            1426 :                 if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
     321              74 :                         buflen = uloc_getVariant ( mod_loc_name ,tag_value , tag_value_len , &status);
     322                 :                 }
     323            1426 :                 if( strcmp(tag_name , LOC_CANONICALIZE_TAG)==0 ){
     324             958 :                         buflen = uloc_canonicalize ( mod_loc_name ,tag_value , tag_value_len , &status);
     325                 :                 }
     326                 : 
     327            1426 :                 if( U_FAILURE( status ) ) {
     328               0 :                         if( status == U_BUFFER_OVERFLOW_ERROR ) {
     329               0 :                                 status = U_ZERO_ERROR;
     330               0 :                                 continue;
     331                 :                         }
     332                 : 
     333                 :                         /* Error in retriving data */
     334               0 :                         *result = 0;
     335               0 :                         if( tag_value ){
     336               0 :                                 efree( tag_value );
     337                 :                         }
     338               0 :                         if( mod_loc_name ){
     339               0 :                                 efree( mod_loc_name);
     340                 :                         }
     341               0 :                         return NULL;
     342                 :                 }
     343            1426 :         } while( buflen > tag_value_len );
     344                 : 
     345            1426 :         if(  buflen ==0 ){
     346                 :                 /* No value found */
     347             188 :                 *result = -1;
     348             188 :                 if( tag_value ){
     349             188 :                         efree( tag_value );
     350                 :                 }
     351             188 :                 if( mod_loc_name ){
     352             188 :                         efree( mod_loc_name);
     353                 :                 }
     354             188 :                 return NULL;
     355                 :         } else {
     356            1238 :                 *result = 1;
     357                 :         }
     358                 : 
     359            1238 :         if( mod_loc_name ){
     360            1238 :                 efree( mod_loc_name);
     361                 :         }
     362            1238 :         return tag_value;
     363                 : }
     364                 : /* }}} */
     365                 : 
     366                 : /* {{{
     367                 : * Gets the value from ICU , called when PHP userspace function is called
     368                 : * common code shared by get_primary_language,get_script or get_region or get_variant
     369                 : */
     370                 : static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
     371             608 : {
     372                 : 
     373             608 :         char*       loc_name            = NULL;
     374             608 :         int         loc_name_len        = 0;
     375                 : 
     376             608 :         char*       tag_value           = NULL;
     377             608 :         char*       empty_result        = "";
     378                 : 
     379             608 :         int         result              = 0;
     380             608 :         char*       msg                 = NULL;
     381                 : 
     382             608 :         UErrorCode  status              = U_ZERO_ERROR;
     383                 : 
     384             608 :         intl_error_reset( NULL TSRMLS_CC );
     385                 : 
     386             608 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
     387                 :         &loc_name ,&loc_name_len ) == FAILURE) {
     388               0 :                 spprintf(&msg , 0, "locale_get_%s : unable to parse input params", tag_name );
     389               0 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  msg , 1 TSRMLS_CC );
     390               0 :                 efree(msg);
     391                 : 
     392               0 :                 RETURN_NULL();
     393                 :     }
     394                 : 
     395             608 :         if(loc_name_len == 0) {
     396               0 :                 loc_name = INTL_G(default_locale);
     397                 :         }
     398                 : 
     399                 :         /* Call ICU get */
     400             608 :         tag_value = get_icu_value_internal( loc_name , tag_name , &result ,0);
     401                 : 
     402                 :         /* No value found */
     403             608 :         if( result == -1 ) {
     404              68 :                 if( tag_value){
     405               0 :                         efree( tag_value);
     406                 :                 }
     407              68 :                 RETURN_STRING( empty_result , TRUE);
     408                 :         }
     409                 : 
     410                 :         /* value found */
     411             540 :         if( tag_value){
     412             532 :                 RETURN_STRING( tag_value , FALSE);
     413                 :         }
     414                 : 
     415                 :         /* Error encountered while fetching the value */
     416               8 :         if( result ==0) {
     417               8 :                 spprintf(&msg , 0, "locale_get_%s : unable to get locale %s", tag_name , tag_name );
     418               8 :                 intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
     419               8 :                 efree(msg);
     420               8 :                 RETURN_NULL();
     421                 :         }
     422                 : 
     423                 : }
     424                 : /* }}} */
     425                 : 
     426                 : /* {{{ proto static string Locale::getScript($locale) 
     427                 :  * gets the script for the $locale 
     428                 :  }}} */
     429                 : /* {{{ proto static string locale_get_script($locale) 
     430                 :  * gets the script for the $locale 
     431                 :  */
     432                 : PHP_FUNCTION( locale_get_script ) 
     433              72 : {
     434              72 :         get_icu_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     435              72 : }
     436                 : /* }}} */
     437                 : 
     438                 : /* {{{ proto static string Locale::getRegion($locale) 
     439                 :  * gets the region for the $locale 
     440                 :  }}} */
     441                 : /* {{{ proto static string locale_get_region($locale) 
     442                 :  * gets the region for the $locale 
     443                 :  */
     444                 : PHP_FUNCTION( locale_get_region ) 
     445              72 : {
     446              72 :         get_icu_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     447              72 : }
     448                 : /* }}} */
     449                 : 
     450                 : /* {{{ proto static string Locale::getPrimaryLanguage($locale) 
     451                 :  * gets the primary language for the $locale 
     452                 :  }}} */
     453                 : /* {{{ proto static string locale_get_primary_language($locale) 
     454                 :  * gets the primary language for the $locale 
     455                 :  */
     456                 : PHP_FUNCTION(locale_get_primary_language ) 
     457              70 : {
     458              70 :         get_icu_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     459              70 : }
     460                 : /* }}} */
     461                 : 
     462                 : 
     463                 : /* {{{
     464                 :  * common code shared by display_xyz functions to  get the value from ICU 
     465                 :  }}} */
     466                 : static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
     467            1152 : {
     468            1152 :         char*       loc_name            = NULL;
     469            1152 :         int         loc_name_len        = 0;
     470                 : 
     471            1152 :         char*       disp_loc_name       = NULL;
     472            1152 :         int         disp_loc_name_len   = 0;
     473                 : 
     474            1152 :         UChar*      disp_name           = NULL;
     475            1152 :         int32_t     disp_name_len       = 0;
     476                 : 
     477            1152 :         char*       mod_loc_name        = NULL;
     478                 : 
     479            1152 :         int32_t     buflen              = 512;
     480            1152 :         UErrorCode  status              = U_ZERO_ERROR;
     481                 : 
     482            1152 :         char*       utf8value           = NULL;
     483            1152 :         int         utf8value_len       = 0;
     484                 : 
     485            1152 :         char*       msg                 = NULL;
     486            1152 :         int         grOffset            = 0;
     487                 : 
     488            1152 :         intl_error_reset( NULL TSRMLS_CC );
     489                 : 
     490            1152 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
     491                 :                 &loc_name, &loc_name_len , 
     492                 :                 &disp_loc_name ,&disp_loc_name_len ) == FAILURE)
     493                 :         {
     494               0 :                 spprintf(&msg , 0, "locale_get_display_%s : unable to parse input params", tag_name );
     495               0 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  msg , 1 TSRMLS_CC );
     496               0 :                 efree(msg);
     497               0 :                 RETURN_FALSE;
     498                 :         }
     499                 : 
     500            1152 :         if(loc_name_len == 0) {
     501               0 :         loc_name = INTL_G(default_locale);
     502                 :         }
     503                 : 
     504            1152 :         if( tag_name != DISP_NAME ){
     505                 :                 /* Handle grandfathered languages */
     506             870 :                 grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
     507             870 :                 if( grOffset >= 0 ){
     508              54 :                         if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
     509              18 :                                 mod_loc_name = getPreferredTag( loc_name );
     510                 :                         } else {
     511                 :                                 /* Since Grandfathered, no value, do nothing, retutn NULL */
     512              36 :                                 RETURN_FALSE;
     513                 :                         }
     514                 :                 }
     515                 :         } /* end of if != LOC_CANONICAL_TAG */
     516                 : 
     517            1116 :         if( mod_loc_name==NULL ){
     518            1098 :                 mod_loc_name = estrdup( loc_name );
     519                 :         }
     520                 : 
     521                 :     /* Get the disp_value for the given locale */
     522                 :     do{
     523            1116 :         disp_name = erealloc( disp_name , buflen  );
     524            1116 :         disp_name_len = buflen;
     525                 : 
     526                 :         /* Check if disp_loc_name passed , if not use default locale */
     527            1116 :         if( !disp_loc_name){
     528               0 :             disp_loc_name = estrdup(INTL_G(default_locale));
     529                 :         }
     530                 : 
     531            1116 :                 if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
     532             222 :                         buflen = uloc_getDisplayLanguage ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     533             894 :                 } else if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
     534             204 :                         buflen = uloc_getDisplayScript ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     535             690 :                 } else if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
     536             204 :                         buflen = uloc_getDisplayCountry ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     537             486 :                 } else if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
     538             204 :                         buflen = uloc_getDisplayVariant ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     539             282 :                 } else if( strcmp(tag_name , DISP_NAME)==0 ){
     540             282 :                         buflen = uloc_getDisplayName ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     541                 :                 }
     542                 : 
     543            1116 :                 if( U_FAILURE( status ) )
     544                 :                 {
     545               0 :                         if( status == U_BUFFER_OVERFLOW_ERROR )
     546                 :                         {
     547               0 :                                 status = U_ZERO_ERROR;
     548               0 :                                 continue;
     549                 :                         }
     550                 : 
     551               0 :                         spprintf(&msg, 0, "locale_get_display_%s : unable to get locale %s", tag_name , tag_name );
     552               0 :                         intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
     553               0 :                         efree(msg);
     554               0 :                         if( disp_name){
     555               0 :                                 efree( disp_name );
     556                 :                         }
     557               0 :                         if( mod_loc_name){
     558               0 :                                 efree( mod_loc_name );
     559                 :                         }
     560               0 :                         RETURN_FALSE;
     561                 :                 }
     562            1116 :         } while( buflen > disp_name_len );
     563                 : 
     564            1116 :         if( mod_loc_name){
     565            1116 :                 efree( mod_loc_name );
     566                 :         }
     567                 :         /* Convert display locale name from UTF-16 to UTF-8. */
     568            1116 :         intl_convert_utf16_to_utf8( &utf8value, &utf8value_len, disp_name, buflen, &status );
     569            1116 :         efree( disp_name );
     570            1116 :         if( U_FAILURE( status ) )
     571                 :         {
     572               0 :                 spprintf(&msg, 0, "locale_get_display_%s :error converting display name for %s to UTF-8", tag_name , tag_name );
     573               0 :                 intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
     574               0 :                 efree(msg);
     575               0 :                 RETURN_FALSE;
     576                 :         }
     577                 : 
     578            1116 :         RETVAL_STRINGL( utf8value, utf8value_len , FALSE);
     579                 : 
     580                 : }
     581                 : /* }}} */
     582                 : 
     583                 : /* {{{ proto static string Locale::getDisplayName($locale[, $in_locale = null])
     584                 : * gets the name for the $locale in $in_locale or default_locale
     585                 :  }}} */
     586                 : /* {{{ proto static string get_display_name($locale[, $in_locale = null])
     587                 : * gets the name for the $locale in $in_locale or default_locale
     588                 : */
     589                 : PHP_FUNCTION(locale_get_display_name) 
     590             282 : {
     591             282 :     get_icu_disp_value_src_php( DISP_NAME , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     592             282 : }
     593                 : /* }}} */
     594                 : 
     595                 : /* {{{ proto static string Locale::getDisplayLanguage($locale[, $in_locale = null])
     596                 : * gets the language for the $locale in $in_locale or default_locale
     597                 :  }}} */
     598                 : /* {{{ proto static string get_display_language($locale[, $in_locale = null])
     599                 : * gets the language for the $locale in $in_locale or default_locale
     600                 : */
     601                 : PHP_FUNCTION(locale_get_display_language) 
     602             222 : {
     603             222 :     get_icu_disp_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     604             222 : }
     605                 : /* }}} */
     606                 : 
     607                 : /* {{{ proto static string Locale::getDisplayScript($locale, $in_locale = null)
     608                 : * gets the script for the $locale in $in_locale or default_locale
     609                 :  }}} */
     610                 : /* {{{ proto static string get_display_script($locale, $in_locale = null)
     611                 : * gets the script for the $locale in $in_locale or default_locale
     612                 : */
     613                 : PHP_FUNCTION(locale_get_display_script) 
     614             216 : {
     615             216 :     get_icu_disp_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     616             216 : }
     617                 : /* }}} */
     618                 : 
     619                 : /* {{{ proto static string Locale::getDisplayRegion($locale, $in_locale = null)
     620                 : * gets the region for the $locale in $in_locale or default_locale
     621                 :  }}} */
     622                 : /* {{{ proto static string get_display_region($locale, $in_locale = null)
     623                 : * gets the region for the $locale in $in_locale or default_locale
     624                 : */
     625                 : PHP_FUNCTION(locale_get_display_region) 
     626             216 : {
     627             216 :     get_icu_disp_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     628             216 : }
     629                 : /* }}} */
     630                 : 
     631                 : /* {{{
     632                 : * proto static string Locale::getDisplayVariant($locale, $in_locale = null)
     633                 : * gets the variant for the $locale in $in_locale or default_locale
     634                 :  }}} */
     635                 : /* {{{
     636                 : * proto static string get_display_variant($locale, $in_locale = null)
     637                 : * gets the variant for the $locale in $in_locale or default_locale
     638                 : */
     639                 : PHP_FUNCTION(locale_get_display_variant) 
     640             216 : {
     641             216 :     get_icu_disp_value_src_php( LOC_VARIANT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     642             216 : }
     643                 : /* }}} */
     644                 : 
     645                 :  /* {{{ proto static array getKeywords(string $locale) {
     646                 :  * return an associative array containing keyword-value
     647                 :  * pairs for this locale. The keys are keys to the array (doh!)
     648                 :  * }}}*/
     649                 :  /* {{{ proto static array locale_get_keywords(string $locale) {
     650                 :  * return an associative array containing keyword-value
     651                 :  * pairs for this locale. The keys are keys to the array (doh!)
     652                 :  */ 
     653                 : PHP_FUNCTION( locale_get_keywords )
     654              74 : {
     655              74 :     UEnumeration*   e        = NULL;
     656              74 :     UErrorCode      status   = U_ZERO_ERROR;
     657                 : 
     658              74 :         const char*             kw_key        = NULL;
     659              74 :     int32_t         kw_key_len    = 0;
     660                 : 
     661              74 :     char*               loc_name        = NULL;
     662              74 :     int                 loc_name_len    = 0;
     663                 : 
     664                 : /* 
     665                 :         ICU expects the buffer to be allocated  before calling the function 
     666                 :         and so the buffer size has been explicitly specified 
     667                 :         ICU uloc.h #define      ULOC_KEYWORD_AND_VALUES_CAPACITY   100 
     668                 :         hence the kw_value buffer size is 100
     669                 : */
     670              74 :         char*           kw_value        = NULL;
     671              74 :     int32_t     kw_value_len    = 100;
     672                 : 
     673              74 :     intl_error_reset( NULL TSRMLS_CC );
     674                 : 
     675              74 :     if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
     676                 :         &loc_name, &loc_name_len ) == FAILURE)
     677                 :     {
     678               0 :         intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     679                 :              "locale_get_keywords: unable to parse input params", 0 TSRMLS_CC );
     680                 : 
     681               0 :         RETURN_FALSE;
     682                 :     }
     683                 : 
     684              74 :     if(loc_name_len == 0) {
     685               0 :         loc_name = INTL_G(default_locale);
     686                 :     }
     687                 : 
     688                 :         /* Get the keywords */
     689              74 :     e = uloc_openKeywords( loc_name, &status );
     690              74 :     if( e != NULL )
     691                 :     {
     692                 :                 /* Traverse it, filling the return array. */
     693               6 :         array_init( return_value );
     694                 : 
     695              24 :         while( ( kw_key = uenum_next( e, &kw_key_len, &status ) ) != NULL ){
     696              12 :                         kw_value = ecalloc( 1 , kw_value_len  );
     697                 : 
     698                 :                         /* Get the keyword value for each keyword */
     699              12 :                         kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len ,  &status );
     700              12 :                         if (status == U_BUFFER_OVERFLOW_ERROR) {
     701               2 :                                 status = U_ZERO_ERROR;
     702               2 :                                 kw_value = erealloc( kw_value , kw_value_len+1);
     703               2 :                                 kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len+1 ,  &status );
     704              10 :                         } else if(!U_FAILURE(status)) {
     705              10 :                                 kw_value = erealloc( kw_value , kw_value_len+1);
     706                 :                         } 
     707              12 :                         if (U_FAILURE(status)) {
     708               0 :                         intl_error_set( NULL, FAILURE, "locale_get_keywords: Error encountered while getting the keyword  value for the  keyword", 0 TSRMLS_CC );
     709               0 :                                 if( kw_value){
     710               0 :                                         efree( kw_value );
     711                 :                                 }
     712               0 :                                 zval_dtor(return_value);
     713               0 :                         RETURN_FALSE;
     714                 :                         }
     715                 : 
     716              12 :                 add_assoc_stringl( return_value, (char *)kw_key, kw_value , kw_value_len, 0);
     717                 :                 } /* end of while */
     718                 : 
     719                 :         } /* end of if e!=NULL */
     720                 : 
     721              74 :     uenum_close( e );
     722                 : }
     723                 : /* }}} */
     724                 : 
     725                 :  /* {{{ proto static string Locale::canonicalize($locale) 
     726                 :  * @return string the canonicalized locale 
     727                 :  * }}} */
     728                 :  /* {{{ proto static string locale_canonicalize(Locale $loc, string $locale) 
     729                 :  * @param string $locale        The locale string to canonicalize
     730                 :  */
     731                 : PHP_FUNCTION(locale_canonicalize)
     732             394 : {
     733             394 :         get_icu_value_src_php( LOC_CANONICALIZE_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     734             394 : }
     735                 : /* }}} */
     736                 : 
     737                 : /* {{{ append_key_value 
     738                 : * Internal function which is called from locale_compose
     739                 : * gets the value for the key_name and appends to the loc_name
     740                 : * returns 1 if successful , -1 if not found , 
     741                 : * 0 if array element is not a string , -2 if buffer-overflow
     742                 : */
     743                 : static int append_key_value(smart_str* loc_name, HashTable* hash_arr, char* key_name)
     744              84 : {
     745              84 :         zval**  ele_value       = NULL;
     746                 : 
     747              84 :         if(zend_hash_find(hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
     748              52 :                 if(Z_TYPE_PP(ele_value)!= IS_STRING ){
     749                 :                         /* element value is not a string */
     750               2 :                         return FAILURE;
     751                 :                 }
     752              50 :                 if(strcmp(key_name, LOC_LANG_TAG) != 0 && 
     753                 :                    strcmp(key_name, LOC_GRANDFATHERED_LANG_TAG)!=0 ) {
     754                 :                         /* not lang or grandfathered tag */
     755              30 :                         smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     756                 :                 }
     757              50 :                 smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
     758              50 :                 return SUCCESS;
     759                 :         }
     760                 : 
     761              32 :         return LOC_NOT_FOUND;
     762                 : }
     763                 : /* }}} */
     764                 : 
     765                 : /* {{{ append_prefix , appends the prefix needed
     766                 : * e.g. private adds 'x'
     767                 : */
     768                 : static void add_prefix(smart_str* loc_name, char* key_name)
     769              18 : {
     770              18 :         if( strncmp(key_name , LOC_PRIVATE_TAG , 7) == 0 ){
     771               4 :                 smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     772               4 :                 smart_str_appendl(loc_name, PRIVATE_PREFIX , sizeof(PRIVATE_PREFIX)-1);
     773                 :         }
     774              18 : }
     775                 : /* }}} */
     776                 : 
     777                 : /* {{{ append_multiple_key_values 
     778                 : * Internal function which is called from locale_compose
     779                 : * gets the multiple values for the key_name and appends to the loc_name
     780                 : * used for 'variant','extlang','private' 
     781                 : * returns 1 if successful , -1 if not found , 
     782                 : * 0 if array element is not a string , -2 if buffer-overflow
     783                 : */
     784                 : static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, char* key_name TSRMLS_DC)
     785              56 : {
     786              56 :         zval**  ele_value       = NULL;
     787              56 :         int     i               = 0;
     788              56 :         int     isFirstSubtag   = 0;
     789              56 :         int     max_value       = 0;
     790                 : 
     791                 :         /* Variant/ Extlang/Private etc. */
     792              56 :         if( zend_hash_find( hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
     793               6 :                 if( Z_TYPE_PP(ele_value) == IS_STRING ){
     794               0 :                         add_prefix( loc_name , key_name);
     795                 : 
     796               0 :                         smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     797               0 :                         smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
     798               0 :                         return SUCCESS;
     799               6 :                 } else if(Z_TYPE_PP(ele_value) == IS_ARRAY ) {
     800                 :                         HashPosition pos;
     801               6 :                         HashTable *arr = HASH_OF(*ele_value);
     802               6 :                         zval **data = NULL;
     803                 : 
     804               6 :                         zend_hash_internal_pointer_reset_ex(arr, &pos);
     805              24 :                         while(zend_hash_get_current_data_ex(arr, (void **)&data, &pos) != FAILURE) {
     806              12 :                                 if(Z_TYPE_PP(data) != IS_STRING) {
     807               0 :                                         return FAILURE;
     808                 :                                 }
     809              12 :                                 if (isFirstSubtag++ == 0){
     810               6 :                                         add_prefix(loc_name , key_name);
     811                 :                                 }
     812              12 :                                 smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     813              12 :                                 smart_str_appendl(loc_name, Z_STRVAL_PP(data) , Z_STRLEN_PP(data));
     814              12 :                                 zend_hash_move_forward_ex(arr, &pos);
     815                 :                         }
     816               6 :                         return SUCCESS;
     817                 :                 } else {
     818               0 :                         return FAILURE;
     819                 :                 }
     820                 :         } else {
     821                 :                 char cur_key_name[31];
     822                 :                 /* Decide the max_value: the max. no. of elements allowed */
     823              50 :                 if( strcmp(key_name , LOC_VARIANT_TAG) ==0 ){
     824              16 :                         max_value  = MAX_NO_VARIANT;
     825                 :                 }
     826              50 :                 if( strcmp(key_name , LOC_EXTLANG_TAG) ==0 ){
     827              18 :                         max_value  = MAX_NO_EXTLANG;
     828                 :                 }
     829              50 :                 if( strcmp(key_name , LOC_PRIVATE_TAG) ==0 ){
     830              16 :                         max_value  = MAX_NO_PRIVATE;
     831                 :                 }
     832                 : 
     833                 :                 /* Multiple variant values as variant0, variant1 ,variant2 */
     834              50 :                 isFirstSubtag = 0;
     835             582 :                 for( i=0 ; i< max_value; i++ ){  
     836             534 :                         snprintf( cur_key_name , 30, "%s%d", key_name , i);   
     837             534 :                         if( zend_hash_find( hash_arr , cur_key_name , strlen(cur_key_name) + 1,(void **)&ele_value ) == SUCCESS ){
     838              26 :                                 if( Z_TYPE_PP(ele_value)!= IS_STRING ){
     839                 :                                         /* variant is not a string */
     840               2 :                                         return FAILURE;
     841                 :                                 }
     842                 :                                 /* Add the contents */
     843              24 :                                 if (isFirstSubtag++ == 0){
     844              12 :                                         add_prefix(loc_name , cur_key_name);
     845                 :                                 }
     846              24 :                                 smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     847              24 :                                 smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
     848                 :                         }
     849                 :                 } /* end of for */
     850                 :         } /* end of else */
     851                 : 
     852              48 :         return SUCCESS;
     853                 : }
     854                 : /* }}} */
     855                 : 
     856                 : /*{{{
     857                 : * If applicable sets error message and aborts locale_compose gracefully
     858                 : * returns 0  if locale_compose needs to be aborted 
     859                 : * otherwise returns 1
     860                 : */
     861                 : static int handleAppendResult( int result, smart_str* loc_name TSRMLS_DC)
     862             138 : {
     863             138 :         intl_error_reset( NULL TSRMLS_CC );
     864             138 :         if( result == FAILURE) {
     865               4 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     866                 :                          "locale_compose: parameter array element is not a string", 0 TSRMLS_CC );
     867               4 :                 smart_str_free(loc_name);
     868               4 :                 return 0;
     869                 :         }
     870             134 :         return 1;
     871                 : }
     872                 : /* }}} */
     873                 : 
     874                 : #define RETURN_SMART_STR(s) smart_str_0((s)); RETURN_STRINGL((s)->c, (s)->len, 0)
     875                 : /* {{{ proto static string Locale::composeLocale($array) 
     876                 : * Creates a locale by combining the parts of locale-ID passed   
     877                 : * }}} */
     878                 : /* {{{ proto static string compose_locale($array) 
     879                 : * Creates a locale by combining the parts of locale-ID passed   
     880                 : * }}} */
     881                 : PHP_FUNCTION(locale_compose)
     882              24 : {
     883              24 :         smart_str       loc_name_s = {0};
     884              24 :         smart_str *loc_name = &loc_name_s;
     885              24 :         zval*                   arr     = NULL;
     886              24 :         HashTable*              hash_arr = NULL;
     887              24 :         int                     result = 0;
     888                 : 
     889              24 :         intl_error_reset( NULL TSRMLS_CC );
     890                 : 
     891              24 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "a",
     892                 :                 &arr) == FAILURE)
     893                 :         {
     894               0 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     895                 :                          "locale_compose: unable to parse input params", 0 TSRMLS_CC );
     896               0 :                 RETURN_FALSE;
     897                 :         }
     898                 : 
     899              24 :         hash_arr = HASH_OF( arr );
     900                 : 
     901              24 :         if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
     902               0 :                 RETURN_FALSE;
     903                 : 
     904                 :         /* Check for grandfathered first */
     905              24 :         result = append_key_value(loc_name, hash_arr,  LOC_GRANDFATHERED_LANG_TAG);     
     906              24 :         if( result == SUCCESS){
     907               0 :                 RETURN_SMART_STR(loc_name);
     908                 :         }
     909              24 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     910               0 :                 RETURN_FALSE;
     911                 :         }
     912                 : 
     913                 :         /* Not grandfathered */
     914              24 :         result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);   
     915              24 :         if( result == LOC_NOT_FOUND ){
     916               2 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     917                 :                 "locale_compose: parameter array does not contain 'language' tag.", 0 TSRMLS_CC );
     918               2 :                 smart_str_free(loc_name);
     919               2 :                 RETURN_FALSE;
     920                 :         }
     921              22 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     922               2 :                 RETURN_FALSE;
     923                 :         }
     924                 : 
     925                 :         /* Extlang */
     926              20 :         result = append_multiple_key_values(loc_name, hash_arr , LOC_EXTLANG_TAG TSRMLS_CC);
     927              20 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     928               2 :                 RETURN_FALSE;
     929                 :         }
     930                 : 
     931                 :         /* Script */
     932              18 :         result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG); 
     933              18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     934               0 :                 RETURN_FALSE;
     935                 :         }
     936                 :         
     937                 :         /* Region */
     938              18 :         result = append_key_value( loc_name, hash_arr , LOC_REGION_TAG);
     939              18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     940               0 :                 RETURN_FALSE;
     941                 :         }
     942                 : 
     943                 :         /* Variant */
     944              18 :         result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC); 
     945              18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     946               0 :                 RETURN_FALSE;
     947                 :         }
     948                 : 
     949                 :         /* Private */
     950              18 :         result = append_multiple_key_values( loc_name, hash_arr , LOC_PRIVATE_TAG TSRMLS_CC);
     951              18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     952               0 :                 RETURN_FALSE;
     953                 :         }
     954                 : 
     955              18 :         RETURN_SMART_STR(loc_name);
     956                 : }
     957                 : /* }}} */
     958                 : 
     959                 : 
     960                 : /*{{{
     961                 : * Parses the locale and returns private subtags  if existing
     962                 : * else returns NULL
     963                 : * e.g. for locale='en_US-x-prv1-prv2-prv3'
     964                 : * returns a pointer to the string 'prv1-prv2-prv3'
     965                 : */
     966                 : static char* get_private_subtags(char* loc_name)
     967              66 : {
     968              66 :         char*   result =NULL;
     969              66 :         int     singletonPos = 0;
     970              66 :         int     len =0; 
     971              66 :         char*   mod_loc_name =NULL;
     972                 : 
     973              66 :         if( loc_name && (len = strlen(loc_name)>0 ) ){
     974              66 :                 mod_loc_name = loc_name ; 
     975              66 :                 len   = strlen(mod_loc_name);
     976             148 :                 while( (singletonPos = getSingletonPos(mod_loc_name))!= -1){
     977                 : 
     978              24 :                         if( singletonPos!=-1){ 
     979              24 :                                 if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){               
     980                 :                                         /* private subtag start found */
     981               8 :                                         if( singletonPos + 2 ==  len){
     982                 :                                                 /* loc_name ends with '-x-' ; return  NULL */
     983                 :                                         }
     984                 :                                         else{
     985                 :                                                 /* result = mod_loc_name + singletonPos +2; */
     986               8 :                                                 result = estrndup(mod_loc_name + singletonPos+2  , (len -( singletonPos +2) ) );
     987                 :                                         }
     988               8 :                                         break;
     989                 :                                 }
     990                 :                                 else{
     991              16 :                                         if( singletonPos + 1 >=  len){
     992                 :                                                 /* String end */
     993               0 :                                                 break;
     994                 :                                         } else {
     995                 :                                                 /* singleton found but not a private subtag , hence check further in the string for the private subtag */
     996              16 :                                                 mod_loc_name = mod_loc_name + singletonPos +1;
     997              16 :                                                 len = strlen(mod_loc_name);
     998                 :                                         }
     999                 :                                 }
    1000                 :                         }
    1001                 : 
    1002                 :                 } /* end of while */
    1003                 :         }
    1004                 :         
    1005              66 :         return result;
    1006                 : }
    1007                 : /* }}} */
    1008                 : 
    1009                 : /* {{{ code used by locale_parse
    1010                 : */
    1011                 : static int add_array_entry(char* loc_name, zval* hash_arr, char* key_name TSRMLS_DC)
    1012             330 : {
    1013             330 :         char*   key_value       = NULL;
    1014             330 :         char*   cur_key_name    = NULL;
    1015             330 :         char*   token           = NULL;
    1016             330 :         char*   last_ptr        = NULL;
    1017                 : 
    1018             330 :         int     result          = 0;
    1019             330 :         int     cur_result      = 0;
    1020             330 :         int     cnt             = 0;
    1021                 : 
    1022                 : 
    1023             330 :         if( strcmp(key_name , LOC_PRIVATE_TAG)==0 ){
    1024              66 :                 key_value = get_private_subtags( loc_name );
    1025              66 :                 result = 1;
    1026                 :         } else {
    1027             264 :                 key_value = get_icu_value_internal( loc_name , key_name , &result,1 );
    1028                 :         }
    1029             462 :         if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) || 
    1030                 :                 ( strcmp(key_name , LOC_VARIANT_TAG)==0) ){
    1031             132 :                 if( result > 0 && key_value){
    1032                 :                         /* Tokenize on the "_" or "-"  */
    1033              20 :                         token = php_strtok_r( key_value , DELIMITER ,&last_ptr);    
    1034              20 :                         if( cur_key_name ){
    1035               0 :                                 efree( cur_key_name);
    1036                 :                         }
    1037              20 :                         cur_key_name = (char*)ecalloc( 25,  25);
    1038              20 :                         sprintf( cur_key_name , "%s%d", key_name , cnt++);    
    1039              20 :                         add_assoc_string( hash_arr, cur_key_name , token ,TRUE );
    1040                 :                         /* tokenize on the "_" or "-" and stop  at singleton if any */
    1041              46 :                         while( (token = php_strtok_r(NULL , DELIMITER , &last_ptr)) && (strlen(token)>1) ){
    1042               6 :                                 sprintf( cur_key_name , "%s%d", key_name , cnt++);    
    1043               6 :                                 add_assoc_string( hash_arr, cur_key_name , token , TRUE );
    1044                 :                         }
    1045                 : 
    1046                 :                         if( key_name == LOC_PRIVATE_TAG ){
    1047                 :                         }
    1048                 :                 }
    1049                 :         } else {
    1050             198 :                 if( result == 1 ){
    1051             124 :                         add_assoc_string( hash_arr, key_name , key_value , TRUE );
    1052             124 :                         cur_result = 1;
    1053                 :                 }
    1054                 :         }
    1055                 : 
    1056             330 :         if( cur_key_name ){
    1057              20 :                 efree( cur_key_name);
    1058                 :         }
    1059                 :         /*if( key_name != LOC_PRIVATE_TAG && key_value){*/
    1060             330 :         if( key_value){
    1061             144 :                 efree(key_value);       
    1062                 :         }
    1063             330 :         return cur_result;
    1064                 : }
    1065                 : /* }}} */
    1066                 : 
    1067                 : /* {{{ proto static array Locale::parseLocale($locale) 
    1068                 : * parses a locale-id into an array the different parts of it
    1069                 :  }}} */
    1070                 : /* {{{ proto static array parse_locale($locale) 
    1071                 : * parses a locale-id into an array the different parts of it
    1072                 : */
    1073                 : PHP_FUNCTION(locale_parse)
    1074              70 : {
    1075              70 :     char*       loc_name        = NULL;
    1076              70 :     int         loc_name_len    = 0;
    1077              70 :     int         grOffset        = 0;
    1078                 : 
    1079              70 :     intl_error_reset( NULL TSRMLS_CC );
    1080                 : 
    1081              70 :     if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
    1082                 :         &loc_name, &loc_name_len ) == FAILURE)
    1083                 :     {
    1084               0 :         intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1085                 :              "locale_parse: unable to parse input params", 0 TSRMLS_CC );
    1086                 : 
    1087               0 :         RETURN_FALSE;
    1088                 :     }
    1089                 : 
    1090              70 :     if(loc_name_len == 0) {
    1091               0 :         loc_name = INTL_G(default_locale);
    1092                 :     }
    1093                 : 
    1094              70 :         array_init( return_value );
    1095                 : 
    1096              70 :         grOffset =  findOffset( LOC_GRANDFATHERED , loc_name );
    1097              70 :         if( grOffset >= 0 ){
    1098               4 :                 add_assoc_string( return_value , LOC_GRANDFATHERED_LANG_TAG , estrdup(loc_name) ,FALSE );
    1099                 :         }
    1100                 :         else{
    1101                 :                 /* Not grandfathered */
    1102              66 :                 add_array_entry( loc_name , return_value , LOC_LANG_TAG TSRMLS_CC);
    1103              66 :                 add_array_entry( loc_name , return_value , LOC_SCRIPT_TAG TSRMLS_CC);
    1104              66 :                 add_array_entry( loc_name , return_value , LOC_REGION_TAG TSRMLS_CC);
    1105              66 :                 add_array_entry( loc_name , return_value , LOC_VARIANT_TAG TSRMLS_CC);
    1106              66 :                 add_array_entry( loc_name , return_value , LOC_PRIVATE_TAG TSRMLS_CC);
    1107                 :         }
    1108                 : }
    1109                 : /* }}} */
    1110                 : 
    1111                 : /* {{{ proto static array Locale::getAllVariants($locale)
    1112                 : * gets an array containing the list of variants, or null
    1113                 :  }}} */
    1114                 : /* {{{ proto static array locale_get_all_variants($locale)
    1115                 : * gets an array containing the list of variants, or null
    1116                 : */
    1117                 : PHP_FUNCTION(locale_get_all_variants)
    1118              22 : {
    1119              22 :         char*   loc_name        = NULL;
    1120              22 :         int     loc_name_len    = 0;
    1121                 : 
    1122              22 :         int     result          = 0;
    1123              22 :         char*   token           = NULL;
    1124              22 :         char*   variant         = NULL;
    1125              22 :         char*   saved_ptr       = NULL;
    1126                 : 
    1127              22 :         intl_error_reset( NULL TSRMLS_CC );
    1128                 :         
    1129              22 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
    1130                 :         &loc_name, &loc_name_len ) == FAILURE)
    1131                 :         {
    1132               0 :         intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1133                 :              "locale_parse: unable to parse input params", 0 TSRMLS_CC );
    1134                 : 
    1135               0 :         RETURN_FALSE;
    1136                 :         }
    1137                 : 
    1138              22 :         if(loc_name_len == 0) {
    1139               0 :                 loc_name = INTL_G(default_locale);
    1140                 :         }
    1141                 : 
    1142                 : 
    1143              22 :         array_init( return_value );
    1144                 : 
    1145                 :         /* If the locale is grandfathered, stop, no variants */
    1146              22 :         if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){ 
    1147                 :                 /* ("Grandfathered Tag. No variants."); */
    1148                 :         }
    1149                 :         else {  
    1150                 :         /* Call ICU variant */
    1151              10 :                 variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0);
    1152              10 :                 if( result > 0 && variant){
    1153                 :                         /* Tokenize on the "_" or "-" */
    1154              10 :                         token = php_strtok_r( variant , DELIMITER , &saved_ptr);    
    1155              10 :                         add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
    1156                 :                         /* tokenize on the "_" or "-" and stop  at singleton if any */
    1157              26 :                         while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
    1158               6 :                                 add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
    1159                 :                         }
    1160                 :                 }
    1161              10 :                 if( variant ){
    1162              10 :                         efree( variant );
    1163                 :                 }
    1164                 :         }
    1165                 :                         
    1166                 : 
    1167                 : }
    1168                 : /* }}} */
    1169                 : 
    1170                 : /*{{{
    1171                 : * Converts to lower case and also replaces all hyphens with the underscore
    1172                 : */
    1173                 : static int strToMatch(char* str ,char *retstr)
    1174            1298 : {
    1175            1298 :         char*   anchor  = NULL;
    1176            1298 :         char*   anchor1 = NULL;
    1177            1298 :         int     result  = 0;
    1178            1298 :         int     len     = 0;
    1179                 : 
    1180            1298 :     if( (!str) || str[0] == '\0'){
    1181               0 :         return result;
    1182                 :     } else {
    1183            1298 :         anchor = retstr;
    1184            1298 :         anchor1 = str;
    1185            1298 :         len = strlen(str);
    1186           13820 :         while( (*str)!='\0' ){
    1187           11224 :                 if( *str == '-' ){
    1188             724 :                         *retstr =  '_';
    1189                 :                 } else {
    1190           10500 :                         *retstr = tolower(*str);
    1191                 :                 }
    1192           11224 :             str++;
    1193           11224 :             retstr++;
    1194                 :         }
    1195            1298 :         *retstr = '\0';
    1196            1298 :         retstr=  anchor;
    1197            1298 :         str=  anchor1;
    1198            1298 :         result = 1;
    1199                 :     }
    1200                 : 
    1201            1298 :     return(result);
    1202                 : }
    1203                 : /* }}} */
    1204                 : 
    1205                 : /* {{{ proto static boolean Locale::filterMatches(string $langtag, string $locale[, bool $canonicalize])
    1206                 : * Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
    1207                 : */
    1208                 : /* }}} */
    1209                 : /* {{{ proto boolean locale_filter_matches(string $langtag, string $locale[, bool $canonicalize])
    1210                 : * Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
    1211                 : */
    1212                 : PHP_FUNCTION(locale_filter_matches)
    1213             384 : {
    1214             384 :         char*           lang_tag        = NULL;
    1215             384 :         int             lang_tag_len    = 0;
    1216             384 :         char*           loc_range       = NULL;
    1217             384 :         int             loc_range_len   = 0;
    1218                 : 
    1219             384 :         int             result          = 0;
    1220             384 :         char*           token           = 0;
    1221             384 :         char*           chrcheck        = NULL;
    1222                 : 
    1223             384 :         char*           can_lang_tag    = NULL;
    1224             384 :         char*           can_loc_range   = NULL;
    1225                 : 
    1226             384 :         char*           cur_lang_tag    = NULL;
    1227             384 :         char*           cur_loc_range   = NULL;
    1228                 : 
    1229             384 :         zend_bool       boolCanonical   = 0;    
    1230             384 :         UErrorCode      status          = U_ZERO_ERROR;
    1231                 : 
    1232             384 :         intl_error_reset( NULL TSRMLS_CC );
    1233                 :         
    1234             384 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss|b",
    1235                 :                 &lang_tag, &lang_tag_len , &loc_range , &loc_range_len , 
    1236                 :                 &boolCanonical) == FAILURE)
    1237                 :         {
    1238               0 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1239                 :                 "locale_filter_matches: unable to parse input params", 0 TSRMLS_CC );
    1240                 : 
    1241               0 :                 RETURN_FALSE;
    1242                 :         }
    1243                 : 
    1244             384 :         if(loc_range_len == 0) {
    1245               0 :                 loc_range = INTL_G(default_locale);
    1246                 :         }
    1247                 : 
    1248             384 :         if( strcmp(loc_range,"*")==0){
    1249               0 :                 RETURN_TRUE;
    1250                 :         }
    1251                 : 
    1252             384 :         if( boolCanonical ){
    1253                 :                 /* canonicalize loc_range */
    1254             192 :                 can_loc_range=get_icu_value_internal( loc_range , LOC_CANONICALIZE_TAG , &result , 0);
    1255             192 :                 if( result ==0) {
    1256               0 :                         intl_error_set( NULL, status, 
    1257                 :                                 "locale_filter_matches : unable to canonicalize loc_range" , 0 TSRMLS_CC );
    1258               0 :                         RETURN_FALSE;
    1259                 :                 }
    1260                 : 
    1261                 :                 /* canonicalize lang_tag */
    1262             192 :                 can_lang_tag = get_icu_value_internal( lang_tag , LOC_CANONICALIZE_TAG , &result ,  0);
    1263             192 :                 if( result ==0) {
    1264               0 :                         intl_error_set( NULL, status, 
    1265                 :                                 "locale_filter_matches : unable to canonicalize lang_tag" , 0 TSRMLS_CC );
    1266               0 :                         RETURN_FALSE;
    1267                 :                 }
    1268                 : 
    1269                 :                 /* Convert to lower case for case-insensitive comparison */
    1270             192 :                 cur_lang_tag = ecalloc( 1, strlen(can_lang_tag) + 1);
    1271                 : 
    1272                 :                 /* Convert to lower case for case-insensitive comparison */
    1273             192 :                 result = strToMatch( can_lang_tag , cur_lang_tag);
    1274             192 :                 if( result == 0) {
    1275               0 :                         efree( cur_lang_tag );
    1276               0 :                         efree( can_lang_tag );
    1277               0 :                         RETURN_FALSE;
    1278                 :                 }
    1279                 : 
    1280             192 :                 cur_loc_range = ecalloc( 1, strlen(can_loc_range) + 1);
    1281             192 :                 result = strToMatch( can_loc_range , cur_loc_range );
    1282             192 :                 if( result == 0) {
    1283               0 :                         efree( cur_lang_tag );
    1284               0 :                         efree( can_lang_tag );
    1285               0 :                         efree( cur_loc_range );
    1286               0 :                         efree( can_loc_range );
    1287               0 :                         RETURN_FALSE;
    1288                 :                 }
    1289                 : 
    1290                 :                 /* check if prefix */
    1291             192 :                 token   = strstr( cur_lang_tag , cur_loc_range );
    1292                 :         
    1293             192 :                 if( token && (token==cur_lang_tag) ){
    1294                 :                         /* check if the char. after match is SEPARATOR */
    1295              38 :                         chrcheck = token + (strlen(cur_loc_range));
    1296              38 :                         if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
    1297              36 :                                 if( cur_lang_tag){
    1298              36 :                                         efree( cur_lang_tag );
    1299                 :                                 }
    1300              36 :                                 if( cur_loc_range){
    1301              36 :                                         efree( cur_loc_range );
    1302                 :                                 }
    1303              36 :                                 if( can_lang_tag){
    1304              36 :                                         efree( can_lang_tag );
    1305                 :                                 }
    1306              36 :                                 if( can_loc_range){
    1307              36 :                                         efree( can_loc_range );
    1308                 :                                 }
    1309              36 :                                 RETURN_TRUE;
    1310                 :                         }
    1311                 :                 }
    1312                 : 
    1313                 :                 /* No prefix as loc_range */
    1314             156 :                 if( cur_lang_tag){
    1315             156 :                         efree( cur_lang_tag );
    1316                 :                 }
    1317             156 :                 if( cur_loc_range){
    1318             156 :                         efree( cur_loc_range );
    1319                 :                 }
    1320             156 :                 if( can_lang_tag){
    1321             156 :                         efree( can_lang_tag );
    1322                 :                 }
    1323             156 :                 if( can_loc_range){
    1324             156 :                         efree( can_loc_range );
    1325                 :                 }
    1326             156 :                 RETURN_FALSE;
    1327                 : 
    1328                 :         } /* end of if isCanonical */
    1329                 :         else{
    1330                 :                 /* Convert to lower case for case-insensitive comparison */
    1331             192 :                 cur_lang_tag = ecalloc( 1, strlen(lang_tag ) + 1);
    1332                 :                 
    1333             192 :                 result = strToMatch( lang_tag , cur_lang_tag);
    1334             192 :                 if( result == 0) {
    1335               0 :                         efree( cur_lang_tag );
    1336               0 :                         RETURN_FALSE;
    1337                 :                 }
    1338             192 :                 cur_loc_range = ecalloc( 1, strlen(loc_range ) + 1);
    1339             192 :                 result = strToMatch( loc_range , cur_loc_range );
    1340             192 :                 if( result == 0) {
    1341               0 :                         efree( cur_lang_tag );
    1342               0 :                         efree( cur_loc_range );
    1343               0 :                         RETURN_FALSE;
    1344                 :                 }
    1345                 : 
    1346                 :                 /* check if prefix */
    1347             192 :                 token   = strstr( cur_lang_tag , cur_loc_range );
    1348                 :                 
    1349             192 :                 if( token && (token==cur_lang_tag) ){
    1350                 :                         /* check if the char. after match is SEPARATOR */
    1351              32 :                         chrcheck = token + (strlen(cur_loc_range));
    1352              32 :                         if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
    1353              30 :                                 if( cur_lang_tag){
    1354              30 :                                         efree( cur_lang_tag );
    1355                 :                                 }
    1356              30 :                                 if( cur_loc_range){
    1357              30 :                                         efree( cur_loc_range );
    1358                 :                                 }
    1359              30 :                                 RETURN_TRUE;
    1360                 :                         }
    1361                 :                 }
    1362                 : 
    1363                 :                 /* No prefix as loc_range */
    1364             162 :                 if( cur_lang_tag){
    1365             162 :                         efree( cur_lang_tag );
    1366                 :                 }
    1367             162 :                 if( cur_loc_range){
    1368             162 :                         efree( cur_loc_range );
    1369                 :                 }
    1370             162 :                 RETURN_FALSE;
    1371                 : 
    1372                 :         }
    1373                 : }
    1374                 : /* }}} */
    1375                 : 
    1376                 : static void array_cleanup( char* arr[] , int arr_size)
    1377              20 : {
    1378              20 :         int i=0;
    1379             360 :         for( i=0; i< arr_size; i++ ){ 
    1380             340 :                 if( arr[i*2] ){
    1381             340 :                         efree( arr[i*2]);
    1382                 :                 }
    1383                 :         }
    1384              20 :         efree(arr);
    1385              20 : }
    1386                 : 
    1387                 : #define LOOKUP_CLEAN_RETURN(value)      array_cleanup(cur_arr, cur_arr_len); return (value)
    1388                 : /* {{{
    1389                 : * returns the lookup result to lookup_loc_range_src_php 
    1390                 : * internal function
    1391                 : */
    1392                 : static char* lookup_loc_range(char* loc_range, HashTable* hash_arr, int canonicalize  TSRMLS_DC)
    1393              20 : {
    1394              20 :         int     i = 0;
    1395              20 :         int     cur_arr_len = 0;
    1396              20 :         int result = 0;
    1397                 : 
    1398              20 :         char* lang_tag = NULL;
    1399              20 :         zval** ele_value = NULL;
    1400              20 :         char** cur_arr = NULL;
    1401                 : 
    1402              20 :         char* cur_loc_range     = NULL;
    1403              20 :         char* can_loc_range     = NULL;
    1404              20 :         int     saved_pos = 0;
    1405                 : 
    1406              20 :         char* return_value = NULL;
    1407                 : 
    1408              20 :         cur_arr = ecalloc(zend_hash_num_elements(hash_arr)*2, sizeof(char *));
    1409                 :         /* convert the array to lowercase , also replace hyphens with the underscore and store it in cur_arr */
    1410              20 :         for(zend_hash_internal_pointer_reset(hash_arr);
    1411             380 :                 zend_hash_has_more_elements(hash_arr) == SUCCESS;
    1412             340 :                 zend_hash_move_forward(hash_arr)) {
    1413                 :                 
    1414             340 :                 if (zend_hash_get_current_data(hash_arr, (void**)&ele_value) == FAILURE) {
    1415                 :                         /* Should never actually fail since the key is known to exist.*/
    1416               0 :                         continue;
    1417                 :                 }
    1418             340 :                 if(Z_TYPE_PP(ele_value)!= IS_STRING) {
    1419                 :                         /* element value is not a string */
    1420               0 :                         intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: locale array element is not a string", 0 TSRMLS_CC);
    1421               0 :                         LOOKUP_CLEAN_RETURN(NULL);
    1422                 :                 } 
    1423             340 :                 cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_PP(ele_value), Z_STRLEN_PP(ele_value));
    1424             340 :                 result = strToMatch(Z_STRVAL_PP(ele_value), cur_arr[cur_arr_len*2]);
    1425             340 :                 if(result == 0) {
    1426               0 :                         intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag", 0 TSRMLS_CC);
    1427               0 :                         LOOKUP_CLEAN_RETURN(NULL);
    1428                 :                 }
    1429             340 :                 cur_arr[cur_arr_len*2+1] = Z_STRVAL_PP(ele_value);
    1430             340 :                 cur_arr_len++ ; 
    1431                 :         } /* end of for */
    1432                 : 
    1433                 :         /* Canonicalize array elements */
    1434              20 :         if(canonicalize) {
    1435             180 :                 for(i=0; i<cur_arr_len; i++) { 
    1436             170 :                         lang_tag = get_icu_value_internal(cur_arr[i*2], LOC_CANONICALIZE_TAG, &result, 0);
    1437             170 :                         if(result != 1 || lang_tag == NULL || !lang_tag[0]) {
    1438               0 :                                 if(lang_tag) {
    1439               0 :                                         efree(lang_tag);
    1440                 :                                 }
    1441               0 :                                 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
    1442               0 :                                 LOOKUP_CLEAN_RETURN(NULL);
    1443                 :                         }
    1444             170 :                         cur_arr[i*2] = erealloc(cur_arr[i*2], strlen(lang_tag)+1);
    1445             170 :                         result = strToMatch(lang_tag, cur_arr[i*2]);    
    1446             170 :                         efree(lang_tag);
    1447             170 :                         if(result == 0) {
    1448               0 :                                 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
    1449               0 :                                 LOOKUP_CLEAN_RETURN(NULL);
    1450                 :                         }
    1451                 :                 }
    1452                 : 
    1453                 :         }
    1454                 : 
    1455              20 :         if(canonicalize) {
    1456                 :                 /* Canonicalize the loc_range */
    1457              10 :                 can_loc_range = get_icu_value_internal(loc_range, LOC_CANONICALIZE_TAG, &result , 0);
    1458              10 :                 if( result != 1 || can_loc_range == NULL || !can_loc_range[0]) {
    1459                 :                         /* Error */
    1460               0 :                         intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize loc_range" , 0 TSRMLS_CC );
    1461               0 :                         if(can_loc_range) {
    1462               0 :                                 efree(can_loc_range);
    1463                 :                         }
    1464               0 :                         LOOKUP_CLEAN_RETURN(NULL);
    1465                 :                 } else {
    1466              10 :                         loc_range = can_loc_range;
    1467                 :                 }
    1468                 :         } 
    1469                 : 
    1470              20 :         cur_loc_range = ecalloc(1, strlen(loc_range)+1);
    1471                 :         /* convert to lower and replace hyphens */
    1472              20 :         result = strToMatch(loc_range, cur_loc_range);  
    1473              20 :         if(can_loc_range) {
    1474              10 :                 efree(can_loc_range);
    1475                 :         }
    1476              20 :         if(result == 0) {
    1477               0 :                 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
    1478               0 :                 LOOKUP_CLEAN_RETURN(NULL);
    1479                 :         }
    1480                 : 
    1481                 :         /* Lookup for the lang_tag match */
    1482              20 :         saved_pos = strlen(cur_loc_range);
    1483              44 :         while(saved_pos > 0) {
    1484             234 :                 for(i=0; i< cur_arr_len; i++){ 
    1485             230 :                         if(cur_arr[i*2] != NULL && strlen(cur_arr[i*2]) == saved_pos && strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) { 
    1486                 :                                 /* Match found */
    1487              20 :                                 return_value = estrdup(canonicalize?cur_arr[i*2]:cur_arr[i*2+1]);
    1488              20 :                                 efree(cur_loc_range);
    1489              20 :                                 LOOKUP_CLEAN_RETURN(return_value);
    1490                 :                         }
    1491                 :                 }
    1492               4 :                 saved_pos = getStrrtokenPos(cur_loc_range, saved_pos);
    1493                 :         }
    1494                 : 
    1495                 :         /* Match not found */
    1496               0 :         efree(cur_loc_range);
    1497               0 :         LOOKUP_CLEAN_RETURN(NULL);
    1498                 : }
    1499                 : /* }}} */
    1500                 : 
    1501                 : /* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) 
    1502                 : * Searchs the items in $langtag for the best match to the language
    1503                 : * range 
    1504                 : */
    1505                 : /* }}} */
    1506                 : /* {{{ proto string locale_lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
    1507                 : * Searchs the items in $langtag for the best match to the language
    1508                 : * range 
    1509                 : */
    1510                 : PHP_FUNCTION(locale_lookup)
    1511              20 : {
    1512              20 :         char*           fallback_loc            = NULL;
    1513              20 :         int             fallback_loc_len        = 0;
    1514              20 :         char*           loc_range               = NULL;
    1515              20 :         int             loc_range_len           = 0;
    1516                 : 
    1517              20 :         zval*           arr                             = NULL;
    1518              20 :         HashTable*      hash_arr                = NULL;
    1519              20 :         zend_bool       boolCanonical   = 0;
    1520              20 :         char*           result                  =NULL;
    1521                 : 
    1522              20 :         intl_error_reset( NULL TSRMLS_CC );
    1523                 : 
    1524              20 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "as|bs", &arr, &loc_range, &loc_range_len,
    1525                 :                 &boolCanonical,     &fallback_loc, &fallback_loc_len) == FAILURE) {
    1526               0 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "locale_lookup: unable to parse input params", 0 TSRMLS_CC );
    1527               0 :                 RETURN_NULL();
    1528                 :         }
    1529                 : 
    1530              20 :         if(loc_range_len == 0) {
    1531               0 :                 loc_range = INTL_G(default_locale);
    1532                 :         }
    1533                 : 
    1534              20 :         hash_arr = HASH_OF(arr);
    1535                 : 
    1536              20 :         if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) {
    1537               0 :                 RETURN_EMPTY_STRING();
    1538                 :         } 
    1539                 :         
    1540              20 :         result = lookup_loc_range(loc_range, hash_arr, boolCanonical TSRMLS_CC);
    1541              20 :         if(result == NULL || result[0] == '\0') {
    1542               0 :                 if( fallback_loc ) {
    1543               0 :                         result = estrndup(fallback_loc, fallback_loc_len);
    1544                 :                 } else {
    1545               0 :                         RETURN_EMPTY_STRING();
    1546                 :                 }
    1547                 :         }
    1548                 : 
    1549              20 :         RETVAL_STRINGL(result, strlen(result), 0);
    1550                 : }
    1551                 : /* }}} */
    1552                 : 
    1553                 : /* {{{ proto string Locale::acceptFromHttp(string $http_accept)
    1554                 : * Tries to find out best available locale based on HTTP “Accept-Language” header
    1555                 : */
    1556                 : /* }}} */
    1557                 : /* {{{ proto string locale_accept_from_http(string $http_accept)
    1558                 : * Tries to find out best available locale based on HTTP “Accept-Language” header
    1559                 : */
    1560                 : PHP_FUNCTION(locale_accept_from_http)
    1561              12 : {
    1562                 :         UEnumeration *available;
    1563              12 :         char *http_accept = NULL;
    1564                 :         int http_accept_len;
    1565              12 :         UErrorCode status = 0;
    1566                 :         int len;
    1567                 :         char resultLocale[INTL_MAX_LOCALE_LEN+1];
    1568                 :         UAcceptResult outResult;
    1569                 : 
    1570              12 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &http_accept, &http_accept_len) == FAILURE)
    1571                 :         {
    1572               2 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1573                 :                 "locale_accept_from_http: unable to parse input parameters", 0 TSRMLS_CC );
    1574               2 :                 RETURN_NULL();
    1575                 :         }
    1576                 :         
    1577              10 :         available = ures_openAvailableLocales(NULL, &status);
    1578              10 :         INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list");
    1579              10 :         len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, 
    1580                 :                                                 &outResult, http_accept, available, &status);
    1581              10 :         uenum_close(available);
    1582              10 :         INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to find acceptable locale");
    1583              10 :         if (len < 0 || outResult == ULOC_ACCEPT_FAILED) {
    1584               2 :                 RETURN_FALSE;
    1585                 :         }
    1586               8 :         RETURN_STRINGL(resultLocale, len, 1);
    1587                 : }
    1588                 : /* }}} */
    1589                 : 
    1590                 : /*
    1591                 :  * Local variables:
    1592                 :  * tab-width: 4
    1593                 :  * c-basic-offset: 4
    1594                 :  * End:
    1595                 :  * vim600: noet sw=4 ts=4 fdm=marker
    1596                 :  * vim<600: noet sw=4 ts=4
    1597                 :  *can_loc_len
    1598                 : */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:01 +0000 (3 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.