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/grapheme - grapheme_util.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 140 161 87.0 %
Date: 2015-01-26 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       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             :    | Author: Ed Batutis <ed@batutis.com>                                  |
      14             :    +----------------------------------------------------------------------+
      15             :  */
      16             : 
      17             : /* {{{ includes */
      18             : #ifdef HAVE_CONFIG_H
      19             : #include "config.h"
      20             : #endif
      21             : 
      22             : #include <php.h>
      23             : #include "grapheme.h"
      24             : #include "grapheme_util.h"
      25             : #include "intl_common.h"
      26             : 
      27             : #include <unicode/utypes.h>
      28             : #include <unicode/ucol.h>
      29             : #include <unicode/ustring.h>
      30             : #include <unicode/ubrk.h>
      31             : #include <unicode/usearch.h>
      32             : 
      33             : #include "ext/standard/php_string.h"
      34             : 
      35             : ZEND_EXTERN_MODULE_GLOBALS( intl )
      36             : 
      37             : /* }}} */
      38             : 
      39             : /* {{{ grapheme_close_global_iterator - clean up */
      40             : void
      41           4 : grapheme_close_global_iterator( void )
      42             : {
      43           4 :         UBreakIterator *global_break_iterator = INTL_G( grapheme_iterator );
      44             : 
      45           4 :         if ( NULL != global_break_iterator ) {
      46           4 :                 ubrk_close(global_break_iterator);
      47             :         }
      48           4 : }
      49             : /* }}} */
      50             : 
      51             : /* {{{ grapheme_substr_ascii f='from' - starting point, l='length' */
      52           9 : void grapheme_substr_ascii(char *str, size_t str_len, int32_t f, int32_t l, char **sub_str, int32_t *sub_str_len)
      53             : {
      54           9 :         int32_t str_len2 = (int32_t)str_len; /* in order to avoid signed/unsigned problems */
      55           9 :     *sub_str = NULL;
      56             : 
      57           9 :     if(str_len > INT32_MAX) {
      58             :         /* We can not return long strings from ICU functions, so we won't here too */
      59           0 :         return;
      60             :     }
      61             : 
      62           9 :     if ((l < 0 && -l > str_len2)) {
      63           0 :         return;
      64           9 :     } else if (l > 0 && l > str_len2) {
      65           2 :         l = str_len2;
      66             :     }
      67             : 
      68           9 :     if (f > str_len2 || (f < 0 && -f > str_len2)) {
      69           0 :         return;
      70             :     }
      71             : 
      72           9 :     if (l < 0 && str_len2 < f - l) {
      73           1 :         return;
      74             :     }
      75             : 
      76             :     /* if "from" position is negative, count start position from the end
      77             :      * of the string
      78             :      */
      79           8 :     if (f < 0) {
      80           1 :         f = str_len2 + f;
      81           1 :         if (f < 0) {
      82           0 :             f = 0;
      83             :         }
      84             :     }
      85             : 
      86             : 
      87             :     /* if "length" position is negative, set it to the length
      88             :      * needed to stop that many chars from the end of the string
      89             :      */
      90           8 :     if (l < 0) {
      91           0 :         l = (str_len2 - f) + l;
      92           0 :         if (l < 0) {
      93           0 :             l = 0;
      94             :         }
      95             :     }
      96             : 
      97           8 :     if (f >= str_len2) {
      98           0 :         return;
      99             :     }
     100             : 
     101           8 :     if ((f + l) > str_len2) {
     102           3 :         l = str_len - f;
     103             :     }
     104             : 
     105           8 :     *sub_str = str + f;
     106           8 :     *sub_str_len = l;
     107             : 
     108           8 :     return;
     109             : }
     110             : /* }}} */
     111             : 
     112             : #define STRPOS_CHECK_STATUS(status, error)                                                      \
     113             :         if ( U_FAILURE( (status) ) ) {                                                                  \
     114             :                 intl_error_set_code( NULL, (status) );                  \
     115             :                 intl_error_set_custom_msg( NULL, (error), 0 );  \
     116             :                 if (uhaystack) {                                                                                        \
     117             :                         efree( uhaystack );                                                                     \
     118             :                 }                                                                                                                       \
     119             :                 if (uneedle) {                                                                                          \
     120             :                         efree( uneedle );                                                                               \
     121             :                 }                                                                                                                       \
     122             :                 if(bi) {                                                                                                        \
     123             :                         ubrk_close (bi);                                                                                \
     124             :                 }                                                                                                                       \
     125             :                 if(src) {                                                                                                       \
     126             :                         usearch_close(src);                                                                             \
     127             :                 }                                                                                                                       \
     128             :                 return -1;                                                                                                      \
     129             :         }
     130             : 
     131             : 
     132             : /* {{{ grapheme_strpos_utf16 - strrpos using utf16*/
     133         129 : int32_t grapheme_strpos_utf16(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset, int32_t *puchar_pos, int f_ignore_case, int last)
     134             : {
     135         129 :         UChar *uhaystack = NULL, *uneedle = NULL;
     136         129 :         int32_t uhaystack_len = 0, uneedle_len = 0, char_pos, ret_pos, offset_pos = 0;
     137             :         unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
     138         129 :         UBreakIterator* bi = NULL;
     139             :         UErrorCode status;
     140         129 :         UStringSearch* src = NULL;
     141             :         UCollator *coll;
     142             : 
     143         129 :         if(puchar_pos) {
     144          55 :                 *puchar_pos = -1;
     145             :         }
     146             :         /* convert the strings to UTF-16. */
     147             : 
     148         129 :         status = U_ZERO_ERROR;
     149         129 :         intl_convert_utf8_to_utf16(&uhaystack, &uhaystack_len, haystack, haystack_len, &status );
     150         129 :         STRPOS_CHECK_STATUS(status, "Error converting input string to UTF-16");
     151             : 
     152         129 :         status = U_ZERO_ERROR;
     153         129 :         intl_convert_utf8_to_utf16(&uneedle, &uneedle_len, needle, needle_len, &status );
     154         129 :         STRPOS_CHECK_STATUS(status, "Error converting needle string to UTF-16");
     155             : 
     156             :         /* get a pointer to the haystack taking into account the offset */
     157         129 :         status = U_ZERO_ERROR;
     158         129 :         bi = grapheme_get_break_iterator(u_break_iterator_buffer, &status );
     159         129 :         STRPOS_CHECK_STATUS(status, "Failed to get iterator");
     160         129 :         status = U_ZERO_ERROR;
     161         129 :         ubrk_setText(bi, uhaystack, uhaystack_len, &status);
     162         129 :         STRPOS_CHECK_STATUS(status, "Failed to set up iterator");
     163             : 
     164         129 :         status = U_ZERO_ERROR;
     165         129 :         src = usearch_open(uneedle, uneedle_len, uhaystack, uhaystack_len, "", bi, &status);
     166         129 :         STRPOS_CHECK_STATUS(status, "Error creating search object");
     167             : 
     168         129 :         if(f_ignore_case) {
     169          76 :                 coll = usearch_getCollator(src);
     170          76 :                 status = U_ZERO_ERROR;
     171          76 :                 ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_SECONDARY, &status);
     172          76 :                 STRPOS_CHECK_STATUS(status, "Error setting collation strength");
     173          76 :                 usearch_reset(src);
     174             :         }
     175             : 
     176         129 :         if(offset != 0) {
     177          16 :                 offset_pos = grapheme_get_haystack_offset(bi, offset);
     178          16 :                 if(offset_pos == -1) {
     179           0 :                         status = U_ILLEGAL_ARGUMENT_ERROR;
     180           0 :                         STRPOS_CHECK_STATUS(status, "Invalid search offset");
     181             :                 }
     182          16 :                 status = U_ZERO_ERROR;
     183          16 :                 usearch_setOffset(src, offset_pos, &status);
     184          16 :                 STRPOS_CHECK_STATUS(status, "Invalid search offset");
     185             :         }
     186             : 
     187             : 
     188         129 :         if(last) {
     189          38 :                 char_pos = usearch_last(src, &status);
     190          38 :                 if(char_pos < offset_pos) {
     191             :                         /* last one is beyound our start offset */
     192          12 :                         char_pos = USEARCH_DONE;
     193             :                 }
     194             :         } else {
     195          91 :                 char_pos = usearch_next(src, &status);
     196             :         }
     197         129 :         STRPOS_CHECK_STATUS(status, "Error looking up string");
     198         229 :         if(char_pos != USEARCH_DONE && ubrk_isBoundary(bi, char_pos)) {
     199         100 :                 ret_pos = grapheme_count_graphemes(bi, uhaystack,char_pos);
     200         100 :                 if(puchar_pos) {
     201          46 :                         *puchar_pos = char_pos;
     202             :                 }
     203             :         } else {
     204          29 :                 ret_pos = -1;
     205             :         }
     206             : 
     207         129 :         if (uhaystack) {
     208         129 :                 efree( uhaystack );
     209             :         }
     210         129 :         if (uneedle) {
     211         129 :                 efree( uneedle );
     212             :         }
     213         129 :         ubrk_close (bi);
     214         129 :         usearch_close (src);
     215             : 
     216         129 :         return ret_pos;
     217             : }
     218             : 
     219             : /* }}} */
     220             : 
     221             : /* {{{ grapheme_ascii_check: ASCII check */
     222         350 : zend_long grapheme_ascii_check(const unsigned char *day, size_t len)
     223             : {
     224         350 :         int ret_len = len;
     225        1532 :         while ( len-- ) {
     226        1047 :         if ( *day++ > 0x7f )
     227         215 :                 return -1;
     228             :         }
     229             : 
     230         135 :         return ret_len;
     231             : }
     232             : 
     233             : /* }}} */
     234             : 
     235             : /* {{{ grapheme_split_string: find and optionally return grapheme boundaries */
     236           4 : int32_t grapheme_split_string(const UChar *text, int32_t text_length, int boundary_array[], int boundary_array_len )
     237             : {
     238             :         unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
     239           4 :         UErrorCode              status = U_ZERO_ERROR;
     240             :         int ret_len, pos;
     241             :         UBreakIterator* bi;
     242             : 
     243           4 :         bi = grapheme_get_break_iterator((void*)u_break_iterator_buffer, &status );
     244             : 
     245           4 :         if( U_FAILURE(status) ) {
     246           0 :                 return -1;
     247             :         }
     248             : 
     249           4 :         ubrk_setText(bi, text, text_length,     &status);
     250             : 
     251           4 :         pos = 0;
     252             : 
     253          27 :         for ( ret_len = 0; pos != UBRK_DONE; ) {
     254             : 
     255          19 :                 pos = ubrk_next(bi);
     256             : 
     257          19 :                 if ( pos != UBRK_DONE ) {
     258             : 
     259          15 :                         if ( NULL != boundary_array && ret_len < boundary_array_len ) {
     260           0 :                                 boundary_array[ret_len] = pos;
     261             :                         }
     262             : 
     263          15 :                         ret_len++;
     264             :                 }
     265             :         }
     266             : 
     267           4 :         ubrk_close(bi);
     268             : 
     269           4 :         return ret_len;
     270             : }
     271             : /* }}} */
     272             : 
     273             : /* {{{ grapheme_count_graphemes */
     274         100 : int32_t grapheme_count_graphemes(UBreakIterator *bi, UChar *string, int32_t string_len)
     275             : {
     276         100 :         int ret_len = 0;
     277         100 :         int pos = 0;
     278         100 :         UErrorCode              status = U_ZERO_ERROR;
     279             : 
     280         100 :         ubrk_setText(bi, string, string_len, &status);
     281             : 
     282             :         do {
     283             : 
     284         420 :                 pos = ubrk_next(bi);
     285             : 
     286         420 :                 if ( UBRK_DONE != pos ) {
     287         320 :                         ret_len++;
     288             :                 }
     289             : 
     290         420 :         } while ( UBRK_DONE != pos );
     291             : 
     292         100 :         return ret_len;
     293             : }
     294             : /* }}} */
     295             : 
     296             : 
     297             : /* {{{  grapheme_get_haystack_offset - bump the haystack pointer based on the grapheme count offset */
     298          16 : int32_t grapheme_get_haystack_offset(UBreakIterator* bi, int32_t offset)
     299             : {
     300             :         int32_t pos;
     301             :         int32_t (*iter_op)(UBreakIterator* bi);
     302             :         int iter_incr;
     303             : 
     304          16 :         if ( 0 == offset ) {
     305           0 :                 return 0;
     306             :         }
     307             : 
     308          16 :         if ( offset < 0 ) {
     309           0 :                 iter_op = ubrk_previous;
     310           0 :                 ubrk_last(bi); /* one past the end */
     311           0 :                 iter_incr = 1;
     312             :         }
     313             :         else {
     314          16 :                 iter_op = ubrk_next;
     315          16 :                 iter_incr = -1;
     316             :         }
     317             : 
     318          16 :         pos = 0;
     319             : 
     320          64 :         while ( pos != UBRK_DONE && offset != 0 ) {
     321             : 
     322          32 :                 pos = iter_op(bi);
     323             : 
     324          32 :                 if ( UBRK_DONE != pos ) {
     325          32 :                         offset += iter_incr;
     326             :                 }
     327             :         }
     328             : 
     329          16 :         if ( offset != 0 ) {
     330           0 :                 return -1;
     331             :         }
     332             : 
     333          16 :         return pos;
     334             : }
     335             : /* }}} */
     336             : 
     337             : /* {{{ grapheme_strrpos_ascii: borrowed from the php ext/standard/string.c */
     338             :  zend_long
     339          38 : grapheme_strrpos_ascii(char *haystack, size_t haystack_len, char *needle, size_t needle_len, int32_t offset)
     340             : {
     341             :         char *p, *e;
     342             : 
     343          38 :         if (offset >= 0) {
     344          38 :                 p = haystack + offset;
     345          38 :                 e = haystack + haystack_len - needle_len;
     346             :         } else {
     347           0 :                 p = haystack;
     348           0 :                 if (needle_len > -offset) {
     349           0 :                         e = haystack + haystack_len - needle_len;
     350             :                 } else {
     351           0 :                         e = haystack + haystack_len + offset;
     352             :                 }
     353             :         }
     354             : 
     355          38 :         if (needle_len == 1) {
     356             :                 /* Single character search can shortcut memcmps */
     357          52 :                 while (e >= p) {
     358          34 :                         if (*e == *needle) {
     359          10 :                                 return (e - p + (offset > 0 ? offset : 0));
     360             :                         }
     361          24 :                         e--;
     362             :                 }
     363           4 :                 return -1;
     364             :         }
     365             : 
     366          56 :         while (e >= p) {
     367          22 :                 if (memcmp(e, needle, needle_len) == 0) {
     368          14 :                         return (e - p + (offset > 0 ? offset : 0));
     369             :                 }
     370           8 :                 e--;
     371             :         }
     372             : 
     373          10 :         return -1;
     374             : }
     375             : 
     376             : /* }}} */
     377             : 
     378             : /* {{{ grapheme_get_break_iterator: get a clone of the global character break iterator */
     379         251 : UBreakIterator* grapheme_get_break_iterator(void *stack_buffer, UErrorCode *status )
     380             : {
     381             :         int32_t buffer_size;
     382             : 
     383         251 :         UBreakIterator *global_break_iterator = INTL_G( grapheme_iterator );
     384             : 
     385         251 :         if ( NULL == global_break_iterator ) {
     386             : 
     387           4 :                 global_break_iterator = ubrk_open(UBRK_CHARACTER,
     388             :                                                                                         NULL,   /* icu default locale - locale has no effect on this iterator */
     389             :                                                                                         NULL,   /* text not set in global iterator */
     390             :                                                                                         0,              /* text length = 0 */
     391             :                                                                                         status);
     392             : 
     393           4 :                 INTL_G(grapheme_iterator) = global_break_iterator;
     394             :         }
     395             : 
     396         251 :         buffer_size = U_BRK_SAFECLONE_BUFFERSIZE;
     397             : 
     398         251 :         return ubrk_safeClone(global_break_iterator, stack_buffer, &buffer_size, status);
     399             : }
     400             : /* }}} */
     401             : 
     402             : /*
     403             :  * Local variables:
     404             :  * tab-width: 4
     405             :  * c-basic-offset: 4
     406             :  * End:
     407             :  * vim600: fdm=marker
     408             :  * vim: noet sw=4 ts=4
     409             :  */
     410             : 

Generated by: LCOV version 1.10

Generated at Mon, 26 Jan 2015 14:46:46 +0000 (21 hours ago)

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