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