PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/intl/collator - collator_sort.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 189 250 75.6 %
Date: 2014-07-27 Functions: 10 11 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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         197 : static int collator_regular_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
      54             : {
      55         197 :         Collator_object* co = NULL;
      56             : 
      57         197 :         int rc      = SUCCESS;
      58             : 
      59         197 :         zval* str1  = collator_convert_object_to_string( op1 TSRMLS_CC );
      60         197 :         zval* str2  = collator_convert_object_to_string( op2 TSRMLS_CC );
      61             : 
      62         197 :         zval* num1  = NULL;
      63         197 :         zval* num2  = NULL;
      64         197 :         zval* norm1 = NULL;
      65         197 :         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         745 :         if( Z_TYPE_P(str1) == IS_STRING && Z_TYPE_P(str2) == IS_STRING &&
      70         350 :                 ( str1 == ( num1 = collator_convert_string_to_number_if_possible( str1 ) ) ||
      71          40 :                   str2 == ( num2 = collator_convert_string_to_number_if_possible( str2 ) ) ) )
      72             :         {
      73             :                 /* Fetch collator object. */
      74         159 :                 co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
      75             : 
      76         159 :                 if (!co || !co->ucoll) {
      77           1 :                         intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
      78           1 :                         intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
      79             :                                 "Object not initialized", 0 TSRMLS_CC );
      80           1 :                         php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
      81             :                 }
      82             : 
      83             :                 /* Compare the strings using ICU. */
      84         790 :                 result->value.lval = ucol_strcoll(
      85         158 :                                 co->ucoll,
      86         316 :                                 INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
      87         316 :                                 INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
      88         158 :                 result->type = IS_LONG;
      89             :         }
      90             :         else
      91             :         {
      92             :                 /* num1 is set if str1 and str2 are strings. */
      93          38 :                 if( num1 )
      94             :                 {
      95          16 :                         if( num1 == str1 )
      96             :                         {
      97             :                                 /* str1 is string but not numeric string
      98             :                                  * just convert it to utf8. 
      99             :                                  */
     100           0 :                                 norm1 = collator_convert_zstr_utf16_to_utf8( str1 );
     101             : 
     102             :                                 /* num2 is not set but str2 is string => do normalization. */
     103           0 :                                 norm2 = collator_normalize_sort_argument( str2 );
     104             :                         }
     105             :                         else
     106             :                         {
     107             :                                 /* str1 is numeric strings => passthru to PHP-compare. */
     108          16 :                                 zval_add_ref( &num1 );
     109          16 :                                 norm1 = num1;
     110             : 
     111             :                                 /* str2 is numeric strings => passthru to PHP-compare. */
     112          16 :                                 zval_add_ref( &num2 );
     113          16 :                                 norm2 = num2;
     114             :                         }
     115             :                 }
     116             :                 else
     117             :                 {
     118             :                         /* num1 is not set if str1 or str2 is not a string => do normalization. */
     119          22 :                         norm1 = collator_normalize_sort_argument( str1 );
     120             : 
     121             :                         /* if num1 is not set then num2 is not set as well => do normalization. */
     122          22 :                         norm2 = collator_normalize_sort_argument( str2 );
     123             :                 }
     124             : 
     125          38 :                 rc = compare_function( result, norm1, norm2 TSRMLS_CC );
     126             : 
     127          38 :                 zval_ptr_dtor( &norm1 );
     128          38 :                 zval_ptr_dtor( &norm2 );
     129             :         }
     130             : 
     131         196 :         if( num1 )
     132         174 :                 zval_ptr_dtor( &num1 );
     133             : 
     134         196 :         if( num2 )
     135          20 :                 zval_ptr_dtor( &num2 );
     136             : 
     137         196 :         zval_ptr_dtor( &str1 );
     138         196 :         zval_ptr_dtor( &str2 );
     139             : 
     140         196 :         return rc;
     141             : }
     142             : /* }}} */
     143             : 
     144             : /* {{{ collator_numeric_compare_function
     145             :  * Convert input args to double and compare it.
     146             :  */
     147           0 : static int collator_numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
     148             : {
     149           0 :         int rc     = SUCCESS;
     150           0 :         zval* num1 = NULL;
     151           0 :         zval* num2 = NULL;
     152             : 
     153           0 :         if( Z_TYPE_P(op1) == IS_STRING )
     154             :         {
     155           0 :                 num1 = collator_convert_string_to_double( op1 );
     156           0 :                 op1 = num1;
     157             :         }
     158             : 
     159           0 :         if( Z_TYPE_P(op2) == IS_STRING )
     160             :         {
     161           0 :                 num2 = collator_convert_string_to_double( op2 );
     162           0 :                 op2 = num2;
     163             :         }
     164             : 
     165           0 :         rc = numeric_compare_function( result, op1, op2 TSRMLS_CC);
     166             : 
     167           0 :         if( num1 )
     168           0 :                 zval_ptr_dtor( &num1 );
     169           0 :         if( num2 )
     170           0 :                 zval_ptr_dtor( &num2 );
     171             : 
     172           0 :         return rc;
     173             : }
     174             : /* }}} */
     175             : 
     176             : /* {{{ collator_icu_compare_function
     177             :  * Direct use of ucol_strcoll.
     178             : */
     179          40 : static int collator_icu_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
     180             : {
     181          40 :         int rc              = SUCCESS;
     182          40 :         Collator_object* co = NULL;
     183          40 :         zval* str1          = NULL;
     184          40 :         zval* str2          = NULL;
     185             : 
     186          40 :         str1 = collator_make_printable_zval( op1 );
     187          40 :         str2 = collator_make_printable_zval( op2 );
     188             : 
     189             :         /* Fetch collator object. */
     190          40 :         co = (Collator_object *) zend_object_store_get_object( INTL_G(current_collator) TSRMLS_CC );
     191             : 
     192             :         /* Compare the strings using ICU. */
     193         200 :         result->value.lval = ucol_strcoll(
     194          40 :                         co->ucoll,
     195          80 :                         INTL_Z_STRVAL_P(str1), INTL_Z_STRLEN_P(str1),
     196          80 :                         INTL_Z_STRVAL_P(str2), INTL_Z_STRLEN_P(str2) );
     197          40 :         result->type = IS_LONG;
     198             : 
     199          40 :         zval_ptr_dtor( &str1 );
     200          40 :         zval_ptr_dtor( &str2 );
     201             : 
     202          40 :         return rc;
     203             : }
     204             : /* }}} */
     205             : 
     206             : /* {{{ collator_compare_func
     207             :  * Taken from PHP5 source (array_data_compare).
     208             :  */
     209         237 : 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         237 :         f = *((Bucket **) a);
     218         237 :         s = *((Bucket **) b);
     219             : 
     220         237 :         first = *((zval **) f->pData);
     221         237 :         second = *((zval **) s->pData);
     222             : 
     223         237 :         if( INTL_G(compare_func)( &result, first, second TSRMLS_CC) == FAILURE )
     224           0 :                 return 0;
     225             : 
     226         236 :         if( Z_TYPE(result) == IS_DOUBLE )
     227             :         {
     228           0 :                 if( Z_DVAL(result) < 0 )
     229           0 :                         return -1;
     230           0 :                 else if( Z_DVAL(result) > 0 )
     231           0 :                         return 1;
     232             :                 else
     233           0 :                         return 0;
     234             :         }
     235             : 
     236         236 :         convert_to_long(&result);
     237             : 
     238         236 :         if( Z_LVAL(result) < 0 )
     239         120 :                 return -1;
     240         116 :         else if( Z_LVAL(result) > 0 )
     241         110 :                 return 1;
     242             : 
     243           6 :         return 0;
     244             : }
     245             : /* }}} */
     246             : 
     247             : /* {{{ collator_cmp_sort_keys
     248             :  * Compare sort keys
     249             :  */
     250         120 : static int collator_cmp_sort_keys( const void *p1, const void *p2 TSRMLS_DC )
     251             : {
     252         120 :         char* key1 = ((collator_sort_key_index_t*)p1)->key;
     253         120 :         char* key2 = ((collator_sort_key_index_t*)p2)->key;
     254             : 
     255         120 :         return strcmp( key1, key2 );
     256             : }
     257             : /* }}} */
     258             : 
     259             : /* {{{ collator_get_compare_function
     260             :  * Choose compare function according to sort flags.
     261             :  */
     262          75 : static collator_compare_func_t collator_get_compare_function( const long sort_flags )
     263             : {
     264             :         collator_compare_func_t func;
     265             : 
     266          75 :         switch( sort_flags )
     267             :         {
     268             :                 case COLLATOR_SORT_NUMERIC:
     269           0 :                         func = collator_numeric_compare_function;
     270           0 :                         break;
     271             : 
     272             :                 case COLLATOR_SORT_STRING:
     273          16 :                         func = collator_icu_compare_function;
     274          16 :                         break;
     275             : 
     276             :                 case COLLATOR_SORT_REGULAR:
     277             :                 default:
     278          59 :                         func = collator_regular_compare_function;
     279             :                         break;
     280             :         }
     281             : 
     282          75 :         return func;
     283             : }
     284             : /* }}} */
     285             : 
     286             : /* {{{ collator_sort_internal
     287             :  * Common code shared by collator_sort() and collator_asort() API functions.
     288             :  */
     289          77 : static void collator_sort_internal( int renumber, INTERNAL_FUNCTION_PARAMETERS )
     290             : {
     291          77 :         zval*          array            = NULL;
     292          77 :         HashTable*     hash             = NULL;
     293          77 :         zval*          saved_collator   = NULL;
     294          77 :         long           sort_flags       = COLLATOR_SORT_REGULAR;
     295             : 
     296          77 :         COLLATOR_METHOD_INIT_VARS
     297             : 
     298             :         /* Parse parameters. */
     299          77 :         if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa|l",
     300             :                 &object, Collator_ce_ptr, &array, &sort_flags ) == FAILURE )
     301             :         {
     302           2 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     303             :                         "collator_sort_internal: unable to parse input params", 0 TSRMLS_CC );
     304             : 
     305           2 :                 RETURN_FALSE;
     306             :         }
     307             : 
     308             :         /* Fetch the object. */
     309          75 :         COLLATOR_METHOD_FETCH_OBJECT;
     310             : 
     311             :         /* Set 'compare function' according to sort flags. */
     312          75 :         INTL_G(compare_func) = collator_get_compare_function( sort_flags );
     313             : 
     314          75 :         hash = HASH_OF( array );
     315             : 
     316             :         /* Convert strings in the specified array from UTF-8 to UTF-16. */
     317          75 :         collator_convert_hash_from_utf8_to_utf16( hash, COLLATOR_ERROR_CODE_P( co ) );
     318          75 :         COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-8 to UTF-16" );
     319             : 
     320             :         /* Save specified collator in the request-global (?) variable. */
     321          75 :         saved_collator = INTL_G( current_collator );
     322          75 :         INTL_G( current_collator ) = object;
     323             : 
     324             :         /* Sort specified array. */
     325          75 :         zend_hash_sort( hash, zend_qsort, collator_compare_func, renumber TSRMLS_CC );
     326             : 
     327             :         /* Restore saved collator. */
     328          74 :         INTL_G( current_collator ) = saved_collator;
     329             : 
     330             :         /* Convert strings in the specified array back to UTF-8. */
     331          74 :         collator_convert_hash_from_utf16_to_utf8( hash, COLLATOR_ERROR_CODE_P( co ) );
     332          74 :         COLLATOR_CHECK_STATUS( co, "Error converting hash from UTF-16 to UTF-8" );
     333             : 
     334          74 :         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          50 : PHP_FUNCTION( collator_sort )
     344             : {
     345          50 :         collator_sort_internal( TRUE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
     346          49 : }
     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          38 : PHP_FUNCTION( collator_sort_with_sort_keys )
     357             : {
     358          38 :         zval*       array                = NULL;
     359          38 :         HashTable*  hash                 = NULL;
     360          38 :         zval**      hashData             = NULL;                     /* currently processed item of input hash */
     361             : 
     362          38 :         char*       sortKeyBuf           = NULL;                     /* buffer to store sort keys */
     363          38 :         uint32_t    sortKeyBufSize       = DEF_SORT_KEYS_BUF_SIZE;   /* buffer size */
     364          38 :         ptrdiff_t   sortKeyBufOffset     = 0;                        /* pos in buffer to store sort key */
     365          38 :         int32_t     sortKeyLen           = 0;                        /* the length of currently processing key */
     366          38 :         uint32_t    bufLeft              = 0;
     367          38 :         uint32_t    bufIncrement         = 0;
     368             : 
     369          38 :         collator_sort_key_index_t* sortKeyIndxBuf = NULL;            /* buffer to store 'indexes' which will be passed to 'qsort' */
     370          38 :         uint32_t    sortKeyIndxBufSize   = DEF_SORT_KEYS_INDX_BUF_SIZE;
     371          38 :         uint32_t    sortKeyIndxSize      = sizeof( collator_sort_key_index_t );
     372             : 
     373          38 :         uint32_t    sortKeyCount         = 0;
     374          38 :         uint32_t    j                    = 0;
     375             : 
     376          38 :         UChar*      utf16_buf            = NULL;                     /* tmp buffer to hold current processing string in utf-16 */
     377          38 :         int         utf16_buf_size       = DEF_UTF16_BUF_SIZE;       /* the length of utf16_buf */
     378          38 :         int         utf16_len            = 0;                        /* length of converted string */
     379             : 
     380          38 :         HashTable* sortedHash            = NULL;
     381             : 
     382          38 :         COLLATOR_METHOD_INIT_VARS
     383             : 
     384             :         /* Parse parameters. */
     385          38 :         if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oa",
     386             :                 &object, Collator_ce_ptr, &array ) == FAILURE )
     387             :         {
     388           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     389             :                         "collator_sort_with_sort_keys: unable to parse input params", 0 TSRMLS_CC );
     390             : 
     391           1 :                 RETURN_FALSE;
     392             :         }
     393             : 
     394             :         /* Fetch the object. */
     395          37 :         COLLATOR_METHOD_FETCH_OBJECT;
     396             : 
     397          37 :         if (!co || !co->ucoll) {
     398           1 :                 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
     399           1 :                 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
     400             :                         "Object not initialized", 0 TSRMLS_CC );
     401           1 :                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
     402             : 
     403           0 :                 RETURN_FALSE;
     404             :         }
     405             : 
     406             :         /*
     407             :          * Sort specified array.
     408             :          */
     409          36 :         hash = HASH_OF( array );
     410             : 
     411          36 :         if( !hash || zend_hash_num_elements( hash ) == 0 )
     412           0 :                 RETURN_TRUE;
     413             : 
     414             :         /* Create bufers */
     415          36 :         sortKeyBuf     = ecalloc( sortKeyBufSize,     sizeof( char    ) );
     416          36 :         sortKeyIndxBuf = ecalloc( sortKeyIndxBufSize, sizeof( uint8_t ) );
     417          36 :         utf16_buf      = eumalloc( utf16_buf_size );
     418             : 
     419             :         /* Iterate through input hash and create a sort key for each value. */
     420          36 :         zend_hash_internal_pointer_reset( hash );
     421         182 :         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         110 :                 utf16_len = utf16_buf_size;
     426             : 
     427             :                 /* Process string values only. */
     428         110 :                 if( Z_TYPE_PP( hashData ) == IS_STRING )
     429             :                 {
     430         108 :                         intl_convert_utf8_to_utf16( &utf16_buf, &utf16_len, Z_STRVAL_PP( hashData ), Z_STRLEN_PP( hashData ), COLLATOR_ERROR_CODE_P( co ) );
     431             : 
     432         108 :                         if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
     433             :                         {
     434           0 :                                 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
     435           0 :                                 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ), "Sort with sort keys failed", 0 TSRMLS_CC );
     436             : 
     437           0 :                                 if( utf16_buf )
     438           0 :                                         efree( utf16_buf );
     439             : 
     440           0 :                                 efree( sortKeyIndxBuf );
     441           0 :                                 efree( sortKeyBuf );
     442             : 
     443           0 :                                 RETURN_FALSE;
     444             :                         }
     445             :                 }
     446             :                 else
     447             :                 {
     448             :                         /* Set empty string */
     449           2 :                         utf16_len = 0;
     450           2 :                         utf16_buf[utf16_len] = 0;
     451             :                 }
     452             : 
     453         110 :                 if( (utf16_len + 1) > utf16_buf_size )
     454           0 :                         utf16_buf_size = utf16_len + 1;
     455             : 
     456             :                 /* Get sort key, reallocating the buffer if needed. */
     457         110 :                 bufLeft = sortKeyBufSize - sortKeyBufOffset;
     458             : 
     459         110 :                 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         110 :                 if( sortKeyLen > bufLeft )
     467             :                 {
     468           0 :                         bufIncrement = ( sortKeyLen > DEF_SORT_KEYS_BUF_INCREMENT ) ? sortKeyLen : DEF_SORT_KEYS_BUF_INCREMENT;
     469             : 
     470           0 :                         sortKeyBufSize += bufIncrement;
     471           0 :                         bufLeft += bufIncrement;
     472             : 
     473           0 :                         sortKeyBuf = erealloc( sortKeyBuf, sortKeyBufSize );
     474             : 
     475           0 :                         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         110 :                 if( ( sortKeyCount + 1 ) * sortKeyIndxSize > sortKeyIndxBufSize )
     480             :                 {
     481           0 :                         bufIncrement = ( sortKeyIndxSize > DEF_SORT_KEYS_INDX_BUF_INCREMENT ) ? sortKeyIndxSize : DEF_SORT_KEYS_INDX_BUF_INCREMENT;
     482             : 
     483           0 :                         sortKeyIndxBufSize += bufIncrement;
     484             : 
     485           0 :                         sortKeyIndxBuf = erealloc( sortKeyIndxBuf, sortKeyIndxBufSize );
     486             :                 }
     487             : 
     488         110 :                 sortKeyIndxBuf[sortKeyCount].key = (char*)sortKeyBufOffset;    /* remeber just offset, cause address */
     489             :                                                                                /* of 'sortKeyBuf' may be changed due to realloc. */
     490         110 :                 sortKeyIndxBuf[sortKeyCount].zstr = hashData;
     491             : 
     492         110 :                 sortKeyBufOffset += sortKeyLen;
     493         110 :                 ++sortKeyCount;
     494             : 
     495         110 :                 zend_hash_move_forward( hash );
     496             :         }
     497             : 
     498             :         /* update ptrs to point to valid keys. */
     499         146 :         for( j = 0; j < sortKeyCount; j++ )
     500         110 :                 sortKeyIndxBuf[j].key = sortKeyBuf + (ptrdiff_t)sortKeyIndxBuf[j].key;
     501             : 
     502             :         /* sort it */
     503          36 :         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          36 :         ALLOC_HASHTABLE( sortedHash );
     507          36 :         zend_hash_init( sortedHash, 0, NULL, ZVAL_PTR_DTOR, 0 );
     508             : 
     509         146 :         for( j = 0; j < sortKeyCount; j++ )
     510             :         {
     511         110 :                 zval_add_ref( sortKeyIndxBuf[j].zstr );
     512         110 :                 zend_hash_next_index_insert( sortedHash, sortKeyIndxBuf[j].zstr, sizeof(zval **), NULL );
     513             :         }
     514             : 
     515             :         /* Save sorted hash into return variable. */
     516          36 :         zval_dtor( array );
     517          36 :         (array)->value.ht = sortedHash;
     518          36 :         (array)->type = IS_ARRAY;
     519             : 
     520          36 :         if( utf16_buf )
     521          36 :                 efree( utf16_buf );
     522             : 
     523          36 :         efree( sortKeyIndxBuf );
     524          36 :         efree( sortKeyBuf );
     525             : 
     526          36 :         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          27 : PHP_FUNCTION( collator_asort )
     536             : {
     537          27 :         collator_sort_internal( FALSE, INTERNAL_FUNCTION_PARAM_PASSTHRU );
     538          27 : }
     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           2 : PHP_FUNCTION( collator_get_sort_key )
     546             : {
     547           2 :         char*            str      = NULL;
     548           2 :         int              str_len  = 0;
     549           2 :         UChar*           ustr     = NULL;
     550           2 :         int              ustr_len = 0;
     551           2 :         uint8_t*         key     = NULL;
     552           2 :         int              key_len = 0;
     553             : 
     554           2 :         COLLATOR_METHOD_INIT_VARS
     555             : 
     556             :         /* Parse parameters. */
     557           2 :         if( zend_parse_method_parameters( ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",
     558             :                 &object, Collator_ce_ptr, &str, &str_len ) == FAILURE )
     559             :         {
     560           1 :                 intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR,
     561             :                          "collator_get_sort_key: unable to parse input params", 0 TSRMLS_CC );
     562             : 
     563           1 :                 RETURN_FALSE;
     564             :         }
     565             : 
     566             :         /* Fetch the object. */
     567           1 :         COLLATOR_METHOD_FETCH_OBJECT;
     568             : 
     569           1 :         if (!co || !co->ucoll) {
     570           1 :                 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
     571           1 :                 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
     572             :                         "Object not initialized", 0 TSRMLS_CC );
     573           1 :                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Object not initialized");
     574             : 
     575           0 :                 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           0 :         intl_convert_utf8_to_utf16(
     584             :                 &ustr, &ustr_len, str, str_len, COLLATOR_ERROR_CODE_P( co ) );
     585           0 :         if( U_FAILURE( COLLATOR_ERROR_CODE( co ) ) )
     586             :         {
     587             :                 /* Set global error code. */
     588           0 :                 intl_error_set_code( NULL, COLLATOR_ERROR_CODE( co ) TSRMLS_CC );
     589             : 
     590             :                 /* Set error messages. */
     591           0 :                 intl_errors_set_custom_msg( COLLATOR_ERROR_P( co ),
     592             :                         "Error converting first argument to UTF-16", 0 TSRMLS_CC );
     593           0 :                 efree( ustr );
     594           0 :                 RETURN_FALSE;
     595             :         }
     596             : 
     597             :         /* ucol_getSortKey is exception in that the key length includes the 
     598             :          * NUL terminator*/
     599           0 :         key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, 0);
     600           0 :         if(!key_len) {
     601           0 :                 efree( ustr );
     602           0 :                 RETURN_FALSE;
     603             :         }
     604           0 :         key = emalloc(key_len);
     605           0 :         key_len = ucol_getSortKey(co->ucoll, ustr, ustr_len, key, key_len);
     606           0 :         efree( ustr );
     607           0 :         if(!key_len) {
     608           0 :                 RETURN_FALSE;
     609             :         }
     610           0 :         RETURN_STRINGL((char *)key, key_len - 1, 0);
     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             :  */

Generated by: LCOV version 1.10

Generated at Sun, 27 Jul 2014 12:58:29 +0000 (47 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.