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/mbstring - php_mbregex.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 521 636 81.9 %
Date: 2018-12-08 Functions: 37 39 94.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2018 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Author: Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>              |
      16             :    +----------------------------------------------------------------------+
      17             :  */
      18             : 
      19             : /* $Id$ */
      20             : 
      21             : 
      22             : #ifdef HAVE_CONFIG_H
      23             : #include "config.h"
      24             : #endif
      25             : 
      26             : #include "php.h"
      27             : #include "php_ini.h"
      28             : 
      29             : #if HAVE_MBREGEX
      30             : 
      31             : #include "zend_smart_str.h"
      32             : #include "ext/standard/info.h"
      33             : #include "php_mbregex.h"
      34             : #include "mbstring.h"
      35             : 
      36             : #include "php_onig_compat.h" /* must come prior to the oniguruma header */
      37             : #include <oniguruma.h>
      38             : #undef UChar
      39             : 
      40             : ZEND_EXTERN_MODULE_GLOBALS(mbstring)
      41             : 
      42             : struct _zend_mb_regex_globals {
      43             :         OnigEncoding default_mbctype;
      44             :         OnigEncoding current_mbctype;
      45             :         HashTable ht_rc;
      46             :         zval search_str;
      47             :         zval *search_str_val;
      48             :         unsigned int search_pos;
      49             :         php_mb_regex_t *search_re;
      50             :         OnigRegion *search_regs;
      51             :         OnigOptionType regex_default_options;
      52             :         OnigSyntaxType *regex_default_syntax;
      53             : };
      54             : 
      55             : #define MBREX(g) (MBSTRG(mb_regex_globals)->g)
      56             : 
      57             : /* {{{ static void php_mb_regex_free_cache() */
      58         237 : static void php_mb_regex_free_cache(zval *el) {
      59         237 :         onig_free((php_mb_regex_t *)Z_PTR_P(el));
      60         237 : }
      61             : /* }}} */
      62             : 
      63             : /* {{{ _php_mb_regex_globals_ctor */
      64       24754 : static int _php_mb_regex_globals_ctor(zend_mb_regex_globals *pglobals)
      65             : {
      66       24754 :         pglobals->default_mbctype = ONIG_ENCODING_UTF8;
      67       24754 :         pglobals->current_mbctype = ONIG_ENCODING_UTF8;
      68       24754 :         zend_hash_init(&(pglobals->ht_rc), 0, NULL, php_mb_regex_free_cache, 1);
      69       24754 :         ZVAL_UNDEF(&pglobals->search_str);
      70       24754 :         pglobals->search_re = (php_mb_regex_t*)NULL;
      71       24754 :         pglobals->search_pos = 0;
      72       24754 :         pglobals->search_regs = (OnigRegion*)NULL;
      73       24754 :         pglobals->regex_default_options = ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE;
      74       24754 :         pglobals->regex_default_syntax = ONIG_SYNTAX_RUBY;
      75       24754 :         return SUCCESS;
      76             : }
      77             : /* }}} */
      78             : 
      79             : /* {{{ _php_mb_regex_globals_dtor */
      80       24796 : static void _php_mb_regex_globals_dtor(zend_mb_regex_globals *pglobals)
      81             : {
      82       24796 :         zend_hash_destroy(&pglobals->ht_rc);
      83       24796 : }
      84             : /* }}} */
      85             : 
      86             : /* {{{ php_mb_regex_globals_alloc */
      87       24754 : zend_mb_regex_globals *php_mb_regex_globals_alloc(void)
      88             : {
      89       24754 :         zend_mb_regex_globals *pglobals = pemalloc(
      90             :                         sizeof(zend_mb_regex_globals), 1);
      91       24754 :         if (!pglobals) {
      92           0 :                 return NULL;
      93             :         }
      94       24754 :         if (SUCCESS != _php_mb_regex_globals_ctor(pglobals)) {
      95           0 :                 pefree(pglobals, 1);
      96           0 :                 return NULL;
      97             :         }
      98       24754 :         return pglobals;
      99             : }
     100             : /* }}} */
     101             : 
     102             : /* {{{ php_mb_regex_globals_free */
     103       24796 : void php_mb_regex_globals_free(zend_mb_regex_globals *pglobals)
     104             : {
     105       24796 :         if (!pglobals) {
     106           0 :                 return;
     107             :         }
     108       24796 :         _php_mb_regex_globals_dtor(pglobals);
     109       24796 :         pefree(pglobals, 1);
     110             : }
     111             : /* }}} */
     112             : 
     113             : /* {{{ PHP_MINIT_FUNCTION(mb_regex) */
     114       24754 : PHP_MINIT_FUNCTION(mb_regex)
     115             : {
     116       24754 :         onig_init();
     117       24754 :         return SUCCESS;
     118             : }
     119             : /* }}} */
     120             : 
     121             : /* {{{ PHP_MSHUTDOWN_FUNCTION(mb_regex) */
     122       24796 : PHP_MSHUTDOWN_FUNCTION(mb_regex)
     123             : {
     124       24796 :         onig_end();
     125       24796 :         return SUCCESS;
     126             : }
     127             : /* }}} */
     128             : 
     129             : /* {{{ PHP_RINIT_FUNCTION(mb_regex) */
     130       24704 : PHP_RINIT_FUNCTION(mb_regex)
     131             : {
     132       24704 :         return MBSTRG(mb_regex_globals) ? SUCCESS: FAILURE;
     133             : }
     134             : /* }}} */
     135             : 
     136             : /* {{{ PHP_RSHUTDOWN_FUNCTION(mb_regex) */
     137       24750 : PHP_RSHUTDOWN_FUNCTION(mb_regex)
     138             : {
     139       24750 :         MBREX(current_mbctype) = MBREX(default_mbctype);
     140             : 
     141       49500 :         if (!Z_ISUNDEF(MBREX(search_str))) {
     142          11 :                 zval_ptr_dtor(&MBREX(search_str));
     143          11 :                 ZVAL_UNDEF(&MBREX(search_str));
     144             :         }
     145       24750 :         MBREX(search_pos) = 0;
     146             : 
     147       24750 :         if (MBREX(search_regs) != NULL) {
     148           5 :                 onig_region_free(MBREX(search_regs), 1);
     149           5 :                 MBREX(search_regs) = (OnigRegion *)NULL;
     150             :         }
     151       24750 :         zend_hash_clean(&MBREX(ht_rc));
     152             : 
     153       24750 :         return SUCCESS;
     154             : }
     155             : /* }}} */
     156             : 
     157             : /* {{{ PHP_MINFO_FUNCTION(mb_regex) */
     158         146 : PHP_MINFO_FUNCTION(mb_regex)
     159             : {
     160             :         char buf[32];
     161         146 :         php_info_print_table_start();
     162         146 :         php_info_print_table_row(2, "Multibyte (japanese) regex support", "enabled");
     163         146 :         snprintf(buf, sizeof(buf), "%d.%d.%d",
     164             :                         ONIGURUMA_VERSION_MAJOR,
     165             :                         ONIGURUMA_VERSION_MINOR,
     166             :                         ONIGURUMA_VERSION_TEENY);
     167             : #ifdef PHP_ONIG_BUNDLED
     168             : #ifdef USE_COMBINATION_EXPLOSION_CHECK
     169         146 :         php_info_print_table_row(2, "Multibyte regex (oniguruma) backtrack check", "On");
     170             : #else   /* USE_COMBINATION_EXPLOSION_CHECK */
     171             :         php_info_print_table_row(2, "Multibyte regex (oniguruma) backtrack check", "Off");
     172             : #endif  /* USE_COMBINATION_EXPLOSION_CHECK */
     173             : #endif /* PHP_BUNDLED_ONIG */
     174         146 :         php_info_print_table_row(2, "Multibyte regex (oniguruma) version", buf);
     175         146 :         php_info_print_table_end();
     176         146 : }
     177             : /* }}} */
     178             : 
     179             : /*
     180             :  * encoding name resolver
     181             :  */
     182             : 
     183             : /* {{{ encoding name map */
     184             : typedef struct _php_mb_regex_enc_name_map_t {
     185             :         const char *names;
     186             :         OnigEncoding code;
     187             : } php_mb_regex_enc_name_map_t;
     188             : 
     189             : php_mb_regex_enc_name_map_t enc_name_map[] = {
     190             : #ifdef ONIG_ENCODING_EUC_JP
     191             :         {
     192             :                 "EUC-JP\0EUCJP\0X-EUC-JP\0UJIS\0EUCJP\0EUCJP-WIN\0",
     193             :                 ONIG_ENCODING_EUC_JP
     194             :         },
     195             : #endif
     196             : #ifdef ONIG_ENCODING_UTF8
     197             :         {
     198             :                 "UTF-8\0UTF8\0",
     199             :                 ONIG_ENCODING_UTF8
     200             :         },
     201             : #endif
     202             : #ifdef ONIG_ENCODING_UTF16_BE
     203             :         {
     204             :                 "UTF-16\0UTF-16BE\0",
     205             :                 ONIG_ENCODING_UTF16_BE
     206             :         },
     207             : #endif
     208             : #ifdef ONIG_ENCODING_UTF16_LE
     209             :         {
     210             :                 "UTF-16LE\0",
     211             :                 ONIG_ENCODING_UTF16_LE
     212             :         },
     213             : #endif
     214             : #ifdef ONIG_ENCODING_UTF32_BE
     215             :         {
     216             :                 "UCS-4\0UTF-32\0UTF-32BE\0",
     217             :                 ONIG_ENCODING_UTF32_BE
     218             :         },
     219             : #endif
     220             : #ifdef ONIG_ENCODING_UTF32_LE
     221             :         {
     222             :                 "UCS-4LE\0UTF-32LE\0",
     223             :                 ONIG_ENCODING_UTF32_LE
     224             :         },
     225             : #endif
     226             : #ifdef ONIG_ENCODING_SJIS
     227             :         {
     228             :                 "SJIS\0CP932\0MS932\0SHIFT_JIS\0SJIS-WIN\0WINDOWS-31J\0",
     229             :                 ONIG_ENCODING_SJIS
     230             :         },
     231             : #endif
     232             : #ifdef ONIG_ENCODING_BIG5
     233             :         {
     234             :                 "BIG5\0BIG-5\0BIGFIVE\0CN-BIG5\0BIG-FIVE\0",
     235             :                 ONIG_ENCODING_BIG5
     236             :         },
     237             : #endif
     238             : #ifdef ONIG_ENCODING_EUC_CN
     239             :         {
     240             :                 "EUC-CN\0EUCCN\0EUC_CN\0GB-2312\0GB2312\0",
     241             :                 ONIG_ENCODING_EUC_CN
     242             :         },
     243             : #endif
     244             : #ifdef ONIG_ENCODING_EUC_TW
     245             :         {
     246             :                 "EUC-TW\0EUCTW\0EUC_TW\0",
     247             :                 ONIG_ENCODING_EUC_TW
     248             :         },
     249             : #endif
     250             : #ifdef ONIG_ENCODING_EUC_KR
     251             :         {
     252             :                 "EUC-KR\0EUCKR\0EUC_KR\0",
     253             :                 ONIG_ENCODING_EUC_KR
     254             :         },
     255             : #endif
     256             : #if defined(ONIG_ENCODING_KOI8) && !PHP_ONIG_BAD_KOI8_ENTRY
     257             :         {
     258             :                 "KOI8\0KOI-8\0",
     259             :                 ONIG_ENCODING_KOI8
     260             :         },
     261             : #endif
     262             : #ifdef ONIG_ENCODING_KOI8_R
     263             :         {
     264             :                 "KOI8R\0KOI8-R\0KOI-8R\0",
     265             :                 ONIG_ENCODING_KOI8_R
     266             :         },
     267             : #endif
     268             : #ifdef ONIG_ENCODING_ISO_8859_1
     269             :         {
     270             :                 "ISO-8859-1\0ISO8859-1\0ISO_8859_1\0ISO8859_1\0",
     271             :                 ONIG_ENCODING_ISO_8859_1
     272             :         },
     273             : #endif
     274             : #ifdef ONIG_ENCODING_ISO_8859_2
     275             :         {
     276             :                 "ISO-8859-2\0ISO8859-2\0ISO_8859_2\0ISO8859_2\0",
     277             :                 ONIG_ENCODING_ISO_8859_2
     278             :         },
     279             : #endif
     280             : #ifdef ONIG_ENCODING_ISO_8859_3
     281             :         {
     282             :                 "ISO-8859-3\0ISO8859-3\0ISO_8859_3\0ISO8859_3\0",
     283             :                 ONIG_ENCODING_ISO_8859_3
     284             :         },
     285             : #endif
     286             : #ifdef ONIG_ENCODING_ISO_8859_4
     287             :         {
     288             :                 "ISO-8859-4\0ISO8859-4\0ISO_8859_4\0ISO8859_4\0",
     289             :                 ONIG_ENCODING_ISO_8859_4
     290             :         },
     291             : #endif
     292             : #ifdef ONIG_ENCODING_ISO_8859_5
     293             :         {
     294             :                 "ISO-8859-5\0ISO8859-5\0ISO_8859_5\0ISO8859_5\0",
     295             :                 ONIG_ENCODING_ISO_8859_5
     296             :         },
     297             : #endif
     298             : #ifdef ONIG_ENCODING_ISO_8859_6
     299             :         {
     300             :                 "ISO-8859-6\0ISO8859-6\0ISO_8859_6\0ISO8859_6\0",
     301             :                 ONIG_ENCODING_ISO_8859_6
     302             :         },
     303             : #endif
     304             : #ifdef ONIG_ENCODING_ISO_8859_7
     305             :         {
     306             :                 "ISO-8859-7\0ISO8859-7\0ISO_8859_7\0ISO8859_7\0",
     307             :                 ONIG_ENCODING_ISO_8859_7
     308             :         },
     309             : #endif
     310             : #ifdef ONIG_ENCODING_ISO_8859_8
     311             :         {
     312             :                 "ISO-8859-8\0ISO8859-8\0ISO_8859_8\0ISO8859_8\0",
     313             :                 ONIG_ENCODING_ISO_8859_8
     314             :         },
     315             : #endif
     316             : #ifdef ONIG_ENCODING_ISO_8859_9
     317             :         {
     318             :                 "ISO-8859-9\0ISO8859-9\0ISO_8859_9\0ISO8859_9\0",
     319             :                 ONIG_ENCODING_ISO_8859_9
     320             :         },
     321             : #endif
     322             : #ifdef ONIG_ENCODING_ISO_8859_10
     323             :         {
     324             :                 "ISO-8859-10\0ISO8859-10\0ISO_8859_10\0ISO8859_10\0",
     325             :                 ONIG_ENCODING_ISO_8859_10
     326             :         },
     327             : #endif
     328             : #ifdef ONIG_ENCODING_ISO_8859_11
     329             :         {
     330             :                 "ISO-8859-11\0ISO8859-11\0ISO_8859_11\0ISO8859_11\0",
     331             :                 ONIG_ENCODING_ISO_8859_11
     332             :         },
     333             : #endif
     334             : #ifdef ONIG_ENCODING_ISO_8859_13
     335             :         {
     336             :                 "ISO-8859-13\0ISO8859-13\0ISO_8859_13\0ISO8859_13\0",
     337             :                 ONIG_ENCODING_ISO_8859_13
     338             :         },
     339             : #endif
     340             : #ifdef ONIG_ENCODING_ISO_8859_14
     341             :         {
     342             :                 "ISO-8859-14\0ISO8859-14\0ISO_8859_14\0ISO8859_14\0",
     343             :                 ONIG_ENCODING_ISO_8859_14
     344             :         },
     345             : #endif
     346             : #ifdef ONIG_ENCODING_ISO_8859_15
     347             :         {
     348             :                 "ISO-8859-15\0ISO8859-15\0ISO_8859_15\0ISO8859_15\0",
     349             :                 ONIG_ENCODING_ISO_8859_15
     350             :         },
     351             : #endif
     352             : #ifdef ONIG_ENCODING_ISO_8859_16
     353             :         {
     354             :                 "ISO-8859-16\0ISO8859-16\0ISO_8859_16\0ISO8859_16\0",
     355             :                 ONIG_ENCODING_ISO_8859_16
     356             :         },
     357             : #endif
     358             : #ifdef ONIG_ENCODING_ASCII
     359             :         {
     360             :                 "ASCII\0US-ASCII\0US_ASCII\0ISO646\0",
     361             :                 ONIG_ENCODING_ASCII
     362             :         },
     363             : #endif
     364             :         { NULL, ONIG_ENCODING_UNDEF }
     365             : };
     366             : /* }}} */
     367             : 
     368             : /* {{{ php_mb_regex_name2mbctype */
     369      197953 : static OnigEncoding _php_mb_regex_name2mbctype(const char *pname)
     370             : {
     371             :         const char *p;
     372             :         php_mb_regex_enc_name_map_t *mapping;
     373             : 
     374      197953 :         if (pname == NULL || !*pname) {
     375       98548 :                 return ONIG_ENCODING_UNDEF;
     376             :         }
     377             : 
     378      206411 :         for (mapping = enc_name_map; mapping->names != NULL; mapping++) {
     379      828627 :                 for (p = mapping->names; *p != '\0'; p += (strlen(p) + 1)) {
     380      721621 :                         if (strcasecmp(p, pname) == 0) {
     381       99213 :                                 return mapping->code;
     382             :                         }
     383             :                 }
     384             :         }
     385             : 
     386         192 :         return ONIG_ENCODING_UNDEF;
     387             : }
     388             : /* }}} */
     389             : 
     390             : /* {{{ php_mb_regex_mbctype2name */
     391         668 : static const char *_php_mb_regex_mbctype2name(OnigEncoding mbctype)
     392             : {
     393             :         php_mb_regex_enc_name_map_t *mapping;
     394             : 
     395        4256 :         for (mapping = enc_name_map; mapping->names != NULL; mapping++) {
     396        4256 :                 if (mapping->code == mbctype) {
     397         668 :                         return mapping->names;
     398             :                 }
     399             :         }
     400             : 
     401           0 :         return NULL;
     402             : }
     403             : /* }}} */
     404             : 
     405             : /* {{{ php_mb_regex_set_mbctype */
     406       74240 : int php_mb_regex_set_mbctype(const char *encname)
     407             : {
     408       74240 :         OnigEncoding mbctype = _php_mb_regex_name2mbctype(encname);
     409       74240 :         if (mbctype == ONIG_ENCODING_UNDEF) {
     410       49348 :                 return FAILURE;
     411             :         }
     412       24892 :         MBREX(current_mbctype) = mbctype;
     413       24892 :         return SUCCESS;
     414             : }
     415             : /* }}} */
     416             : 
     417             : /* {{{ php_mb_regex_set_default_mbctype */
     418      123588 : int php_mb_regex_set_default_mbctype(const char *encname)
     419             : {
     420      123588 :         OnigEncoding mbctype = _php_mb_regex_name2mbctype(encname);
     421      123588 :         if (mbctype == ONIG_ENCODING_UNDEF) {
     422       49348 :                 return FAILURE;
     423             :         }
     424       74240 :         MBREX(default_mbctype) = mbctype;
     425       74240 :         return SUCCESS;
     426             : }
     427             : /* }}} */
     428             : 
     429             : /* {{{ php_mb_regex_get_mbctype */
     430           0 : const char *php_mb_regex_get_mbctype(void)
     431             : {
     432           0 :         return _php_mb_regex_mbctype2name(MBREX(current_mbctype));
     433             : }
     434             : /* }}} */
     435             : 
     436             : /* {{{ php_mb_regex_get_default_mbctype */
     437           0 : const char *php_mb_regex_get_default_mbctype(void)
     438             : {
     439           0 :         return _php_mb_regex_mbctype2name(MBREX(default_mbctype));
     440             : }
     441             : /* }}} */
     442             : 
     443             : /*
     444             :  * regex cache
     445             :  */
     446             : /* {{{ php_mbregex_compile_pattern */
     447         425 : static php_mb_regex_t *php_mbregex_compile_pattern(const char *pattern, int patlen, OnigOptionType options, OnigEncoding enc, OnigSyntaxType *syntax)
     448             : {
     449         425 :         int err_code = 0;
     450         425 :         php_mb_regex_t *retval = NULL, *rc = NULL;
     451             :         OnigErrorInfo err_info;
     452             :         OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
     453             : 
     454         850 :         rc = zend_hash_str_find_ptr(&MBREX(ht_rc), (char *)pattern, patlen);
     455         425 :         if (!rc || onig_get_options(rc) != options || onig_get_encoding(rc) != enc || onig_get_syntax(rc) != syntax) {
     456         238 :                 if ((err_code = onig_new(&retval, (OnigUChar *)pattern, (OnigUChar *)(pattern + patlen), options, enc, syntax, &err_info)) != ONIG_NORMAL) {
     457           1 :                         onig_error_code_to_str(err_str, err_code, &err_info);
     458           1 :                         php_error_docref(NULL, E_WARNING, "mbregex compile err: %s", err_str);
     459           1 :                         retval = NULL;
     460           1 :                         goto out;
     461             :                 }
     462         237 :                 if (rc == MBREX(search_re)) {
     463             :                         /* reuse the new rc? see bug #72399 */
     464         210 :                         MBREX(search_re) = NULL;
     465             :                 }
     466         474 :                 zend_hash_str_update_ptr(&MBREX(ht_rc), (char *)pattern, patlen, retval);
     467             :         } else {
     468         187 :                 retval = rc;
     469             :         }
     470         425 : out:
     471         425 :         return retval;
     472             : }
     473             : /* }}} */
     474             : 
     475             : /* {{{ _php_mb_regex_get_option_string */
     476           7 : static size_t _php_mb_regex_get_option_string(char *str, size_t len, OnigOptionType option, OnigSyntaxType *syntax)
     477             : {
     478           7 :         size_t len_left = len;
     479           7 :         size_t len_req = 0;
     480           7 :         char *p = str;
     481             :         char c;
     482             : 
     483           7 :         if ((option & ONIG_OPTION_IGNORECASE) != 0) {
     484           0 :                 if (len_left > 0) {
     485           0 :                         --len_left;
     486           0 :                         *(p++) = 'i';
     487             :                 }
     488           0 :                 ++len_req;
     489             :         }
     490             : 
     491           7 :         if ((option & ONIG_OPTION_EXTEND) != 0) {
     492           1 :                 if (len_left > 0) {
     493           1 :                         --len_left;
     494           1 :                         *(p++) = 'x';
     495             :                 }
     496           1 :                 ++len_req;
     497             :         }
     498             : 
     499           7 :         if ((option & (ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE)) ==
     500             :                         (ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE)) {
     501           0 :                 if (len_left > 0) {
     502           0 :                         --len_left;
     503           0 :                         *(p++) = 'p';
     504             :                 }
     505           0 :                 ++len_req;
     506             :         } else {
     507           7 :                 if ((option & ONIG_OPTION_MULTILINE) != 0) {
     508           1 :                         if (len_left > 0) {
     509           1 :                                 --len_left;
     510           1 :                                 *(p++) = 'm';
     511             :                         }
     512           1 :                         ++len_req;
     513             :                 }
     514             : 
     515           7 :                 if ((option & ONIG_OPTION_SINGLELINE) != 0) {
     516           0 :                         if (len_left > 0) {
     517           0 :                                 --len_left;
     518           0 :                                 *(p++) = 's';
     519             :                         }
     520           0 :                         ++len_req;
     521             :                 }
     522             :         }
     523           7 :         if ((option & ONIG_OPTION_FIND_LONGEST) != 0) {
     524           0 :                 if (len_left > 0) {
     525           0 :                         --len_left;
     526           0 :                         *(p++) = 'l';
     527             :                 }
     528           0 :                 ++len_req;
     529             :         }
     530           7 :         if ((option & ONIG_OPTION_FIND_NOT_EMPTY) != 0) {
     531           0 :                 if (len_left > 0) {
     532           0 :                         --len_left;
     533           0 :                         *(p++) = 'n';
     534             :                 }
     535           0 :                 ++len_req;
     536             :         }
     537             : 
     538           7 :         c = 0;
     539             : 
     540           7 :         if (syntax == ONIG_SYNTAX_JAVA) {
     541           0 :                 c = 'j';
     542           7 :         } else if (syntax == ONIG_SYNTAX_GNU_REGEX) {
     543           0 :                 c = 'u';
     544           7 :         } else if (syntax == ONIG_SYNTAX_GREP) {
     545           0 :                 c = 'g';
     546           7 :         } else if (syntax == ONIG_SYNTAX_EMACS) {
     547           0 :                 c = 'c';
     548           7 :         } else if (syntax == ONIG_SYNTAX_RUBY) {
     549           7 :                 c = 'r';
     550           0 :         } else if (syntax == ONIG_SYNTAX_PERL) {
     551           0 :                 c = 'z';
     552           0 :         } else if (syntax == ONIG_SYNTAX_POSIX_BASIC) {
     553           0 :                 c = 'b';
     554           0 :         } else if (syntax == ONIG_SYNTAX_POSIX_EXTENDED) {
     555           0 :                 c = 'd';
     556             :         }
     557             : 
     558           7 :         if (c != 0) {
     559           7 :                 if (len_left > 0) {
     560           7 :                         --len_left;
     561           7 :                         *(p++) = c;
     562             :                 }
     563           7 :                 ++len_req;
     564             :         }
     565             : 
     566             : 
     567           7 :         if (len_left > 0) {
     568           7 :                 --len_left;
     569           7 :                 *(p++) = '\0';
     570             :         }
     571           7 :         ++len_req;
     572           7 :         if (len < len_req) {
     573           0 :                 return len_req;
     574             :         }
     575             : 
     576           7 :         return 0;
     577             : }
     578             : /* }}} */
     579             : 
     580             : /* {{{ _php_mb_regex_init_options */
     581             : static void
     582         119 : _php_mb_regex_init_options(const char *parg, int narg, OnigOptionType *option, OnigSyntaxType **syntax, int *eval)
     583             : {
     584             :         int n;
     585             :         char c;
     586         119 :         int optm = 0;
     587             : 
     588         119 :         *syntax = ONIG_SYNTAX_RUBY;
     589             : 
     590         119 :         if (parg != NULL) {
     591         119 :                 n = 0;
     592         322 :                 while(n < narg) {
     593          84 :                         c = parg[n++];
     594          84 :                         switch (c) {
     595           1 :                                 case 'i':
     596           1 :                                         optm |= ONIG_OPTION_IGNORECASE;
     597           1 :                                         break;
     598           9 :                                 case 'x':
     599           9 :                                         optm |= ONIG_OPTION_EXTEND;
     600           9 :                                         break;
     601           1 :                                 case 'm':
     602           1 :                                         optm |= ONIG_OPTION_MULTILINE;
     603           1 :                                         break;
     604           0 :                                 case 's':
     605           0 :                                         optm |= ONIG_OPTION_SINGLELINE;
     606           0 :                                         break;
     607           0 :                                 case 'p':
     608           0 :                                         optm |= ONIG_OPTION_MULTILINE | ONIG_OPTION_SINGLELINE;
     609           0 :                                         break;
     610           0 :                                 case 'l':
     611           0 :                                         optm |= ONIG_OPTION_FIND_LONGEST;
     612           0 :                                         break;
     613           0 :                                 case 'n':
     614           0 :                                         optm |= ONIG_OPTION_FIND_NOT_EMPTY;
     615           0 :                                         break;
     616           0 :                                 case 'j':
     617           0 :                                         *syntax = ONIG_SYNTAX_JAVA;
     618           0 :                                         break;
     619           0 :                                 case 'u':
     620           0 :                                         *syntax = ONIG_SYNTAX_GNU_REGEX;
     621           0 :                                         break;
     622           0 :                                 case 'g':
     623           0 :                                         *syntax = ONIG_SYNTAX_GREP;
     624           0 :                                         break;
     625           0 :                                 case 'c':
     626           0 :                                         *syntax = ONIG_SYNTAX_EMACS;
     627           0 :                                         break;
     628           0 :                                 case 'r':
     629           0 :                                         *syntax = ONIG_SYNTAX_RUBY;
     630           0 :                                         break;
     631           0 :                                 case 'z':
     632           0 :                                         *syntax = ONIG_SYNTAX_PERL;
     633           0 :                                         break;
     634           0 :                                 case 'b':
     635           0 :                                         *syntax = ONIG_SYNTAX_POSIX_BASIC;
     636           0 :                                         break;
     637           0 :                                 case 'd':
     638           0 :                                         *syntax = ONIG_SYNTAX_POSIX_EXTENDED;
     639           0 :                                         break;
     640           2 :                                 case 'e':
     641           2 :                                         if (eval != NULL) *eval = 1;
     642           2 :                                         break;
     643          71 :                                 default:
     644          71 :                                         break;
     645             :                         }
     646             :                 }
     647         119 :                 if (option != NULL) *option|=optm;
     648             :         }
     649         119 : }
     650             : /* }}} */
     651             : 
     652             : /*
     653             :  * php functions
     654             :  */
     655             : 
     656             : /* {{{ proto string mb_regex_encoding([string encoding])
     657             :    Returns the current encoding for regex as a string. */
     658         241 : PHP_FUNCTION(mb_regex_encoding)
     659             : {
     660         241 :         char *encoding = NULL;
     661             :         size_t encoding_len;
     662             :         OnigEncoding mbctype;
     663             : 
     664         241 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &encoding, &encoding_len) == FAILURE) {
     665           2 :                 return;
     666             :         }
     667             : 
     668         239 :         if (!encoding) {
     669         114 :                 const char *retval = _php_mb_regex_mbctype2name(MBREX(current_mbctype));
     670             : 
     671         114 :                 if (retval == NULL) {
     672           0 :                         RETURN_FALSE;
     673             :                 }
     674             : 
     675         228 :                 RETURN_STRING((char *)retval);
     676             :         } else {
     677         125 :                 mbctype = _php_mb_regex_name2mbctype(encoding);
     678             : 
     679         125 :                 if (mbctype == ONIG_ENCODING_UNDEF) {
     680          44 :                         php_error_docref(NULL, E_WARNING, "Unknown encoding \"%s\"", encoding);
     681          44 :                         RETURN_FALSE;
     682             :                 }
     683             : 
     684          81 :                 MBREX(current_mbctype) = mbctype;
     685          81 :                 RETURN_TRUE;
     686             :         }
     687             : }
     688             : /* }}} */
     689             : 
     690             : /* {{{ _php_mb_regex_ereg_exec */
     691         149 : static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase)
     692             : {
     693         149 :         zval *arg_pattern, *array = NULL;
     694             :         char *string;
     695             :         size_t string_len;
     696             :         php_mb_regex_t *re;
     697         149 :         OnigRegion *regs = NULL;
     698             :         int i, match_len, beg, end;
     699             :         OnigOptionType options;
     700             :         char *str;
     701             : 
     702         149 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|z/", &arg_pattern, &string, &string_len, &array) == FAILURE) {
     703          10 :                 RETURN_FALSE;
     704             :         }
     705             : 
     706         145 :         if (!php_mb_check_encoding(
     707             :         string,
     708             :         string_len,
     709         145 :         _php_mb_regex_mbctype2name(MBREX(current_mbctype))
     710             :         )) {
     711           2 :                 if (array != NULL) {
     712           1 :                         zval_dtor(array);
     713           1 :                         array_init(array);
     714             :                 }
     715           2 :                 RETURN_FALSE;
     716             :         }
     717             : 
     718         143 :         if (array != NULL) {
     719         119 :                 zval_dtor(array);
     720         119 :                 array_init(array);
     721             :         }
     722             : 
     723         143 :         options = MBREX(regex_default_options);
     724         143 :         if (icase) {
     725           9 :                 options |= ONIG_OPTION_IGNORECASE;
     726             :         }
     727             : 
     728             :         /* compile the regular expression from the supplied regex */
     729         286 :         if (Z_TYPE_P(arg_pattern) != IS_STRING) {
     730             :                 /* we convert numbers to integers and treat them as a string */
     731          68 :                 if (Z_TYPE_P(arg_pattern) == IS_DOUBLE) {
     732          10 :                         convert_to_long_ex(arg_pattern);        /* get rid of decimal places */
     733             :                 }
     734         102 :                 convert_to_string_ex(arg_pattern);
     735             :                 /* don't bother doing an extended regex with just a number */
     736             :         }
     737             : 
     738         143 :         if (Z_STRLEN_P(arg_pattern) == 0) {
     739          17 :                 php_error_docref(NULL, E_WARNING, "empty pattern");
     740          17 :                 RETVAL_FALSE;
     741          17 :                 goto out;
     742             :         }
     743             : 
     744         126 :         re = php_mbregex_compile_pattern(Z_STRVAL_P(arg_pattern), Z_STRLEN_P(arg_pattern), options, MBREX(current_mbctype), MBREX(regex_default_syntax));
     745         126 :         if (re == NULL) {
     746           1 :                 RETVAL_FALSE;
     747           1 :                 goto out;
     748             :         }
     749             : 
     750         125 :         regs = onig_region_new();
     751             : 
     752             :         /* actually execute the regular expression */
     753         125 :         if (onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, (OnigUChar *)(string + string_len), regs, 0) < 0) {
     754          50 :                 RETVAL_FALSE;
     755          50 :                 goto out;
     756             :         }
     757             : 
     758          75 :         match_len = 1;
     759          75 :         str = string;
     760          75 :         if (array != NULL) {
     761             : 
     762          65 :                 match_len = regs->end[0] - regs->beg[0];
     763         187 :                 for (i = 0; i < regs->num_regs; i++) {
     764         122 :                         beg = regs->beg[i];
     765         122 :                         end = regs->end[i];
     766         122 :                         if (beg >= 0 && beg < end && (size_t)end <= string_len) {
     767         118 :                                 add_index_stringl(array, i, (char *)&str[beg], end - beg);
     768             :                         } else {
     769           4 :                                 add_index_bool(array, i, 0);
     770             :                         }
     771             :                 }
     772             :         }
     773             : 
     774          75 :         if (match_len == 0) {
     775           4 :                 match_len = 1;
     776             :         }
     777          75 :         RETVAL_LONG(match_len);
     778         143 : out:
     779         143 :         if (regs != NULL) {
     780         125 :                 onig_region_free(regs, 1);
     781             :         }
     782             : }
     783             : /* }}} */
     784             : 
     785             : /* {{{ proto int mb_ereg(string pattern, string string [, array registers])
     786             :    Regular expression match for multibyte string */
     787         138 : PHP_FUNCTION(mb_ereg)
     788             : {
     789         138 :         _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
     790         138 : }
     791             : /* }}} */
     792             : 
     793             : /* {{{ proto int mb_eregi(string pattern, string string [, array registers])
     794             :    Case-insensitive regular expression match for multibyte string */
     795          11 : PHP_FUNCTION(mb_eregi)
     796             : {
     797          11 :         _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     798          11 : }
     799             : /* }}} */
     800             : 
     801             : /* {{{ _php_mb_regex_ereg_replace_exec */
     802         194 : static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOptionType options, int is_callable)
     803             : {
     804             :         zval *arg_pattern_zval;
     805             : 
     806             :         char *arg_pattern;
     807             :         size_t arg_pattern_len;
     808             : 
     809             :         char *replace;
     810             :         size_t replace_len;
     811             : 
     812             :         zend_fcall_info arg_replace_fci;
     813             :         zend_fcall_info_cache arg_replace_fci_cache;
     814             : 
     815             :         char *string;
     816             :         size_t string_len;
     817             : 
     818             :         char *p;
     819             :         php_mb_regex_t *re;
     820             :         OnigSyntaxType *syntax;
     821         194 :         OnigRegion *regs = NULL;
     822         194 :         smart_str out_buf = {0};
     823         194 :         smart_str eval_buf = {0};
     824             :         smart_str *pbuf;
     825             :         size_t i;
     826             :         int err, eval, n;
     827             :         OnigUChar *pos;
     828             :         OnigUChar *string_lim;
     829         194 :         char *description = NULL;
     830             :         char pat_buf[6];
     831             : 
     832             :         const mbfl_encoding *enc;
     833             : 
     834             :         {
     835             :                 const char *current_enc_name;
     836         194 :                 current_enc_name = _php_mb_regex_mbctype2name(MBREX(current_mbctype));
     837         194 :                 if (current_enc_name == NULL ||
     838             :                         (enc = mbfl_name2encoding(current_enc_name)) == NULL) {
     839           0 :                         php_error_docref(NULL, E_WARNING, "Unknown error");
     840           7 :                         RETURN_FALSE;
     841             :                 }
     842             :         }
     843         194 :         eval = 0;
     844             :         {
     845         194 :                 char *option_str = NULL;
     846         194 :                 size_t option_str_len = 0;
     847             : 
     848         194 :                 if (!is_callable) {
     849         192 :                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zss|s",
     850             :                                                 &arg_pattern_zval,
     851             :                                                 &replace, &replace_len,
     852             :                                                 &string, &string_len,
     853             :                                                 &option_str, &option_str_len) == FAILURE) {
     854          11 :                                 RETURN_FALSE;
     855             :                         }
     856             :                 } else {
     857           2 :                         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zfs|s",
     858             :                                                 &arg_pattern_zval,
     859             :                                                 &arg_replace_fci, &arg_replace_fci_cache,
     860             :                                                 &string, &string_len,
     861             :                                                 &option_str, &option_str_len) == FAILURE) {
     862           0 :                                 RETURN_FALSE;
     863             :                         }
     864             :                 }
     865             : 
     866         189 :                 if (!php_mb_check_encoding(
     867             :                 string,
     868             :                 string_len,
     869         189 :                 _php_mb_regex_mbctype2name(MBREX(current_mbctype))
     870             :                 )) {
     871           1 :                         RETURN_NULL();
     872             :                 }
     873             : 
     874         188 :                 if (option_str != NULL) {
     875          95 :                         _php_mb_regex_init_options(option_str, option_str_len, &options, &syntax, &eval);
     876             :                 } else {
     877          93 :                         options |= MBREX(regex_default_options);
     878          93 :                         syntax = MBREX(regex_default_syntax);
     879             :                 }
     880             :         }
     881         190 :         if (eval && !is_callable) {
     882           2 :                 php_error_docref(NULL, E_DEPRECATED, "The 'e' option is deprecated, use mb_ereg_replace_callback instead");
     883             :         }
     884         376 :         if (Z_TYPE_P(arg_pattern_zval) == IS_STRING) {
     885         169 :                 arg_pattern = Z_STRVAL_P(arg_pattern_zval);
     886         169 :                 arg_pattern_len = Z_STRLEN_P(arg_pattern_zval);
     887             :         } else {
     888             :                 /* FIXME: this code is not multibyte aware! */
     889          38 :                 convert_to_long_ex(arg_pattern_zval);
     890          19 :                 pat_buf[0] = (char)Z_LVAL_P(arg_pattern_zval);
     891          19 :                 pat_buf[1] = '\0';
     892          19 :                 pat_buf[2] = '\0';
     893          19 :                 pat_buf[3] = '\0';
     894          19 :                 pat_buf[4] = '\0';
     895          19 :                 pat_buf[5] = '\0';
     896             : 
     897          19 :                 arg_pattern = pat_buf;
     898          19 :                 arg_pattern_len = 1;
     899             :         }
     900             :         /* create regex pattern buffer */
     901         188 :         re = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, options, MBREX(current_mbctype), syntax);
     902         188 :         if (re == NULL) {
     903           0 :                 RETURN_FALSE;
     904             :         }
     905             : 
     906         188 :         if (eval || is_callable) {
     907           4 :                 pbuf = &eval_buf;
     908           4 :                 description = zend_make_compiled_string_description("mbregex replace");
     909             :         } else {
     910         184 :                 pbuf = &out_buf;
     911         184 :                 description = NULL;
     912             :         }
     913             : 
     914         188 :         if (is_callable) {
     915           2 :                 if (eval) {
     916           0 :                         php_error_docref(NULL, E_WARNING, "Option 'e' cannot be used with replacement callback");
     917           0 :                         RETURN_FALSE;
     918             :                 }
     919             :         }
     920             : 
     921             :         /* do the actual work */
     922         188 :         err = 0;
     923         188 :         pos = (OnigUChar *)string;
     924         188 :         string_lim = (OnigUChar*)(string + string_len);
     925         188 :         regs = onig_region_new();
     926         909 :         while (err >= 0) {
     927         534 :                 err = onig_search(re, (OnigUChar *)string, (OnigUChar *)string_lim, pos, (OnigUChar *)string_lim, regs, 0);
     928         534 :                 if (err <= -2) {
     929             :                         OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
     930           0 :                         onig_error_code_to_str(err_str, err);
     931           0 :                         php_error_docref(NULL, E_WARNING, "mbregex search failure in php_mbereg_replace_exec(): %s", err_str);
     932           0 :                         break;
     933             :                 }
     934         534 :                 if (err >= 0) {
     935             : #if moriyoshi_0
     936             :                         if (regs->beg[0] == regs->end[0]) {
     937             :                                 php_error_docref(NULL, E_WARNING, "Empty regular expression");
     938             :                                 break;
     939             :                         }
     940             : #endif
     941             :                         /* copy the part of the string before the match */
     942         347 :                         smart_str_appendl(&out_buf, (char *)pos, (size_t)((OnigUChar *)(string + regs->beg[0]) - pos));
     943             : 
     944         347 :                         if (!is_callable) {
     945             :                                 /* copy replacement and backrefs */
     946         342 :                                 i = 0;
     947         342 :                                 p = replace;
     948        1710 :                                 while (i < replace_len) {
     949        1026 :                                         int fwd = (int) php_mb_mbchar_bytes_ex(p, enc);
     950        1026 :                                         n = -1;
     951        1788 :                                         if ((replace_len - i) >= 2 && fwd == 1 &&
     952         779 :                                         p[0] == '\\' && p[1] >= '0' && p[1] <= '9') {
     953          14 :                                                 n = p[1] - '0';
     954             :                                         }
     955        1026 :                                         if (n >= 0 && n < regs->num_regs) {
     956          13 :                                                 if (regs->beg[n] >= 0 && regs->beg[n] < regs->end[n] && (size_t)regs->end[n] <= string_len) {
     957          13 :                                                         smart_str_appendl(pbuf, string + regs->beg[n], regs->end[n] - regs->beg[n]);
     958             :                                                 }
     959          13 :                                                 p += 2;
     960          13 :                                                 i += 2;
     961             :                                         } else {
     962        1013 :                                                 smart_str_appendl(pbuf, p, fwd);
     963        1013 :                                                 p += fwd;
     964        1013 :                                                 i += fwd;
     965             :                                         }
     966             :                                 }
     967             :                         }
     968             : 
     969         347 :                         if (eval) {
     970             :                                 zval v;
     971             :                                 zend_string *eval_str;
     972             :                                 /* null terminate buffer */
     973             :                                 smart_str_0(&eval_buf);
     974             : 
     975           2 :                                 if (eval_buf.s) {
     976           1 :                                         eval_str = eval_buf.s;
     977             :                                 } else {
     978           1 :                                         eval_str = ZSTR_EMPTY_ALLOC();
     979             :                                 }
     980             : 
     981             :                                 /* do eval */
     982           2 :                                 if (zend_eval_stringl(ZSTR_VAL(eval_str), ZSTR_LEN(eval_str), &v, description) == FAILURE) {
     983           1 :                                         efree(description);
     984           1 :                                         zend_throw_error(NULL, "Failed evaluating code: %s%s", PHP_EOL, ZSTR_VAL(eval_str));
     985           1 :                                         onig_region_free(regs, 0);
     986             :                                         smart_str_free(&out_buf);
     987             :                                         smart_str_free(&eval_buf);
     988           1 :                                         RETURN_FALSE;
     989             :                                 }
     990             : 
     991             :                                 /* result of eval */
     992           1 :                                 convert_to_string(&v);
     993           1 :                                 smart_str_appendl(&out_buf, Z_STRVAL(v), Z_STRLEN(v));
     994             :                                 /* Clean up */
     995             :                                 smart_str_free(&eval_buf);
     996             :                                 zval_dtor(&v);
     997         345 :                         } else if (is_callable) {
     998             :                                 zval args[1];
     999             :                                 zval subpats, retval;
    1000             :                                 int i;
    1001             : 
    1002           5 :                                 array_init(&subpats);
    1003          14 :                                 for (i = 0; i < regs->num_regs; i++) {
    1004           9 :                                         add_next_index_stringl(&subpats, string + regs->beg[i], regs->end[i] - regs->beg[i]);
    1005             :                                 }
    1006             : 
    1007           5 :                                 ZVAL_COPY_VALUE(&args[0], &subpats);
    1008             :                                 /* null terminate buffer */
    1009             :                                 smart_str_0(&eval_buf);
    1010             : 
    1011           5 :                                 arg_replace_fci.param_count = 1;
    1012           5 :                                 arg_replace_fci.params = args;
    1013           5 :                                 arg_replace_fci.retval = &retval;
    1014          10 :                                 if (zend_call_function(&arg_replace_fci, &arg_replace_fci_cache) == SUCCESS &&
    1015           5 :                                                 !Z_ISUNDEF(retval)) {
    1016           4 :                                         convert_to_string_ex(&retval);
    1017           4 :                                         smart_str_appendl(&out_buf, Z_STRVAL(retval), Z_STRLEN(retval));
    1018             :                                         smart_str_free(&eval_buf);
    1019           4 :                                         zval_ptr_dtor(&retval);
    1020             :                                 } else {
    1021           1 :                                         if (!EG(exception)) {
    1022           0 :                                                 php_error_docref(NULL, E_WARNING, "Unable to call custom replacement function");
    1023             :                                         }
    1024             :                                 }
    1025           5 :                                 zval_ptr_dtor(&subpats);
    1026             :                         }
    1027             : 
    1028         346 :                         n = regs->end[0];
    1029         346 :                         if ((pos - (OnigUChar *)string) < n) {
    1030         318 :                                 pos = (OnigUChar *)string + n;
    1031             :                         } else {
    1032          28 :                                 if (pos < string_lim) {
    1033             :                                         smart_str_appendl(&out_buf, (char *)pos, 1);
    1034             :                                 }
    1035          28 :                                 pos++;
    1036             :                         }
    1037             :                 } else { /* nomatch */
    1038             :                         /* stick that last bit of string on our output */
    1039         187 :                         if (string_lim - pos > 0) {
    1040         131 :                                 smart_str_appendl(&out_buf, (char *)pos, string_lim - pos);
    1041             :                         }
    1042             :                 }
    1043         533 :                 onig_region_free(regs, 0);
    1044             :         }
    1045             : 
    1046         187 :         if (description) {
    1047           3 :                 efree(description);
    1048             :         }
    1049         187 :         if (regs != NULL) {
    1050         187 :                 onig_region_free(regs, 1);
    1051             :         }
    1052             :         smart_str_free(&eval_buf);
    1053             : 
    1054         187 :         if (err <= -2) {
    1055             :                 smart_str_free(&out_buf);
    1056           0 :                 RETVAL_FALSE;
    1057         187 :         } else if (out_buf.s) {
    1058             :                 smart_str_0(&out_buf);
    1059         177 :                 RETVAL_STR(out_buf.s);
    1060             :         } else {
    1061          10 :                 RETVAL_EMPTY_STRING();
    1062             :         }
    1063             : }
    1064             : /* }}} */
    1065             : 
    1066             : /* {{{ proto string mb_ereg_replace(string pattern, string replacement, string string [, string option])
    1067             :    Replace regular expression for multibyte string */
    1068         125 : PHP_FUNCTION(mb_ereg_replace)
    1069             : {
    1070         125 :         _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
    1071         125 : }
    1072             : /* }}} */
    1073             : 
    1074             : /* {{{ proto string mb_eregi_replace(string pattern, string replacement, string string)
    1075             :    Case insensitive replace regular expression for multibyte string */
    1076          67 : PHP_FUNCTION(mb_eregi_replace)
    1077             : {
    1078          67 :         _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, ONIG_OPTION_IGNORECASE, 0);
    1079          67 : }
    1080             : /* }}} */
    1081             : 
    1082             : /* {{{ proto string mb_ereg_replace_callback(string pattern, string callback, string string [, string option])
    1083             :     regular expression for multibyte string using replacement callback */
    1084           2 : PHP_FUNCTION(mb_ereg_replace_callback)
    1085             : {
    1086           2 :         _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
    1087           2 : }
    1088             : /* }}} */
    1089             : 
    1090             : /* {{{ proto array mb_split(string pattern, string string [, int limit])
    1091             :    split multibyte string into array by regular expression */
    1092          87 : PHP_FUNCTION(mb_split)
    1093             : {
    1094             :         char *arg_pattern;
    1095             :         size_t arg_pattern_len;
    1096             :         php_mb_regex_t *re;
    1097          87 :         OnigRegion *regs = NULL;
    1098             :         char *string;
    1099             :         OnigUChar *pos, *chunk_pos;
    1100             :         size_t string_len;
    1101             : 
    1102             :         int n, err;
    1103          87 :         zend_long count = -1;
    1104             : 
    1105          87 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|l", &arg_pattern, &arg_pattern_len, &string, &string_len, &count) == FAILURE) {
    1106          22 :                 RETURN_FALSE;
    1107             :         }
    1108             : 
    1109          76 :         if (count > 0) {
    1110          60 :                 count--;
    1111             :         }
    1112             : 
    1113             :         /* create regex pattern buffer */
    1114          76 :         if ((re = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, MBREX(regex_default_options), MBREX(current_mbctype), MBREX(regex_default_syntax))) == NULL) {
    1115           0 :                 RETURN_FALSE;
    1116             :         }
    1117             : 
    1118          76 :         array_init(return_value);
    1119             : 
    1120          76 :         chunk_pos = pos = (OnigUChar *)string;
    1121          76 :         err = 0;
    1122          76 :         regs = onig_region_new();
    1123             :         /* churn through str, generating array entries as we go */
    1124         333 :         while (count != 0 && (pos - (OnigUChar *)string) < (ptrdiff_t)string_len) {
    1125             :                 int beg, end;
    1126         214 :                 err = onig_search(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), pos, (OnigUChar *)(string + string_len), regs, 0);
    1127         214 :                 if (err < 0) {
    1128          33 :                         break;
    1129             :                 }
    1130         181 :                 beg = regs->beg[0], end = regs->end[0];
    1131             :                 /* add it to the array */
    1132         181 :                 if ((pos - (OnigUChar *)string) < end) {
    1133          74 :                         if ((size_t)beg < string_len && beg >= (chunk_pos - (OnigUChar *)string)) {
    1134          74 :                                 add_next_index_stringl(return_value, (char *)chunk_pos, ((OnigUChar *)(string + beg) - chunk_pos));
    1135          74 :                                 --count;
    1136             :                         } else {
    1137           0 :                                 err = -2;
    1138           0 :                                 break;
    1139             :                         }
    1140             :                         /* point at our new starting point */
    1141          74 :                         chunk_pos = pos = (OnigUChar *)string + end;
    1142             :                 } else {
    1143         107 :                         pos++;
    1144             :                 }
    1145         181 :                 onig_region_free(regs, 0);
    1146             :         }
    1147             : 
    1148          76 :         onig_region_free(regs, 1);
    1149             : 
    1150             :         /* see if we encountered an error */
    1151          76 :         if (err <= -2) {
    1152             :                 OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
    1153           0 :                 onig_error_code_to_str(err_str, err);
    1154           0 :                 php_error_docref(NULL, E_WARNING, "mbregex search failure in mbsplit(): %s", err_str);
    1155             :                 zval_dtor(return_value);
    1156           0 :                 RETURN_FALSE;
    1157             :         }
    1158             : 
    1159             :         /* otherwise we just have one last element to add to the array */
    1160          76 :         n = ((OnigUChar *)(string + string_len) - chunk_pos);
    1161          76 :         if (n > 0) {
    1162          61 :                 add_next_index_stringl(return_value, (char *)chunk_pos, n);
    1163             :         } else {
    1164          15 :                 add_next_index_stringl(return_value, "", 0);
    1165             :         }
    1166             : }
    1167             : /* }}} */
    1168             : 
    1169             : /* {{{ proto bool mb_ereg_match(string pattern, string string [,string option])
    1170             :    Regular expression match for multibyte string */
    1171           7 : PHP_FUNCTION(mb_ereg_match)
    1172             : {
    1173             :         char *arg_pattern;
    1174             :         size_t arg_pattern_len;
    1175             : 
    1176             :         char *string;
    1177             :         size_t string_len;
    1178             : 
    1179             :         php_mb_regex_t *re;
    1180             :         OnigSyntaxType *syntax;
    1181           7 :         OnigOptionType option = 0;
    1182             :         int err;
    1183             : 
    1184             :         {
    1185           7 :                 char *option_str = NULL;
    1186           7 :                 size_t option_str_len = 0;
    1187             : 
    1188           7 :                 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s",
    1189             :                                           &arg_pattern, &arg_pattern_len, &string, &string_len,
    1190             :                                           &option_str, &option_str_len)==FAILURE) {
    1191           3 :                         RETURN_FALSE;
    1192             :                 }
    1193             : 
    1194           4 :                 if (option_str != NULL) {
    1195           1 :                         _php_mb_regex_init_options(option_str, option_str_len, &option, &syntax, NULL);
    1196             :                 } else {
    1197           3 :                         option |= MBREX(regex_default_options);
    1198           3 :                         syntax = MBREX(regex_default_syntax);
    1199             :                 }
    1200             :         }
    1201             : 
    1202           4 :         if ((re = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, option, MBREX(current_mbctype), syntax)) == NULL) {
    1203           0 :                 RETURN_FALSE;
    1204             :         }
    1205             : 
    1206             :         /* match */
    1207           4 :         err = onig_match(re, (OnigUChar *)string, (OnigUChar *)(string + string_len), (OnigUChar *)string, NULL, 0);
    1208           4 :         if (err >= 0) {
    1209           2 :                 RETVAL_TRUE;
    1210             :         } else {
    1211           2 :                 RETVAL_FALSE;
    1212             :         }
    1213             : }
    1214             : /* }}} */
    1215             : 
    1216             : /* regex search */
    1217             : /* {{{ _php_mb_regex_ereg_search_exec */
    1218             : static void
    1219          81 : _php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAMETERS, int mode)
    1220             : {
    1221          81 :         char *arg_pattern = NULL, *arg_options = NULL;
    1222             :         size_t arg_pattern_len, arg_options_len;
    1223             :         int n, i, err, pos, len, beg, end;
    1224             :         OnigOptionType option;
    1225             :         OnigUChar *str;
    1226             :         OnigSyntaxType *syntax;
    1227             : 
    1228          81 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ss", &arg_pattern, &arg_pattern_len, &arg_options, &arg_options_len) == FAILURE) {
    1229           2 :                 return;
    1230             :         }
    1231             : 
    1232          81 :         option = MBREX(regex_default_options);
    1233             : 
    1234          81 :         if (arg_options) {
    1235           0 :                 option = 0;
    1236           0 :                 _php_mb_regex_init_options(arg_options, arg_options_len, &option, &syntax, NULL);
    1237             :         }
    1238             : 
    1239          81 :         if (arg_pattern) {
    1240             :                 /* create regex pattern buffer */
    1241          12 :                 if ((MBREX(search_re) = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, option, MBREX(current_mbctype), MBREX(regex_default_syntax))) == NULL) {
    1242           0 :                         RETURN_FALSE;
    1243             :                 }
    1244             :         }
    1245             : 
    1246          81 :         pos = MBREX(search_pos);
    1247          81 :         str = NULL;
    1248          81 :         len = 0;
    1249         242 :         if (!Z_ISUNDEF(MBREX(search_str)) && Z_TYPE(MBREX(search_str)) == IS_STRING){
    1250          80 :                 str = (OnigUChar *)Z_STRVAL(MBREX(search_str));
    1251          80 :                 len = Z_STRLEN(MBREX(search_str));
    1252             :         }
    1253             : 
    1254          81 :         if (MBREX(search_re) == NULL) {
    1255           2 :                 php_error_docref(NULL, E_WARNING, "No regex given");
    1256           2 :                 RETURN_FALSE;
    1257             :         }
    1258             : 
    1259          79 :         if (str == NULL) {
    1260           0 :                 php_error_docref(NULL, E_WARNING, "No string given");
    1261           0 :                 RETURN_FALSE;
    1262             :         }
    1263             : 
    1264          79 :         if (MBREX(search_regs)) {
    1265          56 :                 onig_region_free(MBREX(search_regs), 1);
    1266             :         }
    1267          79 :         MBREX(search_regs) = onig_region_new();
    1268             : 
    1269          79 :         err = onig_search(MBREX(search_re), str, str + len, str + pos, str  + len, MBREX(search_regs), 0);
    1270          79 :         if (err == ONIG_MISMATCH) {
    1271          18 :                 MBREX(search_pos) = len;
    1272          18 :                 RETVAL_FALSE;
    1273          61 :         } else if (err <= -2) {
    1274             :                 OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
    1275           0 :                 onig_error_code_to_str(err_str, err);
    1276           0 :                 php_error_docref(NULL, E_WARNING, "mbregex search failure in mbregex_search(): %s", err_str);
    1277           0 :                 RETVAL_FALSE;
    1278             :         } else {
    1279          61 :                 switch (mode) {
    1280          45 :                 case 1:
    1281          45 :                         array_init(return_value);
    1282          45 :                         beg = MBREX(search_regs)->beg[0];
    1283          45 :                         end = MBREX(search_regs)->end[0];
    1284          45 :                         add_next_index_long(return_value, beg);
    1285          45 :                         add_next_index_long(return_value, end - beg);
    1286          45 :                         break;
    1287           5 :                 case 2:
    1288           5 :                         array_init(return_value);
    1289           5 :                         n = MBREX(search_regs)->num_regs;
    1290          10 :                         for (i = 0; i < n; i++) {
    1291           5 :                                 beg = MBREX(search_regs)->beg[i];
    1292           5 :                                 end = MBREX(search_regs)->end[i];
    1293           5 :                                 if (beg >= 0 && beg <= end && end <= len) {
    1294           5 :                                         add_index_stringl(return_value, i, (char *)&str[beg], end - beg);
    1295             :                                 } else {
    1296           0 :                                         add_index_bool(return_value, i, 0);
    1297             :                                 }
    1298             :                         }
    1299           5 :                         break;
    1300          11 :                 default:
    1301          11 :                         RETVAL_TRUE;
    1302          11 :                         break;
    1303             :                 }
    1304          61 :                 end = MBREX(search_regs)->end[0];
    1305          61 :                 if (pos <= end) {
    1306          61 :                         MBREX(search_pos) = end;
    1307             :                 } else {
    1308           0 :                         MBREX(search_pos) = pos + 1;
    1309             :                 }
    1310             :         }
    1311             : 
    1312          79 :         if (err < 0) {
    1313          18 :                 onig_region_free(MBREX(search_regs), 1);
    1314          18 :                 MBREX(search_regs) = (OnigRegion *)NULL;
    1315             :         }
    1316             : }
    1317             : /* }}} */
    1318             : 
    1319             : /* {{{ proto bool mb_ereg_search([string pattern[, string option]])
    1320             :    Regular expression search for multibyte string */
    1321          12 : PHP_FUNCTION(mb_ereg_search)
    1322             : {
    1323          12 :         _php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1324          12 : }
    1325             : /* }}} */
    1326             : 
    1327             : /* {{{ proto array mb_ereg_search_pos([string pattern[, string option]])
    1328             :    Regular expression search for multibyte string */
    1329          62 : PHP_FUNCTION(mb_ereg_search_pos)
    1330             : {
    1331          62 :         _php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1332          62 : }
    1333             : /* }}} */
    1334             : 
    1335             : /* {{{ proto array mb_ereg_search_regs([string pattern[, string option]])
    1336             :    Regular expression search for multibyte string */
    1337           7 : PHP_FUNCTION(mb_ereg_search_regs)
    1338             : {
    1339           7 :         _php_mb_regex_ereg_search_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
    1340           7 : }
    1341             : /* }}} */
    1342             : 
    1343             : /* {{{ proto bool mb_ereg_search_init(string string [, string pattern[, string option]])
    1344             :    Initialize string and regular expression for search. */
    1345          30 : PHP_FUNCTION(mb_ereg_search_init)
    1346             : {
    1347          30 :         size_t argc = ZEND_NUM_ARGS();
    1348             :         zend_string *arg_str;
    1349          30 :         char *arg_pattern = NULL, *arg_options = NULL;
    1350          30 :         size_t arg_pattern_len = 0, arg_options_len = 0;
    1351          30 :         OnigSyntaxType *syntax = NULL;
    1352             :         OnigOptionType option;
    1353             : 
    1354          30 :         if (zend_parse_parameters(argc, "S|ss", &arg_str, &arg_pattern, &arg_pattern_len, &arg_options, &arg_options_len) == FAILURE) {
    1355           7 :                 return;
    1356             :         }
    1357             : 
    1358          27 :         if (argc > 1 && arg_pattern_len == 0) {
    1359           1 :                 php_error_docref(NULL, E_WARNING, "Empty pattern");
    1360           1 :                 RETURN_FALSE;
    1361             :         }
    1362             : 
    1363          26 :         option = MBREX(regex_default_options);
    1364          26 :         syntax = MBREX(regex_default_syntax);
    1365             : 
    1366          26 :         if (argc == 3) {
    1367          16 :                 option = 0;
    1368          16 :                 _php_mb_regex_init_options(arg_options, arg_options_len, &option, &syntax, NULL);
    1369             :         }
    1370             : 
    1371          26 :         if (argc > 1) {
    1372             :                 /* create regex pattern buffer */
    1373          19 :                 if ((MBREX(search_re) = php_mbregex_compile_pattern(arg_pattern, arg_pattern_len, option, MBREX(current_mbctype), syntax)) == NULL) {
    1374           0 :                         RETURN_FALSE;
    1375             :                 }
    1376             :         }
    1377             : 
    1378          52 :         if (!Z_ISNULL(MBREX(search_str))) {
    1379          26 :                 zval_ptr_dtor(&MBREX(search_str));
    1380             :         }
    1381             : 
    1382          26 :         ZVAL_STR_COPY(&MBREX(search_str), arg_str);
    1383             : 
    1384          78 :         if (php_mb_check_encoding(
    1385          26 :         ZSTR_VAL(arg_str),
    1386          26 :         ZSTR_LEN(arg_str),
    1387          26 :         _php_mb_regex_mbctype2name(MBREX(current_mbctype))
    1388             :         )) {
    1389          25 :                 MBREX(search_pos) = 0;
    1390          25 :                 RETVAL_TRUE;
    1391             :         } else {
    1392           1 :                 MBREX(search_pos) = ZSTR_LEN(arg_str);
    1393           1 :                 RETVAL_FALSE;
    1394             :         }
    1395             : 
    1396          26 :         if (MBREX(search_regs) != NULL) {
    1397           0 :                 onig_region_free(MBREX(search_regs), 1);
    1398           0 :                 MBREX(search_regs) = NULL;
    1399             :         }
    1400             : }
    1401             : /* }}} */
    1402             : 
    1403             : /* {{{ proto array mb_ereg_search_getregs(void)
    1404             :    Get matched substring of the last time */
    1405          50 : PHP_FUNCTION(mb_ereg_search_getregs)
    1406             : {
    1407             :         int n, i, len, beg, end;
    1408             :         OnigUChar *str;
    1409             : 
    1410         150 :         if (MBREX(search_regs) != NULL && Z_TYPE(MBREX(search_str)) == IS_STRING) {
    1411          50 :                 array_init(return_value);
    1412             : 
    1413          50 :                 str = (OnigUChar *)Z_STRVAL(MBREX(search_str));
    1414          50 :                 len = Z_STRLEN(MBREX(search_str));
    1415          50 :                 n = MBREX(search_regs)->num_regs;
    1416         144 :                 for (i = 0; i < n; i++) {
    1417          94 :                         beg = MBREX(search_regs)->beg[i];
    1418          94 :                         end = MBREX(search_regs)->end[i];
    1419          94 :                         if (beg >= 0 && beg <= end && end <= len) {
    1420          94 :                                 add_index_stringl(return_value, i, (char *)&str[beg], end - beg);
    1421             :                         } else {
    1422           0 :                                 add_index_bool(return_value, i, 0);
    1423             :                         }
    1424             :                 }
    1425             :         } else {
    1426           0 :                 RETVAL_FALSE;
    1427             :         }
    1428          50 : }
    1429             : /* }}} */
    1430             : 
    1431             : /* {{{ proto int mb_ereg_search_getpos(void)
    1432             :    Get search start position */
    1433          63 : PHP_FUNCTION(mb_ereg_search_getpos)
    1434             : {
    1435          63 :         RETVAL_LONG(MBREX(search_pos));
    1436          63 : }
    1437             : /* }}} */
    1438             : 
    1439             : /* {{{ proto bool mb_ereg_search_setpos(int position)
    1440             :    Set search start position */
    1441          11 : PHP_FUNCTION(mb_ereg_search_setpos)
    1442             : {
    1443             :         zend_long position;
    1444             : 
    1445          11 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
    1446           0 :                 return;
    1447             :         }
    1448             : 
    1449             :         /* Accept negative position if length of search string can be determined */
    1450          18 :         if ((position < 0) && (!Z_ISUNDEF(MBREX(search_str))) && (Z_TYPE(MBREX(search_str)) == IS_STRING)) {
    1451           3 :                 position += Z_STRLEN(MBREX(search_str));
    1452             :         }
    1453             : 
    1454          28 :         if (position < 0 || (!Z_ISUNDEF(MBREX(search_str)) && Z_TYPE(MBREX(search_str)) == IS_STRING && (size_t)position > Z_STRLEN(MBREX(search_str)))) {
    1455           4 :                 php_error_docref(NULL, E_WARNING, "Position is out of range");
    1456           4 :                 MBREX(search_pos) = 0;
    1457           4 :                 RETURN_FALSE;
    1458             :         }
    1459             : 
    1460           7 :         MBREX(search_pos) = position;
    1461           7 :         RETURN_TRUE;
    1462             : }
    1463             : /* }}} */
    1464             : 
    1465             : /* {{{ php_mb_regex_set_options */
    1466           7 : static void _php_mb_regex_set_options(OnigOptionType options, OnigSyntaxType *syntax, OnigOptionType *prev_options, OnigSyntaxType **prev_syntax)
    1467             : {
    1468           7 :         if (prev_options != NULL) {
    1469           0 :                 *prev_options = MBREX(regex_default_options);
    1470             :         }
    1471           7 :         if (prev_syntax != NULL) {
    1472           0 :                 *prev_syntax = MBREX(regex_default_syntax);
    1473             :         }
    1474           7 :         MBREX(regex_default_options) = options;
    1475           7 :         MBREX(regex_default_syntax) = syntax;
    1476           7 : }
    1477             : /* }}} */
    1478             : 
    1479             : /* {{{ proto string mb_regex_set_options([string options])
    1480             :    Set or get the default options for mbregex functions */
    1481           7 : PHP_FUNCTION(mb_regex_set_options)
    1482             : {
    1483             :         OnigOptionType opt;
    1484             :         OnigSyntaxType *syntax;
    1485           7 :         char *string = NULL;
    1486             :         size_t string_len;
    1487             :         char buf[16];
    1488             : 
    1489           7 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s",
    1490             :                                   &string, &string_len) == FAILURE) {
    1491           0 :                 RETURN_FALSE;
    1492             :         }
    1493           7 :         if (string != NULL) {
    1494           7 :                 opt = 0;
    1495           7 :                 syntax = NULL;
    1496           7 :                 _php_mb_regex_init_options(string, string_len, &opt, &syntax, NULL);
    1497           7 :                 _php_mb_regex_set_options(opt, syntax, NULL, NULL);
    1498             :         } else {
    1499           0 :                 opt = MBREX(regex_default_options);
    1500           0 :                 syntax = MBREX(regex_default_syntax);
    1501             :         }
    1502           7 :         _php_mb_regex_get_option_string(buf, sizeof(buf), opt, syntax);
    1503             : 
    1504          14 :         RETVAL_STRING(buf);
    1505             : }
    1506             : /* }}} */
    1507             : 
    1508             : #endif  /* HAVE_MBREGEX */
    1509             : 
    1510             : /*
    1511             :  * Local variables:
    1512             :  * tab-width: 4
    1513             :  * c-basic-offset: 4
    1514             :  * End:
    1515             :  * vim600: fdm=marker
    1516             :  * vim: noet sw=4 ts=4
    1517             :  */

Generated by: LCOV version 1.10

Generated at Sat, 08 Dec 2018 23:47:40 +0000 (8 days ago)

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