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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:14 +0000 (6 days ago)

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