Back to index

php5  5.3.10
collator_sort.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | This source file is subject to version 3.01 of the PHP license,      |
00006    | that is bundled with this package in the file LICENSE, and is        |
00007    | available through the world-wide-web at the following url:           |
00008    | http://www.php.net/license/3_01.txt                                  |
00009    | If you did not receive a copy of the PHP license and are unable to   |
00010    | obtain it through the world-wide-web, please send a note to          |
00011    | license@php.net so we can mail you a copy immediately.               |
00012    +----------------------------------------------------------------------+
00013    | Authors: Vadim Savchuk <vsavchuk@productengine.com>                  |
00014    |          Dmitry Lakhtyuk <dlakhtyuk@productengine.com>               |
00015    +----------------------------------------------------------------------+
00016  */
00017 
00018 #ifdef HAVE_CONFIG_H
00019 #include "config.h"
00020 #endif
00021 
00022 #include "php_intl.h"
00023 #include "collator.h"
00024 #include "collator_class.h"
00025 #include "collator_sort.h"
00026 #include "collator_convert.h"
00027 #include "intl_convert.h"
00028 
00029 #if !defined(HAVE_PTRDIFF_T) && !defined(_PTRDIFF_T_DEFINED)
00030 typedef long ptrdiff_t;
00031 #endif
00032 
00037 typedef struct _collator_sort_key_index {
00038        char* key;       /* pointer to sort key */
00039        zval** zstr;     /* pointer to original string(hash-item) */
00040 } collator_sort_key_index_t;
00041 
00042 ZEND_EXTERN_MODULE_GLOBALS( intl )
00043 
00044 static const size_t DEF_SORT_KEYS_BUF_SIZE = 1048576;
00045 static const size_t DEF_SORT_KEYS_BUF_INCREMENT = 1048576;
00046 
00047 static const size_t DEF_SORT_KEYS_INDX_BUF_SIZE = 1048576;
00048 static const size_t DEF_SORT_KEYS_INDX_BUF_INCREMENT = 1048576;
00049 
00050 static const size_t DEF_UTF16_BUF_SIZE = 1024;
00051 
00052 /* {{{ collator_regular_compare_function */
00053 static int collator_regular_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
00054 {
00055        Collator_object* co = NULL;
00056 
00057        int rc      = SUCCESS;
00058 
00059        zval* str1  = collator_convert_object_to_string( op1 TSRMLS_CC );
00060        zval* str2  = collator_convert_object_to_string( op2 TSRMLS_CC );
00061 
00062        zval* num1  = NULL;
00063        zval* num2  = NULL;
00064        zval* norm1 = NULL;
00065        zval* norm2 = NULL;
00066 
00067        /* If both args are strings AND either of args is not numeric string
00068         * then use ICU-compare. Otherwise PHP-compare. */
00069        if( Z_TYPE_P(str1) == IS_STRING && Z_TYPE_P(str2) == IS_STRING &&
00070               ( str1 == ( num1 = collator_convert_string_to_number_if_possible( str1 ) ) ||
00071                 str2 == ( num2 = collator_convert_string_to_number_if_possible( str2 ) ) ) )
00072        {
00073               /* Fetch collator object. */
00074               co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
00075 
00076               if (!co || !co->ucoll) {
00077                      intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
00078                      intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
00079                             "Object not initialized", 0 TSRMLS_CC );
00080                      php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
00081               }
00082 
00083               /* Compare the strings using ICU. */
00084               result->value.lval = ucol_strcoll(
00085                             co->ucoll,
00086                             INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
00087                             INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
00088               result->type = IS_LONG;
00089        }
00090        else
00091        {
00092               /* num1 is set if str1 and str2 are strings. */
00093               if( num1 )
00094               {
00095                      if( num1 == str1 )
00096                      {
00097                             /* str1 is string but not numeric string
00098                              * just convert it to utf8. 
00099                              */
00100                             norm1 = collator_convert_zstr_utf16_to_utf8( str1 );
00101 
00102                             /* num2 is not set but str2 is string => do normalization. */
00103                             norm2 = collator_normalize_sort_argument( str2 );
00104                      }
00105                      else
00106                      {
00107                             /* str1 is numeric strings => passthru to PHP-compare. */
00108                             zval_add_ref( &num1 );
00109                             norm1 = num1;
00110 
00111                             /* str2 is numeric strings => passthru to PHP-compare. */
00112                             zval_add_ref( &num2 );
00113                             norm2 = num2;
00114                      }
00115               }
00116               else
00117               {
00118                      /* num1 is not set if str1 or str2 is not a string => do normalization. */
00119                      norm1 = collator_normalize_sort_argument( str1 );
00120 
00121                      /* if num1 is not set then num2 is not set as well => do normalization. */
00122                      norm2 = collator_normalize_sort_argument( str2 );
00123               }
00124 
00125               rc = compare_function( result, norm1, norm2 TSRMLS_CC );
00126 
00127               zval_ptr_dtor( &norm1 );
00128               zval_ptr_dtor( &norm2 );
00129        }
00130 
00131        if( num1 )
00132               zval_ptr_dtor( &num1 );
00133 
00134        if( num2 )
00135               zval_ptr_dtor( &num2 );
00136 
00137        zval_ptr_dtor( &str1 );
00138        zval_ptr_dtor( &str2 );
00139 
00140        return rc;
00141 }
00142 /* }}} */
00143 
00144 /* {{{ collator_numeric_compare_function
00145  * Convert input args to double and compare it.
00146  */
00147 static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
00148 {
00149        int rc     = SUCCESS;
00150        zval* num1 = NULL;
00151        zval* num2 = NULL;
00152 
00153        if( Z_TYPE_P(op1) == IS_STRING )
00154        {
00155               num1 = collator_convert_string_to_double( op1 );
00156               op1 = num1;
00157        }
00158 
00159        if( Z_TYPE_P(op2) == IS_STRING )
00160        {
00161               num2 = collator_convert_string_to_double( op2 );
00162               op2 = num2;
00163        }
00164 
00165        rc = numeric_compare_function( result, op1, op2 TSRMLS_CC);
00166 
00167        if( num1 )
00168               zval_ptr_dtor( &num1 );
00169        if( num2 )
00170               zval_ptr_dtor( &num2 );
00171 
00172        return rc;
00173 }
00174 /* }}} */
00175 
00176 /* {{{ collator_icu_compare_function
00177  * Direct use of ucol_strcoll.
00178 */
00179 static int collator_icu_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
00180 {
00181        int rc              = SUCCESS;
00182        Collator_object* co = NULL;
00183        zval* str1          = NULL;
00184        zval* str2          = NULL;
00185 
00186        str1 = collator_make_printable_zval( op1 );
00187        str2 = collator_make_printable_zval( op2 );
00188 
00189        /* Fetch collator object. */
00190        co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
00191 
00192        /* Compare the strings using ICU. */
00193        result->value.lval = ucol_strcoll(
00194                      co->ucoll,
00195                      INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
00196                      INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
00197        result->type = IS_LONG;
00198 
00199        zval_ptr_dtor( &str1 );
00200        zval_ptr_dtor( &str2 );
00201 
00202        return rc;
00203 }
00204 /* }}} */
00205 
00206 /* {{{ collator_compare_func
00207  * Taken from PHP5 source (array_data_compare).
00208  */
00209 static int collator_compare_func( const void* a, const void* b TSRMLS_DC )
00210 {
00211        Bucket *f;
00212        Bucket *s;
00213        zval result;
00214        zval *first;
00215        zval *second;
00216 
00217        f = *((Bucket **) a);
00218        s = *((Bucket **) b);
00219 
00220        first = *((zval **) f->pData);
00221        second = *((zval **) s->pData);
00222 
00223        if( INTL_G(compare_func)( &result, first, second TSRMLS_CC) == FAILURE )
00224               return 0;
00225 
00226        if( Z_TYPE(result) == IS_DOUBLE )
00227        {
00228               if( Z_DVAL(result) < 0 )
00229                      return -1;
00230               else if( Z_DVAL(result) > 0 )
00231                      return 1;
00232               else
00233                      return 0;
00234        }
00235 
00236        convert_to_long(&result);
00237 
00238        if( Z_LVAL(result) < 0 )
00239               return -1;
00240        else if( Z_LVAL(result) > 0 )
00241               return 1;
00242 
00243        return 0;
00244 }
00245 /* }}} */
00246 
00247 /* {{{ collator_cmp_sort_keys
00248  * Compare sort keys
00249  */
00250 static int collator_cmp_sort_keys( const void *p1, const void *p2 TSRMLS_DC )
00251 {
00252        char* key1 = ((collator_sort_key_index_t*)p1)->key;
00253        char* key2 = ((collator_sort_key_index_t*)p2)->key;
00254 
00255        return strcmp( key1, key2 );
00256 }
00257 /* }}} */
00258 
00259 /* {{{ collator_get_compare_function
00260  * Choose compare function according to sort flags.
00261  */
00262 static collator_compare_func_t collator_get_compare_function( const long sort_flags )
00263 {
00264        collator_compare_func_t func;
00265 
00266        switch( sort_flags )
00267        {
00268               case COLLATOR_SORT_NUMERIC:
00269                      func = collator_numeric_compare_function;
00270                      break;
00271 
00272               case COLLATOR_SORT_STRING:
00273                      func = collator_icu_compare_function;
00274                      break;
00275 
00276               case COLLATOR_SORT_REGULAR:
00277               default:
00278                      func = collator_regular_compare_function;
00279                      break;
00280        }
00281 
00282        return func;
00283 }
00284 /* }}} */
00285 
00286 /* {{{ collator_sort_internal
00287  * Common code shared by collator_sort() and collator_asort() API functions.
00288  */
00289 static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
00290 {
00291        zval*          array            = NULL;
00292        HashTable*     hash             = NULL;
00293        zval*          saved_collator   = NULL;
00294        long           sort_flags       = COLLATOR_SORT_REGULAR;
00295 
00296        COLLATOR_METHOD_INIT_VARS
00297 
00298        /* Parse parameters. */
00299        if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa|l",
00300               &object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
00301        {
00302               intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
00303                      "collator_sort_internal: unable to parse input params", 0 TSRMLS_CC );
00304 
00305               RETURN_FALSE;
00306        }
00307 
00308        /* Fetch the object. */
00309        COLLATOR_METHOD_FETCH_OBJECT;
00310 
00311        /* Set 'compare function' according to sort flags. */
00312        INTL_G(compare_func) = collator_get_compare_function( sort_flags );
00313 
00314        hash = HASH_OF( array );
00315 
00316        /* Convert strings in the specified array from UTF-8 to UTF-16. */
00317        collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
00318        COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
00319 
00320        /* Save specified collator in the request-global (?) variable. */
00321        saved_collator = INTL_G( current_collator );
00322        INTL_G( current_collator ) = object;
00323 
00324        /* Sort specified array. */
00325        zend_hash_sort( hash, zend_qsort, collator_compare_func, renumber TSRMLS_CC );
00326 
00327        /* Restore saved collator. */
00328        INTL_G( current_collator ) = saved_collator;
00329 
00330        /* Convert strings in the specified array back to UTF-8. */
00331        collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
00332        COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
00333 
00334        RETURN_TRUE;
00335 }
00336 /* }}} */
00337 
00338 /* {{{ proto bool Collator::sort( Collator $coll, array(string) $arr [, int $sort_flags] )
00339  * Sort array using specified collator. }}} */
00340 /* {{{ proto bool collator_sort(  Collator $coll, array(string) $arr [, int $sort_flags] )
00341  * Sort array using specified collator.
00342  */
00343 PHP_FUNCTION( collator_sort )
00344 {
00345        collator_sort_internal( TRUE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
00346 }
00347 /* }}} */
00348 
00349 /* {{{ proto bool Collator::sortWithSortKeys( Collator $coll, array(string) $arr )
00350  * Equivalent to standard PHP sort using Collator.
00351  * Uses ICU ucol_getSortKey for performance. }}} */
00352 /* {{{ proto bool collator_sort_with_sort_keys( Collator $coll, array(string) $arr )
00353  * Equivalent to standard PHP sort using Collator.
00354  * Uses ICU ucol_getSortKey for performance.
00355  */
00356 PHP_FUNCTION( collator_sort_with_sort_keys )
00357 {
00358        zval*       array                = NULL;
00359        HashTable*  hash                 = NULL;
00360        zval**      hashData             = NULL;                     /* currently processed item of input hash */
00361 
00362        char*       sortKeyBuf           = NULL;                     /* buffer to store sort keys */
00363        uint32_t    sortKeyBufSize       = DEF_SORT_KEYS_BUF_SIZE;   /* buffer size */
00364        ptrdiff_t   sortKeyBufOffset     = 0;                        /* pos in buffer to store sort key */
00365        int32_t     sortKeyLen           = 0;                        /* the length of currently processing key */
00366        uint32_t    bufLeft              = 0;
00367        uint32_t    bufIncrement         = 0;
00368 
00369        collator_sort_key_index_t* sortKeyIndxBuf = NULL;            /* buffer to store 'indexes' which will be passed to 'qsort' */
00370        uint32_t    sortKeyIndxBufSize   = DEF_SORT_KEYS_INDX_BUF_SIZE;
00371        uint32_t    sortKeyIndxSize      = sizeof( collator_sort_key_index_t );
00372 
00373        uint32_t    sortKeyCount         = 0;
00374        uint32_t    j                    = 0;
00375 
00376        UChar*      utf16_buf            = NULL;                     /* tmp buffer to hold current processing string in utf-16 */
00377        int         utf16_buf_size       = DEF_UTF16_BUF_SIZE;       /* the length of utf16_buf */
00378        int         utf16_len            = 0;                        /* length of converted string */
00379 
00380        HashTable* sortedHash            = NULL;
00381 
00382        COLLATOR_METHOD_INIT_VARS
00383 
00384        /* Parse parameters. */
00385        if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
00386               &object, Collator_ce_ptr, &array ) == FAILURE )
00387        {
00388               intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
00389                      "collator_sort_with_sort_keys: unable to parse input params", 0 TSRMLS_CC );
00390 
00391               RETURN_FALSE;
00392        }
00393 
00394        /* Fetch the object. */
00395        COLLATOR_METHOD_FETCH_OBJECT;
00396 
00397        if (!co || !co->ucoll) {
00398               intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
00399               intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
00400                      "Object not initialized", 0 TSRMLS_CC );
00401               php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
00402 
00403               RETURN_FALSE;
00404        }
00405 
00406        /*
00407         * Sort specified array.
00408         */
00409        hash = HASH_OF( array );
00410 
00411        if( !hash || zend_hash_num_elements( hash ) == 0 )
00412               RETURN_TRUE;
00413 
00414        /* Create bufers */
00415        sortKeyBuf     = ecalloc( sortKeyBufSize,     sizeof( char    ) );
00416        sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
00417        utf16_buf      = eumalloc( utf16_buf_size );
00418 
00419        /* Iterate through input hash and create a sort key for each value. */
00420        zend_hash_internal_pointer_reset( hash );
00421        while( zend_hash_get_current_data( hash, (void**) &hashData ) == SUCCESS )
00422        {
00423               /* Convert current hash item from UTF-8 to UTF-16LE and save the result to utf16_buf. */
00424 
00425               utf16_len = utf16_buf_size;
00426 
00427               /* Process string values only. */
00428               if( Z_TYPE_PP( hashData ) == IS_STRING )
00429               {
00430                      intl_convert_utf8_to_utf16( &utf16_buf, &utf16_len, Z_STRVAL_PP( hashData ), Z_STRLEN_PP( hashData ), COLLATOR_ERROR_CODE_P( co ) );
00431 
00432                      if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
00433                      {
00434                             intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
00435                             intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Sort with sort keys failed", 0 TSRMLS_CC );
00436 
00437                             if( utf16_buf )
00438                                    efree( utf16_buf );
00439 
00440                             efree( sortKeyIndxBuf );
00441                             efree( sortKeyBuf );
00442 
00443                             RETURN_FALSE;
00444                      }
00445               }
00446               else
00447               {
00448                      /* Set empty string */
00449                      utf16_len = 0;
00450                      utf16_buf[utf16_len] = 0;
00451               }
00452 
00453               if( (utf16_len + 1) > utf16_buf_size )
00454                      utf16_buf_size = utf16_len + 1;
00455 
00456               /* Get sort key, reallocating the buffer if needed. */
00457               bufLeft = sortKeyBufSize - sortKeyBufOffset;
00458 
00459               sortKeyLen = ucol_getSortKey( co->ucoll,
00460                                                                  utf16_buf,
00461                                                                  utf16_len,
00462                                                                  (uint8_t*)sortKeyBuf + sortKeyBufOffset,
00463                                                                  bufLeft );
00464 
00465               /* check for sortKeyBuf overflow, increasing its size of the buffer if needed */
00466               if( sortKeyLen > bufLeft )
00467               {
00468                      bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT;
00469 
00470                      sortKeyBufSize += bufIncrement;
00471                      bufLeft += bufIncrement;
00472 
00473                      sortKeyBuf = erealloc( sortKeyBuf, sortKeyBufSize );
00474 
00475                      sortKeyLen = ucol_getSortKey( co->ucoll, utf16_buf, utf16_len, (uint8_t*)sortKeyBuf + sortKeyBufOffset, bufLeft );
00476               }
00477 
00478               /*  check sortKeyIndxBuf overflow, increasing its size of the buffer if needed */
00479               if( ( sortKeyCount + 1 ) * sortKeyIndxSize > sortKeyIndxBufSize )
00480               {
00481                      bufIncrement = ( sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT ) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT;
00482 
00483                      sortKeyIndxBufSize += bufIncrement;
00484 
00485                      sortKeyIndxBuf = erealloc( sortKeyIndxBuf, sortKeyIndxBufSize );
00486               }
00487 
00488               sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset;    /* remeber just offset, cause address */
00489                                                                              /* of 'sortKeyBuf' may be changed due to realloc. */
00490               sortKeyIndxBuf[sortKeyCount].zstr = hashData;
00491 
00492               sortKeyBufOffset += sortKeyLen;
00493               ++sortKeyCount;
00494 
00495               zend_hash_move_forward( hash );
00496        }
00497 
00498        /* update ptrs to point to valid keys. */
00499        for( j = 0; j < sortKeyCount; j++ )
00500               sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
00501 
00502        /* sort it */
00503        zend_qsort( sortKeyIndxBuf, sortKeyCount, sortKeyIndxSize, collator_cmp_sort_keys TSRMLS_CC );
00504 
00505        /* for resulting hash we'll assign new hash keys rather then reordering */
00506        ALLOC_HASHTABLE( sortedHash );
00507        zend_hash_init( sortedHash, 0, NULL, ZVAL_PTR_DTOR, 0 );
00508 
00509        for( j = 0; j < sortKeyCount; j++ )
00510        {
00511               zval_add_ref( sortKeyIndxBuf[j].zstr );
00512               zend_hash_next_index_insert( sortedHash, sortKeyIndxBuf[j].zstr, sizeof(zval **), NULL );
00513        }
00514 
00515        /* Save sorted hash into return variable. */
00516        zval_dtor( array );
00517        (array)->value.ht = sortedHash;
00518        (array)->type = IS_ARRAY;
00519 
00520        if( utf16_buf )
00521               efree( utf16_buf );
00522 
00523        efree( sortKeyIndxBuf );
00524        efree( sortKeyBuf );
00525 
00526        RETURN_TRUE;
00527 }
00528 /* }}} */
00529 
00530 /* {{{ proto bool Collator::asort( Collator $coll, array(string) $arr )
00531  * Sort array using specified collator, maintaining index association. }}} */
00532 /* {{{ proto bool collator_asort( Collator $coll, array(string) $arr )
00533  * Sort array using specified collator, maintaining index association.
00534  */
00535 PHP_FUNCTION( collator_asort )
00536 {
00537        collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
00538 }
00539 /* }}} */
00540 
00541 /* {{{ proto bool Collator::getSortKey( Collator $coll, string $str )
00542  * Get a sort key for a string from a Collator. }}} */
00543 /* {{{ proto bool collator_get_sort_key( Collator $coll, string $str )
00544  * Get a sort key for a string from a Collator. }}} */
00545 PHP_FUNCTION( collator_get_sort_key )
00546 {
00547        char*            str      = NULL;
00548        int              str_len  = 0;
00549        UChar*           ustr     = NULL;
00550        int              ustr_len = 0;
00551        uint8_t*         key     = NULL;
00552        int              key_len = 0;
00553 
00554        COLLATOR_METHOD_INIT_VARS
00555 
00556        /* Parse parameters. */
00557        if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
00558               &object, Collator_ce_ptr, &str, &str_len ) == FAILURE )
00559        {
00560               intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
00561                       "collator_get_sort_key: unable to parse input params", 0 TSRMLS_CC );
00562 
00563               RETURN_FALSE;
00564        }
00565 
00566        /* Fetch the object. */
00567        COLLATOR_METHOD_FETCH_OBJECT;
00568 
00569        if (!co || !co->ucoll) {
00570               intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
00571               intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
00572                      "Object not initialized", 0 TSRMLS_CC );
00573               php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
00574 
00575               RETURN_FALSE;
00576        }
00577 
00578        /*
00579         * Compare given strings (converting them to UTF-16 first).
00580         */
00581 
00582        /* First convert the strings to UTF-16. */
00583        intl_convert_utf8_to_utf16(
00584               &ustr, &ustr_len, str, str_len, COLLATOR_ERROR_CODE_P( co ) );
00585        if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
00586        {
00587               /* Set global error code. */
00588               intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
00589 
00590               /* Set error messages. */
00591               intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
00592                      "Error converting first argument to UTF-16", 0 TSRMLS_CC );
00593               efree( ustr );
00594               RETURN_FALSE;
00595        }
00596 
00597        key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, 0);
00598        if(!key_len) {
00599               efree( ustr );
00600               RETURN_FALSE;
00601        }
00602        key = emalloc(key_len);
00603        key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, key_len);
00604        efree( ustr );
00605        if(!key_len) {
00606               RETURN_FALSE;
00607        }
00608        RETURN_STRINGL((char *)key, key_len, 0);
00609 }
00610 /* }}} */
00611 
00612 /*
00613  * Local variables:
00614  * tab-width: 4
00615  * c-basic-offset: 4
00616  * End:
00617  * vim600: noet sw=4 ts=4 fdm=marker
00618  * vim<600: noet sw=4 ts=4
00619  */