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

LCOV - code coverage report
Current view: top level - ext/intl/locale - locale_methods.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 599 703 85.2 %
Date: 2014-07-27 Functions: 34 34 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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$ */
      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        1468 : static int16_t findOffset(const char* const* list, const char* key)
     110             : {
     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          18 : static char* getPreferredTag(char* gf_tag)
     125             : { 
     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           4 : static int getStrrtokenPos(char* str, int savedPos)
     146             : {
     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         346 : static int getSingletonPos(char* str)
     176             : {
     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          78 : PHP_NAMED_FUNCTION(zif_locale_get_default)
     210             : {
     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          75 : PHP_NAMED_FUNCTION(zif_locale_set_default)
     225             : {
     226          75 :         char* locale_name = NULL;
     227          75 :         int   len=0;    
     228             : 
     229          75 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC,  "s",
     230             :                 &locale_name ,&len ) == FAILURE)
     231             :         {
     232           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     233             :                                 "locale_set_default: unable to parse input params", 0 TSRMLS_CC );
     234             : 
     235           1 :                 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        1446 : static char* get_icu_value_internal( char* loc_name , char* tag_name, int* result , int fromParseLocale)
     255             : {
     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( strcmp(tag_name, LOC_CANONICALIZE_TAG) != 0 ){
     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         612 : static void get_icu_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
     371             : {
     372             : 
     373         612 :         char*       loc_name            = NULL;
     374         612 :         int         loc_name_len        = 0;
     375             : 
     376         612 :         char*       tag_value           = NULL;
     377         612 :         char*       empty_result        = "";
     378             : 
     379         612 :         int         result              = 0;
     380         612 :         char*       msg                 = NULL;
     381             : 
     382         612 :         UErrorCode  status              = U_ZERO_ERROR;
     383             : 
     384         612 :         intl_error_reset( NULL TSRMLS_CC );
     385             : 
     386         612 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
     387             :         &loc_name ,&loc_name_len ) == FAILURE) {
     388           4 :                 spprintf(&msg , 0, "locale_get_%s : unable to parse input params", tag_name );
     389           4 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  msg , 1 TSRMLS_CC );
     390           4 :                 efree(msg);
     391             : 
     392           4 :                 RETURN_FALSE;
     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          73 : PHP_FUNCTION( locale_get_script ) 
     433             : {
     434          73 :         get_icu_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     435          73 : }
     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          73 : PHP_FUNCTION( locale_get_region ) 
     445             : {
     446          73 :         get_icu_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     447          73 : }
     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          71 : PHP_FUNCTION(locale_get_primary_language ) 
     457             : {
     458          71 :         get_icu_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     459          71 : }
     460             : /* }}} */
     461             : 
     462             : 
     463             : /* {{{
     464             :  * common code shared by display_xyz functions to  get the value from ICU 
     465             :  }}} */
     466        1160 : static void get_icu_disp_value_src_php( char* tag_name, INTERNAL_FUNCTION_PARAMETERS) 
     467             : {
     468        1160 :         char*       loc_name            = NULL;
     469        1160 :         int         loc_name_len        = 0;
     470             : 
     471        1160 :         char*       disp_loc_name       = NULL;
     472        1160 :         int         disp_loc_name_len   = 0;
     473        1160 :         int         free_loc_name       = 0;
     474             : 
     475        1160 :         UChar*      disp_name           = NULL;
     476        1160 :         int32_t     disp_name_len       = 0;
     477             : 
     478        1160 :         char*       mod_loc_name        = NULL;
     479             : 
     480        1160 :         int32_t     buflen              = 512;
     481        1160 :         UErrorCode  status              = U_ZERO_ERROR;
     482             : 
     483        1160 :         char*       utf8value           = NULL;
     484        1160 :         int         utf8value_len       = 0;
     485             : 
     486        1160 :         char*       msg                 = NULL;
     487        1160 :         int         grOffset            = 0;
     488             : 
     489        1160 :         intl_error_reset( NULL TSRMLS_CC );
     490             : 
     491        1160 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
     492             :                 &loc_name, &loc_name_len , 
     493             :                 &disp_loc_name ,&disp_loc_name_len ) == FAILURE)
     494             :         {
     495           5 :                 spprintf(&msg , 0, "locale_get_display_%s : unable to parse input params", tag_name );
     496           5 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,  msg , 1 TSRMLS_CC );
     497           5 :                 efree(msg);
     498           5 :                 RETURN_FALSE;
     499             :         }
     500             : 
     501        1155 :         if(loc_name_len == 0) {
     502           0 :         loc_name = INTL_G(default_locale);
     503             :         }
     504             : 
     505        1155 :         if( strcmp(tag_name, DISP_NAME) != 0 ){
     506             :                 /* Handle grandfathered languages */
     507         870 :                 grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
     508         870 :                 if( grOffset >= 0 ){
     509          54 :                         if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
     510          18 :                                 mod_loc_name = getPreferredTag( loc_name );
     511             :                         } else {
     512             :                                 /* Since Grandfathered, no value, do nothing, retutn NULL */
     513          36 :                                 RETURN_FALSE;
     514             :                         }
     515             :                 }
     516             :         } /* end of if != LOC_CANONICAL_TAG */
     517             : 
     518        1119 :         if( mod_loc_name==NULL ){
     519        1101 :                 mod_loc_name = estrdup( loc_name );
     520             :         }
     521             :         
     522             :         /* Check if disp_loc_name passed , if not use default locale */
     523        1119 :         if( !disp_loc_name){
     524           0 :                 disp_loc_name = estrdup(INTL_G(default_locale));
     525           0 :                 free_loc_name = 1;
     526             :         }
     527             : 
     528             :     /* Get the disp_value for the given locale */
     529             :     do{
     530        1120 :         disp_name = erealloc( disp_name , buflen * sizeof(UChar)  );
     531        1120 :         disp_name_len = buflen;
     532             : 
     533        1120 :                 if( strcmp(tag_name , LOC_LANG_TAG)==0 ){
     534         222 :                         buflen = uloc_getDisplayLanguage ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     535         898 :                 } else if( strcmp(tag_name , LOC_SCRIPT_TAG)==0 ){
     536         204 :                         buflen = uloc_getDisplayScript ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     537         694 :                 } else if( strcmp(tag_name , LOC_REGION_TAG)==0 ){
     538         204 :                         buflen = uloc_getDisplayCountry ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     539         490 :                 } else if( strcmp(tag_name , LOC_VARIANT_TAG)==0 ){
     540         204 :                         buflen = uloc_getDisplayVariant ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     541         286 :                 } else if( strcmp(tag_name , DISP_NAME)==0 ){
     542         286 :                         buflen = uloc_getDisplayName ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &status);
     543             :                 }
     544             : 
     545             :                 /* U_STRING_NOT_TERMINATED_WARNING is admissible here; don't look for it */
     546        1120 :                 if( U_FAILURE( status ) )
     547             :                 {
     548           1 :                         if( status == U_BUFFER_OVERFLOW_ERROR )
     549             :                         {
     550           1 :                                 status = U_ZERO_ERROR;
     551           1 :                                 continue;
     552             :                         }
     553             : 
     554           0 :                         spprintf(&msg, 0, "locale_get_display_%s : unable to get locale %s", tag_name , tag_name );
     555           0 :                         intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
     556           0 :                         efree(msg);
     557           0 :                         if( disp_name){
     558           0 :                                 efree( disp_name );
     559             :                         }
     560           0 :                         if( mod_loc_name){
     561           0 :                                 efree( mod_loc_name );
     562             :                         }
     563           0 :                         if (free_loc_name) {
     564           0 :                                 efree(disp_loc_name);
     565           0 :                                 disp_loc_name = NULL;
     566             :                         }
     567           0 :                         RETURN_FALSE;
     568             :                 }
     569        1120 :         } while( buflen > disp_name_len );
     570             : 
     571        1119 :         if( mod_loc_name){
     572        1119 :                 efree( mod_loc_name );
     573             :         }
     574        1119 :         if (free_loc_name) {
     575           0 :                 efree(disp_loc_name);
     576           0 :                 disp_loc_name = NULL;
     577             :         }
     578             :         /* Convert display locale name from UTF-16 to UTF-8. */
     579        1119 :         intl_convert_utf16_to_utf8( &utf8value, &utf8value_len, disp_name, buflen, &status );
     580        1119 :         efree( disp_name );
     581        1119 :         if( U_FAILURE( status ) )
     582             :         {
     583           0 :                 spprintf(&msg, 0, "locale_get_display_%s :error converting display name for %s to UTF-8", tag_name , tag_name );
     584           0 :                 intl_error_set( NULL, status, msg , 1 TSRMLS_CC );
     585           0 :                 efree(msg);
     586           0 :                 RETURN_FALSE;
     587             :         }
     588             : 
     589        1119 :         RETVAL_STRINGL( utf8value, utf8value_len , FALSE);
     590             : 
     591             : }
     592             : /* }}} */
     593             : 
     594             : /* {{{ proto static string Locale::getDisplayName($locale[, $in_locale = null])
     595             : * gets the name for the $locale in $in_locale or default_locale
     596             :  }}} */
     597             : /* {{{ proto static string get_display_name($locale[, $in_locale = null])
     598             : * gets the name for the $locale in $in_locale or default_locale
     599             : */
     600         286 : PHP_FUNCTION(locale_get_display_name) 
     601             : {
     602         286 :     get_icu_disp_value_src_php( DISP_NAME , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     603         286 : }
     604             : /* }}} */
     605             : 
     606             : /* {{{ proto static string Locale::getDisplayLanguage($locale[, $in_locale = null])
     607             : * gets the language for the $locale in $in_locale or default_locale
     608             :  }}} */
     609             : /* {{{ proto static string get_display_language($locale[, $in_locale = null])
     610             : * gets the language for the $locale in $in_locale or default_locale
     611             : */
     612         223 : PHP_FUNCTION(locale_get_display_language) 
     613             : {
     614         223 :     get_icu_disp_value_src_php( LOC_LANG_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     615         223 : }
     616             : /* }}} */
     617             : 
     618             : /* {{{ proto static string Locale::getDisplayScript($locale, $in_locale = null)
     619             : * gets the script for the $locale in $in_locale or default_locale
     620             :  }}} */
     621             : /* {{{ proto static string get_display_script($locale, $in_locale = null)
     622             : * gets the script for the $locale in $in_locale or default_locale
     623             : */
     624         217 : PHP_FUNCTION(locale_get_display_script) 
     625             : {
     626         217 :     get_icu_disp_value_src_php( LOC_SCRIPT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     627         217 : }
     628             : /* }}} */
     629             : 
     630             : /* {{{ proto static string Locale::getDisplayRegion($locale, $in_locale = null)
     631             : * gets the region for the $locale in $in_locale or default_locale
     632             :  }}} */
     633             : /* {{{ proto static string get_display_region($locale, $in_locale = null)
     634             : * gets the region for the $locale in $in_locale or default_locale
     635             : */
     636         217 : PHP_FUNCTION(locale_get_display_region) 
     637             : {
     638         217 :     get_icu_disp_value_src_php( LOC_REGION_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     639         217 : }
     640             : /* }}} */
     641             : 
     642             : /* {{{
     643             : * proto static string Locale::getDisplayVariant($locale, $in_locale = null)
     644             : * gets the variant for the $locale in $in_locale or default_locale
     645             :  }}} */
     646             : /* {{{
     647             : * proto static string get_display_variant($locale, $in_locale = null)
     648             : * gets the variant for the $locale in $in_locale or default_locale
     649             : */
     650         217 : PHP_FUNCTION(locale_get_display_variant) 
     651             : {
     652         217 :     get_icu_disp_value_src_php( LOC_VARIANT_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     653         217 : }
     654             : /* }}} */
     655             : 
     656             :  /* {{{ proto static array getKeywords(string $locale) {
     657             :  * return an associative array containing keyword-value
     658             :  * pairs for this locale. The keys are keys to the array (doh!)
     659             :  * }}}*/
     660             :  /* {{{ proto static array locale_get_keywords(string $locale) {
     661             :  * return an associative array containing keyword-value
     662             :  * pairs for this locale. The keys are keys to the array (doh!)
     663             :  */ 
     664          75 : PHP_FUNCTION( locale_get_keywords )
     665             : {
     666          75 :     UEnumeration*   e        = NULL;
     667          75 :     UErrorCode      status   = U_ZERO_ERROR;
     668             : 
     669          75 :         const char*             kw_key        = NULL;
     670          75 :     int32_t         kw_key_len    = 0;
     671             : 
     672          75 :     char*               loc_name        = NULL;
     673          75 :     int                 loc_name_len    = 0;
     674             : 
     675             : /* 
     676             :         ICU expects the buffer to be allocated  before calling the function 
     677             :         and so the buffer size has been explicitly specified 
     678             :         ICU uloc.h #define      ULOC_KEYWORD_AND_VALUES_CAPACITY   100 
     679             :         hence the kw_value buffer size is 100
     680             : */
     681          75 :         char*           kw_value        = NULL;
     682          75 :     int32_t     kw_value_len    = 100;
     683             : 
     684          75 :     intl_error_reset( NULL TSRMLS_CC );
     685             : 
     686          75 :     if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
     687             :         &loc_name, &loc_name_len ) == FAILURE)
     688             :     {
     689           1 :         intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     690             :              "locale_get_keywords: unable to parse input params", 0 TSRMLS_CC );
     691             : 
     692           1 :         RETURN_FALSE;
     693             :     }
     694             : 
     695          74 :     if(loc_name_len == 0) {
     696           0 :         loc_name = INTL_G(default_locale);
     697             :     }
     698             : 
     699             :         /* Get the keywords */
     700          74 :     e = uloc_openKeywords( loc_name, &status );
     701          74 :     if( e != NULL )
     702             :     {
     703             :                 /* Traverse it, filling the return array. */
     704           6 :         array_init( return_value );
     705             : 
     706          24 :         while( ( kw_key = uenum_next( e, &kw_key_len, &status ) ) != NULL ){
     707          12 :                         kw_value = ecalloc( 1 , kw_value_len  );
     708             : 
     709             :                         /* Get the keyword value for each keyword */
     710          12 :                         kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len ,  &status );
     711          12 :                         if (status == U_BUFFER_OVERFLOW_ERROR) {
     712           2 :                                 status = U_ZERO_ERROR;
     713           2 :                                 kw_value = erealloc( kw_value , kw_value_len+1);
     714           2 :                                 kw_value_len=uloc_getKeywordValue( loc_name,kw_key, kw_value, kw_value_len+1 ,  &status );
     715          10 :                         } else if(!U_FAILURE(status)) {
     716          10 :                                 kw_value = erealloc( kw_value , kw_value_len+1);
     717             :                         } 
     718          12 :                         if (U_FAILURE(status)) {
     719           0 :                         intl_error_set( NULL, FAILURE, "locale_get_keywords: Error encountered while getting the keyword  value for the  keyword", 0 TSRMLS_CC );
     720           0 :                                 if( kw_value){
     721           0 :                                         efree( kw_value );
     722             :                                 }
     723           0 :                                 zval_dtor(return_value);
     724           0 :                         RETURN_FALSE;
     725             :                         }
     726             : 
     727          12 :                 add_assoc_stringl( return_value, (char *)kw_key, kw_value , kw_value_len, 0);
     728             :                 } /* end of while */
     729             : 
     730             :         } /* end of if e!=NULL */
     731             : 
     732          74 :     uenum_close( e );
     733             : }
     734             : /* }}} */
     735             : 
     736             :  /* {{{ proto static string Locale::canonicalize($locale) 
     737             :  * @return string the canonicalized locale 
     738             :  * }}} */
     739             :  /* {{{ proto static string locale_canonicalize(Locale $loc, string $locale) 
     740             :  * @param string $locale        The locale string to canonicalize
     741             :  */
     742         395 : PHP_FUNCTION(locale_canonicalize)
     743             : {
     744         395 :         get_icu_value_src_php( LOC_CANONICALIZE_TAG , INTERNAL_FUNCTION_PARAM_PASSTHRU );
     745         395 : }
     746             : /* }}} */
     747             : 
     748             : /* {{{ append_key_value 
     749             : * Internal function which is called from locale_compose
     750             : * gets the value for the key_name and appends to the loc_name
     751             : * returns 1 if successful , -1 if not found , 
     752             : * 0 if array element is not a string , -2 if buffer-overflow
     753             : */
     754          84 : static int append_key_value(smart_str* loc_name, HashTable* hash_arr, char* key_name)
     755             : {
     756          84 :         zval**  ele_value       = NULL;
     757             : 
     758          84 :         if(zend_hash_find(hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
     759          52 :                 if(Z_TYPE_PP(ele_value)!= IS_STRING ){
     760             :                         /* element value is not a string */
     761           2 :                         return FAILURE;
     762             :                 }
     763          80 :                 if(strcmp(key_name, LOC_LANG_TAG) != 0 && 
     764          30 :                    strcmp(key_name, LOC_GRANDFATHERED_LANG_TAG)!=0 ) {
     765             :                         /* not lang or grandfathered tag */
     766          30 :                         smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     767             :                 }
     768          50 :                 smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
     769          50 :                 return SUCCESS;
     770             :         }
     771             : 
     772          32 :         return LOC_NOT_FOUND;
     773             : }
     774             : /* }}} */
     775             : 
     776             : /* {{{ append_prefix , appends the prefix needed
     777             : * e.g. private adds 'x'
     778             : */
     779          18 : static void add_prefix(smart_str* loc_name, char* key_name)
     780             : {
     781          18 :         if( strncmp(key_name , LOC_PRIVATE_TAG , 7) == 0 ){
     782           4 :                 smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     783           4 :                 smart_str_appendl(loc_name, PRIVATE_PREFIX , sizeof(PRIVATE_PREFIX)-1);
     784             :         }
     785          18 : }
     786             : /* }}} */
     787             : 
     788             : /* {{{ append_multiple_key_values 
     789             : * Internal function which is called from locale_compose
     790             : * gets the multiple values for the key_name and appends to the loc_name
     791             : * used for 'variant','extlang','private' 
     792             : * returns 1 if successful , -1 if not found , 
     793             : * 0 if array element is not a string , -2 if buffer-overflow
     794             : */
     795          56 : static int append_multiple_key_values(smart_str* loc_name, HashTable* hash_arr, char* key_name TSRMLS_DC)
     796             : {
     797          56 :         zval**  ele_value       = NULL;
     798          56 :         int     i               = 0;
     799          56 :         int     isFirstSubtag   = 0;
     800          56 :         int     max_value       = 0;
     801             : 
     802             :         /* Variant/ Extlang/Private etc. */
     803          56 :         if( zend_hash_find( hash_arr , key_name , strlen(key_name) + 1 ,(void **)&ele_value ) == SUCCESS ) {
     804           6 :                 if( Z_TYPE_PP(ele_value) == IS_STRING ){
     805           0 :                         add_prefix( loc_name , key_name);
     806             : 
     807           0 :                         smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     808           0 :                         smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
     809           0 :                         return SUCCESS;
     810           6 :                 } else if(Z_TYPE_PP(ele_value) == IS_ARRAY ) {
     811             :                         HashPosition pos;
     812           6 :                         HashTable *arr = HASH_OF(*ele_value);
     813           6 :                         zval **data = NULL;
     814             : 
     815           6 :                         zend_hash_internal_pointer_reset_ex(arr, &pos);
     816          24 :                         while(zend_hash_get_current_data_ex(arr, (void **)&data, &pos) != FAILURE) {
     817          12 :                                 if(Z_TYPE_PP(data) != IS_STRING) {
     818           0 :                                         return FAILURE;
     819             :                                 }
     820          12 :                                 if (isFirstSubtag++ == 0){
     821           6 :                                         add_prefix(loc_name , key_name);
     822             :                                 }
     823          12 :                                 smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     824          12 :                                 smart_str_appendl(loc_name, Z_STRVAL_PP(data) , Z_STRLEN_PP(data));
     825          12 :                                 zend_hash_move_forward_ex(arr, &pos);
     826             :                         }
     827           6 :                         return SUCCESS;
     828             :                 } else {
     829           0 :                         return FAILURE;
     830             :                 }
     831             :         } else {
     832             :                 char cur_key_name[31];
     833             :                 /* Decide the max_value: the max. no. of elements allowed */
     834          50 :                 if( strcmp(key_name , LOC_VARIANT_TAG) ==0 ){
     835          16 :                         max_value  = MAX_NO_VARIANT;
     836             :                 }
     837          50 :                 if( strcmp(key_name , LOC_EXTLANG_TAG) ==0 ){
     838          18 :                         max_value  = MAX_NO_EXTLANG;
     839             :                 }
     840          50 :                 if( strcmp(key_name , LOC_PRIVATE_TAG) ==0 ){
     841          16 :                         max_value  = MAX_NO_PRIVATE;
     842             :                 }
     843             : 
     844             :                 /* Multiple variant values as variant0, variant1 ,variant2 */
     845          50 :                 isFirstSubtag = 0;
     846         582 :                 for( i=0 ; i< max_value; i++ ){  
     847         534 :                         snprintf( cur_key_name , 30, "%s%d", key_name , i);   
     848         534 :                         if( zend_hash_find( hash_arr , cur_key_name , strlen(cur_key_name) + 1,(void **)&ele_value ) == SUCCESS ){
     849          26 :                                 if( Z_TYPE_PP(ele_value)!= IS_STRING ){
     850             :                                         /* variant is not a string */
     851           2 :                                         return FAILURE;
     852             :                                 }
     853             :                                 /* Add the contents */
     854          24 :                                 if (isFirstSubtag++ == 0){
     855          12 :                                         add_prefix(loc_name , cur_key_name);
     856             :                                 }
     857          24 :                                 smart_str_appendl(loc_name, SEPARATOR , sizeof(SEPARATOR)-1);
     858          24 :                                 smart_str_appendl(loc_name, Z_STRVAL_PP(ele_value) , Z_STRLEN_PP(ele_value));
     859             :                         }
     860             :                 } /* end of for */
     861             :         } /* end of else */
     862             : 
     863          48 :         return SUCCESS;
     864             : }
     865             : /* }}} */
     866             : 
     867             : /*{{{
     868             : * If applicable sets error message and aborts locale_compose gracefully
     869             : * returns 0  if locale_compose needs to be aborted 
     870             : * otherwise returns 1
     871             : */
     872         138 : static int handleAppendResult( int result, smart_str* loc_name TSRMLS_DC)
     873             : {
     874         138 :         intl_error_reset( NULL TSRMLS_CC );
     875         138 :         if( result == FAILURE) {
     876           4 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     877             :                          "locale_compose: parameter array element is not a string", 0 TSRMLS_CC );
     878           4 :                 smart_str_free(loc_name);
     879           4 :                 return 0;
     880             :         }
     881         134 :         return 1;
     882             : }
     883             : /* }}} */
     884             : 
     885             : #define RETURN_SMART_STR(s) smart_str_0((s)); RETURN_STRINGL((s)->c, (s)->len, 0)
     886             : /* {{{ proto static string Locale::composeLocale($array) 
     887             : * Creates a locale by combining the parts of locale-ID passed   
     888             : * }}} */
     889             : /* {{{ proto static string compose_locale($array) 
     890             : * Creates a locale by combining the parts of locale-ID passed   
     891             : * }}} */
     892          25 : PHP_FUNCTION(locale_compose)
     893             : {
     894          25 :         smart_str       loc_name_s = {0};
     895          25 :         smart_str *loc_name = &loc_name_s;
     896          25 :         zval*                   arr     = NULL;
     897          25 :         HashTable*              hash_arr = NULL;
     898          25 :         int                     result = 0;
     899             : 
     900          25 :         intl_error_reset( NULL TSRMLS_CC );
     901             : 
     902          25 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "a",
     903             :                 &arr) == FAILURE)
     904             :         {
     905           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     906             :                          "locale_compose: unable to parse input params", 0 TSRMLS_CC );
     907           1 :                 RETURN_FALSE;
     908             :         }
     909             : 
     910          24 :         hash_arr = HASH_OF( arr );
     911             : 
     912          24 :         if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
     913           0 :                 RETURN_FALSE;
     914             : 
     915             :         /* Check for grandfathered first */
     916          24 :         result = append_key_value(loc_name, hash_arr,  LOC_GRANDFATHERED_LANG_TAG);     
     917          24 :         if( result == SUCCESS){
     918           0 :                 RETURN_SMART_STR(loc_name);
     919             :         }
     920          24 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     921           0 :                 RETURN_FALSE;
     922             :         }
     923             : 
     924             :         /* Not grandfathered */
     925          24 :         result = append_key_value(loc_name, hash_arr , LOC_LANG_TAG);   
     926          24 :         if( result == LOC_NOT_FOUND ){
     927           2 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     928             :                 "locale_compose: parameter array does not contain 'language' tag.", 0 TSRMLS_CC );
     929           2 :                 smart_str_free(loc_name);
     930           2 :                 RETURN_FALSE;
     931             :         }
     932          22 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     933           2 :                 RETURN_FALSE;
     934             :         }
     935             : 
     936             :         /* Extlang */
     937          20 :         result = append_multiple_key_values(loc_name, hash_arr , LOC_EXTLANG_TAG TSRMLS_CC);
     938          20 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     939           2 :                 RETURN_FALSE;
     940             :         }
     941             : 
     942             :         /* Script */
     943          18 :         result = append_key_value(loc_name, hash_arr , LOC_SCRIPT_TAG); 
     944          18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     945           0 :                 RETURN_FALSE;
     946             :         }
     947             :         
     948             :         /* Region */
     949          18 :         result = append_key_value( loc_name, hash_arr , LOC_REGION_TAG);
     950          18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     951           0 :                 RETURN_FALSE;
     952             :         }
     953             : 
     954             :         /* Variant */
     955          18 :         result = append_multiple_key_values( loc_name, hash_arr , LOC_VARIANT_TAG TSRMLS_CC); 
     956          18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     957           0 :                 RETURN_FALSE;
     958             :         }
     959             : 
     960             :         /* Private */
     961          18 :         result = append_multiple_key_values( loc_name, hash_arr , LOC_PRIVATE_TAG TSRMLS_CC);
     962          18 :         if( !handleAppendResult( result, loc_name TSRMLS_CC)){
     963           0 :                 RETURN_FALSE;
     964             :         }
     965             : 
     966          18 :         RETURN_SMART_STR(loc_name);
     967             : }
     968             : /* }}} */
     969             : 
     970             : 
     971             : /*{{{
     972             : * Parses the locale and returns private subtags  if existing
     973             : * else returns NULL
     974             : * e.g. for locale='en_US-x-prv1-prv2-prv3'
     975             : * returns a pointer to the string 'prv1-prv2-prv3'
     976             : */
     977          66 : static char* get_private_subtags(char* loc_name)
     978             : {
     979          66 :         char*   result =NULL;
     980          66 :         int     singletonPos = 0;
     981          66 :         int     len =0; 
     982          66 :         char*   mod_loc_name =NULL;
     983             : 
     984          66 :         if( loc_name && (len = strlen(loc_name)>0 ) ){
     985          66 :                 mod_loc_name = loc_name ; 
     986          66 :                 len   = strlen(mod_loc_name);
     987         148 :                 while( (singletonPos = getSingletonPos(mod_loc_name))!= -1){
     988             : 
     989          24 :                         if( singletonPos!=-1){ 
     990          24 :                                 if( (*(mod_loc_name+singletonPos)=='x') || (*(mod_loc_name+singletonPos)=='X') ){               
     991             :                                         /* private subtag start found */
     992           8 :                                         if( singletonPos + 2 ==  len){
     993             :                                                 /* loc_name ends with '-x-' ; return  NULL */
     994             :                                         }
     995             :                                         else{
     996             :                                                 /* result = mod_loc_name + singletonPos +2; */
     997           8 :                                                 result = estrndup(mod_loc_name + singletonPos+2  , (len -( singletonPos +2) ) );
     998             :                                         }
     999           8 :                                         break;
    1000             :                                 }
    1001             :                                 else{
    1002          16 :                                         if( singletonPos + 1 >=  len){
    1003             :                                                 /* String end */
    1004           0 :                                                 break;
    1005             :                                         } else {
    1006             :                                                 /* singleton found but not a private subtag , hence check further in the string for the private subtag */
    1007          16 :                                                 mod_loc_name = mod_loc_name + singletonPos +1;
    1008          16 :                                                 len = strlen(mod_loc_name);
    1009             :                                         }
    1010             :                                 }
    1011             :                         }
    1012             : 
    1013             :                 } /* end of while */
    1014             :         }
    1015             :         
    1016          66 :         return result;
    1017             : }
    1018             : /* }}} */
    1019             : 
    1020             : /* {{{ code used by locale_parse
    1021             : */
    1022         330 : static int add_array_entry(char* loc_name, zval* hash_arr, char* key_name TSRMLS_DC)
    1023             : {
    1024         330 :         char*   key_value       = NULL;
    1025         330 :         char*   cur_key_name    = NULL;
    1026         330 :         char*   token           = NULL;
    1027         330 :         char*   last_ptr        = NULL;
    1028             : 
    1029         330 :         int     result          = 0;
    1030         330 :         int     cur_result      = 0;
    1031         330 :         int     cnt             = 0;
    1032             : 
    1033             : 
    1034         330 :         if( strcmp(key_name , LOC_PRIVATE_TAG)==0 ){
    1035          66 :                 key_value = get_private_subtags( loc_name );
    1036          66 :                 result = 1;
    1037             :         } else {
    1038         264 :                 key_value = get_icu_value_internal( loc_name , key_name , &result,1 );
    1039             :         }
    1040         726 :         if( (strcmp(key_name , LOC_PRIVATE_TAG)==0) || 
    1041         264 :                 ( strcmp(key_name , LOC_VARIANT_TAG)==0) ){
    1042         132 :                 if( result > 0 && key_value){
    1043             :                         /* Tokenize on the "_" or "-"  */
    1044          20 :                         token = php_strtok_r( key_value , DELIMITER ,&last_ptr);    
    1045          20 :                         if( cur_key_name ){
    1046           0 :                                 efree( cur_key_name);
    1047             :                         }
    1048          20 :                         cur_key_name = (char*)ecalloc( 25,  25);
    1049          20 :                         sprintf( cur_key_name , "%s%d", key_name , cnt++);    
    1050          20 :                         add_assoc_string( hash_arr, cur_key_name , token ,TRUE );
    1051             :                         /* tokenize on the "_" or "-" and stop  at singleton if any */
    1052          46 :                         while( (token = php_strtok_r(NULL , DELIMITER , &last_ptr)) && (strlen(token)>1) ){
    1053           6 :                                 sprintf( cur_key_name , "%s%d", key_name , cnt++);    
    1054           6 :                                 add_assoc_string( hash_arr, cur_key_name , token , TRUE );
    1055             :                         }
    1056             : /*
    1057             :                         if( strcmp(key_name, LOC_PRIVATE_TAG) == 0 ){
    1058             :                         }
    1059             : */
    1060             :                 }
    1061             :         } else {
    1062         198 :                 if( result == 1 ){
    1063         124 :                         add_assoc_string( hash_arr, key_name , key_value , TRUE );
    1064         124 :                         cur_result = 1;
    1065             :                 }
    1066             :         }
    1067             : 
    1068         330 :         if( cur_key_name ){
    1069          20 :                 efree( cur_key_name);
    1070             :         }
    1071             :         /*if( key_name != LOC_PRIVATE_TAG && key_value){*/
    1072         330 :         if( key_value){
    1073         144 :                 efree(key_value);       
    1074             :         }
    1075         330 :         return cur_result;
    1076             : }
    1077             : /* }}} */
    1078             : 
    1079             : /* {{{ proto static array Locale::parseLocale($locale) 
    1080             : * parses a locale-id into an array the different parts of it
    1081             :  }}} */
    1082             : /* {{{ proto static array parse_locale($locale) 
    1083             : * parses a locale-id into an array the different parts of it
    1084             : */
    1085          71 : PHP_FUNCTION(locale_parse)
    1086             : {
    1087          71 :     char*       loc_name        = NULL;
    1088          71 :     int         loc_name_len    = 0;
    1089          71 :     int         grOffset        = 0;
    1090             : 
    1091          71 :     intl_error_reset( NULL TSRMLS_CC );
    1092             : 
    1093          71 :     if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
    1094             :         &loc_name, &loc_name_len ) == FAILURE)
    1095             :     {
    1096           1 :         intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1097             :              "locale_parse: unable to parse input params", 0 TSRMLS_CC );
    1098             : 
    1099           1 :         RETURN_FALSE;
    1100             :     }
    1101             : 
    1102          70 :     if(loc_name_len == 0) {
    1103           0 :         loc_name = INTL_G(default_locale);
    1104             :     }
    1105             : 
    1106          70 :         array_init( return_value );
    1107             : 
    1108          70 :         grOffset =  findOffset( LOC_GRANDFATHERED , loc_name );
    1109          70 :         if( grOffset >= 0 ){
    1110           4 :                 add_assoc_string( return_value , LOC_GRANDFATHERED_LANG_TAG , estrdup(loc_name) ,FALSE );
    1111             :         }
    1112             :         else{
    1113             :                 /* Not grandfathered */
    1114          66 :                 add_array_entry( loc_name , return_value , LOC_LANG_TAG TSRMLS_CC);
    1115          66 :                 add_array_entry( loc_name , return_value , LOC_SCRIPT_TAG TSRMLS_CC);
    1116          66 :                 add_array_entry( loc_name , return_value , LOC_REGION_TAG TSRMLS_CC);
    1117          66 :                 add_array_entry( loc_name , return_value , LOC_VARIANT_TAG TSRMLS_CC);
    1118          66 :                 add_array_entry( loc_name , return_value , LOC_PRIVATE_TAG TSRMLS_CC);
    1119             :         }
    1120             : }
    1121             : /* }}} */
    1122             : 
    1123             : /* {{{ proto static array Locale::getAllVariants($locale)
    1124             : * gets an array containing the list of variants, or null
    1125             :  }}} */
    1126             : /* {{{ proto static array locale_get_all_variants($locale)
    1127             : * gets an array containing the list of variants, or null
    1128             : */
    1129          23 : PHP_FUNCTION(locale_get_all_variants)
    1130             : {
    1131          23 :         char*   loc_name        = NULL;
    1132          23 :         int     loc_name_len    = 0;
    1133             : 
    1134          23 :         int     result          = 0;
    1135          23 :         char*   token           = NULL;
    1136          23 :         char*   variant         = NULL;
    1137          23 :         char*   saved_ptr       = NULL;
    1138             : 
    1139          23 :         intl_error_reset( NULL TSRMLS_CC );
    1140             :         
    1141          23 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s",
    1142             :         &loc_name, &loc_name_len ) == FAILURE)
    1143             :         {
    1144           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1145             :              "locale_parse: unable to parse input params", 0 TSRMLS_CC );
    1146             : 
    1147           1 :                 RETURN_FALSE;
    1148             :         }
    1149             : 
    1150          22 :         if(loc_name_len == 0) {
    1151           0 :                 loc_name = INTL_G(default_locale);
    1152             :         }
    1153             : 
    1154             : 
    1155          22 :         array_init( return_value );
    1156             : 
    1157             :         /* If the locale is grandfathered, stop, no variants */
    1158          22 :         if( findOffset( LOC_GRANDFATHERED , loc_name ) >=  0 ){ 
    1159             :                 /* ("Grandfathered Tag. No variants."); */
    1160             :         }
    1161             :         else {  
    1162             :         /* Call ICU variant */
    1163          10 :                 variant = get_icu_value_internal( loc_name , LOC_VARIANT_TAG , &result ,0);
    1164          10 :                 if( result > 0 && variant){
    1165             :                         /* Tokenize on the "_" or "-" */
    1166          10 :                         token = php_strtok_r( variant , DELIMITER , &saved_ptr);    
    1167          10 :                         add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
    1168             :                         /* tokenize on the "_" or "-" and stop  at singleton if any */
    1169          26 :                         while( (token = php_strtok_r(NULL , DELIMITER, &saved_ptr)) && (strlen(token)>1) ){
    1170           6 :                                 add_next_index_stringl( return_value, token , strlen(token) ,TRUE );
    1171             :                         }
    1172             :                 }
    1173          10 :                 if( variant ){
    1174          10 :                         efree( variant );
    1175             :                 }
    1176             :         }
    1177             :                         
    1178             : 
    1179             : }
    1180             : /* }}} */
    1181             : 
    1182             : /*{{{
    1183             : * Converts to lower case and also replaces all hyphens with the underscore
    1184             : */
    1185        1298 : static int strToMatch(char* str ,char *retstr)
    1186             : {
    1187        1298 :         char*   anchor  = NULL;
    1188        1298 :         char*   anchor1 = NULL;
    1189        1298 :         int     result  = 0;
    1190        1298 :         int     len     = 0;
    1191             : 
    1192        1298 :     if( (!str) || str[0] == '\0'){
    1193           0 :         return result;
    1194             :     } else {
    1195        1298 :         anchor = retstr;
    1196        1298 :         anchor1 = str;
    1197        1298 :         len = strlen(str);
    1198       13820 :         while( (*str)!='\0' ){
    1199       11224 :                 if( *str == '-' ){
    1200         724 :                         *retstr =  '_';
    1201             :                 } else {
    1202       10500 :                         *retstr = tolower(*str);
    1203             :                 }
    1204       11224 :             str++;
    1205       11224 :             retstr++;
    1206             :         }
    1207        1298 :         *retstr = '\0';
    1208        1298 :         retstr=  anchor;
    1209        1298 :         str=  anchor1;
    1210        1298 :         result = 1;
    1211             :     }
    1212             : 
    1213        1298 :     return(result);
    1214             : }
    1215             : /* }}} */
    1216             : 
    1217             : /* {{{ proto static boolean Locale::filterMatches(string $langtag, string $locale[, bool $canonicalize])
    1218             : * Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
    1219             : */
    1220             : /* }}} */
    1221             : /* {{{ proto boolean locale_filter_matches(string $langtag, string $locale[, bool $canonicalize])
    1222             : * Checks if a $langtag filter matches with $locale according to RFC 4647's basic filtering algorithm 
    1223             : */
    1224         385 : PHP_FUNCTION(locale_filter_matches)
    1225             : {
    1226         385 :         char*           lang_tag        = NULL;
    1227         385 :         int             lang_tag_len    = 0;
    1228         385 :         char*           loc_range       = NULL;
    1229         385 :         int             loc_range_len   = 0;
    1230             : 
    1231         385 :         int             result          = 0;
    1232         385 :         char*           token           = 0;
    1233         385 :         char*           chrcheck        = NULL;
    1234             : 
    1235         385 :         char*           can_lang_tag    = NULL;
    1236         385 :         char*           can_loc_range   = NULL;
    1237             : 
    1238         385 :         char*           cur_lang_tag    = NULL;
    1239         385 :         char*           cur_loc_range   = NULL;
    1240             : 
    1241         385 :         zend_bool       boolCanonical   = 0;    
    1242         385 :         UErrorCode      status          = U_ZERO_ERROR;
    1243             : 
    1244         385 :         intl_error_reset( NULL TSRMLS_CC );
    1245             :         
    1246         385 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "ss|b",
    1247             :                 &lang_tag, &lang_tag_len , &loc_range , &loc_range_len , 
    1248             :                 &boolCanonical) == FAILURE)
    1249             :         {
    1250           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1251             :                 "locale_filter_matches: unable to parse input params", 0 TSRMLS_CC );
    1252             : 
    1253           1 :                 RETURN_FALSE;
    1254             :         }
    1255             : 
    1256         384 :         if(loc_range_len == 0) {
    1257           0 :                 loc_range = INTL_G(default_locale);
    1258             :         }
    1259             : 
    1260         384 :         if( strcmp(loc_range,"*")==0){
    1261           0 :                 RETURN_TRUE;
    1262             :         }
    1263             : 
    1264         384 :         if( boolCanonical ){
    1265             :                 /* canonicalize loc_range */
    1266         192 :                 can_loc_range=get_icu_value_internal( loc_range , LOC_CANONICALIZE_TAG , &result , 0);
    1267         192 :                 if( result ==0) {
    1268           0 :                         intl_error_set( NULL, status, 
    1269             :                                 "locale_filter_matches : unable to canonicalize loc_range" , 0 TSRMLS_CC );
    1270           0 :                         RETURN_FALSE;
    1271             :                 }
    1272             : 
    1273             :                 /* canonicalize lang_tag */
    1274         192 :                 can_lang_tag = get_icu_value_internal( lang_tag , LOC_CANONICALIZE_TAG , &result ,  0);
    1275         192 :                 if( result ==0) {
    1276           0 :                         intl_error_set( NULL, status, 
    1277             :                                 "locale_filter_matches : unable to canonicalize lang_tag" , 0 TSRMLS_CC );
    1278           0 :                         RETURN_FALSE;
    1279             :                 }
    1280             : 
    1281             :                 /* Convert to lower case for case-insensitive comparison */
    1282         192 :                 cur_lang_tag = ecalloc( 1, strlen(can_lang_tag) + 1);
    1283             : 
    1284             :                 /* Convert to lower case for case-insensitive comparison */
    1285         192 :                 result = strToMatch( can_lang_tag , cur_lang_tag);
    1286         192 :                 if( result == 0) {
    1287           0 :                         efree( cur_lang_tag );
    1288           0 :                         efree( can_lang_tag );
    1289           0 :                         RETURN_FALSE;
    1290             :                 }
    1291             : 
    1292         192 :                 cur_loc_range = ecalloc( 1, strlen(can_loc_range) + 1);
    1293         192 :                 result = strToMatch( can_loc_range , cur_loc_range );
    1294         192 :                 if( result == 0) {
    1295           0 :                         efree( cur_lang_tag );
    1296           0 :                         efree( can_lang_tag );
    1297           0 :                         efree( cur_loc_range );
    1298           0 :                         efree( can_loc_range );
    1299           0 :                         RETURN_FALSE;
    1300             :                 }
    1301             : 
    1302             :                 /* check if prefix */
    1303         192 :                 token   = strstr( cur_lang_tag , cur_loc_range );
    1304             :         
    1305         192 :                 if( token && (token==cur_lang_tag) ){
    1306             :                         /* check if the char. after match is SEPARATOR */
    1307          38 :                         chrcheck = token + (strlen(cur_loc_range));
    1308          38 :                         if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
    1309          36 :                                 if( cur_lang_tag){
    1310          36 :                                         efree( cur_lang_tag );
    1311             :                                 }
    1312          36 :                                 if( cur_loc_range){
    1313          36 :                                         efree( cur_loc_range );
    1314             :                                 }
    1315          36 :                                 if( can_lang_tag){
    1316          36 :                                         efree( can_lang_tag );
    1317             :                                 }
    1318          36 :                                 if( can_loc_range){
    1319          36 :                                         efree( can_loc_range );
    1320             :                                 }
    1321          36 :                                 RETURN_TRUE;
    1322             :                         }
    1323             :                 }
    1324             : 
    1325             :                 /* No prefix as loc_range */
    1326         156 :                 if( cur_lang_tag){
    1327         156 :                         efree( cur_lang_tag );
    1328             :                 }
    1329         156 :                 if( cur_loc_range){
    1330         156 :                         efree( cur_loc_range );
    1331             :                 }
    1332         156 :                 if( can_lang_tag){
    1333         156 :                         efree( can_lang_tag );
    1334             :                 }
    1335         156 :                 if( can_loc_range){
    1336         156 :                         efree( can_loc_range );
    1337             :                 }
    1338         156 :                 RETURN_FALSE;
    1339             : 
    1340             :         } /* end of if isCanonical */
    1341             :         else{
    1342             :                 /* Convert to lower case for case-insensitive comparison */
    1343         192 :                 cur_lang_tag = ecalloc( 1, strlen(lang_tag ) + 1);
    1344             :                 
    1345         192 :                 result = strToMatch( lang_tag , cur_lang_tag);
    1346         192 :                 if( result == 0) {
    1347           0 :                         efree( cur_lang_tag );
    1348           0 :                         RETURN_FALSE;
    1349             :                 }
    1350         192 :                 cur_loc_range = ecalloc( 1, strlen(loc_range ) + 1);
    1351         192 :                 result = strToMatch( loc_range , cur_loc_range );
    1352         192 :                 if( result == 0) {
    1353           0 :                         efree( cur_lang_tag );
    1354           0 :                         efree( cur_loc_range );
    1355           0 :                         RETURN_FALSE;
    1356             :                 }
    1357             : 
    1358             :                 /* check if prefix */
    1359         192 :                 token   = strstr( cur_lang_tag , cur_loc_range );
    1360             :                 
    1361         192 :                 if( token && (token==cur_lang_tag) ){
    1362             :                         /* check if the char. after match is SEPARATOR */
    1363          32 :                         chrcheck = token + (strlen(cur_loc_range));
    1364          32 :                         if( isIDSeparator(*chrcheck) || isEndOfTag(*chrcheck) ){ 
    1365          30 :                                 if( cur_lang_tag){
    1366          30 :                                         efree( cur_lang_tag );
    1367             :                                 }
    1368          30 :                                 if( cur_loc_range){
    1369          30 :                                         efree( cur_loc_range );
    1370             :                                 }
    1371          30 :                                 RETURN_TRUE;
    1372             :                         }
    1373             :                 }
    1374             : 
    1375             :                 /* No prefix as loc_range */
    1376         162 :                 if( cur_lang_tag){
    1377         162 :                         efree( cur_lang_tag );
    1378             :                 }
    1379         162 :                 if( cur_loc_range){
    1380         162 :                         efree( cur_loc_range );
    1381             :                 }
    1382         162 :                 RETURN_FALSE;
    1383             : 
    1384             :         }
    1385             : }
    1386             : /* }}} */
    1387             : 
    1388          20 : static void array_cleanup( char* arr[] , int arr_size)
    1389             : {
    1390          20 :         int i=0;
    1391         360 :         for( i=0; i< arr_size; i++ ){ 
    1392         340 :                 if( arr[i*2] ){
    1393         340 :                         efree( arr[i*2]);
    1394             :                 }
    1395             :         }
    1396          20 :         efree(arr);
    1397          20 : }
    1398             : 
    1399             : #define LOOKUP_CLEAN_RETURN(value)      array_cleanup(cur_arr, cur_arr_len); return (value)
    1400             : /* {{{
    1401             : * returns the lookup result to lookup_loc_range_src_php 
    1402             : * internal function
    1403             : */
    1404          20 : static char* lookup_loc_range(char* loc_range, HashTable* hash_arr, int canonicalize  TSRMLS_DC)
    1405             : {
    1406          20 :         int     i = 0;
    1407          20 :         int     cur_arr_len = 0;
    1408          20 :         int result = 0;
    1409             : 
    1410          20 :         char* lang_tag = NULL;
    1411          20 :         zval** ele_value = NULL;
    1412          20 :         char** cur_arr = NULL;
    1413             : 
    1414          20 :         char* cur_loc_range     = NULL;
    1415          20 :         char* can_loc_range     = NULL;
    1416          20 :         int     saved_pos = 0;
    1417             : 
    1418          20 :         char* return_value = NULL;
    1419             : 
    1420          20 :         cur_arr = ecalloc(zend_hash_num_elements(hash_arr)*2, sizeof(char *));
    1421             :         /* convert the array to lowercase , also replace hyphens with the underscore and store it in cur_arr */
    1422         380 :         for(zend_hash_internal_pointer_reset(hash_arr);
    1423         360 :                 zend_hash_has_more_elements(hash_arr) == SUCCESS;
    1424         340 :                 zend_hash_move_forward(hash_arr)) {
    1425             :                 
    1426         340 :                 if (zend_hash_get_current_data(hash_arr, (void**)&ele_value) == FAILURE) {
    1427             :                         /* Should never actually fail since the key is known to exist.*/
    1428           0 :                         continue;
    1429             :                 }
    1430         340 :                 if(Z_TYPE_PP(ele_value)!= IS_STRING) {
    1431             :                         /* element value is not a string */
    1432           0 :                         intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: locale array element is not a string", 0 TSRMLS_CC);
    1433           0 :                         LOOKUP_CLEAN_RETURN(NULL);
    1434             :                 } 
    1435         340 :                 cur_arr[cur_arr_len*2] = estrndup(Z_STRVAL_PP(ele_value), Z_STRLEN_PP(ele_value));
    1436         340 :                 result = strToMatch(Z_STRVAL_PP(ele_value), cur_arr[cur_arr_len*2]);
    1437         340 :                 if(result == 0) {
    1438           0 :                         intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag", 0 TSRMLS_CC);
    1439           0 :                         LOOKUP_CLEAN_RETURN(NULL);
    1440             :                 }
    1441         340 :                 cur_arr[cur_arr_len*2+1] = Z_STRVAL_PP(ele_value);
    1442         340 :                 cur_arr_len++ ; 
    1443             :         } /* end of for */
    1444             : 
    1445             :         /* Canonicalize array elements */
    1446          20 :         if(canonicalize) {
    1447         180 :                 for(i=0; i<cur_arr_len; i++) { 
    1448         170 :                         lang_tag = get_icu_value_internal(cur_arr[i*2], LOC_CANONICALIZE_TAG, &result, 0);
    1449         170 :                         if(result != 1 || lang_tag == NULL || !lang_tag[0]) {
    1450           0 :                                 if(lang_tag) {
    1451           0 :                                         efree(lang_tag);
    1452             :                                 }
    1453           0 :                                 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
    1454           0 :                                 LOOKUP_CLEAN_RETURN(NULL);
    1455             :                         }
    1456         170 :                         cur_arr[i*2] = erealloc(cur_arr[i*2], strlen(lang_tag)+1);
    1457         170 :                         result = strToMatch(lang_tag, cur_arr[i*2]);    
    1458         170 :                         efree(lang_tag);
    1459         170 :                         if(result == 0) {
    1460           0 :                                 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
    1461           0 :                                 LOOKUP_CLEAN_RETURN(NULL);
    1462             :                         }
    1463             :                 }
    1464             : 
    1465             :         }
    1466             : 
    1467          20 :         if(canonicalize) {
    1468             :                 /* Canonicalize the loc_range */
    1469          10 :                 can_loc_range = get_icu_value_internal(loc_range, LOC_CANONICALIZE_TAG, &result , 0);
    1470          10 :                 if( result != 1 || can_loc_range == NULL || !can_loc_range[0]) {
    1471             :                         /* Error */
    1472           0 :                         intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize loc_range" , 0 TSRMLS_CC );
    1473           0 :                         if(can_loc_range) {
    1474           0 :                                 efree(can_loc_range);
    1475             :                         }
    1476           0 :                         LOOKUP_CLEAN_RETURN(NULL);
    1477             :                 } else {
    1478          10 :                         loc_range = can_loc_range;
    1479             :                 }
    1480             :         } 
    1481             : 
    1482          20 :         cur_loc_range = ecalloc(1, strlen(loc_range)+1);
    1483             :         /* convert to lower and replace hyphens */
    1484          20 :         result = strToMatch(loc_range, cur_loc_range);  
    1485          20 :         if(can_loc_range) {
    1486          10 :                 efree(can_loc_range);
    1487             :         }
    1488          20 :         if(result == 0) {
    1489           0 :                 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "lookup_loc_range: unable to canonicalize lang_tag" , 0 TSRMLS_CC);
    1490           0 :                 LOOKUP_CLEAN_RETURN(NULL);
    1491             :         }
    1492             : 
    1493             :         /* Lookup for the lang_tag match */
    1494          20 :         saved_pos = strlen(cur_loc_range);
    1495          44 :         while(saved_pos > 0) {
    1496         234 :                 for(i=0; i< cur_arr_len; i++){ 
    1497         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) { 
    1498             :                                 /* Match found */
    1499          20 :                                 return_value = estrdup(canonicalize?cur_arr[i*2]:cur_arr[i*2+1]);
    1500          20 :                                 efree(cur_loc_range);
    1501          20 :                                 LOOKUP_CLEAN_RETURN(return_value);
    1502             :                         }
    1503             :                 }
    1504           4 :                 saved_pos = getStrrtokenPos(cur_loc_range, saved_pos);
    1505             :         }
    1506             : 
    1507             :         /* Match not found */
    1508           0 :         efree(cur_loc_range);
    1509           0 :         LOOKUP_CLEAN_RETURN(NULL);
    1510             : }
    1511             : /* }}} */
    1512             : 
    1513             : /* {{{ proto string Locale::lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]]) 
    1514             : * Searchs the items in $langtag for the best match to the language
    1515             : * range 
    1516             : */
    1517             : /* }}} */
    1518             : /* {{{ proto string locale_lookup(array $langtag, string $locale[, bool $canonicalize[, string $default = null]])
    1519             : * Searchs the items in $langtag for the best match to the language
    1520             : * range 
    1521             : */
    1522          21 : PHP_FUNCTION(locale_lookup)
    1523             : {
    1524          21 :         char*           fallback_loc            = NULL;
    1525          21 :         int             fallback_loc_len        = 0;
    1526          21 :         char*           loc_range               = NULL;
    1527          21 :         int             loc_range_len           = 0;
    1528             : 
    1529          21 :         zval*           arr                             = NULL;
    1530          21 :         HashTable*      hash_arr                = NULL;
    1531          21 :         zend_bool       boolCanonical   = 0;
    1532          21 :         char*           result                  =NULL;
    1533             : 
    1534          21 :         intl_error_reset( NULL TSRMLS_CC );
    1535             : 
    1536          21 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "as|bs", &arr, &loc_range, &loc_range_len,
    1537             :                 &boolCanonical,     &fallback_loc, &fallback_loc_len) == FAILURE) {
    1538           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "locale_lookup: unable to parse input params", 0 TSRMLS_CC );
    1539           1 :                 RETURN_FALSE;
    1540             :         }
    1541             : 
    1542          20 :         if(loc_range_len == 0) {
    1543           0 :                 loc_range = INTL_G(default_locale);
    1544             :         }
    1545             : 
    1546          20 :         hash_arr = HASH_OF(arr);
    1547             : 
    1548          20 :         if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) {
    1549           0 :                 RETURN_EMPTY_STRING();
    1550             :         } 
    1551             :         
    1552          20 :         result = lookup_loc_range(loc_range, hash_arr, boolCanonical TSRMLS_CC);
    1553          20 :         if(result == NULL || result[0] == '\0') {
    1554           0 :                 if( fallback_loc ) {
    1555           0 :                         result = estrndup(fallback_loc, fallback_loc_len);
    1556             :                 } else {
    1557           0 :                         RETURN_EMPTY_STRING();
    1558             :                 }
    1559             :         }
    1560             : 
    1561          20 :         RETVAL_STRINGL(result, strlen(result), 0);
    1562             : }
    1563             : /* }}} */
    1564             : 
    1565             : /* {{{ proto string Locale::acceptFromHttp(string $http_accept)
    1566             : * Tries to find out best available locale based on HTTP �Accept-Language� header
    1567             : */
    1568             : /* }}} */
    1569             : /* {{{ proto string locale_accept_from_http(string $http_accept)
    1570             : * Tries to find out best available locale based on HTTP �Accept-Language� header
    1571             : */
    1572          13 : PHP_FUNCTION(locale_accept_from_http)
    1573             : {
    1574             :         UEnumeration *available;
    1575          13 :         char *http_accept = NULL;
    1576             :         int http_accept_len;
    1577          13 :         UErrorCode status = 0;
    1578             :         int len;
    1579             :         char resultLocale[INTL_MAX_LOCALE_LEN+1];
    1580             :         UAcceptResult outResult;
    1581             : 
    1582          13 :         if(zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s", &http_accept, &http_accept_len) == FAILURE)
    1583             :         {
    1584           3 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
    1585             :                 "locale_accept_from_http: unable to parse input parameters", 0 TSRMLS_CC );
    1586           3 :                 RETURN_FALSE;
    1587             :         }
    1588             :         
    1589          10 :         available = ures_openAvailableLocales(NULL, &status);
    1590          10 :         INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to retrieve locale list");
    1591          10 :         len = uloc_acceptLanguageFromHTTP(resultLocale, INTL_MAX_LOCALE_LEN, 
    1592             :                                                 &outResult, http_accept, available, &status);
    1593          10 :         uenum_close(available);
    1594          10 :         INTL_CHECK_STATUS(status, "locale_accept_from_http: failed to find acceptable locale");
    1595          10 :         if (len < 0 || outResult == ULOC_ACCEPT_FAILED) {
    1596           2 :                 RETURN_FALSE;
    1597             :         }
    1598           8 :         RETURN_STRINGL(resultLocale, len, 1);
    1599             : }
    1600             : /* }}} */
    1601             : 
    1602             : /*
    1603             :  * Local variables:
    1604             :  * tab-width: 4
    1605             :  * c-basic-offset: 4
    1606             :  * End:
    1607             :  * vim600: noet sw=4 ts=4 fdm=marker
    1608             :  * vim<600: noet sw=4 ts=4
    1609             :  *can_loc_len
    1610             : */

Generated by: LCOV version 1.10

Generated at Sun, 27 Jul 2014 12:58:30 +0000 (3 days ago)

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