Annotation of embedaddon/php/ext/intl/grapheme/grapheme_util.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | This source file is subject to version 3.01 of the PHP license,      |
                      6:    | that is bundled with this package in the file LICENSE, and is        |
                      7:    | available through the world-wide-web at the following url:           |
                      8:    | http://www.php.net/license/3_01.txt                                  |
                      9:    | If you did not receive a copy of the PHP license and are unable to   |
                     10:    | obtain it through the world-wide-web, please send a note to          |
                     11:    | license@php.net so we can mail you a copy immediately.               |
                     12:    +----------------------------------------------------------------------+
                     13:    | 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>
1.1.1.2 ! misho      31: #include <unicode/usearch.h>
1.1       misho      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: grapheme_close_global_iterator( TSRMLS_D )
                     42: {
                     43:        UBreakIterator *global_break_iterator = INTL_G( grapheme_iterator );
                     44: 
                     45:        if ( NULL != global_break_iterator ) {
                     46:                ubrk_close(global_break_iterator);
                     47:        }
                     48: }
                     49: /* }}} */
                     50: 
                     51: /* {{{ grapheme_substr_ascii f='from' - starting point, l='length' */
1.1.1.2 ! misho      52: void grapheme_substr_ascii(char *str, int str_len, int f, int l, int argc, char **sub_str, int *sub_str_len)
1.1       misho      53: {
                     54:     *sub_str = NULL;
                     55: 
                     56:     if (argc > 2) {
                     57:         if ((l < 0 && -l > str_len)) {
                     58:             return;
                     59:         } else if (l > str_len) {
                     60:             l = str_len;
                     61:         }
                     62:     } else {
                     63:         l = str_len;
                     64:     }
                     65: 
                     66:     if (f > str_len || (f < 0 && -f > str_len)) {
                     67:         return;
                     68:     }
                     69: 
                     70:     if (l < 0 && (l + str_len - f) < 0) {
                     71:         return;
                     72:     }
                     73: 
                     74:     /* if "from" position is negative, count start position from the end
                     75:      * of the string
                     76:      */
                     77:     if (f < 0) {
                     78:         f = str_len + f;
                     79:         if (f < 0) {
                     80:             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:     if (l < 0) {
                     89:         l = (str_len - f) + l;
                     90:         if (l < 0) {
                     91:             l = 0;
                     92:         }
                     93:     }
                     94: 
                     95:     if (f >= str_len) {
                     96:         return;
                     97:     }
                     98: 
                     99:     if ((f + l) > str_len) {
                    100:         l = str_len - f;
                    101:     }
                    102: 
                    103:     *sub_str = str + f;
                    104:     *sub_str_len = l;
                    105: 
                    106:     return;
                    107: }
                    108: /* }}} */
                    109: 
1.1.1.2 ! misho     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;                                                                                                      \
1.1       misho     127:        }
                    128: 
                    129: 
                    130: /* {{{ grapheme_strpos_utf16 - strrpos using utf16*/
1.1.1.2 ! misho     131: 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)
1.1       misho     132: {
1.1.1.2 ! misho     133:        UChar *uhaystack = NULL, *uneedle = NULL;
        !           134:        int32_t uhaystack_len = 0, uneedle_len = 0, char_pos, ret_pos, offset_pos = 0;
1.1       misho     135:        unsigned char u_break_iterator_buffer[U_BRK_SAFECLONE_BUFFERSIZE];
1.1.1.2 ! misho     136:        UBreakIterator* bi = NULL;
1.1       misho     137:        UErrorCode status;
1.1.1.2 ! misho     138:        UStringSearch* src = NULL;
        !           139:        UCollator *coll;
1.1       misho     140: 
1.1.1.2 ! misho     141:        if(puchar_pos) {
        !           142:                *puchar_pos = -1;
        !           143:        }
1.1       misho     144:        /* convert the strings to UTF-16. */
                    145: 
                    146:        status = U_ZERO_ERROR;
                    147:        intl_convert_utf8_to_utf16(&uhaystack, &uhaystack_len, (char *) haystack, haystack_len, &status );
1.1.1.2 ! misho     148:        STRPOS_CHECK_STATUS(status, "Error converting input string to UTF-16");
1.1       misho     149: 
1.1.1.2 ! misho     150:        status = U_ZERO_ERROR;
        !           151:        intl_convert_utf8_to_utf16(&uneedle, &uneedle_len, (char *) needle, needle_len, &status );
        !           152:        STRPOS_CHECK_STATUS(status, "Error converting input string to UTF-16");
1.1       misho     153: 
                    154:        /* get a pointer to the haystack taking into account the offset */
                    155:        status = U_ZERO_ERROR;
                    156:        bi = grapheme_get_break_iterator(u_break_iterator_buffer, &status TSRMLS_CC );
1.1.1.2 ! misho     157:        STRPOS_CHECK_STATUS(status, "Failed to get iterator");
        !           158:        status = U_ZERO_ERROR;
        !           159:        ubrk_setText(bi, uhaystack, uhaystack_len, &status);
        !           160:        STRPOS_CHECK_STATUS(status, "Failed to set up iterator");
1.1       misho     161: 
1.1.1.2 ! misho     162:        status = U_ZERO_ERROR;
        !           163:        src = usearch_open(uneedle, uneedle_len, uhaystack, uhaystack_len, "", bi, &status);
        !           164:        STRPOS_CHECK_STATUS(status, "Error creating search object");
        !           165: 
        !           166:        if(f_ignore_case) {
        !           167:                coll = usearch_getCollator(src);
        !           168:                status = U_ZERO_ERROR;
        !           169:                ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_SECONDARY, &status);
        !           170:                STRPOS_CHECK_STATUS(status, "Error setting collation strength");
        !           171:                usearch_reset(src);
1.1       misho     172:        }
                    173: 
1.1.1.2 ! misho     174:        if(offset != 0) {
        !           175:                offset_pos = grapheme_get_haystack_offset(bi, offset);
        !           176:                if(offset_pos == -1) {
        !           177:                        status = U_ILLEGAL_ARGUMENT_ERROR;
        !           178:                        STRPOS_CHECK_STATUS(status, "Invalid search offset");   
        !           179:                }
        !           180:                status = U_ZERO_ERROR;
        !           181:                usearch_setOffset(src, offset_pos, &status);    
        !           182:                STRPOS_CHECK_STATUS(status, "Invalid search offset");
1.1       misho     183:        }
                    184: 
                    185: 
1.1.1.2 ! misho     186:        if(last) {
        !           187:                char_pos = usearch_last(src, &status);
        !           188:                if(char_pos < offset_pos) {
        !           189:                        /* last one is beyound our start offset */
        !           190:                        char_pos = USEARCH_DONE;
1.1       misho     191:                }
1.1.1.2 ! misho     192:        } else {
        !           193:                char_pos = usearch_next(src, &status);
1.1       misho     194:        }
1.1.1.2 ! misho     195:        STRPOS_CHECK_STATUS(status, "Error looking up string");
        !           196:        if(char_pos != USEARCH_DONE && ubrk_isBoundary(bi, char_pos)) {
        !           197:                ret_pos = grapheme_count_graphemes(bi, uhaystack,char_pos);
        !           198:                if(puchar_pos) {
        !           199:                        *puchar_pos = char_pos;
        !           200:                }
        !           201:        } else {
        !           202:                ret_pos = -1;
1.1       misho     203:        }
                    204: 
                    205:        if (uhaystack) {
                    206:                efree( uhaystack );
                    207:        }
                    208:        if (uneedle) {
                    209:                efree( uneedle );
                    210:        }
                    211:        ubrk_close (bi);
1.1.1.2 ! misho     212:        usearch_close (src);
1.1       misho     213: 
                    214:        return ret_pos;
                    215: }
                    216: 
                    217: /* }}} */
                    218: 
                    219: /* {{{ grapheme_ascii_check: ASCII check */
                    220: int grapheme_ascii_check(const unsigned char *day, int32_t len)
                    221: {
                    222:        int ret_len = len;
                    223:        while ( len-- ) {
                    224:        if ( *day++ > 0x7f )
                    225:                return -1;
                    226:        }
                    227: 
                    228:        return ret_len;
                    229: }
                    230: 
                    231: /* }}} */
                    232: 
                    233: /* {{{ grapheme_split_string: find and optionally return grapheme boundaries */
                    234: 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:        UErrorCode              status = U_ZERO_ERROR;
                    238:        int ret_len, pos;
                    239:        UBreakIterator* bi;
                    240: 
                    241:        bi = grapheme_get_break_iterator((void*)u_break_iterator_buffer, &status TSRMLS_CC );
                    242: 
                    243:        if( U_FAILURE(status) ) {
                    244:                return -1;
                    245:        }
                    246:        
                    247:        ubrk_setText(bi, text, text_length,     &status);
                    248: 
                    249:        pos = 0;
                    250:        
                    251:        for ( ret_len = 0; pos != UBRK_DONE; ) {
                    252:        
                    253:                pos = ubrk_next(bi);
                    254:                
                    255:                if ( pos != UBRK_DONE ) {
                    256:                
                    257:                        if ( NULL != boundary_array && ret_len < boundary_array_len ) {
                    258:                                boundary_array[ret_len] = pos;
                    259:                        }
                    260: 
                    261:                        ret_len++;
                    262:                }
                    263:        }
                    264:                        
                    265:        ubrk_close(bi);
                    266:        
                    267:        return ret_len;
                    268: }
                    269: /* }}} */
                    270: 
                    271: /* {{{ grapheme_count_graphemes */
1.1.1.2 ! misho     272: int32_t grapheme_count_graphemes(UBreakIterator *bi, UChar *string, int32_t string_len)
1.1       misho     273: {
                    274:        int ret_len = 0;
                    275:        int pos = 0;
                    276:        UErrorCode              status = U_ZERO_ERROR;
                    277:        
                    278:        ubrk_setText(bi, string, string_len, &status);
                    279: 
                    280:        do {
                    281:        
                    282:                pos = ubrk_next(bi);
                    283:                
                    284:                if ( UBRK_DONE != pos ) {
                    285:                        ret_len++;
                    286:                }
                    287:                
                    288:        } while ( UBRK_DONE != pos );
                    289:        
                    290:        return ret_len;
                    291: }
                    292: /* }}} */
                    293: 
                    294: 
                    295: /* {{{         grapheme_get_haystack_offset - bump the haystack pointer based on the grapheme count offset */
1.1.1.2 ! misho     296: int grapheme_get_haystack_offset(UBreakIterator* bi, int32_t offset)
1.1       misho     297: {
                    298:        int32_t pos;
                    299:        int32_t (*iter_op)(UBreakIterator* bi);
                    300:        int iter_incr;
                    301: 
                    302:        if ( 0 == offset ) {
1.1.1.2 ! misho     303:                return 0;
1.1       misho     304:        }
                    305:        
                    306:        if ( offset < 0 ) {
                    307:                iter_op = ubrk_previous;
                    308:                ubrk_last(bi); /* one past the end */
                    309:                iter_incr = 1;
                    310:        }
                    311:        else {
                    312:                iter_op = ubrk_next;
                    313:                iter_incr = -1;
                    314:        }
                    315:        
                    316:        pos = 0;
                    317:        
                    318:        while ( pos != UBRK_DONE && offset != 0 ) {
                    319:        
                    320:                pos = iter_op(bi);
                    321:                
                    322:                if ( UBRK_DONE != pos ) {
                    323:                        offset += iter_incr;
                    324:                }
                    325:        }
                    326: 
                    327:        if ( offset != 0 ) {
1.1.1.2 ! misho     328:                return -1;
1.1       misho     329:        }
                    330:        
1.1.1.2 ! misho     331:        return pos;
1.1       misho     332: }
                    333: /* }}} */
                    334: 
                    335: /* {{{ grapheme_strrpos_ascii: borrowed from the php ext/standard/string.c */
                    336:  int32_t
                    337: 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:        if (offset >= 0) {
                    342:                p = haystack + offset;
                    343:                e = haystack + haystack_len - needle_len;
                    344:        } else {
                    345:                p = haystack;
                    346:                if (needle_len > -offset) {
                    347:                        e = haystack + haystack_len - needle_len;
                    348:                } else {
                    349:                        e = haystack + haystack_len + offset;
                    350:                }
                    351:        }
                    352: 
                    353:        if (needle_len == 1) {
                    354:                /* Single character search can shortcut memcmps */
                    355:                while (e >= p) {
                    356:                        if (*e == *needle) {
                    357:                                return (e - p + (offset > 0 ? offset : 0));
                    358:                        }
                    359:                        e--;
                    360:                }
                    361:                return -1;
                    362:        }
                    363: 
                    364:        while (e >= p) {
                    365:                if (memcmp(e, needle, needle_len) == 0) {
                    366:                        return (e - p + (offset > 0 ? offset : 0));
                    367:                }
                    368:                e--;
                    369:        }
                    370: 
                    371:        return -1;
                    372: }
                    373: 
                    374: /* }}} */
                    375: 
                    376: /* {{{ grapheme_get_break_iterator: get a clone of the global character break iterator */
1.1.1.2 ! misho     377: UBreakIterator* grapheme_get_break_iterator(void *stack_buffer, UErrorCode *status TSRMLS_DC )
1.1       misho     378: {
                    379:        int32_t buffer_size;
                    380: 
                    381:        UBreakIterator *global_break_iterator = INTL_G( grapheme_iterator );
                    382: 
                    383:        if ( NULL == global_break_iterator ) {
                    384: 
                    385:                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:                INTL_G(grapheme_iterator) = global_break_iterator;
                    392:        }
                    393: 
                    394:        buffer_size = U_BRK_SAFECLONE_BUFFERSIZE;
                    395: 
                    396:        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: 

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