19#include <unicode/ustring.h>
20#include <unicode/udata.h>
21#include <unicode/putil.h>
22#include <unicode/ures.h>
42#define EXTLANG_PREFIX "a"
43#define PRIVATE_PREFIX "x"
44#define DISP_NAME "name"
46#define MAX_NO_VARIANT 15
47#define MAX_NO_EXTLANG 3
48#define MAX_NO_PRIVATE 15
49#define MAX_NO_LOOKUP_LANG_TAG 100
51#define LOC_NOT_FOUND 1
54#define VARIANT_KEYNAME_LEN 11
55#define EXTLANG_KEYNAME_LEN 10
56#define PRIVATE_KEYNAME_LEN 11
64static const char *
const LOC_GRANDFATHERED[] = {
126static const char *
const LOC_PREFERRED_GRANDFATHERED[] = {
181#define isIDSeparator(a) (a == '_' || a == '-')
182#define isKeywordSeparator(a) (a == '@' )
183#define isEndOfTag(a) (a == '\0' )
185#define isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
189#define isIDPrefix(s) (isPrefixLetter(s[0])&&isIDSeparator(s[1]))
190#define isKeywordPrefix(s) ( isKeywordSeparator(s[0]) )
194#define isTerminator(a) ((a==0)||(a=='.')||(a=='@'))
198static int16_t findOffset(
const char*
const* list,
const char*
key)
200 const char*
const* anchor = list;
201 while (*list !=
NULL) {
203 return (int16_t)(list - anchor);
213static char* getPreferredTag(
const char* gf_tag)
218 grOffset = findOffset( LOC_GRANDFATHERED ,gf_tag);
222 if( LOC_PREFERRED_GRANDFATHERED[grOffset] !=
NULL ){
242 for(i=savedPos-1; i>=0; i--) {
267static zend_off_t getSingletonPos(
const char* str)
274 for( i=0; (size_t)i <
len ; i++){
342static zend_string* get_icu_value_internal(
const char* loc_name ,
char* tag_name,
int*
result ,
int fromParseLocale)
345 int32_t tag_value_len = 512;
347 char* mod_loc_name =
NULL;
349 int32_t buflen = 512;
358 zend_off_t grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
361 return zend_string_init(loc_name,
strlen(loc_name), 0);
368 if( fromParseLocale==1 ){
374 return zend_string_init(loc_name,
strlen(loc_name), 0);
378 singletonPos = getSingletonPos( loc_name );
379 if( singletonPos == 0){
383 }
else if( singletonPos > 0 ){
386 mod_loc_name =
estrndup ( loc_name , singletonPos-1);
392 if( mod_loc_name ==
NULL){
393 mod_loc_name =
estrdup(loc_name );
399 tag_value = zend_string_realloc( tag_value , buflen, 0);
401 tag_value = zend_string_alloc( buflen, 0);
403 tag_value_len = buflen;
406 buflen = uloc_getScript ( mod_loc_name , tag_value->
val , tag_value_len , &
status);
409 buflen = uloc_getLanguage ( mod_loc_name , tag_value->
val , tag_value_len , &
status);
412 buflen = uloc_getCountry ( mod_loc_name , tag_value->
val , tag_value_len , &
status);
415 buflen = uloc_getVariant ( mod_loc_name , tag_value->
val , tag_value_len , &
status);
418 buflen = uloc_canonicalize ( mod_loc_name , tag_value->
val , tag_value_len , &
status);
421 if( U_FAILURE(
status ) ) {
434 efree( mod_loc_name);
438 }
while( buflen > tag_value_len );
447 efree( mod_loc_name);
455 efree( mod_loc_name);
470 char* loc_name =
NULL;
471 size_t loc_name_len = 0;
474 char* empty_result =
"";
487 if(loc_name_len == 0) {
489 loc_name_len =
strlen(loc_name);
495 tag_value = get_icu_value_internal( loc_name , tag_name , &
result ,0);
513 spprintf(&
msg , 0,
"locale_get_%s : unable to get locale %s", tag_name , tag_name );
549 char* loc_name =
NULL;
550 size_t loc_name_len = 0;
552 char* disp_loc_name =
NULL;
553 size_t disp_loc_name_len = 0;
554 int free_loc_name = 0;
556 UChar* disp_name =
NULL;
557 int32_t disp_name_len = 0;
559 char* mod_loc_name =
NULL;
561 int32_t buflen = 512;
576 if(loc_name_len > ULOC_FULLNAME_CAPACITY) {
578 spprintf(&
msg , 0,
"locale_get_display_%s : name too long", tag_name );
584 if(loc_name_len == 0) {
590 int grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
593 mod_loc_name = getPreferredTag( loc_name );
601 if( mod_loc_name==
NULL ){
602 mod_loc_name =
estrdup( loc_name );
613 disp_name =
erealloc( disp_name , buflen *
sizeof(UChar) );
614 disp_name_len = buflen;
617 buflen = uloc_getDisplayLanguage ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &
status);
619 buflen = uloc_getDisplayScript ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &
status);
621 buflen = uloc_getDisplayCountry ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &
status);
623 buflen = uloc_getDisplayVariant ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &
status);
625 buflen = uloc_getDisplayName ( mod_loc_name , disp_loc_name , disp_name , disp_name_len , &
status);
637 spprintf(&
msg, 0,
"locale_get_display_%s : unable to get locale %s", tag_name , tag_name );
644 efree( mod_loc_name );
647 efree((
void *)disp_loc_name);
648 disp_loc_name =
NULL;
652 }
while( buflen > disp_name_len );
655 efree( mod_loc_name );
658 efree((
void *)disp_loc_name);
659 disp_loc_name =
NULL;
666 spprintf(&
msg, 0,
"locale_get_display_%s :error converting display name for %s to UTF-8", tag_name , tag_name );
726 UEnumeration* e =
NULL;
729 const char* kw_key =
NULL;
730 int32_t kw_key_len = 0;
732 char* loc_name =
NULL;
733 size_t loc_name_len = 0;
743 if(loc_name_len == 0) {
748 e = uloc_openKeywords( loc_name, &
status );
760 while( ( kw_key = uenum_next( e, &kw_key_len, &
status ) ) !=
NULL ){
761 int32_t kw_value_len = 100;
762 zend_string *kw_value_str = zend_string_alloc(kw_value_len, 0);
765 kw_value_len=uloc_getKeywordValue( loc_name, kw_key,
ZSTR_VAL(kw_value_str), kw_value_len, &
status );
768 kw_value_str = zend_string_extend(kw_value_str, kw_value_len, 0);
769 kw_value_len=uloc_getKeywordValue( loc_name,kw_key,
ZSTR_VAL(kw_value_str), kw_value_len+1, &
status );
770 }
else if(!U_FAILURE(
status)) {
771 kw_value_str = zend_string_truncate(kw_value_str, kw_value_len, 0);
776 zend_string_efree( kw_value_str );
782 add_assoc_str(
return_value, (
char *)kw_key, kw_value_str);
810 if ((ele_value = zend_hash_str_find_deref(hash_arr , key_name,
strlen(key_name))) !=
NULL ) {
831static void add_prefix(
smart_str* loc_name,
char* key_name)
847static int append_multiple_key_values(
smart_str* loc_name,
HashTable* hash_arr,
char* key_name)
850 int isFirstSubtag = 0;
853 if ((ele_value = zend_hash_str_find_deref( hash_arr , key_name ,
strlen(key_name))) !=
NULL) {
855 add_prefix( loc_name , key_name);
869 if (isFirstSubtag++ == 0){
870 add_prefix(loc_name , key_name);
880 char cur_key_name[31];
881 int max_value = 0, i;
895 for( i=0 ; i< max_value; i++ ){
896 snprintf( cur_key_name , 30,
"%s%d", key_name , i);
897 if ((ele_value = zend_hash_str_find_deref( hash_arr , cur_key_name ,
strlen(cur_key_name))) !=
NULL) {
903 if (isFirstSubtag++ == 0){
904 add_prefix(loc_name , cur_key_name);
926 "locale_compose: parameter array element is not a string", 0 );
927 smart_str_free(loc_name);
934#define RETURN_SMART_STR(str) smart_str_0((str)); RETURN_NEW_STR((str)->s)
955 if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 )
963 if( !handleAppendResult(
result, loc_name)){
971 smart_str_free(loc_name);
974 if( !handleAppendResult(
result, loc_name)){
980 if( !handleAppendResult(
result, loc_name)){
986 if( !handleAppendResult(
result, loc_name)){
992 if( !handleAppendResult(
result, loc_name)){
998 if( !handleAppendResult(
result, loc_name)){
1004 if( !handleAppendResult(
result, loc_name)){
1019static zend_string* get_private_subtags(
const char* loc_name)
1023 const char* mod_loc_name =
NULL;
1025 if( loc_name && (
len =
strlen(loc_name)) > 0 ){
1027 mod_loc_name = loc_name ;
1028 while( (singletonPos = getSingletonPos(mod_loc_name)) > -1){
1029 if( (*(mod_loc_name+singletonPos)==
'x') || (*(mod_loc_name+singletonPos)==
'X') ){
1031 if( singletonPos + 2 ==
len){
1036 result = zend_string_init(mod_loc_name + singletonPos+2 , (
len -( singletonPos +2) ), 0);
1041 if((
size_t)(singletonPos + 1) >=
len){
1046 mod_loc_name = mod_loc_name + singletonPos +1;
1058static int add_array_entry(
const char* loc_name,
zval* hash_arr,
char* key_name)
1061 char* cur_key_name =
NULL;
1063 char* last_ptr =
NULL;
1070 key_value = get_private_subtags( loc_name );
1073 key_value = get_icu_value_internal( loc_name , key_name , &
result,1 );
1082 efree( cur_key_name);
1085 size_t cur_key_name_size = (
sizeof(
"-2147483648") - 1) +
strlen(key_name) + 1;
1086 cur_key_name =
emalloc(cur_key_name_size);
1087 snprintf( cur_key_name, cur_key_name_size ,
"%s%d", key_name , cnt++);
1088 add_assoc_string( hash_arr, cur_key_name , token);
1091 snprintf( cur_key_name , cur_key_name_size,
"%s%d", key_name , cnt++);
1092 add_assoc_string( hash_arr, cur_key_name , token);
1104 add_assoc_str( hash_arr, key_name ,
key_value);
1112 efree( cur_key_name);
1122 char* loc_name =
NULL;
1123 size_t loc_name_len = 0;
1134 if(loc_name_len == 0) {
1140 grOffset = findOffset( LOC_GRANDFATHERED , loc_name );
1141 if( grOffset >= 0 ){
1158 char* loc_name =
NULL;
1159 size_t loc_name_len = 0;
1164 char* saved_ptr =
NULL;
1172 if(loc_name_len == 0) {
1174 loc_name_len =
strlen(loc_name);
1182 if( findOffset( LOC_GRANDFATHERED , loc_name ) >= 0 ){
1207static int strToMatch(
const char* str ,
char *retstr)
1209 char* anchor =
NULL;
1210 const char* anchor1 =
NULL;
1213 if( (!str) || str[0] ==
'\0'){
1218 while( (*str)!=
'\0' ){
1222 *retstr = tolower(*str);
1242 char* lang_tag =
NULL;
1243 size_t lang_tag_len = 0;
1244 char* loc_range =
NULL;
1245 size_t loc_range_len = 0;
1249 char* chrcheck =
NULL;
1254 char* cur_lang_tag =
NULL;
1255 char* cur_loc_range =
NULL;
1257 bool boolCanonical = 0;
1269 if(loc_range_len == 0) {
1271 loc_range_len =
strlen(loc_range);
1274 if(
strcmp(loc_range,
"*")==0){
1281 if( boolCanonical ){
1286 "locale_filter_matches : unable to canonicalize loc_range" , 0 );
1294 "locale_filter_matches : unable to canonicalize lang_tag" , 0 );
1299 cur_lang_tag =
ecalloc( 1, can_lang_tag->
len + 1);
1302 result = strToMatch( can_lang_tag->
val , cur_lang_tag);
1304 efree( cur_lang_tag );
1309 cur_loc_range =
ecalloc( 1, can_loc_range->
len + 1);
1310 result = strToMatch( can_loc_range->
val , cur_loc_range );
1312 efree( cur_lang_tag );
1314 efree( cur_loc_range );
1320 token =
strstr( cur_lang_tag , cur_loc_range );
1322 if( token && (token==cur_lang_tag) ){
1324 chrcheck = token + (
strlen(cur_loc_range));
1326 efree( cur_lang_tag );
1327 efree( cur_loc_range );
1340 efree( cur_lang_tag );
1343 efree( cur_loc_range );
1358 result = strToMatch( lang_tag , cur_lang_tag);
1360 efree( cur_lang_tag );
1364 result = strToMatch( loc_range , cur_loc_range );
1366 efree( cur_lang_tag );
1367 efree( cur_loc_range );
1372 token =
strstr( cur_lang_tag , cur_loc_range );
1374 if( token && (token==cur_lang_tag) ){
1376 chrcheck = token + (
strlen(cur_loc_range));
1378 efree( cur_lang_tag );
1379 efree( cur_loc_range );
1386 efree( cur_lang_tag );
1389 efree( cur_loc_range );
1397static void array_cleanup(
char* arr[] ,
int arr_size)
1400 for( i=0; i< arr_size; i++ ){
1408#define LOOKUP_CLEAN_RETURN(value) array_cleanup(cur_arr, cur_arr_len); return (value)
1413static zend_string* lookup_loc_range(
const char* loc_range,
HashTable* hash_arr,
int canonicalize )
1416 int cur_arr_len = 0;
1422 char* cur_loc_range =
NULL;
1428 char **cur_arr =
ecalloc(zend_hash_num_elements(hash_arr)*2,
sizeof(
char *));
1443 cur_arr[cur_arr_len*2+1] =
Z_STRVAL_P(ele_value);
1449 for(i=0; i<cur_arr_len; i++) {
1458 cur_arr[i*2] =
erealloc(cur_arr[i*2], lang_tag->
len+1);
1459 result = strToMatch(lang_tag->
val, cur_arr[i*2]);
1472 if(
result != 1 || can_loc_range ==
NULL || !can_loc_range->
val[0]) {
1480 loc_range = can_loc_range->
val;
1486 result = strToMatch(loc_range, cur_loc_range);
1496 saved_pos =
strlen(cur_loc_range);
1497 while(saved_pos > 0) {
1498 for(i=0; i< cur_arr_len; i++){
1499 if(cur_arr[i*2] !=
NULL &&
strlen(cur_arr[i*2]) == saved_pos &&
strncmp(cur_loc_range, cur_arr[i*2], saved_pos) == 0) {
1501 char *str = canonicalize ? cur_arr[i*2] : cur_arr[i*2+1];
1503 efree(cur_loc_range);
1507 saved_pos = getStrrtokenPos(cur_loc_range, saved_pos);
1511 efree(cur_loc_range);
1526 char* loc_range =
NULL;
1527 size_t loc_range_len = 0;
1531 bool boolCanonical = 0;
1544 if(loc_range_len == 0) {
1545 if(fallback_loc_str) {
1546 loc_range =
ZSTR_VAL(fallback_loc_str);
1547 loc_range_len =
ZSTR_LEN(fallback_loc_str);
1550 loc_range_len =
strlen(loc_range);
1558 if( !hash_arr || zend_hash_num_elements( hash_arr ) == 0 ) {
1562 result_str = lookup_loc_range(loc_range, hash_arr, boolCanonical);
1563 if(result_str ==
NULL ||
ZSTR_VAL(result_str)[0] ==
'\0') {
1564 if( fallback_loc_str ) {
1565 result_str = zend_string_copy(fallback_loc_str);
1580 UEnumeration *available;
1581 char *http_accept =
NULL;
1582 size_t http_accept_len;
1586 UAcceptResult outResult;
1591 if(http_accept_len > ULOC_FULLNAME_CAPACITY) {
1593 char *
start = http_accept;
1599 if(
len > ULOC_FULLNAME_CAPACITY) {
1601 "locale_accept_from_http: locale string too long", 0 );
1610 available = ures_openAvailableLocales(
NULL, &
status);
1613 &outResult, http_accept, available, &
status);
1614 uenum_close(available);
1616 if (
len < 0 || outResult == ULOC_ACCEPT_FAILED) {
strstr(string $haystack, string $needle, bool $before_needle=false)
strchr(string $haystack, string $needle, bool $before_needle=false)
const U_BUFFER_OVERFLOW_ERROR
const U_ILLEGAL_ARGUMENT_ERROR
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
zend_string * intl_convert_utf16_to_utf8(const UChar *src, int32_t src_len, UErrorCode *status)
#define INTL_CHECK_STATUS(err, msg)
#define INTL_MAX_LOCALE_LEN
#define INTL_CHECK_LOCALE_LEN(locale_len)
void intl_error_set(intl_error *err, UErrorCode code, const char *msg, int copyMsg)
void intl_error_reset(intl_error *err)
#define LOC_GRANDFATHERED_LANG_TAG
#define LOC_CANONICALIZE_TAG
#define RETURN_SMART_STR(str)
#define isKeywordSeparator(a)
#define LOOKUP_CLEAN_RETURN(value)
#define PHP_NAMED_FUNCTION
unsigned const char * end
#define PHP_INI_STAGE_RUNTIME
const char * intl_locale_get_default(void)
locale_get_keywords(string $locale)
locale_get_region(string $locale)
locale_canonicalize(string $locale)
locale_get_primary_language(string $locale)
locale_accept_from_http(string $header)
locale_lookup(array $languageTag, string $locale, bool $canonicalize=false, ?string $defaultLocale=null)
locale_get_all_variants(string $locale)
locale_get_script(string $locale)
locale_filter_matches(string $languageTag, string $locale, bool $canonicalize=false)
locale_get_display_region(string $locale, ?string $displayLocale=null)
locale_get_display_name(string $locale, ?string $displayLocale=null)
locale_get_display_script(string $locale, ?string $displayLocale=null)
locale_get_display_variant(string $locale, ?string $displayLocale=null)
locale_get_display_language(string $locale, ?string $displayLocale=null)
locale_compose(array $subtags)
locale_parse(string $locale)
PHPAPI char * php_strtok_r(char *s, const char *delim, char **last)
unsigned char key[REFLECTION_KEY_LEN]
#define INTERNAL_FUNCTION_PARAMETERS
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
ZEND_API zend_result add_next_index_stringl(zval *arg, const char *str, size_t length)
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
#define RETURN_STRINGL(s, l)
#define ZEND_PARSE_PARAMETERS_END()
#define Z_PARAM_STR_OR_NULL(dest)
#define ZEND_PARSE_PARAMETERS_NONE()
#define RETVAL_NEW_STR(s)
#define Z_PARAM_STRING(dest, dest_len)
#define Z_PARAM_STR(dest)
#define Z_PARAM_STRING_OR_NULL(dest, dest_len)
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
#define ZEND_EXTERN_MODULE_GLOBALS(module_name)
#define Z_PARAM_BOOL(dest)
#define RETURN_EMPTY_STRING()
#define Z_PARAM_ARRAY(dest)
#define estrndup(s, length)
#define ecalloc(nmemb, size)
#define erealloc(ptr, size)
strncmp(string $string1, string $string2, int $length)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
#define strcasecmp(s1, s2)
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
#define ZEND_HASH_FOREACH_END()
#define ZEND_HASH_FOREACH_VAL(ht, _val)
ZEND_API zend_result zend_alter_ini_entry(zend_string *name, zend_string *new_value, int modify_type, int stage)
struct _zend_string zend_string
#define Z_STRVAL_P(zval_p)
#define Z_ARRVAL_P(zval_p)
struct _zend_array HashTable
#define Z_STRLEN_P(zval_p)