Annotation of embedaddon/php/ext/intl/collator/collator_sort.c, revision 1.1.1.2

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: Vadim Savchuk <vsavchuk@productengine.com>                  |
                     14:    |          Dmitry Lakhtyuk <dlakhtyuk@productengine.com>               |
                     15:    +----------------------------------------------------------------------+
                     16:  */
                     17: 
                     18: #ifdef HAVE_CONFIG_H
                     19: #include "config.h"
                     20: #endif
                     21: 
                     22: #include "php_intl.h"
                     23: #include "collator.h"
                     24: #include "collator_class.h"
                     25: #include "collator_sort.h"
                     26: #include "collator_convert.h"
                     27: #include "intl_convert.h"
                     28: 
                     29: #if !defined(HAVE_PTRDIFF_T) && !defined(_PTRDIFF_T_DEFINED)
                     30: typedef long ptrdiff_t;
                     31: #endif
                     32: 
                     33: /**
                     34:  * Declare 'index' which will point to sort key in sort key
                     35:  * buffer.
                     36:  */
                     37: typedef struct _collator_sort_key_index {
                     38:        char* key;       /* pointer to sort key */
                     39:        zval** zstr;     /* pointer to original string(hash-item) */
                     40: } collator_sort_key_index_t;
                     41: 
                     42: ZEND_EXTERN_MODULE_GLOBALS( intl )
                     43: 
                     44: static const size_t DEF_SORT_KEYS_BUF_SIZE = 1048576;
                     45: static const size_t DEF_SORT_KEYS_BUF_INCREMENT = 1048576;
                     46: 
                     47: static const size_t DEF_SORT_KEYS_INDX_BUF_SIZE = 1048576;
                     48: static const size_t DEF_SORT_KEYS_INDX_BUF_INCREMENT = 1048576;
                     49: 
                     50: static const size_t DEF_UTF16_BUF_SIZE = 1024;
                     51: 
                     52: /* {{{ collator_regular_compare_function */
                     53: static int collator_regular_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
                     54: {
                     55:        Collator_object* co = NULL;
                     56: 
                     57:        int rc      = SUCCESS;
                     58: 
                     59:        zval* str1  = collator_convert_object_to_string( op1 TSRMLS_CC );
                     60:        zval* str2  = collator_convert_object_to_string( op2 TSRMLS_CC );
                     61: 
                     62:        zval* num1  = NULL;
                     63:        zval* num2  = NULL;
                     64:        zval* norm1 = NULL;
                     65:        zval* norm2 = NULL;
                     66: 
                     67:        /* If both args are strings AND either of args is not numeric string
                     68:         * then use ICU-compare. Otherwise PHP-compare. */
                     69:        if( Z_TYPE_P(str1) == IS_STRING && Z_TYPE_P(str2) == IS_STRING &&
                     70:                ( str1 == ( num1 = collator_convert_string_to_number_if_possible( str1 ) ) ||
                     71:                  str2 == ( num2 = collator_convert_string_to_number_if_possible( str2 ) ) ) )
                     72:        {
                     73:                /* Fetch collator object. */
                     74:                co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
                     75: 
                     76:                if (!co || !co->ucoll) {
                     77:                        intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
                     78:                        intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
                     79:                                "Object not initialized", 0 TSRMLS_CC );
                     80:                        php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
                     81:                }
                     82: 
                     83:                /* Compare the strings using ICU. */
                     84:                result->value.lval = ucol_strcoll(
                     85:                                co->ucoll,
                     86:                                INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
                     87:                                INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
                     88:                result->type = IS_LONG;
                     89:        }
                     90:        else
                     91:        {
                     92:                /* num1 is set if str1 and str2 are strings. */
                     93:                if( num1 )
                     94:                {
                     95:                        if( num1 == str1 )
                     96:                        {
                     97:                                /* str1 is string but not numeric string
                     98:                                 * just convert it to utf8. 
                     99:                                 */
                    100:                                norm1 = collator_convert_zstr_utf16_to_utf8( str1 );
                    101: 
                    102:                                /* num2 is not set but str2 is string => do normalization. */
                    103:                                norm2 = collator_normalize_sort_argument( str2 );
                    104:                        }
                    105:                        else
                    106:                        {
                    107:                                /* str1 is numeric strings => passthru to PHP-compare. */
                    108:                                zval_add_ref( &num1 );
                    109:                                norm1 = num1;
                    110: 
                    111:                                /* str2 is numeric strings => passthru to PHP-compare. */
                    112:                                zval_add_ref( &num2 );
                    113:                                norm2 = num2;
                    114:                        }
                    115:                }
                    116:                else
                    117:                {
                    118:                        /* num1 is not set if str1 or str2 is not a string => do normalization. */
                    119:                        norm1 = collator_normalize_sort_argument( str1 );
                    120: 
                    121:                        /* if num1 is not set then num2 is not set as well => do normalization. */
                    122:                        norm2 = collator_normalize_sort_argument( str2 );
                    123:                }
                    124: 
                    125:                rc = compare_function( result, norm1, norm2 TSRMLS_CC );
                    126: 
                    127:                zval_ptr_dtor( &norm1 );
                    128:                zval_ptr_dtor( &norm2 );
                    129:        }
                    130: 
                    131:        if( num1 )
                    132:                zval_ptr_dtor( &num1 );
                    133: 
                    134:        if( num2 )
                    135:                zval_ptr_dtor( &num2 );
                    136: 
                    137:        zval_ptr_dtor( &str1 );
                    138:        zval_ptr_dtor( &str2 );
                    139: 
                    140:        return rc;
                    141: }
                    142: /* }}} */
                    143: 
                    144: /* {{{ collator_numeric_compare_function
                    145:  * Convert input args to double and compare it.
                    146:  */
                    147: static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
                    148: {
                    149:        int rc     = SUCCESS;
                    150:        zval* num1 = NULL;
                    151:        zval* num2 = NULL;
                    152: 
                    153:        if( Z_TYPE_P(op1) == IS_STRING )
                    154:        {
                    155:                num1 = collator_convert_string_to_double( op1 );
                    156:                op1 = num1;
                    157:        }
                    158: 
                    159:        if( Z_TYPE_P(op2) == IS_STRING )
                    160:        {
                    161:                num2 = collator_convert_string_to_double( op2 );
                    162:                op2 = num2;
                    163:        }
                    164: 
                    165:        rc = numeric_compare_function( result, op1, op2 TSRMLS_CC);
                    166: 
                    167:        if( num1 )
                    168:                zval_ptr_dtor( &num1 );
                    169:        if( num2 )
                    170:                zval_ptr_dtor( &num2 );
                    171: 
                    172:        return rc;
                    173: }
                    174: /* }}} */
                    175: 
                    176: /* {{{ collator_icu_compare_function
                    177:  * Direct use of ucol_strcoll.
                    178: */
                    179: static int collator_icu_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
                    180: {
                    181:        int rc              = SUCCESS;
                    182:        Collator_object* co = NULL;
                    183:        zval* str1          = NULL;
                    184:        zval* str2          = NULL;
                    185: 
                    186:        str1 = collator_make_printable_zval( op1 );
                    187:        str2 = collator_make_printable_zval( op2 );
                    188: 
                    189:        /* Fetch collator object. */
                    190:        co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
                    191: 
                    192:        /* Compare the strings using ICU. */
                    193:        result->value.lval = ucol_strcoll(
                    194:                        co->ucoll,
                    195:                        INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
                    196:                        INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
                    197:        result->type = IS_LONG;
                    198: 
                    199:        zval_ptr_dtor( &str1 );
                    200:        zval_ptr_dtor( &str2 );
                    201: 
                    202:        return rc;
                    203: }
                    204: /* }}} */
                    205: 
                    206: /* {{{ collator_compare_func
                    207:  * Taken from PHP5 source (array_data_compare).
                    208:  */
                    209: static int collator_compare_func( const void* a, const void* b TSRMLS_DC )
                    210: {
                    211:        Bucket *f;
                    212:        Bucket *s;
                    213:        zval result;
                    214:        zval *first;
                    215:        zval *second;
                    216: 
                    217:        f = *((Bucket **) a);
                    218:        s = *((Bucket **) b);
                    219: 
                    220:        first = *((zval **) f->pData);
                    221:        second = *((zval **) s->pData);
                    222: 
                    223:        if( INTL_G(compare_func)( &result, first, second TSRMLS_CC) == FAILURE )
                    224:                return 0;
                    225: 
                    226:        if( Z_TYPE(result) == IS_DOUBLE )
                    227:        {
                    228:                if( Z_DVAL(result) < 0 )
                    229:                        return -1;
                    230:                else if( Z_DVAL(result) > 0 )
                    231:                        return 1;
                    232:                else
                    233:                        return 0;
                    234:        }
                    235: 
                    236:        convert_to_long(&result);
                    237: 
                    238:        if( Z_LVAL(result) < 0 )
                    239:                return -1;
                    240:        else if( Z_LVAL(result) > 0 )
                    241:                return 1;
                    242: 
                    243:        return 0;
                    244: }
                    245: /* }}} */
                    246: 
                    247: /* {{{ collator_cmp_sort_keys
                    248:  * Compare sort keys
                    249:  */
                    250: static int collator_cmp_sort_keys( const void *p1, const void *p2 TSRMLS_DC )
                    251: {
                    252:        char* key1 = ((collator_sort_key_index_t*)p1)->key;
                    253:        char* key2 = ((collator_sort_key_index_t*)p2)->key;
                    254: 
                    255:        return strcmp( key1, key2 );
                    256: }
                    257: /* }}} */
                    258: 
                    259: /* {{{ collator_get_compare_function
                    260:  * Choose compare function according to sort flags.
                    261:  */
                    262: static collator_compare_func_t collator_get_compare_function( const long sort_flags )
                    263: {
                    264:        collator_compare_func_t func;
                    265: 
                    266:        switch( sort_flags )
                    267:        {
                    268:                case COLLATOR_SORT_NUMERIC:
                    269:                        func = collator_numeric_compare_function;
                    270:                        break;
                    271: 
                    272:                case COLLATOR_SORT_STRING:
                    273:                        func = collator_icu_compare_function;
                    274:                        break;
                    275: 
                    276:                case COLLATOR_SORT_REGULAR:
                    277:                default:
                    278:                        func = collator_regular_compare_function;
                    279:                        break;
                    280:        }
                    281: 
                    282:        return func;
                    283: }
                    284: /* }}} */
                    285: 
                    286: /* {{{ collator_sort_internal
                    287:  * Common code shared by collator_sort() and collator_asort() API functions.
                    288:  */
                    289: static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
                    290: {
                    291:        zval*          array            = NULL;
                    292:        HashTable*     hash             = NULL;
                    293:        zval*          saved_collator   = NULL;
                    294:        long           sort_flags       = COLLATOR_SORT_REGULAR;
                    295: 
                    296:        COLLATOR_METHOD_INIT_VARS
                    297: 
                    298:        /* Parse parameters. */
                    299:        if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa|l",
                    300:                &object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
                    301:        {
                    302:                intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
                    303:                        "collator_sort_internal: unable to parse input params", 0 TSRMLS_CC );
                    304: 
                    305:                RETURN_FALSE;
                    306:        }
                    307: 
                    308:        /* Fetch the object. */
                    309:        COLLATOR_METHOD_FETCH_OBJECT;
                    310: 
                    311:        /* Set 'compare function' according to sort flags. */
                    312:        INTL_G(compare_func) = collator_get_compare_function( sort_flags );
                    313: 
                    314:        hash = HASH_OF( array );
                    315: 
                    316:        /* Convert strings in the specified array from UTF-8 to UTF-16. */
                    317:        collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
                    318:        COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
                    319: 
                    320:        /* Save specified collator in the request-global (?) variable. */
                    321:        saved_collator = INTL_G( current_collator );
                    322:        INTL_G( current_collator ) = object;
                    323: 
                    324:        /* Sort specified array. */
                    325:        zend_hash_sort( hash, zend_qsort, collator_compare_func, renumber TSRMLS_CC );
                    326: 
                    327:        /* Restore saved collator. */
                    328:        INTL_G( current_collator ) = saved_collator;
                    329: 
                    330:        /* Convert strings in the specified array back to UTF-8. */
                    331:        collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
                    332:        COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
                    333: 
                    334:        RETURN_TRUE;
                    335: }
                    336: /* }}} */
                    337: 
                    338: /* {{{ proto bool Collator::sort( Collator $coll, array(string) $arr [, int $sort_flags] )
                    339:  * Sort array using specified collator. }}} */
                    340: /* {{{ proto bool collator_sort(  Collator $coll, array(string) $arr [, int $sort_flags] )
                    341:  * Sort array using specified collator.
                    342:  */
                    343: PHP_FUNCTION( collator_sort )
                    344: {
                    345:        collator_sort_internal( TRUE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
                    346: }
                    347: /* }}} */
                    348: 
                    349: /* {{{ proto bool Collator::sortWithSortKeys( Collator $coll, array(string) $arr )
                    350:  * Equivalent to standard PHP sort using Collator.
                    351:  * Uses ICU ucol_getSortKey for performance. }}} */
                    352: /* {{{ proto bool collator_sort_with_sort_keys( Collator $coll, array(string) $arr )
                    353:  * Equivalent to standard PHP sort using Collator.
                    354:  * Uses ICU ucol_getSortKey for performance.
                    355:  */
                    356: PHP_FUNCTION( collator_sort_with_sort_keys )
                    357: {
                    358:        zval*       array                = NULL;
                    359:        HashTable*  hash                 = NULL;
                    360:        zval**      hashData             = NULL;                     /* currently processed item of input hash */
                    361: 
                    362:        char*       sortKeyBuf           = NULL;                     /* buffer to store sort keys */
                    363:        uint32_t    sortKeyBufSize       = DEF_SORT_KEYS_BUF_SIZE;   /* buffer size */
                    364:        ptrdiff_t   sortKeyBufOffset     = 0;                        /* pos in buffer to store sort key */
                    365:        int32_t     sortKeyLen           = 0;                        /* the length of currently processing key */
                    366:        uint32_t    bufLeft              = 0;
                    367:        uint32_t    bufIncrement         = 0;
                    368: 
                    369:        collator_sort_key_index_t* sortKeyIndxBuf = NULL;            /* buffer to store 'indexes' which will be passed to 'qsort' */
                    370:        uint32_t    sortKeyIndxBufSize   = DEF_SORT_KEYS_INDX_BUF_SIZE;
                    371:        uint32_t    sortKeyIndxSize      = sizeof( collator_sort_key_index_t );
                    372: 
                    373:        uint32_t    sortKeyCount         = 0;
                    374:        uint32_t    j                    = 0;
                    375: 
                    376:        UChar*      utf16_buf            = NULL;                     /* tmp buffer to hold current processing string in utf-16 */
                    377:        int         utf16_buf_size       = DEF_UTF16_BUF_SIZE;       /* the length of utf16_buf */
                    378:        int         utf16_len            = 0;                        /* length of converted string */
                    379: 
                    380:        HashTable* sortedHash            = NULL;
                    381: 
                    382:        COLLATOR_METHOD_INIT_VARS
                    383: 
                    384:        /* Parse parameters. */
                    385:        if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
                    386:                &object, Collator_ce_ptr, &array ) == FAILURE )
                    387:        {
                    388:                intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
                    389:                        "collator_sort_with_sort_keys: unable to parse input params", 0 TSRMLS_CC );
                    390: 
                    391:                RETURN_FALSE;
                    392:        }
                    393: 
                    394:        /* Fetch the object. */
                    395:        COLLATOR_METHOD_FETCH_OBJECT;
                    396: 
                    397:        if (!co || !co->ucoll) {
                    398:                intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
                    399:                intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
                    400:                        "Object not initialized", 0 TSRMLS_CC );
                    401:                php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
                    402: 
                    403:                RETURN_FALSE;
                    404:        }
                    405: 
                    406:        /*
                    407:         * Sort specified array.
                    408:         */
                    409:        hash = HASH_OF( array );
                    410: 
                    411:        if( !hash || zend_hash_num_elements( hash ) == 0 )
                    412:                RETURN_TRUE;
                    413: 
                    414:        /* Create bufers */
                    415:        sortKeyBuf     = ecalloc( sortKeyBufSize,     sizeof( char    ) );
                    416:        sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
                    417:        utf16_buf      = eumalloc( utf16_buf_size );
                    418: 
                    419:        /* Iterate through input hash and create a sort key for each value. */
                    420:        zend_hash_internal_pointer_reset( hash );
                    421:        while( zend_hash_get_current_data( hash, (void**) &hashData ) == SUCCESS )
                    422:        {
                    423:                /* Convert current hash item from UTF-8 to UTF-16LE and save the result to utf16_buf. */
                    424: 
                    425:                utf16_len = utf16_buf_size;
                    426: 
                    427:                /* Process string values only. */
                    428:                if( Z_TYPE_PP( hashData ) == IS_STRING )
                    429:                {
                    430:                        intl_convert_utf8_to_utf16( &utf16_buf, &utf16_len, Z_STRVAL_PP( hashData ), Z_STRLEN_PP( hashData ), COLLATOR_ERROR_CODE_P( co ) );
                    431: 
                    432:                        if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
                    433:                        {
                    434:                                intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
                    435:                                intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Sort with sort keys failed", 0 TSRMLS_CC );
                    436: 
                    437:                                if( utf16_buf )
                    438:                                        efree( utf16_buf );
                    439: 
                    440:                                efree( sortKeyIndxBuf );
                    441:                                efree( sortKeyBuf );
                    442: 
                    443:                                RETURN_FALSE;
                    444:                        }
                    445:                }
                    446:                else
                    447:                {
                    448:                        /* Set empty string */
                    449:                        utf16_len = 0;
                    450:                        utf16_buf[utf16_len] = 0;
                    451:                }
                    452: 
                    453:                if( (utf16_len + 1) > utf16_buf_size )
                    454:                        utf16_buf_size = utf16_len + 1;
                    455: 
                    456:                /* Get sort key, reallocating the buffer if needed. */
                    457:                bufLeft = sortKeyBufSize - sortKeyBufOffset;
                    458: 
                    459:                sortKeyLen = ucol_getSortKey( co->ucoll,
                    460:                                                                          utf16_buf,
                    461:                                                                          utf16_len,
                    462:                                                                          (uint8_t*)sortKeyBuf + sortKeyBufOffset,
                    463:                                                                          bufLeft );
                    464: 
                    465:                /* check for sortKeyBuf overflow, increasing its size of the buffer if needed */
                    466:                if( sortKeyLen > bufLeft )
                    467:                {
                    468:                        bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT;
                    469: 
                    470:                        sortKeyBufSize += bufIncrement;
                    471:                        bufLeft += bufIncrement;
                    472: 
                    473:                        sortKeyBuf = erealloc( sortKeyBuf, sortKeyBufSize );
                    474: 
                    475:                        sortKeyLen = ucol_getSortKey( co->ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft );
                    476:                }
                    477: 
                    478:                /*  check sortKeyIndxBuf overflow, increasing its size of the buffer if needed */
                    479:                if( ( sortKeyCount + 1 ) * sortKeyIndxSize > sortKeyIndxBufSize )
                    480:                {
                    481:                        bufIncrement = ( sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT ) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT;
                    482: 
                    483:                        sortKeyIndxBufSize += bufIncrement;
                    484: 
                    485:                        sortKeyIndxBuf = erealloc( sortKeyIndxBuf, sortKeyIndxBufSize );
                    486:                }
                    487: 
                    488:                sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset;    /* remeber just offset, cause address */
                    489:                                                                               /* of 'sortKeyBuf' may be changed due to realloc. */
                    490:                sortKeyIndxBuf[sortKeyCount].zstr = hashData;
                    491: 
                    492:                sortKeyBufOffset += sortKeyLen;
                    493:                ++sortKeyCount;
                    494: 
                    495:                zend_hash_move_forward( hash );
                    496:        }
                    497: 
                    498:        /* update ptrs to point to valid keys. */
                    499:        for( j = 0; j < sortKeyCount; j++ )
                    500:                sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
                    501: 
                    502:        /* sort it */
                    503:        zend_qsort( sortKeyIndxBuf, sortKeyCount, sortKeyIndxSize, collator_cmp_sort_keys TSRMLS_CC );
                    504: 
                    505:        /* for resulting hash we'll assign new hash keys rather then reordering */
                    506:        ALLOC_HASHTABLE( sortedHash );
                    507:        zend_hash_init( sortedHash, 0, NULL, ZVAL_PTR_DTOR, 0 );
                    508: 
                    509:        for( j = 0; j < sortKeyCount; j++ )
                    510:        {
                    511:                zval_add_ref( sortKeyIndxBuf[j].zstr );
                    512:                zend_hash_next_index_insert( sortedHash, sortKeyIndxBuf[j].zstr, sizeof(zval **), NULL );
                    513:        }
                    514: 
                    515:        /* Save sorted hash into return variable. */
                    516:        zval_dtor( array );
                    517:        (array)->value.ht = sortedHash;
                    518:        (array)->type = IS_ARRAY;
                    519: 
                    520:        if( utf16_buf )
                    521:                efree( utf16_buf );
                    522: 
                    523:        efree( sortKeyIndxBuf );
                    524:        efree( sortKeyBuf );
                    525: 
                    526:        RETURN_TRUE;
                    527: }
                    528: /* }}} */
                    529: 
                    530: /* {{{ proto bool Collator::asort( Collator $coll, array(string) $arr )
                    531:  * Sort array using specified collator, maintaining index association. }}} */
                    532: /* {{{ proto bool collator_asort( Collator $coll, array(string) $arr )
                    533:  * Sort array using specified collator, maintaining index association.
                    534:  */
                    535: PHP_FUNCTION( collator_asort )
                    536: {
                    537:        collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
                    538: }
                    539: /* }}} */
                    540: 
                    541: /* {{{ proto bool Collator::getSortKey( Collator $coll, string $str )
                    542:  * Get a sort key for a string from a Collator. }}} */
                    543: /* {{{ proto bool collator_get_sort_key( Collator $coll, string $str )
                    544:  * Get a sort key for a string from a Collator. }}} */
                    545: PHP_FUNCTION( collator_get_sort_key )
                    546: {
                    547:        char*            str      = NULL;
                    548:        int              str_len  = 0;
                    549:        UChar*           ustr     = NULL;
                    550:        int              ustr_len = 0;
                    551:        uint8_t*         key     = NULL;
                    552:        int              key_len = 0;
                    553: 
                    554:        COLLATOR_METHOD_INIT_VARS
                    555: 
                    556:        /* Parse parameters. */
                    557:        if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
                    558:                &object, Collator_ce_ptr, &str, &str_len ) == FAILURE )
                    559:        {
                    560:                intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
                    561:                         "collator_get_sort_key: unable to parse input params", 0 TSRMLS_CC );
                    562: 
                    563:                RETURN_FALSE;
                    564:        }
                    565: 
                    566:        /* Fetch the object. */
                    567:        COLLATOR_METHOD_FETCH_OBJECT;
                    568: 
                    569:        if (!co || !co->ucoll) {
                    570:                intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
                    571:                intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
                    572:                        "Object not initialized", 0 TSRMLS_CC );
                    573:                php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
                    574: 
                    575:                RETURN_FALSE;
                    576:        }
                    577: 
                    578:        /*
                    579:         * Compare given strings (converting them to UTF-16 first).
                    580:         */
                    581: 
                    582:        /* First convert the strings to UTF-16. */
                    583:        intl_convert_utf8_to_utf16(
                    584:                &ustr, &ustr_len, str, str_len, COLLATOR_ERROR_CODE_P( co ) );
                    585:        if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
                    586:        {
                    587:                /* Set global error code. */
                    588:                intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
                    589: 
                    590:                /* Set error messages. */
                    591:                intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
                    592:                        "Error converting first argument to UTF-16", 0 TSRMLS_CC );
                    593:                efree( ustr );
                    594:                RETURN_FALSE;
                    595:        }
                    596: 
1.1.1.2 ! misho     597:        /* ucol_getSortKey is exception in that the key length includes the 
        !           598:         * NUL terminator*/
1.1       misho     599:        key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, 0);
                    600:        if(!key_len) {
                    601:                efree( ustr );
                    602:                RETURN_FALSE;
                    603:        }
                    604:        key = emalloc(key_len);
                    605:        key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, key_len);
                    606:        efree( ustr );
                    607:        if(!key_len) {
                    608:                RETURN_FALSE;
                    609:        }
1.1.1.2 ! misho     610:        RETURN_STRINGL((char *)key, key_len - 1, 0);
1.1       misho     611: }
                    612: /* }}} */
                    613: 
                    614: /*
                    615:  * Local variables:
                    616:  * tab-width: 4
                    617:  * c-basic-offset: 4
                    618:  * End:
                    619:  * vim600: noet sw=4 ts=4 fdm=marker
                    620:  * vim<600: noet sw=4 ts=4
                    621:  */

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