Annotation of embedaddon/php/ext/intl/locale/locale_methods.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>