Back to index

php5  5.3.10
mbstring.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>              |
00016    |         Rui Hirokawa <hirokawa@php.net>                              |
00017    +----------------------------------------------------------------------+
00018  */
00019 
00020 /* $Id: mbstring.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 /*
00023  * PHP 4 Multibyte String module "mbstring"
00024  *
00025  * History:
00026  *   2000.5.19  Release php-4.0RC2_jstring-1.0
00027  *   2001.4.1   Release php4_jstring-1.0.91
00028  *   2001.4.30  Release php4_jstring-1.1 (contribute to The PHP Group)
00029  *   2001.5.1   Renamed from jstring to mbstring (hirokawa@php.net)
00030  */
00031 
00032 /*
00033  * PHP3 Internationalization support program.
00034  *
00035  * Copyright (c) 1999,2000 by the PHP3 internationalization team.
00036  * All rights reserved.
00037  *
00038  * See README_PHP3-i18n-ja for more detail.
00039  *
00040  * Authors:
00041  *    Hironori Sato <satoh@jpnnet.com>
00042  *    Shigeru Kanemoto <sgk@happysize.co.jp>
00043  *    Tsukada Takuya <tsukada@fminn.nagano.nagano.jp>
00044  *    Rui Hirokawa <rui_hirokawa@ybb.ne.jp>
00045  */
00046 
00047 /* {{{ includes */
00048 #ifdef HAVE_CONFIG_H
00049 #include "config.h"
00050 #endif
00051 
00052 #include "php.h"
00053 #include "php_ini.h"
00054 #include "php_variables.h"
00055 #include "mbstring.h"
00056 #include "ext/standard/php_string.h"
00057 #include "ext/standard/php_mail.h"
00058 #include "ext/standard/exec.h"
00059 #include "ext/standard/php_smart_str.h"
00060 #include "ext/standard/url.h"
00061 #include "main/php_output.h"
00062 #include "ext/standard/info.h"
00063 
00064 #include "libmbfl/mbfl/mbfl_allocators.h"
00065 
00066 #include "php_variables.h"
00067 #include "php_globals.h"
00068 #include "rfc1867.h"
00069 #include "php_content_types.h"
00070 #include "SAPI.h"
00071 #include "php_unicode.h"
00072 #include "TSRM.h"
00073 
00074 #include "mb_gpc.h"
00075 
00076 #if HAVE_MBREGEX
00077 #include "php_mbregex.h"
00078 #endif
00079 
00080 #ifdef ZEND_MULTIBYTE
00081 #include "zend_multibyte.h"
00082 #endif /* ZEND_MULTIBYTE */
00083 
00084 #if HAVE_ONIG
00085 #include "php_onig_compat.h"
00086 #include <oniguruma.h>
00087 #undef UChar
00088 #elif HAVE_PCRE || HAVE_BUNDLED_PCRE
00089 #include "ext/pcre/php_pcre.h"
00090 #endif
00091 /* }}} */
00092 
00093 #if HAVE_MBSTRING
00094 
00095 /* {{{ prototypes */
00096 ZEND_DECLARE_MODULE_GLOBALS(mbstring)
00097 
00098 static PHP_GINIT_FUNCTION(mbstring);
00099 static PHP_GSHUTDOWN_FUNCTION(mbstring);
00100 
00101 #ifdef ZEND_MULTIBYTE
00102 static size_t php_mb_oddlen(const unsigned char *string, size_t length, const char *encoding TSRMLS_DC);
00103 static int php_mb_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const char *encoding_to, const char *encoding_from TSRMLS_DC);
00104 static char* php_mb_encoding_detector(const unsigned char *arg_string, size_t arg_length, char *arg_list TSRMLS_DC);
00105 static int php_mb_set_zend_encoding(TSRMLS_D);
00106 #endif
00107 /* }}} */
00108 
00109 /* {{{ php_mb_default_identify_list */
00110 typedef struct _php_mb_nls_ident_list {
00111        enum mbfl_no_language lang;
00112        const enum mbfl_no_encoding* list;
00113        int list_size;
00114 } php_mb_nls_ident_list;
00115 
00116 static const enum mbfl_no_encoding php_mb_default_identify_list_ja[] = {
00117        mbfl_no_encoding_ascii,
00118        mbfl_no_encoding_jis,
00119        mbfl_no_encoding_utf8,
00120        mbfl_no_encoding_euc_jp,
00121        mbfl_no_encoding_sjis
00122 };
00123 
00124 static const enum mbfl_no_encoding php_mb_default_identify_list_cn[] = {
00125        mbfl_no_encoding_ascii,
00126        mbfl_no_encoding_utf8,
00127        mbfl_no_encoding_euc_cn,
00128        mbfl_no_encoding_cp936
00129 };
00130 
00131 static const enum mbfl_no_encoding php_mb_default_identify_list_tw_hk[] = {
00132        mbfl_no_encoding_ascii,
00133        mbfl_no_encoding_utf8,
00134        mbfl_no_encoding_euc_tw,
00135        mbfl_no_encoding_big5
00136 };
00137 
00138 static const enum mbfl_no_encoding php_mb_default_identify_list_kr[] = {
00139        mbfl_no_encoding_ascii,
00140        mbfl_no_encoding_utf8,
00141        mbfl_no_encoding_euc_kr,
00142        mbfl_no_encoding_uhc
00143 };
00144 
00145 static const enum mbfl_no_encoding php_mb_default_identify_list_ru[] = {
00146        mbfl_no_encoding_ascii,
00147        mbfl_no_encoding_utf8,
00148        mbfl_no_encoding_koi8r,
00149        mbfl_no_encoding_cp1251,
00150        mbfl_no_encoding_cp866
00151 };
00152 
00153 static const enum mbfl_no_encoding php_mb_default_identify_list_hy[] = {
00154        mbfl_no_encoding_ascii,
00155        mbfl_no_encoding_utf8,
00156        mbfl_no_encoding_armscii8
00157 };
00158 
00159 static const enum mbfl_no_encoding php_mb_default_identify_list_tr[] = {
00160        mbfl_no_encoding_ascii,
00161        mbfl_no_encoding_utf8,
00162        mbfl_no_encoding_cp1254,
00163        mbfl_no_encoding_8859_9
00164 };
00165 
00166 static const enum mbfl_no_encoding php_mb_default_identify_list_ua[] = {
00167        mbfl_no_encoding_ascii,
00168        mbfl_no_encoding_utf8,
00169        mbfl_no_encoding_koi8u
00170 };
00171 
00172 static const enum mbfl_no_encoding php_mb_default_identify_list_neut[] = {
00173        mbfl_no_encoding_ascii,
00174        mbfl_no_encoding_utf8
00175 };
00176 
00177 
00178 static const php_mb_nls_ident_list php_mb_default_identify_list[] = {
00179        { mbfl_no_language_japanese, php_mb_default_identify_list_ja, sizeof(php_mb_default_identify_list_ja) / sizeof(php_mb_default_identify_list_ja[0]) },
00180        { mbfl_no_language_korean, php_mb_default_identify_list_kr, sizeof(php_mb_default_identify_list_kr) / sizeof(php_mb_default_identify_list_kr[0]) },
00181        { mbfl_no_language_traditional_chinese, php_mb_default_identify_list_tw_hk, sizeof(php_mb_default_identify_list_tw_hk) / sizeof(php_mb_default_identify_list_tw_hk[0]) },
00182        { mbfl_no_language_simplified_chinese, php_mb_default_identify_list_cn, sizeof(php_mb_default_identify_list_cn) / sizeof(php_mb_default_identify_list_cn[0]) },
00183        { mbfl_no_language_russian, php_mb_default_identify_list_ru, sizeof(php_mb_default_identify_list_ru) / sizeof(php_mb_default_identify_list_ru[0]) },
00184        { mbfl_no_language_armenian, php_mb_default_identify_list_hy, sizeof(php_mb_default_identify_list_hy) / sizeof(php_mb_default_identify_list_hy[0]) },
00185        { mbfl_no_language_turkish, php_mb_default_identify_list_tr, sizeof(php_mb_default_identify_list_tr) / sizeof(php_mb_default_identify_list_tr[0]) },
00186        { mbfl_no_language_ukrainian, php_mb_default_identify_list_ua, sizeof(php_mb_default_identify_list_ua) / sizeof(php_mb_default_identify_list_ua[0]) },
00187        { mbfl_no_language_neutral, php_mb_default_identify_list_neut, sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]) }
00188 };
00189 
00190 /* }}} */
00191 
00192 /* {{{ mb_overload_def mb_ovld[] */
00193 static const struct mb_overload_def mb_ovld[] = {
00194        {MB_OVERLOAD_MAIL, "mail", "mb_send_mail", "mb_orig_mail"},
00195        {MB_OVERLOAD_STRING, "strlen", "mb_strlen", "mb_orig_strlen"},
00196        {MB_OVERLOAD_STRING, "strpos", "mb_strpos", "mb_orig_strpos"},
00197        {MB_OVERLOAD_STRING, "strrpos", "mb_strrpos", "mb_orig_strrpos"},
00198        {MB_OVERLOAD_STRING, "stripos", "mb_stripos", "mb_orig_stripos"},
00199        {MB_OVERLOAD_STRING, "strripos", "mb_strripos", "mb_orig_strripos"},
00200        {MB_OVERLOAD_STRING, "strstr", "mb_strstr", "mb_orig_strstr"},
00201        {MB_OVERLOAD_STRING, "strrchr", "mb_strrchr", "mb_orig_strrchr"},
00202        {MB_OVERLOAD_STRING, "stristr", "mb_stristr", "mb_orig_stristr"},
00203        {MB_OVERLOAD_STRING, "substr", "mb_substr", "mb_orig_substr"},
00204        {MB_OVERLOAD_STRING, "strtolower", "mb_strtolower", "mb_orig_strtolower"},
00205        {MB_OVERLOAD_STRING, "strtoupper", "mb_strtoupper", "mb_orig_strtoupper"},
00206        {MB_OVERLOAD_STRING, "substr_count", "mb_substr_count", "mb_orig_substr_count"},
00207 #if HAVE_MBREGEX
00208        {MB_OVERLOAD_REGEX, "ereg", "mb_ereg", "mb_orig_ereg"},
00209        {MB_OVERLOAD_REGEX, "eregi", "mb_eregi", "mb_orig_eregi"},
00210        {MB_OVERLOAD_REGEX, "ereg_replace", "mb_ereg_replace", "mb_orig_ereg_replace"},
00211        {MB_OVERLOAD_REGEX, "eregi_replace", "mb_eregi_replace", "mb_orig_eregi_replace"},
00212        {MB_OVERLOAD_REGEX, "split", "mb_split", "mb_orig_split"},
00213 #endif
00214        {0, NULL, NULL, NULL}
00215 }; 
00216 /* }}} */
00217 
00218 /* {{{ arginfo */
00219 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_language, 0, 0, 0)
00220        ZEND_ARG_INFO(0, language)
00221 ZEND_END_ARG_INFO()
00222 
00223 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_internal_encoding, 0, 0, 0)
00224        ZEND_ARG_INFO(0, encoding)
00225 ZEND_END_ARG_INFO()
00226 
00227 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_input, 0, 0, 0)
00228        ZEND_ARG_INFO(0, type)
00229 ZEND_END_ARG_INFO()
00230 
00231 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_http_output, 0, 0, 0)
00232        ZEND_ARG_INFO(0, encoding)
00233 ZEND_END_ARG_INFO()
00234 
00235 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_order, 0, 0, 0)
00236        ZEND_ARG_INFO(0, encoding)
00237 ZEND_END_ARG_INFO()
00238 
00239 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substitute_character, 0, 0, 0)
00240        ZEND_ARG_INFO(0, substchar)
00241 ZEND_END_ARG_INFO()
00242 
00243 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_preferred_mime_name, 0, 0, 1)
00244        ZEND_ARG_INFO(0, encoding)
00245 ZEND_END_ARG_INFO()
00246 
00247 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_parse_str, 0, 0, 1)
00248        ZEND_ARG_INFO(0, encoded_string)
00249        ZEND_ARG_INFO(1, result)
00250 ZEND_END_ARG_INFO()
00251 
00252 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_output_handler, 0, 0, 2)
00253        ZEND_ARG_INFO(0, contents)
00254        ZEND_ARG_INFO(0, status)
00255 ZEND_END_ARG_INFO()
00256 
00257 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strlen, 0, 0, 1)
00258        ZEND_ARG_INFO(0, str)
00259        ZEND_ARG_INFO(0, encoding)
00260 ZEND_END_ARG_INFO()
00261 
00262 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strpos, 0, 0, 2)
00263        ZEND_ARG_INFO(0, haystack)
00264        ZEND_ARG_INFO(0, needle)
00265        ZEND_ARG_INFO(0, offset)
00266        ZEND_ARG_INFO(0, encoding)
00267 ZEND_END_ARG_INFO()
00268 
00269 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrpos, 0, 0, 2)
00270        ZEND_ARG_INFO(0, haystack)
00271        ZEND_ARG_INFO(0, needle)
00272        ZEND_ARG_INFO(0, offset)
00273        ZEND_ARG_INFO(0, encoding)
00274 ZEND_END_ARG_INFO()
00275 
00276 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stripos, 0, 0, 2)
00277        ZEND_ARG_INFO(0, haystack)
00278        ZEND_ARG_INFO(0, needle)
00279        ZEND_ARG_INFO(0, offset)
00280        ZEND_ARG_INFO(0, encoding)
00281 ZEND_END_ARG_INFO()
00282 
00283 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strripos, 0, 0, 2)
00284        ZEND_ARG_INFO(0, haystack)
00285        ZEND_ARG_INFO(0, needle)
00286        ZEND_ARG_INFO(0, offset)
00287        ZEND_ARG_INFO(0, encoding)
00288 ZEND_END_ARG_INFO()
00289 
00290 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strstr, 0, 0, 2)
00291        ZEND_ARG_INFO(0, haystack)
00292        ZEND_ARG_INFO(0, needle)
00293        ZEND_ARG_INFO(0, part)
00294        ZEND_ARG_INFO(0, encoding)
00295 ZEND_END_ARG_INFO()
00296 
00297 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrchr, 0, 0, 2)
00298        ZEND_ARG_INFO(0, haystack)
00299        ZEND_ARG_INFO(0, needle)
00300        ZEND_ARG_INFO(0, part)
00301        ZEND_ARG_INFO(0, encoding)
00302 ZEND_END_ARG_INFO()
00303 
00304 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_stristr, 0, 0, 2)
00305        ZEND_ARG_INFO(0, haystack)
00306        ZEND_ARG_INFO(0, needle)
00307        ZEND_ARG_INFO(0, part)
00308        ZEND_ARG_INFO(0, encoding)
00309 ZEND_END_ARG_INFO()
00310 
00311 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strrichr, 0, 0, 2)
00312        ZEND_ARG_INFO(0, haystack)
00313        ZEND_ARG_INFO(0, needle)
00314        ZEND_ARG_INFO(0, part)
00315        ZEND_ARG_INFO(0, encoding)
00316 ZEND_END_ARG_INFO()
00317 
00318 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr_count, 0, 0, 2)
00319        ZEND_ARG_INFO(0, haystack)
00320        ZEND_ARG_INFO(0, needle)
00321        ZEND_ARG_INFO(0, encoding)
00322 ZEND_END_ARG_INFO()
00323 
00324 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_substr, 0, 0, 2)
00325        ZEND_ARG_INFO(0, str)
00326        ZEND_ARG_INFO(0, start)
00327        ZEND_ARG_INFO(0, length)
00328        ZEND_ARG_INFO(0, encoding)
00329 ZEND_END_ARG_INFO()
00330 
00331 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strcut, 0, 0, 2)
00332        ZEND_ARG_INFO(0, str)
00333        ZEND_ARG_INFO(0, start)
00334        ZEND_ARG_INFO(0, length)
00335        ZEND_ARG_INFO(0, encoding)
00336 ZEND_END_ARG_INFO()
00337 
00338 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strwidth, 0, 0, 1)
00339        ZEND_ARG_INFO(0, str)
00340        ZEND_ARG_INFO(0, encoding)
00341 ZEND_END_ARG_INFO()
00342 
00343 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strimwidth, 0, 0, 3)
00344        ZEND_ARG_INFO(0, str)
00345        ZEND_ARG_INFO(0, start)
00346        ZEND_ARG_INFO(0, width)
00347        ZEND_ARG_INFO(0, trimmarker)
00348        ZEND_ARG_INFO(0, encoding)
00349 ZEND_END_ARG_INFO()
00350 
00351 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_encoding, 0, 0, 2)
00352        ZEND_ARG_INFO(0, str)
00353        ZEND_ARG_INFO(0, to)
00354        ZEND_ARG_INFO(0, from)
00355 ZEND_END_ARG_INFO()
00356 
00357 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_case, 0, 0, 2)
00358        ZEND_ARG_INFO(0, sourcestring)
00359        ZEND_ARG_INFO(0, mode)
00360        ZEND_ARG_INFO(0, encoding)
00361 ZEND_END_ARG_INFO()
00362 
00363 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtoupper, 0, 0, 1)
00364        ZEND_ARG_INFO(0, sourcestring)
00365        ZEND_ARG_INFO(0, encoding)
00366 ZEND_END_ARG_INFO()
00367 
00368 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_strtolower, 0, 0, 1)
00369        ZEND_ARG_INFO(0, sourcestring)
00370        ZEND_ARG_INFO(0, encoding)
00371 ZEND_END_ARG_INFO()
00372 
00373 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_detect_encoding, 0, 0, 1)
00374        ZEND_ARG_INFO(0, str)
00375        ZEND_ARG_INFO(0, encoding_list)
00376        ZEND_ARG_INFO(0, strict)
00377 ZEND_END_ARG_INFO()
00378 
00379 ZEND_BEGIN_ARG_INFO(arginfo_mb_list_encodings, 0)
00380 ZEND_END_ARG_INFO()
00381 
00382 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encoding_aliases, 0, 0, 1)
00383        ZEND_ARG_INFO(0, encoding)
00384 ZEND_END_ARG_INFO()
00385 
00386 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_mimeheader, 0, 0, 1)
00387        ZEND_ARG_INFO(0, str)
00388        ZEND_ARG_INFO(0, charset)
00389        ZEND_ARG_INFO(0, transfer)
00390        ZEND_ARG_INFO(0, linefeed)
00391        ZEND_ARG_INFO(0, indent)
00392 ZEND_END_ARG_INFO()
00393 
00394 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_mimeheader, 0, 0, 1)
00395        ZEND_ARG_INFO(0, string)
00396 ZEND_END_ARG_INFO()
00397 
00398 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_kana, 0, 0, 1)
00399        ZEND_ARG_INFO(0, str)
00400        ZEND_ARG_INFO(0, option)
00401        ZEND_ARG_INFO(0, encoding)
00402 ZEND_END_ARG_INFO()
00403 
00404 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_variables, 1, 0, 3)
00405        ZEND_ARG_INFO(0, to)
00406        ZEND_ARG_INFO(0, from)
00407        ZEND_ARG_INFO(1, ...)
00408 ZEND_END_ARG_INFO()
00409 
00410 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_numericentity, 0, 0, 2)
00411        ZEND_ARG_INFO(0, string)
00412        ZEND_ARG_INFO(0, convmap)
00413        ZEND_ARG_INFO(0, encoding)
00414 ZEND_END_ARG_INFO()
00415 
00416 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_decode_numericentity, 0, 0, 2)
00417        ZEND_ARG_INFO(0, string)
00418        ZEND_ARG_INFO(0, convmap)
00419        ZEND_ARG_INFO(0, encoding)
00420 ZEND_END_ARG_INFO()
00421 
00422 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_send_mail, 0, 0, 3)
00423        ZEND_ARG_INFO(0, to)
00424        ZEND_ARG_INFO(0, subject)
00425        ZEND_ARG_INFO(0, message)
00426        ZEND_ARG_INFO(0, additional_headers)
00427        ZEND_ARG_INFO(0, additional_parameters)
00428 ZEND_END_ARG_INFO()
00429 
00430 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_get_info, 0, 0, 0)
00431        ZEND_ARG_INFO(0, type)
00432 ZEND_END_ARG_INFO()
00433 
00434 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_check_encoding, 0, 0, 0)
00435        ZEND_ARG_INFO(0, var)
00436        ZEND_ARG_INFO(0, encoding)
00437 ZEND_END_ARG_INFO()
00438 
00439 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_encoding, 0, 0, 0)
00440        ZEND_ARG_INFO(0, encoding)
00441 ZEND_END_ARG_INFO()
00442 
00443 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg, 0, 0, 2)
00444        ZEND_ARG_INFO(0, pattern)
00445        ZEND_ARG_INFO(0, string)
00446        ZEND_ARG_INFO(1, registers)
00447 ZEND_END_ARG_INFO()
00448 
00449 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi, 0, 0, 2)
00450        ZEND_ARG_INFO(0, pattern)
00451        ZEND_ARG_INFO(0, string)
00452        ZEND_ARG_INFO(1, registers)
00453 ZEND_END_ARG_INFO()
00454 
00455 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace, 0, 0, 3)
00456        ZEND_ARG_INFO(0, pattern)
00457        ZEND_ARG_INFO(0, replacement)
00458        ZEND_ARG_INFO(0, string)
00459        ZEND_ARG_INFO(0, option)
00460 ZEND_END_ARG_INFO()
00461 
00462 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi_replace, 0, 0, 3)
00463        ZEND_ARG_INFO(0, pattern)
00464        ZEND_ARG_INFO(0, replacement)
00465        ZEND_ARG_INFO(0, string)
00466 ZEND_END_ARG_INFO()
00467 
00468 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_split, 0, 0, 2)
00469        ZEND_ARG_INFO(0, pattern)
00470        ZEND_ARG_INFO(0, string)
00471        ZEND_ARG_INFO(0, limit)
00472 ZEND_END_ARG_INFO()
00473 
00474 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_match, 0, 0, 2)
00475        ZEND_ARG_INFO(0, pattern)
00476        ZEND_ARG_INFO(0, string)
00477        ZEND_ARG_INFO(0, option)
00478 ZEND_END_ARG_INFO()
00479 
00480 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search, 0, 0, 0)
00481        ZEND_ARG_INFO(0, pattern)
00482        ZEND_ARG_INFO(0, option)
00483 ZEND_END_ARG_INFO()
00484 
00485 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_pos, 0, 0, 0)
00486        ZEND_ARG_INFO(0, pattern)
00487        ZEND_ARG_INFO(0, option)
00488 ZEND_END_ARG_INFO()
00489 
00490 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_regs, 0, 0, 0)
00491        ZEND_ARG_INFO(0, pattern)
00492        ZEND_ARG_INFO(0, option)
00493 ZEND_END_ARG_INFO()
00494 
00495 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_init, 0, 0, 1)
00496        ZEND_ARG_INFO(0, string)
00497        ZEND_ARG_INFO(0, pattern)
00498        ZEND_ARG_INFO(0, option)
00499 ZEND_END_ARG_INFO()
00500 
00501 ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getregs, 0)
00502 ZEND_END_ARG_INFO()
00503 
00504 ZEND_BEGIN_ARG_INFO(arginfo_mb_ereg_search_getpos, 0)
00505 ZEND_END_ARG_INFO()
00506 
00507 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_search_setpos, 0, 0, 1)
00508        ZEND_ARG_INFO(0, position)
00509 ZEND_END_ARG_INFO()
00510 
00511 ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_regex_set_options, 0, 0, 0)
00512        ZEND_ARG_INFO(0, options)
00513 ZEND_END_ARG_INFO()
00514 /* }}} */
00515 
00516 /* {{{ zend_function_entry mbstring_functions[] */
00517 const zend_function_entry mbstring_functions[] = {
00518        PHP_FE(mb_convert_case,                   arginfo_mb_convert_case)
00519        PHP_FE(mb_strtoupper,                     arginfo_mb_strtoupper)
00520        PHP_FE(mb_strtolower,                     arginfo_mb_strtolower)
00521        PHP_FE(mb_language,                       arginfo_mb_language)
00522        PHP_FE(mb_internal_encoding,       arginfo_mb_internal_encoding)
00523        PHP_FE(mb_http_input,                     arginfo_mb_http_input)
00524        PHP_FE(mb_http_output,                    arginfo_mb_http_output)
00525        PHP_FE(mb_detect_order,                   arginfo_mb_detect_order)
00526        PHP_FE(mb_substitute_character,    arginfo_mb_substitute_character)
00527        PHP_FE(mb_parse_str,               arginfo_mb_parse_str)
00528        PHP_FE(mb_output_handler,          arginfo_mb_output_handler)
00529        PHP_FE(mb_preferred_mime_name,     arginfo_mb_preferred_mime_name)
00530        PHP_FE(mb_strlen,                         arginfo_mb_strlen)
00531        PHP_FE(mb_strpos,                         arginfo_mb_strpos)
00532        PHP_FE(mb_strrpos,                        arginfo_mb_strrpos)
00533        PHP_FE(mb_stripos,                        arginfo_mb_stripos)
00534        PHP_FE(mb_strripos,                       arginfo_mb_strripos)
00535        PHP_FE(mb_strstr,                         arginfo_mb_strstr)
00536        PHP_FE(mb_strrchr,                        arginfo_mb_strrchr)
00537        PHP_FE(mb_stristr,                        arginfo_mb_stristr)
00538        PHP_FE(mb_strrichr,                       arginfo_mb_strrichr)
00539        PHP_FE(mb_substr_count,                   arginfo_mb_substr_count)
00540        PHP_FE(mb_substr,                         arginfo_mb_substr)
00541        PHP_FE(mb_strcut,                         arginfo_mb_strcut)
00542        PHP_FE(mb_strwidth,                       arginfo_mb_strwidth)
00543        PHP_FE(mb_strimwidth,                     arginfo_mb_strimwidth)
00544        PHP_FE(mb_convert_encoding,        arginfo_mb_convert_encoding)
00545        PHP_FE(mb_detect_encoding,         arginfo_mb_detect_encoding)
00546        PHP_FE(mb_list_encodings,          arginfo_mb_list_encodings)
00547        PHP_FE(mb_encoding_aliases,        arginfo_mb_encoding_aliases)
00548        PHP_FE(mb_convert_kana,                   arginfo_mb_convert_kana)
00549        PHP_FE(mb_encode_mimeheader,       arginfo_mb_encode_mimeheader)
00550        PHP_FE(mb_decode_mimeheader,       arginfo_mb_decode_mimeheader)
00551        PHP_FE(mb_convert_variables,       arginfo_mb_convert_variables)
00552        PHP_FE(mb_encode_numericentity,    arginfo_mb_encode_numericentity)
00553        PHP_FE(mb_decode_numericentity,    arginfo_mb_decode_numericentity)
00554        PHP_FE(mb_send_mail,               arginfo_mb_send_mail)
00555        PHP_FE(mb_get_info,                       arginfo_mb_get_info)
00556        PHP_FE(mb_check_encoding,          arginfo_mb_check_encoding)
00557 #if HAVE_MBREGEX
00558        PHP_MBREGEX_FUNCTION_ENTRIES
00559 #endif
00560        PHP_FE_END
00561 };
00562 /* }}} */
00563 
00564 /* {{{ zend_module_entry mbstring_module_entry */
00565 zend_module_entry mbstring_module_entry = {
00566     STANDARD_MODULE_HEADER,
00567        "mbstring",
00568        mbstring_functions,
00569        PHP_MINIT(mbstring),
00570        PHP_MSHUTDOWN(mbstring),
00571        PHP_RINIT(mbstring),
00572        PHP_RSHUTDOWN(mbstring),
00573        PHP_MINFO(mbstring),
00574     NO_VERSION_YET,
00575     PHP_MODULE_GLOBALS(mbstring),
00576     PHP_GINIT(mbstring),
00577     PHP_GSHUTDOWN(mbstring),
00578     NULL,
00579        STANDARD_MODULE_PROPERTIES_EX
00580 };
00581 /* }}} */
00582 
00583 /* {{{ static sapi_post_entry php_post_entries[] */
00584 static sapi_post_entry php_post_entries[] = {
00585        { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data,   php_std_post_handler },
00586        { MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
00587        { NULL, 0, NULL, NULL }
00588 };
00589 /* }}} */
00590 
00591 #ifdef COMPILE_DL_MBSTRING
00592 ZEND_GET_MODULE(mbstring)
00593 #endif
00594 
00595 /* {{{ allocators */
00596 static void *_php_mb_allocators_malloc(unsigned int sz)
00597 {
00598        return emalloc(sz);
00599 }
00600 
00601 static void *_php_mb_allocators_realloc(void *ptr, unsigned int sz)
00602 {
00603        return erealloc(ptr, sz);
00604 }
00605 
00606 static void *_php_mb_allocators_calloc(unsigned int nelems, unsigned int szelem)
00607 {
00608        return ecalloc(nelems, szelem);
00609 }
00610 
00611 static void _php_mb_allocators_free(void *ptr)
00612 {
00613        efree(ptr);
00614 } 
00615 
00616 static void *_php_mb_allocators_pmalloc(unsigned int sz)
00617 {
00618        return pemalloc(sz, 1);
00619 }
00620 
00621 static void *_php_mb_allocators_prealloc(void *ptr, unsigned int sz)
00622 {
00623        return perealloc(ptr, sz, 1);
00624 }
00625 
00626 static void _php_mb_allocators_pfree(void *ptr)
00627 {
00628        pefree(ptr, 1);
00629 } 
00630 
00631 static mbfl_allocators _php_mb_allocators = {
00632        _php_mb_allocators_malloc,
00633        _php_mb_allocators_realloc,
00634        _php_mb_allocators_calloc,
00635        _php_mb_allocators_free,
00636        _php_mb_allocators_pmalloc,
00637        _php_mb_allocators_prealloc,
00638        _php_mb_allocators_pfree
00639 };
00640 /* }}} */
00641 
00642 /* {{{ static sapi_post_entry mbstr_post_entries[] */
00643 static sapi_post_entry mbstr_post_entries[] = {
00644        { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_mb_post_handler },
00645        { MULTIPART_CONTENT_TYPE,    sizeof(MULTIPART_CONTENT_TYPE)-1,    NULL,                         rfc1867_post_handler },
00646        { NULL, 0, NULL, NULL }
00647 };
00648 /* }}} */
00649 
00650 /* {{{ static int php_mb_parse_encoding_list()
00651  *  Return 0 if input contains any illegal encoding, otherwise 1.
00652  *  Even if any illegal encoding is detected the result may contain a list 
00653  *  of parsed encodings.
00654  */
00655 static int
00656 php_mb_parse_encoding_list(const char *value, int value_length, enum mbfl_no_encoding **return_list, int *return_size, int persistent TSRMLS_DC)
00657 {
00658        int n, l, size, bauto, ret = 1;
00659        char *p, *p1, *p2, *endp, *tmpstr;
00660        enum mbfl_no_encoding no_encoding;
00661        enum mbfl_no_encoding *src, *entry, *list;
00662 
00663        list = NULL;
00664        if (value == NULL || value_length <= 0) {
00665               if (return_list) {
00666                      *return_list = NULL;
00667               }
00668               if (return_size) {
00669                      *return_size = 0;
00670               }
00671               return 0;
00672        } else {
00673               enum mbfl_no_encoding *identify_list;
00674               int identify_list_size;
00675 
00676               identify_list = MBSTRG(default_detect_order_list);
00677               identify_list_size = MBSTRG(default_detect_order_list_size);
00678 
00679               /* copy the value string for work */
00680               if (value[0]=='"' && value[value_length-1]=='"' && value_length>2) {
00681                      tmpstr = (char *)estrndup(value+1, value_length-2);
00682                      value_length -= 2;
00683               }
00684               else
00685                      tmpstr = (char *)estrndup(value, value_length);
00686               if (tmpstr == NULL) {
00687                      return 0;
00688               }
00689               /* count the number of listed encoding names */
00690               endp = tmpstr + value_length;
00691               n = 1;
00692               p1 = tmpstr;
00693               while ((p2 = php_memnstr(p1, ",", 1, endp)) != NULL) {
00694                      p1 = p2 + 1;
00695                      n++;
00696               }
00697               size = n + identify_list_size;
00698               /* make list */
00699               list = (enum mbfl_no_encoding *)pecalloc(size, sizeof(int), persistent);
00700               if (list != NULL) {
00701                      entry = list;
00702                      n = 0;
00703                      bauto = 0;
00704                      p1 = tmpstr;
00705                      do {
00706                             p2 = p = php_memnstr(p1, ",", 1, endp);
00707                             if (p == NULL) {
00708                                    p = endp;
00709                             }
00710                             *p = '\0';
00711                             /* trim spaces */
00712                             while (p1 < p && (*p1 == ' ' || *p1 == '\t')) {
00713                                    p1++;
00714                             }
00715                             p--;
00716                             while (p > p1 && (*p == ' ' || *p == '\t')) {
00717                                    *p = '\0';
00718                                    p--;
00719                             }
00720                             /* convert to the encoding number and check encoding */
00721                             if (strcasecmp(p1, "auto") == 0) {
00722                                    if (!bauto) {
00723                                           bauto = 1;
00724                                           l = identify_list_size;
00725                                           src = identify_list;
00726                                           while (l > 0) {
00727                                                  *entry++ = *src++;
00728                                                  l--;
00729                                                  n++;
00730                                           }
00731                                    }
00732                             } else {
00733                                    no_encoding = mbfl_name2no_encoding(p1);
00734                                    if (no_encoding != mbfl_no_encoding_invalid) {
00735                                           *entry++ = no_encoding;
00736                                           n++;
00737                                    } else {
00738                                           ret = 0;
00739                                    }
00740                             }
00741                             p1 = p2 + 1;
00742                      } while (n < size && p2 != NULL);
00743                      if (n > 0) {
00744                             if (return_list) {
00745                                    *return_list = list;
00746                             } else {
00747                                    pefree(list, persistent);
00748                             }
00749                      } else {
00750                             pefree(list, persistent);
00751                             if (return_list) {
00752                                    *return_list = NULL;
00753                             }
00754                             ret = 0;
00755                      }
00756                      if (return_size) {
00757                             *return_size = n;
00758                      }
00759               } else {
00760                      if (return_list) {
00761                             *return_list = NULL;
00762                      }
00763                      if (return_size) {
00764                             *return_size = 0;
00765                      }
00766                      ret = 0;
00767               }
00768               efree(tmpstr);
00769        }
00770 
00771        return ret;
00772 }
00773 /* }}} */
00774 
00775 /* {{{ MBSTRING_API php_mb_check_encoding_list */
00776 MBSTRING_API int php_mb_check_encoding_list(const char *encoding_list TSRMLS_DC) {
00777        return php_mb_parse_encoding_list(encoding_list, strlen(encoding_list), NULL, NULL, 0 TSRMLS_CC); 
00778 }
00779 /* }}} */
00780 
00781 /* {{{ static int php_mb_parse_encoding_array()
00782  *  Return 0 if input contains any illegal encoding, otherwise 1.
00783  *  Even if any illegal encoding is detected the result may contain a list 
00784  *  of parsed encodings.
00785  */
00786 static int
00787 php_mb_parse_encoding_array(zval *array, enum mbfl_no_encoding **return_list, int *return_size, int persistent TSRMLS_DC)
00788 {
00789        zval **hash_entry;
00790        HashTable *target_hash;
00791        int i, n, l, size, bauto,ret = 1;
00792        enum mbfl_no_encoding no_encoding;
00793        enum mbfl_no_encoding *src, *list, *entry;
00794 
00795        list = NULL;
00796        if (Z_TYPE_P(array) == IS_ARRAY) {
00797               enum mbfl_no_encoding *identify_list;
00798               int identify_list_size;
00799 
00800               identify_list = MBSTRG(default_detect_order_list);
00801               identify_list_size = MBSTRG(default_detect_order_list_size);
00802 
00803               target_hash = Z_ARRVAL_P(array);
00804               zend_hash_internal_pointer_reset(target_hash);
00805               i = zend_hash_num_elements(target_hash);
00806               size = i + identify_list_size;
00807               list = (enum mbfl_no_encoding *)pecalloc(size, sizeof(int), persistent);
00808               if (list != NULL) {
00809                      entry = list;
00810                      bauto = 0;
00811                      n = 0;
00812                      while (i > 0) {
00813                             if (zend_hash_get_current_data(target_hash, (void **) &hash_entry) == FAILURE) {
00814                                    break;
00815                             }
00816                             convert_to_string_ex(hash_entry);
00817                             if (strcasecmp(Z_STRVAL_PP(hash_entry), "auto") == 0) {
00818                                    if (!bauto) {
00819                                           bauto = 1;
00820                                           l = identify_list_size; 
00821                                           src = identify_list;
00822                                           while (l > 0) {
00823                                                  *entry++ = *src++;
00824                                                  l--;
00825                                                  n++;
00826                                           }
00827                                    }
00828                             } else {
00829                                    no_encoding = mbfl_name2no_encoding(Z_STRVAL_PP(hash_entry));
00830                                    if (no_encoding != mbfl_no_encoding_invalid) {
00831                                           *entry++ = no_encoding;
00832                                           n++;
00833                                    } else {
00834                                           ret = 0;
00835                                    }
00836                             }
00837                             zend_hash_move_forward(target_hash);
00838                             i--;
00839                      }
00840                      if (n > 0) {
00841                             if (return_list) {
00842                                    *return_list = list;
00843                             } else {
00844                                    pefree(list, persistent);
00845                             }
00846                      } else {
00847                             pefree(list, persistent);
00848                             if (return_list) {
00849                                    *return_list = NULL;
00850                             }
00851                             ret = 0;
00852                      }
00853                      if (return_size) {
00854                             *return_size = n;
00855                      }
00856               } else {
00857                      if (return_list) {
00858                             *return_list = NULL;
00859                      }
00860                      if (return_size) {
00861                             *return_size = 0;
00862                      }
00863                      ret = 0;
00864               }
00865        }
00866 
00867        return ret;
00868 }
00869 /* }}} */
00870 
00871 static void *_php_mb_compile_regex(const char *pattern TSRMLS_DC);
00872 static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len);
00873 static void _php_mb_free_regex(void *opaque);
00874 
00875 #if HAVE_ONIG
00876 /* {{{ _php_mb_compile_regex */
00877 static void *_php_mb_compile_regex(const char *pattern TSRMLS_DC)
00878 {
00879        php_mb_regex_t *retval;
00880        OnigErrorInfo err_info;
00881        int err_code;
00882 
00883        if ((err_code = onig_new(&retval,
00884                      (const OnigUChar *)pattern,
00885                      (const OnigUChar *)pattern + strlen(pattern),
00886                      ONIG_OPTION_IGNORECASE | ONIG_OPTION_DONT_CAPTURE_GROUP,
00887                      ONIG_ENCODING_ASCII, &OnigSyntaxPerl, &err_info))) {
00888               OnigUChar err_str[ONIG_MAX_ERROR_MESSAGE_LEN];
00889               onig_error_code_to_str(err_str, err_code, err_info);
00890               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", pattern, err_str);
00891               retval = NULL;
00892        }
00893        return retval;
00894 }
00895 /* }}} */
00896 
00897 /* {{{ _php_mb_match_regex */
00898 static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len)
00899 {
00900        return onig_search((php_mb_regex_t *)opaque, (const OnigUChar *)str,
00901                      (const OnigUChar*)str + str_len, (const OnigUChar *)str,
00902                      (const OnigUChar*)str + str_len, NULL, ONIG_OPTION_NONE) >= 0;
00903 }
00904 /* }}} */
00905 
00906 /* {{{ _php_mb_free_regex */
00907 static void _php_mb_free_regex(void *opaque)
00908 {
00909        onig_free((php_mb_regex_t *)opaque);
00910 }
00911 /* }}} */
00912 #elif HAVE_PCRE || HAVE_BUNDLED_PCRE
00913 /* {{{ _php_mb_compile_regex */
00914 static void *_php_mb_compile_regex(const char *pattern TSRMLS_DC)
00915 {
00916        pcre *retval;
00917        const char *err_str;
00918        int err_offset;
00919 
00920        if (!(retval = pcre_compile(pattern,
00921                      PCRE_CASELESS, &err_str, &err_offset, NULL))) {
00922               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (offset=%d): %s", pattern, err_offset, err_str);
00923        }
00924        return retval;
00925 }
00926 /* }}} */
00927 
00928 /* {{{ _php_mb_match_regex */
00929 static int _php_mb_match_regex(void *opaque, const char *str, size_t str_len)
00930 {
00931        return pcre_exec((pcre *)opaque, NULL, str, (int)str_len, 0,
00932                      0, NULL, 0) >= 0;
00933 }
00934 /* }}} */
00935 
00936 /* {{{ _php_mb_free_regex */
00937 static void _php_mb_free_regex(void *opaque)
00938 {
00939        pcre_free(opaque);
00940 }
00941 /* }}} */
00942 #endif
00943 
00944 /* {{{ php_mb_nls_get_default_detect_order_list */
00945 static int php_mb_nls_get_default_detect_order_list(enum mbfl_no_language lang, enum mbfl_no_encoding **plist, int* plist_size)
00946 {
00947        size_t i;
00948 
00949        *plist = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut;
00950        *plist_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]);
00951 
00952        for (i = 0; i < sizeof(php_mb_default_identify_list) / sizeof(php_mb_default_identify_list[0]); i++) {
00953               if (php_mb_default_identify_list[i].lang == lang) {
00954                      *plist = (enum mbfl_no_encoding *)php_mb_default_identify_list[i].list;
00955                      *plist_size = php_mb_default_identify_list[i].list_size;
00956                      return 1;
00957               }
00958        }
00959        return 0;
00960 }
00961 /* }}} */
00962 
00963 /* {{{ php.ini directive handler */
00964 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_language) */
00965 static PHP_INI_MH(OnUpdate_mbstring_language)
00966 {
00967        enum mbfl_no_language no_language;
00968 
00969        no_language = mbfl_name2no_language(new_value);
00970        if (no_language == mbfl_no_language_invalid) {
00971               MBSTRG(language) = mbfl_no_language_neutral;
00972               return FAILURE;
00973        }
00974        MBSTRG(language) = no_language;
00975        php_mb_nls_get_default_detect_order_list(no_language, &MBSTRG(default_detect_order_list), &MBSTRG(default_detect_order_list_size));
00976        return SUCCESS;
00977 }
00978 /* }}} */
00979 
00980 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_detect_order) */
00981 static PHP_INI_MH(OnUpdate_mbstring_detect_order)
00982 {
00983        enum mbfl_no_encoding *list;
00984        int size;
00985 
00986        if (php_mb_parse_encoding_list(new_value, new_value_length, &list, &size, 1 TSRMLS_CC)) {
00987               if (MBSTRG(detect_order_list)) {
00988                      free(MBSTRG(detect_order_list));
00989               }
00990               MBSTRG(detect_order_list) = list;
00991               MBSTRG(detect_order_list_size) = size;
00992        } else {
00993               if (MBSTRG(detect_order_list)) {
00994                      free(MBSTRG(detect_order_list));
00995                      MBSTRG(detect_order_list) = NULL;
00996               }
00997               return FAILURE;
00998        }
00999 
01000        return SUCCESS;
01001 }
01002 /* }}} */
01003 
01004 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_input) */
01005 static PHP_INI_MH(OnUpdate_mbstring_http_input)
01006 {
01007        enum mbfl_no_encoding *list;
01008        int size;
01009 
01010        if (php_mb_parse_encoding_list(new_value, new_value_length, &list, &size, 1 TSRMLS_CC)) {
01011               if (MBSTRG(http_input_list)) {
01012                      free(MBSTRG(http_input_list));
01013               }
01014               MBSTRG(http_input_list) = list;
01015               MBSTRG(http_input_list_size) = size;
01016        } else {
01017               if (MBSTRG(http_input_list)) {
01018                      free(MBSTRG(http_input_list));
01019                      MBSTRG(http_input_list) = NULL;
01020               }
01021               MBSTRG(http_input_list_size) = 0;
01022               return FAILURE;
01023        }
01024 
01025        return SUCCESS;
01026 }
01027 /* }}} */
01028 
01029 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output) */
01030 static PHP_INI_MH(OnUpdate_mbstring_http_output)
01031 {
01032        enum mbfl_no_encoding no_encoding;
01033 
01034        no_encoding = mbfl_name2no_encoding(new_value);
01035        if (no_encoding != mbfl_no_encoding_invalid) {
01036               MBSTRG(http_output_encoding) = no_encoding;
01037               MBSTRG(current_http_output_encoding) = no_encoding;
01038        } else {
01039               MBSTRG(http_output_encoding) = mbfl_no_encoding_pass;
01040               MBSTRG(current_http_output_encoding) = mbfl_no_encoding_pass;
01041               if (new_value != NULL && new_value_length > 0) {
01042                      return FAILURE;
01043               }
01044        }
01045 
01046        return SUCCESS;
01047 }
01048 /* }}} */
01049 
01050 /* {{{ static _php_mb_ini_mbstring_internal_encoding_set */
01051 int _php_mb_ini_mbstring_internal_encoding_set(const char *new_value, uint new_value_length TSRMLS_DC)
01052 {
01053        enum mbfl_no_encoding no_encoding;
01054        const char *enc_name = NULL;
01055        uint enc_name_len = 0;
01056    
01057        no_encoding = new_value ? mbfl_name2no_encoding(new_value):
01058                             mbfl_no_encoding_invalid;
01059        if (no_encoding != mbfl_no_encoding_invalid) {
01060               enc_name = new_value;
01061               enc_name_len = new_value_length;
01062        } else {
01063               switch (MBSTRG(language)) {
01064                      case mbfl_no_language_uni:
01065                             enc_name = "UTF-8";
01066                             enc_name_len = sizeof("UTF-8") - 1;
01067                             break;
01068                      case mbfl_no_language_japanese:
01069                             enc_name = "EUC-JP";
01070                             enc_name_len = sizeof("EUC-JP") - 1;
01071                             break;
01072                      case mbfl_no_language_korean:
01073                             enc_name = "EUC-KR";
01074                             enc_name_len = sizeof("EUC-KR") - 1;
01075                             break;
01076                      case mbfl_no_language_simplified_chinese:
01077                             enc_name = "EUC-CN";
01078                             enc_name_len = sizeof("EUC-CN") - 1;
01079                             break;
01080                      case mbfl_no_language_traditional_chinese:
01081                             enc_name = "EUC-TW";
01082                             enc_name_len = sizeof("EUC-TW") - 1;
01083                             break;
01084                      case mbfl_no_language_russian:
01085                             enc_name = "KOI8-R";
01086                             enc_name_len = sizeof("KOI8-R") - 1;
01087                             break;
01088                      case mbfl_no_language_german:
01089                             enc_name = "ISO-8859-15";
01090                             enc_name_len = sizeof("ISO-8859-15") - 1;
01091                             break;
01092                      case mbfl_no_language_armenian:
01093                             enc_name = "ArmSCII-8";
01094                             enc_name_len = sizeof("ArmSCII-8") - 1;
01095                             break;
01096                      case mbfl_no_language_turkish:
01097                             enc_name = "ISO-8859-9";
01098                             enc_name_len = sizeof("ISO-8859-9") - 1;
01099                             break;
01100                      default:
01101                             enc_name = "ISO-8859-1";
01102                             enc_name_len = sizeof("ISO-8859-1") - 1;
01103                             break;
01104               }
01105               no_encoding = mbfl_name2no_encoding(enc_name);
01106        }
01107        MBSTRG(internal_encoding) = no_encoding;
01108        MBSTRG(current_internal_encoding) = no_encoding;
01109 #if HAVE_MBREGEX
01110        {
01111               const char *enc_name = new_value;
01112               if (FAILURE == php_mb_regex_set_default_mbctype(enc_name TSRMLS_CC)) {
01113                      /* falls back to EUC-JP if an unknown encoding name is given */
01114                      enc_name = "EUC-JP";
01115                      php_mb_regex_set_default_mbctype(enc_name TSRMLS_CC);
01116               }
01117               php_mb_regex_set_mbctype(new_value TSRMLS_CC);
01118        }
01119 #endif
01120        return SUCCESS;
01121 }
01122 /* }}} */
01123 
01124 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_internal_encoding) */
01125 static PHP_INI_MH(OnUpdate_mbstring_internal_encoding)
01126 {
01127        if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN
01128                      || stage == PHP_INI_STAGE_RUNTIME) {
01129               return _php_mb_ini_mbstring_internal_encoding_set(new_value, new_value_length TSRMLS_CC);
01130        } else {
01131               /* the corresponding mbstring globals needs to be set according to the
01132                * ini value in the later stage because it never falls back to the
01133                * default value if 1. no value for mbstring.internal_encoding is given,
01134                * 2. mbstring.language directive is processed in per-dir or runtime
01135                * context and 3. call to the handler for mbstring.language is done
01136                * after mbstring.internal_encoding is handled. */
01137               return SUCCESS;
01138        }
01139 }
01140 /* }}} */
01141 
01142 #ifdef ZEND_MULTIBYTE
01143 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_script_encoding) */
01144 static PHP_INI_MH(OnUpdate_mbstring_script_encoding)
01145 {
01146        int *list, size;
01147 
01148        if (php_mb_parse_encoding_list(new_value, new_value_length, &list, &size, 1 TSRMLS_CC)) {
01149               if (MBSTRG(script_encoding_list) != NULL) {
01150                      free(MBSTRG(script_encoding_list));
01151               }
01152               MBSTRG(script_encoding_list) = list;
01153               MBSTRG(script_encoding_list_size) = size;
01154        } else {
01155               if (MBSTRG(script_encoding_list) != NULL) {
01156                      free(MBSTRG(script_encoding_list));
01157               }
01158               MBSTRG(script_encoding_list) = NULL;
01159               MBSTRG(script_encoding_list_size) = 0;
01160               return FAILURE;
01161        }
01162 
01163        return SUCCESS;
01164 }
01165 /* }}} */
01166 #endif /* ZEND_MULTIBYTE */
01167 
01168 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_substitute_character) */
01169 static PHP_INI_MH(OnUpdate_mbstring_substitute_character)
01170 {
01171        int c;
01172        char *endptr = NULL;
01173 
01174        if (new_value != NULL) {
01175               if (strcasecmp("none", new_value) == 0) {
01176                      MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
01177                      MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
01178               } else if (strcasecmp("long", new_value) == 0) {
01179                      MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
01180                      MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
01181               } else if (strcasecmp("entity", new_value) == 0) {
01182                      MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
01183                      MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
01184               } else {
01185                      MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01186                      MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01187                      if (new_value_length >0) {
01188                             c = strtol(new_value, &endptr, 0);
01189                             if (*endptr == '\0') {
01190                                    MBSTRG(filter_illegal_substchar) = c;
01191                                    MBSTRG(current_filter_illegal_substchar) = c;
01192                             }
01193                      }
01194               }
01195        } else {
01196               MBSTRG(filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01197               MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01198               MBSTRG(filter_illegal_substchar) = 0x3f;  /* '?' */
01199               MBSTRG(current_filter_illegal_substchar) = 0x3f; /* '?' */
01200        }
01201 
01202        return SUCCESS;
01203 }
01204 /* }}} */
01205 
01206 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_encoding_translation) */
01207 static PHP_INI_MH(OnUpdate_mbstring_encoding_translation)
01208 {
01209        if (new_value == NULL) {
01210           return FAILURE;
01211        }
01212 
01213        OnUpdateBool(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
01214 
01215        if (MBSTRG(encoding_translation)) {
01216               sapi_unregister_post_entry(php_post_entries TSRMLS_CC);
01217               sapi_register_post_entries(mbstr_post_entries TSRMLS_CC);
01218        } else {
01219               sapi_unregister_post_entry(mbstr_post_entries TSRMLS_CC);
01220               sapi_register_post_entries(php_post_entries TSRMLS_CC);
01221        }
01222 
01223        return SUCCESS;
01224 }
01225 /* }}} */
01226 
01227 /* {{{ static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes */
01228 static PHP_INI_MH(OnUpdate_mbstring_http_output_conv_mimetypes)
01229 {
01230        zval tmp;
01231        void *re = NULL;
01232 
01233        if (!new_value) {
01234               new_value = entry->orig_value;
01235               new_value_length = entry->orig_value_length;
01236        }
01237        php_trim(new_value, new_value_length, NULL, 0, &tmp, 3 TSRMLS_CC);
01238 
01239        if (Z_STRLEN(tmp) > 0) {
01240               if (!(re = _php_mb_compile_regex(Z_STRVAL(tmp) TSRMLS_CC))) {
01241                      zval_dtor(&tmp);
01242                      return FAILURE;
01243               }
01244        }
01245 
01246        if (MBSTRG(http_output_conv_mimetypes)) {
01247               _php_mb_free_regex(MBSTRG(http_output_conv_mimetypes));
01248        }
01249 
01250        MBSTRG(http_output_conv_mimetypes) = re;
01251 
01252        zval_dtor(&tmp);
01253        return SUCCESS;
01254 }
01255 /* }}} */
01256 /* }}} */
01257 
01258 /* {{{ php.ini directive registration */
01259 PHP_INI_BEGIN()
01260        PHP_INI_ENTRY("mbstring.language", "neutral", PHP_INI_ALL, OnUpdate_mbstring_language)
01261        PHP_INI_ENTRY("mbstring.detect_order", NULL, PHP_INI_ALL, OnUpdate_mbstring_detect_order)
01262        PHP_INI_ENTRY("mbstring.http_input", "pass", PHP_INI_ALL, OnUpdate_mbstring_http_input)
01263        PHP_INI_ENTRY("mbstring.http_output", "pass", PHP_INI_ALL, OnUpdate_mbstring_http_output)
01264        PHP_INI_ENTRY("mbstring.internal_encoding", NULL, PHP_INI_ALL, OnUpdate_mbstring_internal_encoding)
01265 #ifdef ZEND_MULTIBYTE
01266        PHP_INI_ENTRY("mbstring.script_encoding", NULL, PHP_INI_ALL, OnUpdate_mbstring_script_encoding)
01267 #endif /* ZEND_MULTIBYTE */
01268        PHP_INI_ENTRY("mbstring.substitute_character", NULL, PHP_INI_ALL, OnUpdate_mbstring_substitute_character)
01269        STD_PHP_INI_ENTRY("mbstring.func_overload", "0", 
01270        PHP_INI_SYSTEM, OnUpdateLong, func_overload, zend_mbstring_globals, mbstring_globals)
01271 
01272        STD_PHP_INI_BOOLEAN("mbstring.encoding_translation", "0",
01273               PHP_INI_SYSTEM | PHP_INI_PERDIR,
01274               OnUpdate_mbstring_encoding_translation, 
01275               encoding_translation, zend_mbstring_globals, mbstring_globals)                              
01276        PHP_INI_ENTRY("mbstring.http_output_conv_mimetypes",
01277               "^(text/|application/xhtml\\+xml)",
01278               PHP_INI_ALL,
01279               OnUpdate_mbstring_http_output_conv_mimetypes)
01280 
01281        STD_PHP_INI_BOOLEAN("mbstring.strict_detection", "0",
01282               PHP_INI_ALL,
01283               OnUpdateLong,
01284               strict_detection, zend_mbstring_globals, mbstring_globals)
01285 PHP_INI_END()
01286 /* }}} */
01287 
01288 /* {{{ module global initialize handler */
01289 static PHP_GINIT_FUNCTION(mbstring)
01290 {
01291        mbstring_globals->language = mbfl_no_language_uni;
01292        mbstring_globals->internal_encoding = mbfl_no_encoding_invalid;
01293        mbstring_globals->current_internal_encoding = mbstring_globals->internal_encoding;
01294 #ifdef ZEND_MULTIBYTE
01295        mbstring_globals->script_encoding_list = NULL;
01296        mbstring_globals->script_encoding_list_size = 0;
01297 #endif /* ZEND_MULTIBYTE */
01298        mbstring_globals->http_output_encoding = mbfl_no_encoding_pass;
01299        mbstring_globals->current_http_output_encoding = mbfl_no_encoding_pass;
01300        mbstring_globals->http_input_identify = mbfl_no_encoding_invalid;
01301        mbstring_globals->http_input_identify_get = mbfl_no_encoding_invalid;
01302        mbstring_globals->http_input_identify_post = mbfl_no_encoding_invalid;
01303        mbstring_globals->http_input_identify_cookie = mbfl_no_encoding_invalid;
01304        mbstring_globals->http_input_identify_string = mbfl_no_encoding_invalid;
01305        mbstring_globals->http_input_list = NULL;
01306        mbstring_globals->http_input_list_size = 0;
01307        mbstring_globals->detect_order_list = NULL;
01308        mbstring_globals->detect_order_list_size = 0;
01309        mbstring_globals->current_detect_order_list = NULL;
01310        mbstring_globals->current_detect_order_list_size = 0;
01311        mbstring_globals->default_detect_order_list = (enum mbfl_no_encoding *) php_mb_default_identify_list_neut;
01312        mbstring_globals->default_detect_order_list_size = sizeof(php_mb_default_identify_list_neut) / sizeof(php_mb_default_identify_list_neut[0]);
01313        mbstring_globals->filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01314        mbstring_globals->filter_illegal_substchar = 0x3f;      /* '?' */
01315        mbstring_globals->current_filter_illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01316        mbstring_globals->current_filter_illegal_substchar = 0x3f;     /* '?' */
01317        mbstring_globals->illegalchars = 0;
01318        mbstring_globals->func_overload = 0;
01319        mbstring_globals->encoding_translation = 0;
01320        mbstring_globals->strict_detection = 0;
01321        mbstring_globals->outconv = NULL;
01322        mbstring_globals->http_output_conv_mimetypes = NULL;
01323 #if HAVE_MBREGEX
01324        mbstring_globals->mb_regex_globals = php_mb_regex_globals_alloc(TSRMLS_C);
01325 #endif
01326 }
01327 /* }}} */
01328 
01329 /* {{{ PHP_GSHUTDOWN_FUNCTION */
01330 static PHP_GSHUTDOWN_FUNCTION(mbstring)
01331 {
01332        if (mbstring_globals->http_input_list) {
01333               free(mbstring_globals->http_input_list);
01334        }
01335 #ifdef ZEND_MULTIBYTE
01336        if (mbstring_globals->script_encoding_list) {
01337               free(mbstring_globals->script_encoding_list);
01338        }
01339 #endif /* ZEND_MULTIBYTE */
01340        if (mbstring_globals->detect_order_list) {
01341               free(mbstring_globals->detect_order_list);
01342        }
01343        if (mbstring_globals->http_output_conv_mimetypes) {
01344               _php_mb_free_regex(mbstring_globals->http_output_conv_mimetypes);
01345        }
01346 #if HAVE_MBREGEX
01347        php_mb_regex_globals_free(mbstring_globals->mb_regex_globals TSRMLS_CC);
01348 #endif
01349 }
01350 /* }}} */
01351 
01352 /* {{{ PHP_MINIT_FUNCTION(mbstring) */
01353 PHP_MINIT_FUNCTION(mbstring)
01354 {
01355        __mbfl_allocators = &_php_mb_allocators;
01356 
01357        REGISTER_INI_ENTRIES();
01358 
01359        /* This is a global handler. Should not be set in a per-request handler. */
01360        sapi_register_treat_data(mbstr_treat_data);
01361 
01362        /* Post handlers are stored in the thread-local context. */
01363        if (MBSTRG(encoding_translation)) {
01364               sapi_register_post_entries(mbstr_post_entries TSRMLS_CC);
01365        }
01366 
01367        REGISTER_LONG_CONSTANT("MB_OVERLOAD_MAIL", MB_OVERLOAD_MAIL, CONST_CS | CONST_PERSISTENT);
01368        REGISTER_LONG_CONSTANT("MB_OVERLOAD_STRING", MB_OVERLOAD_STRING, CONST_CS | CONST_PERSISTENT);
01369        REGISTER_LONG_CONSTANT("MB_OVERLOAD_REGEX", MB_OVERLOAD_REGEX, CONST_CS | CONST_PERSISTENT);
01370 
01371        REGISTER_LONG_CONSTANT("MB_CASE_UPPER", PHP_UNICODE_CASE_UPPER, CONST_CS | CONST_PERSISTENT);
01372        REGISTER_LONG_CONSTANT("MB_CASE_LOWER", PHP_UNICODE_CASE_LOWER, CONST_CS | CONST_PERSISTENT);
01373        REGISTER_LONG_CONSTANT("MB_CASE_TITLE", PHP_UNICODE_CASE_TITLE, CONST_CS | CONST_PERSISTENT);
01374 
01375 #if HAVE_MBREGEX
01376        PHP_MINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
01377 #endif
01378        return SUCCESS;
01379 }
01380 /* }}} */
01381 
01382 /* {{{ PHP_MSHUTDOWN_FUNCTION(mbstring) */
01383 PHP_MSHUTDOWN_FUNCTION(mbstring)
01384 {
01385        UNREGISTER_INI_ENTRIES();
01386        
01387 #if HAVE_MBREGEX
01388        PHP_MSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
01389 #endif
01390 
01391        return SUCCESS;
01392 }
01393 /* }}} */
01394 
01395 /* {{{ PHP_RINIT_FUNCTION(mbstring) */
01396 PHP_RINIT_FUNCTION(mbstring)
01397 {
01398        int n;
01399        enum mbfl_no_encoding *list=NULL, *entry;
01400        zend_function *func, *orig;
01401        const struct mb_overload_def *p;
01402 
01403        MBSTRG(current_internal_encoding) = MBSTRG(internal_encoding);
01404        MBSTRG(current_http_output_encoding) = MBSTRG(http_output_encoding);
01405        MBSTRG(current_filter_illegal_mode) = MBSTRG(filter_illegal_mode);
01406        MBSTRG(current_filter_illegal_substchar) = MBSTRG(filter_illegal_substchar);
01407 
01408        MBSTRG(illegalchars) = 0;
01409 
01410        n = 0;
01411        if (MBSTRG(detect_order_list)) {
01412               list = MBSTRG(detect_order_list);
01413               n = MBSTRG(detect_order_list_size);
01414        }
01415        if (n <= 0) {
01416               list = MBSTRG(default_detect_order_list);
01417               n = MBSTRG(default_detect_order_list_size);
01418        }
01419        entry = (enum mbfl_no_encoding *)safe_emalloc(n, sizeof(int), 0);
01420        MBSTRG(current_detect_order_list) = entry;
01421        MBSTRG(current_detect_order_list_size) = n;
01422        while (n > 0) {
01423               *entry++ = *list++;
01424               n--;
01425        }
01426 
01427        /* override original function. */
01428        if (MBSTRG(func_overload)){
01429               p = &(mb_ovld[0]);
01430               
01431               while (p->type > 0) {
01432                      if ((MBSTRG(func_overload) & p->type) == p->type && 
01433                             zend_hash_find(EG(function_table), p->save_func,
01434                                    strlen(p->save_func)+1, (void **)&orig) != SUCCESS) {
01435 
01436                             zend_hash_find(EG(function_table), p->ovld_func, strlen(p->ovld_func)+1 , (void **)&func);
01437                             
01438                             if (zend_hash_find(EG(function_table), p->orig_func, strlen(p->orig_func)+1, (void **)&orig) != SUCCESS) {
01439                                    php_error_docref("ref.mbstring" TSRMLS_CC, E_WARNING, "mbstring couldn't find function %s.", p->orig_func);
01440                                    return FAILURE;
01441                             } else {
01442                                    zend_hash_add(EG(function_table), p->save_func, strlen(p->save_func)+1, orig, sizeof(zend_function), NULL);
01443 
01444                                    if (zend_hash_update(EG(function_table), p->orig_func, strlen(p->orig_func)+1, func, sizeof(zend_function), 
01445                                           NULL) == FAILURE) {
01446                                           php_error_docref("ref.mbstring" TSRMLS_CC, E_WARNING, "mbstring couldn't replace function %s.", p->orig_func);
01447                                           return FAILURE;
01448                                    }
01449                             }
01450                      }
01451                      p++;
01452               }
01453        }
01454 #if HAVE_MBREGEX
01455        PHP_RINIT(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
01456 #endif
01457 #ifdef ZEND_MULTIBYTE
01458        zend_multibyte_set_internal_encoding(mbfl_no_encoding2name(MBSTRG(internal_encoding)) TSRMLS_CC);
01459        php_mb_set_zend_encoding(TSRMLS_C);
01460 #endif /* ZEND_MULTIBYTE */
01461 
01462        return SUCCESS;
01463 }
01464 /* }}} */
01465 
01466 /* {{{ PHP_RSHUTDOWN_FUNCTION(mbstring) */
01467 PHP_RSHUTDOWN_FUNCTION(mbstring)
01468 {
01469        const struct mb_overload_def *p;
01470        zend_function *orig;
01471 
01472        if (MBSTRG(current_detect_order_list) != NULL) {
01473               efree(MBSTRG(current_detect_order_list));
01474               MBSTRG(current_detect_order_list) = NULL;
01475               MBSTRG(current_detect_order_list_size) = 0;
01476        }
01477        if (MBSTRG(outconv) != NULL) {
01478               MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv));
01479               mbfl_buffer_converter_delete(MBSTRG(outconv));
01480               MBSTRG(outconv) = NULL;
01481        }
01482 
01483        /* clear http input identification. */
01484        MBSTRG(http_input_identify) = mbfl_no_encoding_invalid;
01485        MBSTRG(http_input_identify_post) = mbfl_no_encoding_invalid;
01486        MBSTRG(http_input_identify_get) = mbfl_no_encoding_invalid;
01487        MBSTRG(http_input_identify_cookie) = mbfl_no_encoding_invalid;
01488        MBSTRG(http_input_identify_string) = mbfl_no_encoding_invalid;
01489 
01490        /*  clear overloaded function. */
01491        if (MBSTRG(func_overload)){
01492               p = &(mb_ovld[0]);
01493               while (p->type > 0) {
01494                      if ((MBSTRG(func_overload) & p->type) == p->type && 
01495                             zend_hash_find(EG(function_table), p->save_func,
01496                                                     strlen(p->save_func)+1, (void **)&orig) == SUCCESS) {
01497                             
01498                             zend_hash_update(EG(function_table), p->orig_func, strlen(p->orig_func)+1, orig, sizeof(zend_function), NULL);
01499                             zend_hash_del(EG(function_table), p->save_func, strlen(p->save_func)+1);
01500                      }
01501                      p++;
01502               }
01503        }
01504 
01505 #if HAVE_MBREGEX
01506        PHP_RSHUTDOWN(mb_regex) (INIT_FUNC_ARGS_PASSTHRU);
01507 #endif
01508 
01509        return SUCCESS;
01510 }
01511 /* }}} */
01512 
01513 /* {{{ PHP_MINFO_FUNCTION(mbstring) */
01514 PHP_MINFO_FUNCTION(mbstring)
01515 {
01516        php_info_print_table_start();
01517        php_info_print_table_row(2, "Multibyte Support", "enabled");
01518        php_info_print_table_row(2, "Multibyte string engine", "libmbfl");
01519        php_info_print_table_row(2, "HTTP input encoding translation", MBSTRG(encoding_translation) ? "enabled": "disabled");  
01520        php_info_print_table_end();
01521 
01522        php_info_print_table_start();
01523        php_info_print_table_header(1, "mbstring extension makes use of \"streamable kanji code filter and converter\", which is distributed under the GNU Lesser General Public License version 2.1.");
01524        php_info_print_table_end();
01525 
01526 #if HAVE_MBREGEX
01527        PHP_MINFO(mb_regex)(ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU);
01528 #endif
01529 
01530        DISPLAY_INI_ENTRIES();
01531 }
01532 /* }}} */
01533 
01534 /* {{{ proto string mb_language([string language])
01535    Sets the current language or Returns the current language as a string */
01536 PHP_FUNCTION(mb_language)
01537 {
01538        char *name = NULL;
01539        int name_len = 0;
01540 
01541        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
01542               return;
01543        }
01544        if (name == NULL) {
01545               RETVAL_STRING((char *)mbfl_no_language2name(MBSTRG(language)), 1);
01546        } else {
01547               if (FAILURE == zend_alter_ini_entry(
01548                             "mbstring.language", sizeof("mbstring.language"),
01549                             name, name_len, PHP_INI_USER, PHP_INI_STAGE_RUNTIME)) {
01550                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown language \"%s\"", name);
01551                      RETVAL_FALSE;
01552               } else {
01553                      RETVAL_TRUE;
01554               }
01555        }
01556 }
01557 /* }}} */
01558 
01559 /* {{{ proto string mb_internal_encoding([string encoding])
01560    Sets the current internal encoding or Returns the current internal encoding as a string */
01561 PHP_FUNCTION(mb_internal_encoding)
01562 {
01563        char *name = NULL;
01564        int name_len;
01565        enum mbfl_no_encoding no_encoding;
01566 
01567        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name, &name_len) == FAILURE) {
01568               RETURN_FALSE;
01569        }
01570        if (name == NULL) {
01571               name = (char *)mbfl_no_encoding2name(MBSTRG(current_internal_encoding));
01572               if (name != NULL) {
01573                      RETURN_STRING(name, 1);
01574               } else {
01575                      RETURN_FALSE;
01576               }
01577        } else {
01578               no_encoding = mbfl_name2no_encoding(name);
01579               if (no_encoding == mbfl_no_encoding_invalid) {
01580                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name);
01581                      RETURN_FALSE;
01582               } else {
01583                      MBSTRG(current_internal_encoding) = no_encoding;
01584 #ifdef ZEND_MULTIBYTE
01585                      /* TODO: make independent from mbstring.encoding_translation? */
01586                      if (MBSTRG(encoding_translation)) {
01587                             zend_multibyte_set_internal_encoding(name TSRMLS_CC);
01588                      }
01589 #endif /* ZEND_MULTIBYTE */
01590                      RETURN_TRUE;
01591               }
01592        }
01593 }
01594 /* }}} */
01595 
01596 /* {{{ proto mixed mb_http_input([string type])
01597    Returns the input encoding */
01598 PHP_FUNCTION(mb_http_input)
01599 {
01600        char *typ = NULL;
01601        int typ_len;
01602        int retname, n;
01603        char *name, *list, *temp;
01604        enum mbfl_no_encoding *entry;
01605        enum mbfl_no_encoding result = mbfl_no_encoding_invalid;
01606 
01607        retname = 1;
01608        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &typ, &typ_len) == FAILURE) {
01609               RETURN_FALSE;
01610        }
01611        if (typ == NULL) {
01612               result = MBSTRG(http_input_identify);
01613        } else {
01614               switch (*typ) {
01615               case 'G':
01616               case 'g':
01617                      result = MBSTRG(http_input_identify_get);
01618                      break;
01619               case 'P':
01620               case 'p':
01621                      result = MBSTRG(http_input_identify_post);
01622                      break;
01623               case 'C':
01624               case 'c':
01625                      result = MBSTRG(http_input_identify_cookie);
01626                      break;
01627               case 'S':
01628               case 's':
01629                      result = MBSTRG(http_input_identify_string);
01630                      break;
01631               case 'I':
01632               case 'i':
01633                      array_init(return_value);
01634                      entry = MBSTRG(http_input_list);
01635                      n = MBSTRG(http_input_list_size);
01636                      while (n > 0) {
01637                             name = (char *)mbfl_no_encoding2name(*entry);
01638                             if (name) {
01639                                    add_next_index_string(return_value, name, 1);
01640                             }
01641                             entry++;
01642                             n--;
01643                      }
01644                      retname = 0;
01645                      break;
01646               case 'L':
01647               case 'l':
01648                      entry = MBSTRG(http_input_list);
01649                      n = MBSTRG(http_input_list_size);
01650                      list = NULL;
01651                      while (n > 0) {
01652                             name = (char *)mbfl_no_encoding2name(*entry);
01653                             if (name) {
01654                                    if (list) {
01655                                           temp = list;
01656                                           spprintf(&list, 0, "%s,%s", temp, name);
01657                                           efree(temp);
01658                                           if (!list) { 
01659                                                  break;
01660                                           }
01661                                    } else {
01662                                           list = estrdup(name);
01663                                    }
01664                             }
01665                             entry++;
01666                             n--;
01667                      }
01668                      if (!list) {
01669                             RETURN_FALSE;
01670                      }
01671                      RETVAL_STRING(list, 0);
01672                      retname = 0;
01673                      break;
01674               default:
01675                      result = MBSTRG(http_input_identify);
01676                      break;
01677               }
01678        }
01679 
01680        if (retname) {
01681               if (result != mbfl_no_encoding_invalid &&
01682                      (name = (char *)mbfl_no_encoding2name(result)) != NULL) {
01683                      RETVAL_STRING(name, 1);
01684               } else {
01685                      RETVAL_FALSE;
01686               }
01687        }
01688 }
01689 /* }}} */
01690 
01691 /* {{{ proto string mb_http_output([string encoding])
01692    Sets the current output_encoding or returns the current output_encoding as a string */
01693 PHP_FUNCTION(mb_http_output)
01694 {
01695        char *name = NULL;
01696        int name_len;
01697        enum mbfl_no_encoding no_encoding;
01698 
01699        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", (char **)&name, &name_len) == FAILURE) {
01700               RETURN_FALSE;
01701        }
01702 
01703        if (name == NULL) {
01704               name = (char *)mbfl_no_encoding2name(MBSTRG(current_http_output_encoding));
01705               if (name != NULL) {
01706                      RETURN_STRING(name, 1);
01707               } else {
01708                      RETURN_FALSE;
01709               }
01710        } else {
01711               no_encoding = mbfl_name2no_encoding(name);
01712               if (no_encoding == mbfl_no_encoding_invalid) {
01713                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name);
01714                      RETURN_FALSE;
01715               } else {
01716                      MBSTRG(current_http_output_encoding) = no_encoding;
01717                      RETURN_TRUE;
01718               }
01719        }
01720 }
01721 /* }}} */
01722 
01723 /* {{{ proto bool|array mb_detect_order([mixed encoding-list])
01724    Sets the current detect_order or Return the current detect_order as a array */
01725 PHP_FUNCTION(mb_detect_order)
01726 {
01727        zval **arg1 = NULL;
01728        int n, size;
01729        enum mbfl_no_encoding *list, *entry;
01730        char *name;
01731 
01732        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &arg1) == FAILURE) {
01733               return;
01734        }
01735 
01736        if (!arg1) {
01737               array_init(return_value);
01738               entry = MBSTRG(current_detect_order_list);
01739               n = MBSTRG(current_detect_order_list_size);
01740               while (n > 0) {
01741                      name = (char *)mbfl_no_encoding2name(*entry);
01742                      if (name) {
01743                             add_next_index_string(return_value, name, 1);
01744                      }
01745                      entry++;
01746                      n--;
01747               }
01748        } else {
01749               list = NULL;
01750               size = 0;
01751               switch (Z_TYPE_PP(arg1)) {
01752               case IS_ARRAY:
01753                      if (!php_mb_parse_encoding_array(*arg1, &list, &size, 0 TSRMLS_CC)) {
01754                             if (list) {
01755                                    efree(list);
01756                             }
01757                             RETURN_FALSE;
01758                      }
01759                      break;
01760               default:
01761                      convert_to_string_ex(arg1);
01762                      if (!php_mb_parse_encoding_list(Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1), &list, &size, 0 TSRMLS_CC)) {
01763                             if (list) {
01764                                    efree(list);
01765                             }
01766                             RETURN_FALSE;
01767                      }
01768                      break;
01769               }
01770 
01771               if (list == NULL) {
01772                      RETURN_FALSE;
01773               }
01774 
01775               if (MBSTRG(current_detect_order_list)) {
01776                      efree(MBSTRG(current_detect_order_list));
01777               }
01778               MBSTRG(current_detect_order_list) = list;
01779               MBSTRG(current_detect_order_list_size) = size;
01780               RETURN_TRUE;
01781        }
01782 }
01783 /* }}} */
01784 
01785 /* {{{ proto mixed mb_substitute_character([mixed substchar])
01786    Sets the current substitute_character or returns the current substitute_character */
01787 PHP_FUNCTION(mb_substitute_character)
01788 {
01789        zval **arg1 = NULL;
01790 
01791        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|Z", &arg1) == FAILURE) {
01792               return;
01793        }
01794 
01795        if (!arg1) {
01796               if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
01797                      RETURN_STRING("none", 1);
01798               } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
01799                      RETURN_STRING("long", 1);
01800               } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
01801                      RETURN_STRING("entity", 1);
01802               } else {
01803                      RETURN_LONG(MBSTRG(current_filter_illegal_substchar));
01804               }
01805        } else {
01806               RETVAL_TRUE;
01807 
01808               switch (Z_TYPE_PP(arg1)) {
01809               case IS_STRING:
01810                      if (strncasecmp("none", Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)) == 0) {
01811                             MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
01812                      } else if (strncasecmp("long", Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)) == 0) {
01813                             MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG;
01814                      } else if (strncasecmp("entity", Z_STRVAL_PP(arg1), Z_STRLEN_PP(arg1)) == 0) {
01815                             MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY;
01816                      } else {
01817                             convert_to_long_ex(arg1);
01818 
01819                             if (Z_LVAL_PP(arg1) < 0xffff && Z_LVAL_PP(arg1) > 0x0) {
01820                                    MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01821                                    MBSTRG(current_filter_illegal_substchar) = Z_LVAL_PP(arg1);
01822                             } else {
01823                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown character.");
01824                                    RETURN_FALSE;
01825                             }
01826                      }
01827                      break;
01828               default:
01829                      convert_to_long_ex(arg1);
01830                      if (Z_LVAL_PP(arg1) < 0xffff && Z_LVAL_PP(arg1) > 0x0) {
01831                             MBSTRG(current_filter_illegal_mode) = MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR;
01832                             MBSTRG(current_filter_illegal_substchar) = Z_LVAL_PP(arg1);
01833                      } else {
01834                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown character.");
01835                             RETURN_FALSE;
01836                      }
01837                      break;
01838               }
01839        }
01840 }
01841 /* }}} */
01842 
01843 /* {{{ proto string mb_preferred_mime_name(string encoding)
01844    Return the preferred MIME name (charset) as a string */
01845 PHP_FUNCTION(mb_preferred_mime_name)
01846 {
01847        enum mbfl_no_encoding no_encoding;
01848        char *name = NULL;
01849        int name_len;
01850 
01851        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
01852               return;
01853        } else {
01854               no_encoding = mbfl_name2no_encoding(name);
01855               if (no_encoding == mbfl_no_encoding_invalid) {
01856                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name);
01857                      RETVAL_FALSE;
01858               } else {
01859                      const char *preferred_name = mbfl_no2preferred_mime_name(no_encoding);
01860                      if (preferred_name == NULL || *preferred_name == '\0') {
01861                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "No MIME preferred name corresponding to \"%s\"", name);
01862                             RETVAL_FALSE;
01863                      } else {
01864                             RETVAL_STRING((char *)preferred_name, 1);
01865                      }
01866               }
01867        }
01868 }
01869 /* }}} */
01870 
01871 #define IS_SJIS1(c) ((((c)>=0x81 && (c)<=0x9f) || ((c)>=0xe0 && (c)<=0xf5)) ? 1 : 0)
01872 #define IS_SJIS2(c) ((((c)>=0x40 && (c)<=0x7e) || ((c)>=0x80 && (c)<=0xfc)) ? 1 : 0)
01873 
01874 /* {{{ proto bool mb_parse_str(string encoded_string [, array result])
01875    Parses GET/POST/COOKIE data and sets global variables */
01876 PHP_FUNCTION(mb_parse_str)
01877 {
01878        zval *track_vars_array = NULL;
01879        char *encstr = NULL;
01880        int encstr_len;
01881        php_mb_encoding_handler_info_t info;
01882        enum mbfl_no_encoding detected;
01883 
01884        track_vars_array = NULL;
01885        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &encstr, &encstr_len, &track_vars_array) == FAILURE) {
01886               return;
01887        }
01888 
01889        /* Clear out the array */
01890        if (track_vars_array != NULL) {
01891               zval_dtor(track_vars_array);
01892               array_init(track_vars_array);
01893        }
01894 
01895        encstr = estrndup(encstr, encstr_len);
01896 
01897        info.data_type              = PARSE_STRING;
01898        info.separator              = PG(arg_separator).input; 
01899        info.force_register_globals = (track_vars_array == NULL);
01900        info.report_errors          = 1;
01901        info.to_encoding            = MBSTRG(current_internal_encoding);
01902        info.to_language            = MBSTRG(language);
01903        info.from_encodings         = MBSTRG(http_input_list);
01904        info.num_from_encodings     = MBSTRG(http_input_list_size); 
01905        info.from_language          = MBSTRG(language);
01906 
01907        detected = _php_mb_encoding_handler_ex(&info, track_vars_array, encstr TSRMLS_CC);
01908 
01909        MBSTRG(http_input_identify) = detected;
01910 
01911        RETVAL_BOOL(detected != mbfl_no_encoding_invalid);
01912 
01913        if (encstr != NULL) efree(encstr);
01914 }
01915 /* }}} */
01916 
01917 /* {{{ proto string mb_output_handler(string contents, int status)
01918    Returns string in output buffer converted to the http_output encoding */
01919 PHP_FUNCTION(mb_output_handler)
01920 {
01921        char *arg_string;
01922        int arg_string_len;
01923        long arg_status;
01924        mbfl_string string, result;
01925        const char *charset;
01926        char *p;
01927        enum mbfl_no_encoding encoding;
01928        int last_feed, len;
01929        unsigned char send_text_mimetype = 0;
01930        char *s, *mimetype = NULL;
01931 
01932        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &arg_string, &arg_string_len, &arg_status) == FAILURE) {
01933               return;
01934        }
01935 
01936        encoding = MBSTRG(current_http_output_encoding);
01937 
01938        /* start phase only */
01939        if ((arg_status & PHP_OUTPUT_HANDLER_START) != 0) {
01940               /* delete the converter just in case. */
01941               if (MBSTRG(outconv)) {
01942                      MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv));
01943                      mbfl_buffer_converter_delete(MBSTRG(outconv));
01944                      MBSTRG(outconv) = NULL;
01945               }
01946               if (encoding == mbfl_no_encoding_pass) {
01947                      RETURN_STRINGL(arg_string, arg_string_len, 1);
01948               }
01949 
01950               /* analyze mime type */
01951               if (SG(sapi_headers).mimetype &&
01952                      _php_mb_match_regex(
01953                             MBSTRG(http_output_conv_mimetypes),
01954                             SG(sapi_headers).mimetype,
01955                             strlen(SG(sapi_headers).mimetype))) {
01956                      if ((s = strchr(SG(sapi_headers).mimetype,';')) == NULL){
01957                             mimetype = estrdup(SG(sapi_headers).mimetype);
01958                      } else {
01959                             mimetype = estrndup(SG(sapi_headers).mimetype,s-SG(sapi_headers).mimetype);
01960                      }
01961                      send_text_mimetype = 1;
01962               } else if (SG(sapi_headers).send_default_content_type) {
01963                      mimetype = SG(default_mimetype) ? SG(default_mimetype) : SAPI_DEFAULT_MIMETYPE;
01964               }
01965 
01966               /* if content-type is not yet set, set it and activate the converter */
01967               if (SG(sapi_headers).send_default_content_type || send_text_mimetype) {
01968                      charset = mbfl_no2preferred_mime_name(encoding);
01969                      if (charset) {
01970                             len = spprintf( &p, 0, "Content-Type: %s; charset=%s",  mimetype, charset ); 
01971                             if (sapi_add_header(p, len, 0) != FAILURE) {
01972                                    SG(sapi_headers).send_default_content_type = 0;
01973                             }
01974                      }
01975                      /* activate the converter */
01976                      MBSTRG(outconv) = mbfl_buffer_converter_new(MBSTRG(current_internal_encoding), encoding, 0);
01977                      if (send_text_mimetype){
01978                             efree(mimetype);
01979                      }
01980               }
01981        }
01982 
01983        /* just return if the converter is not activated. */
01984        if (MBSTRG(outconv) == NULL) {
01985               RETURN_STRINGL(arg_string, arg_string_len, 1);
01986        }
01987 
01988        /* flag */
01989        last_feed = ((arg_status & PHP_OUTPUT_HANDLER_END) != 0);
01990        /* mode */
01991        mbfl_buffer_converter_illegal_mode(MBSTRG(outconv), MBSTRG(current_filter_illegal_mode));
01992        mbfl_buffer_converter_illegal_substchar(MBSTRG(outconv), MBSTRG(current_filter_illegal_substchar));
01993  
01994        /* feed the string */
01995        mbfl_string_init(&string);
01996        string.no_language = MBSTRG(language);
01997        string.no_encoding = MBSTRG(current_internal_encoding);
01998        string.val = (unsigned char *)arg_string;
01999        string.len = arg_string_len;
02000        mbfl_buffer_converter_feed(MBSTRG(outconv), &string);
02001        if (last_feed) {
02002               mbfl_buffer_converter_flush(MBSTRG(outconv));
02003        } 
02004        /* get the converter output, and return it */
02005        mbfl_buffer_converter_result(MBSTRG(outconv), &result);
02006        RETVAL_STRINGL((char *)result.val, result.len, 0);             /* the string is already strdup()'ed */
02007  
02008        /* delete the converter if it is the last feed. */
02009        if (last_feed) {
02010               MBSTRG(illegalchars) += mbfl_buffer_illegalchars(MBSTRG(outconv));
02011               mbfl_buffer_converter_delete(MBSTRG(outconv));
02012               MBSTRG(outconv) = NULL;
02013        }
02014 }
02015 /* }}} */
02016 
02017 /* {{{ proto int mb_strlen(string str [, string encoding])
02018    Get character numbers of a string */
02019 PHP_FUNCTION(mb_strlen)
02020 {
02021        int n;
02022        mbfl_string string;
02023        char *enc_name = NULL;
02024        int enc_name_len;
02025 
02026        mbfl_string_init(&string);
02027 
02028        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) {
02029               RETURN_FALSE;
02030        }
02031 
02032        string.no_language = MBSTRG(language);
02033        if (enc_name == NULL) {
02034               string.no_encoding = MBSTRG(current_internal_encoding);
02035        } else {
02036               string.no_encoding = mbfl_name2no_encoding(enc_name);
02037               if (string.no_encoding == mbfl_no_encoding_invalid) {
02038                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02039                      RETURN_FALSE;
02040               }
02041        }
02042 
02043        n = mbfl_strlen(&string);
02044        if (n >= 0) {
02045               RETVAL_LONG(n);
02046        } else {
02047               RETVAL_FALSE;
02048        }
02049 }
02050 /* }}} */
02051 
02052 /* {{{ proto int mb_strpos(string haystack, string needle [, int offset [, string encoding]])
02053    Find position of first occurrence of a string within another */
02054 PHP_FUNCTION(mb_strpos)
02055 {
02056        int n, reverse = 0;
02057        long offset;
02058        mbfl_string haystack, needle;
02059        char *enc_name = NULL;
02060        int enc_name_len;
02061        
02062        mbfl_string_init(&haystack);
02063        mbfl_string_init(&needle);
02064        haystack.no_language = MBSTRG(language);
02065        haystack.no_encoding = MBSTRG(current_internal_encoding);
02066        needle.no_language = MBSTRG(language);
02067        needle.no_encoding = MBSTRG(current_internal_encoding);
02068        offset = 0;
02069 
02070        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &offset, &enc_name, &enc_name_len) == FAILURE) {
02071               RETURN_FALSE;
02072        }
02073 
02074        if (enc_name != NULL) {
02075               haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
02076               if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02077                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02078                      RETURN_FALSE;
02079               }
02080        }
02081 
02082        if (offset < 0 || offset > mbfl_strlen(&haystack)) {
02083               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
02084               RETURN_FALSE;
02085        }
02086        if (needle.len == 0) {
02087               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
02088               RETURN_FALSE;
02089        }
02090 
02091        n = mbfl_strpos(&haystack, &needle, offset, reverse);
02092        if (n >= 0) {
02093               RETVAL_LONG(n);
02094        } else {
02095               switch (-n) {
02096               case 1:
02097                      break;
02098               case 2:
02099                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Needle has not positive length");
02100                      break;
02101               case 4:
02102                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding or conversion error");
02103                      break;
02104               case 8:
02105                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Argument is empty");
02106                      break;
02107               default:
02108                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error in mb_strpos");
02109                      break;
02110               }
02111               RETVAL_FALSE;
02112        }
02113 }
02114 /* }}} */
02115 
02116 /* {{{ proto int mb_strrpos(string haystack, string needle [, int offset [, string encoding]])
02117    Find position of last occurrence of a string within another */
02118 PHP_FUNCTION(mb_strrpos)
02119 {
02120        int n;
02121        mbfl_string haystack, needle;
02122        char *enc_name = NULL;
02123        int enc_name_len;
02124        zval **zoffset = NULL;
02125        long offset = 0, str_flg;
02126        char *enc_name2 = NULL;
02127        int enc_name_len2;
02128 
02129        mbfl_string_init(&haystack);
02130        mbfl_string_init(&needle);
02131        haystack.no_language = MBSTRG(language);
02132        haystack.no_encoding = MBSTRG(current_internal_encoding);
02133        needle.no_language = MBSTRG(language);
02134        needle.no_encoding = MBSTRG(current_internal_encoding);
02135 
02136        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Zs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &zoffset, &enc_name, &enc_name_len) == FAILURE) {
02137               RETURN_FALSE;
02138        }
02139 
02140        if (zoffset) {
02141               if (Z_TYPE_PP(zoffset) == IS_STRING) {
02142                      enc_name2     = Z_STRVAL_PP(zoffset);
02143                      enc_name_len2 = Z_STRLEN_PP(zoffset);
02144                      str_flg       = 1;
02145 
02146                      if (enc_name2 != NULL) {
02147                             switch (*enc_name2) {
02148                             case '0':
02149                             case '1':
02150                             case '2':
02151                             case '3':
02152                             case '4':
02153                             case '5':
02154                             case '6':
02155                             case '7':
02156                             case '8':
02157                             case '9':
02158                             case ' ':
02159                             case '-':
02160                             case '.':
02161                                    break;
02162                             default :
02163                                    str_flg = 0;
02164                                    break;
02165                             }
02166                      }
02167 
02168                      if (str_flg) {
02169                             convert_to_long_ex(zoffset);
02170                             offset   = Z_LVAL_PP(zoffset);
02171                      } else {
02172                             enc_name     = enc_name2;
02173                             enc_name_len = enc_name_len2;
02174                      }
02175               } else {
02176                      convert_to_long_ex(zoffset);
02177                      offset = Z_LVAL_PP(zoffset);
02178               }
02179        }
02180 
02181        if (enc_name != NULL) {
02182               haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
02183               if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02184                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02185                      RETURN_FALSE;
02186               }
02187        }
02188 
02189        if (haystack.len <= 0) {
02190               RETURN_FALSE;
02191        }
02192        if (needle.len <= 0) {
02193               RETURN_FALSE;
02194        }
02195 
02196        {
02197               int haystack_char_len = mbfl_strlen(&haystack);
02198               if ((offset > 0 && offset > haystack_char_len) ||
02199                      (offset < 0 && -offset > haystack_char_len)) {
02200                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
02201                      RETURN_FALSE;
02202               }
02203        }
02204 
02205        n = mbfl_strpos(&haystack, &needle, offset, 1);
02206        if (n >= 0) {
02207               RETVAL_LONG(n);
02208        } else {
02209               RETVAL_FALSE;
02210        }
02211 }
02212 /* }}} */
02213 
02214 /* {{{ proto int mb_stripos(string haystack, string needle [, int offset [, string encoding]])
02215    Finds position of first occurrence of a string within another, case insensitive */
02216 PHP_FUNCTION(mb_stripos)
02217 {
02218        int n;
02219        long offset;
02220        mbfl_string haystack, needle;
02221        char *from_encoding = (char*)mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02222        int from_encoding_len;
02223        n = -1;
02224        offset = 0;
02225 
02226        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &offset, &from_encoding, &from_encoding_len) == FAILURE) {
02227               RETURN_FALSE;
02228        }
02229        if (needle.len == 0) {
02230               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
02231               RETURN_FALSE;
02232        }
02233        n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding TSRMLS_CC);
02234 
02235        if (n >= 0) {
02236               RETVAL_LONG(n);
02237        } else {
02238               RETVAL_FALSE;
02239        }
02240 }
02241 /* }}} */
02242 
02243 /* {{{ proto int mb_strripos(string haystack, string needle [, int offset [, string encoding]])
02244    Finds position of last occurrence of a string within another, case insensitive */
02245 PHP_FUNCTION(mb_strripos)
02246 {
02247        int n;
02248        long offset;
02249        mbfl_string haystack, needle;
02250        const char *from_encoding = mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02251        int from_encoding_len;
02252        n = -1;
02253        offset = 0;
02254 
02255        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ls", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &offset, &from_encoding, &from_encoding_len) == FAILURE) {
02256               RETURN_FALSE;
02257        }
02258 
02259        n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, offset, from_encoding TSRMLS_CC);
02260 
02261        if (n >= 0) {
02262               RETVAL_LONG(n);
02263        } else {
02264               RETVAL_FALSE;
02265        }
02266 }
02267 /* }}} */
02268 
02269 /* {{{ proto string mb_strstr(string haystack, string needle[, bool part[, string encoding]])
02270    Finds first occurrence of a string within another */
02271 PHP_FUNCTION(mb_strstr)
02272 {
02273        int n, len, mblen;
02274        mbfl_string haystack, needle, result, *ret = NULL;
02275        char *enc_name = NULL;
02276        int enc_name_len;
02277        zend_bool part = 0;
02278 
02279        mbfl_string_init(&haystack);
02280        mbfl_string_init(&needle);
02281        haystack.no_language = MBSTRG(language);
02282        haystack.no_encoding = MBSTRG(current_internal_encoding);
02283        needle.no_language = MBSTRG(language);
02284        needle.no_encoding = MBSTRG(current_internal_encoding);
02285 
02286        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, (int *)&haystack.len, (char **)&needle.val, (int *)&needle.len, &part, &enc_name, &enc_name_len) == FAILURE) {
02287               RETURN_FALSE;
02288        }
02289 
02290        if (enc_name != NULL) {
02291               haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
02292               if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02293                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02294                      RETURN_FALSE;
02295               }
02296        }
02297 
02298        if (needle.len <= 0) {
02299               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
02300               RETURN_FALSE;
02301        }
02302        n = mbfl_strpos(&haystack, &needle, 0, 0);
02303        if (n >= 0) {
02304               mblen = mbfl_strlen(&haystack);
02305               if (part) {
02306                      ret = mbfl_substr(&haystack, &result, 0, n);
02307                      if (ret != NULL) {
02308                             RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02309                      } else {
02310                             RETVAL_FALSE;
02311                      }
02312               } else {
02313                      len = (mblen - n);
02314                      ret = mbfl_substr(&haystack, &result, n, len);
02315                      if (ret != NULL) {
02316                             RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02317                      } else {
02318                             RETVAL_FALSE;
02319                      }
02320               }
02321        } else {
02322               RETVAL_FALSE;
02323        }
02324 }
02325 /* }}} */
02326 
02327 /* {{{ proto string mb_strrchr(string haystack, string needle[, bool part[, string encoding]])
02328    Finds the last occurrence of a character in a string within another */
02329 PHP_FUNCTION(mb_strrchr)
02330 {
02331        int n, len, mblen;
02332        mbfl_string haystack, needle, result, *ret = NULL;
02333        char *enc_name = NULL;
02334        int enc_name_len;
02335        zend_bool part = 0;
02336 
02337        mbfl_string_init(&haystack);
02338        mbfl_string_init(&needle);
02339        haystack.no_language = MBSTRG(language);
02340        haystack.no_encoding = MBSTRG(current_internal_encoding);
02341        needle.no_language = MBSTRG(language);
02342        needle.no_encoding = MBSTRG(current_internal_encoding);
02343 
02344        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &part, &enc_name, &enc_name_len) == FAILURE) {
02345               RETURN_FALSE;
02346        }
02347 
02348        if (enc_name != NULL) {
02349               haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
02350               if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02351                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02352                      RETURN_FALSE;
02353               }
02354        }
02355 
02356        if (haystack.len <= 0) {
02357               RETURN_FALSE;
02358        }
02359        if (needle.len <= 0) {
02360               RETURN_FALSE;
02361        }
02362        n = mbfl_strpos(&haystack, &needle, 0, 1);
02363        if (n >= 0) {
02364               mblen = mbfl_strlen(&haystack);
02365               if (part) {
02366                      ret = mbfl_substr(&haystack, &result, 0, n);
02367                      if (ret != NULL) {
02368                             RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02369                      } else {
02370                             RETVAL_FALSE;
02371                      }
02372               } else {
02373                      len = (mblen - n);
02374                      ret = mbfl_substr(&haystack, &result, n, len);
02375                      if (ret != NULL) {
02376                             RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02377                      } else {
02378                             RETVAL_FALSE;
02379                      }
02380               }
02381        } else {
02382               RETVAL_FALSE;
02383        }
02384 }
02385 /* }}} */
02386 
02387 /* {{{ proto string mb_stristr(string haystack, string needle[, bool part[, string encoding]])
02388    Finds first occurrence of a string within another, case insensitive */
02389 PHP_FUNCTION(mb_stristr)
02390 {
02391        zend_bool part = 0;
02392        unsigned int from_encoding_len, len, mblen;
02393        int n;
02394        mbfl_string haystack, needle, result, *ret = NULL;
02395        const char *from_encoding = mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02396        mbfl_string_init(&haystack);
02397        mbfl_string_init(&needle);
02398        haystack.no_language = MBSTRG(language);
02399        haystack.no_encoding = MBSTRG(current_internal_encoding);
02400        needle.no_language = MBSTRG(language);
02401        needle.no_encoding = MBSTRG(current_internal_encoding);
02402 
02403 
02404        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &part, &from_encoding, &from_encoding_len) == FAILURE) {
02405               RETURN_FALSE;
02406        }
02407 
02408        if (!needle.len) {
02409               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
02410               RETURN_FALSE;
02411        }
02412 
02413        haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
02414        if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02415               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
02416               RETURN_FALSE;
02417        }
02418 
02419        n = php_mb_stripos(0, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding TSRMLS_CC);
02420 
02421        if (n <0) {
02422               RETURN_FALSE;
02423        }
02424 
02425        mblen = mbfl_strlen(&haystack);
02426 
02427        if (part) {
02428               ret = mbfl_substr(&haystack, &result, 0, n);
02429               if (ret != NULL) {
02430                      RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02431               } else {
02432                      RETVAL_FALSE;
02433               }
02434        } else {
02435               len = (mblen - n);
02436               ret = mbfl_substr(&haystack, &result, n, len);
02437               if (ret != NULL) {
02438                      RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02439               } else {
02440                      RETVAL_FALSE;
02441               }
02442        }
02443 }
02444 /* }}} */
02445 
02446 /* {{{ proto string mb_strrichr(string haystack, string needle[, bool part[, string encoding]])
02447    Finds the last occurrence of a character in a string within another, case insensitive */
02448 PHP_FUNCTION(mb_strrichr)
02449 {
02450        zend_bool part = 0;
02451        int n, from_encoding_len, len, mblen;
02452        mbfl_string haystack, needle, result, *ret = NULL;
02453        char *from_encoding = (char*)mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02454        mbfl_string_init(&haystack);
02455        mbfl_string_init(&needle);
02456        haystack.no_language = MBSTRG(language);
02457        haystack.no_encoding = MBSTRG(current_internal_encoding);
02458        needle.no_language = MBSTRG(language);
02459        needle.no_encoding = MBSTRG(current_internal_encoding);
02460 
02461 
02462        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|bs", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &part, &from_encoding, &from_encoding_len) == FAILURE) {
02463               RETURN_FALSE;
02464        }
02465 
02466        haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
02467        if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02468               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
02469               RETURN_FALSE;
02470        }
02471 
02472        n = php_mb_stripos(1, (char *)haystack.val, haystack.len, (char *)needle.val, needle.len, 0, from_encoding TSRMLS_CC);
02473 
02474        if (n <0) {
02475               RETURN_FALSE;
02476        }
02477 
02478        mblen = mbfl_strlen(&haystack);
02479 
02480        if (part) {
02481               ret = mbfl_substr(&haystack, &result, 0, n);
02482               if (ret != NULL) {
02483                      RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02484               } else {
02485                      RETVAL_FALSE;
02486               }
02487        } else {
02488               len = (mblen - n);
02489               ret = mbfl_substr(&haystack, &result, n, len);
02490               if (ret != NULL) {
02491                      RETVAL_STRINGL((char *)ret->val, ret->len, 0);
02492               } else {
02493                      RETVAL_FALSE;
02494               }
02495        }
02496 }
02497 /* }}} */
02498 
02499 /* {{{ proto int mb_substr_count(string haystack, string needle [, string encoding])
02500    Count the number of substring occurrences */
02501 PHP_FUNCTION(mb_substr_count)
02502 {
02503        int n;
02504        mbfl_string haystack, needle;
02505        char *enc_name = NULL;
02506        int enc_name_len;
02507 
02508        mbfl_string_init(&haystack);
02509        mbfl_string_init(&needle);
02510        haystack.no_language = MBSTRG(language);
02511        haystack.no_encoding = MBSTRG(current_internal_encoding);
02512        needle.no_language = MBSTRG(language);
02513        needle.no_encoding = MBSTRG(current_internal_encoding);
02514 
02515        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s", (char **)&haystack.val, &haystack.len, (char **)&needle.val, &needle.len, &enc_name, &enc_name_len) == FAILURE) {
02516               return;
02517        }
02518 
02519        if (enc_name != NULL) {
02520               haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(enc_name);
02521               if (haystack.no_encoding == mbfl_no_encoding_invalid) {
02522                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02523                      RETURN_FALSE;
02524               }
02525        }
02526 
02527        if (needle.len <= 0) {
02528               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring");
02529               RETURN_FALSE;
02530        }
02531 
02532        n = mbfl_substr_count(&haystack, &needle);
02533        if (n >= 0) {
02534               RETVAL_LONG(n);
02535        } else {
02536               RETVAL_FALSE;
02537        }
02538 }
02539 /* }}} */
02540 
02541 /* {{{ proto string mb_substr(string str, int start [, int length [, string encoding]])
02542    Returns part of a string */
02543 PHP_FUNCTION(mb_substr)
02544 {
02545        size_t argc = ZEND_NUM_ARGS();
02546        char *str, *encoding;
02547        long from, len;
02548        int mblen, str_len, encoding_len;
02549        mbfl_string string, result, *ret;
02550 
02551        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls", &str, &str_len, &from, &len, &encoding, &encoding_len) == FAILURE) {
02552               return;
02553        }
02554 
02555        mbfl_string_init(&string);
02556        string.no_language = MBSTRG(language);
02557        string.no_encoding = MBSTRG(current_internal_encoding);
02558 
02559        if (argc == 4) {
02560               string.no_encoding = mbfl_name2no_encoding(encoding);
02561               if (string.no_encoding == mbfl_no_encoding_invalid) {
02562                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding);
02563                      RETURN_FALSE;
02564               }
02565        }
02566 
02567        string.val = (unsigned char *)str;
02568        string.len = str_len;
02569 
02570        if (argc < 3) {
02571               len = str_len;
02572        }
02573 
02574        /* measures length */
02575        mblen = 0;
02576        if (from < 0 || len < 0) {
02577               mblen = mbfl_strlen(&string);
02578        }
02579 
02580        /* if "from" position is negative, count start position from the end
02581         * of the string
02582         */
02583        if (from < 0) {
02584               from = mblen + from;
02585               if (from < 0) {
02586                      from = 0;
02587               }
02588        }
02589 
02590        /* if "length" position is negative, set it to the length
02591         * needed to stop that many chars from the end of the string
02592         */
02593        if (len < 0) {
02594               len = (mblen - from) + len;
02595               if (len < 0) {
02596                      len = 0;
02597               }
02598        }
02599 
02600        if (((MBSTRG(func_overload) & MB_OVERLOAD_STRING) == MB_OVERLOAD_STRING)
02601               && (from >= mbfl_strlen(&string))) {
02602               RETURN_FALSE;
02603        }
02604 
02605        ret = mbfl_substr(&string, &result, from, len);
02606        if (NULL == ret) {
02607               RETURN_FALSE;
02608        }
02609 
02610        RETURN_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */
02611 }
02612 /* }}} */
02613 
02614 /* {{{ proto string mb_strcut(string str, int start [, int length [, string encoding]])
02615    Returns part of a string */
02616 PHP_FUNCTION(mb_strcut)
02617 {
02618        size_t argc = ZEND_NUM_ARGS();
02619        char *encoding;
02620        long from, len;
02621        int encoding_len;
02622        mbfl_string string, result, *ret;
02623 
02624        mbfl_string_init(&string);
02625        string.no_language = MBSTRG(language);
02626        string.no_encoding = MBSTRG(current_internal_encoding);
02627 
02628        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|ls", (char **)&string.val, (int **)&string.len, &from, &len, &encoding, &encoding_len) == FAILURE) {
02629               return;
02630        }
02631 
02632        if (argc == 4) {
02633               string.no_encoding = mbfl_name2no_encoding(encoding);
02634               if (string.no_encoding == mbfl_no_encoding_invalid) {
02635                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding);
02636                      RETURN_FALSE;
02637               }
02638        }
02639 
02640        if (argc < 3) {
02641               len = string.len;
02642        }
02643 
02644        /* if "from" position is negative, count start position from the end
02645         * of the string
02646         */
02647        if (from < 0) {
02648               from = string.len + from;
02649               if (from < 0) {
02650                      from = 0;
02651               }
02652        }
02653 
02654        /* if "length" position is negative, set it to the length
02655         * needed to stop that many chars from the end of the string
02656         */
02657        if (len < 0) {
02658               len = (string.len - from) + len;
02659               if (len < 0) {
02660                      len = 0;
02661               }
02662        }
02663 
02664        if ((unsigned int)from > string.len) {
02665               RETURN_FALSE;
02666        }
02667 
02668        ret = mbfl_strcut(&string, &result, from, len);
02669        if (ret == NULL) {
02670               RETURN_FALSE;
02671        }
02672 
02673        RETURN_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */
02674 }
02675 /* }}} */
02676 
02677 /* {{{ proto int mb_strwidth(string str [, string encoding])
02678    Gets terminal width of a string */
02679 PHP_FUNCTION(mb_strwidth)
02680 {
02681        int n;
02682        mbfl_string string;
02683        char *enc_name = NULL;
02684        int enc_name_len;
02685 
02686        mbfl_string_init(&string);
02687 
02688        string.no_language = MBSTRG(language);
02689        string.no_encoding = MBSTRG(current_internal_encoding);
02690 
02691        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) {
02692               return;
02693        }
02694 
02695        if (enc_name != NULL) {
02696               string.no_encoding = mbfl_name2no_encoding(enc_name);
02697               if (string.no_encoding == mbfl_no_encoding_invalid) {
02698                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);
02699                      RETURN_FALSE;
02700               }
02701        }
02702 
02703        n = mbfl_strwidth(&string);
02704        if (n >= 0) {
02705               RETVAL_LONG(n);
02706        } else {
02707               RETVAL_FALSE;
02708        }
02709 }
02710 /* }}} */
02711 
02712 /* {{{ proto string mb_strimwidth(string str, int start, int width [, string trimmarker [, string encoding]])
02713    Trim the string in terminal width */
02714 PHP_FUNCTION(mb_strimwidth)
02715 {
02716        char *str, *trimmarker, *encoding;
02717        long from, width;
02718        int str_len, trimmarker_len, encoding_len;
02719        mbfl_string string, result, marker, *ret;
02720 
02721        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll|ss", &str, &str_len, &from, &width, &trimmarker, &trimmarker_len, &encoding, &encoding_len) == FAILURE) {
02722               return;
02723        }
02724 
02725        mbfl_string_init(&string);
02726        mbfl_string_init(&marker);
02727        string.no_language = MBSTRG(language);
02728        string.no_encoding = MBSTRG(current_internal_encoding);
02729        marker.no_language = MBSTRG(language);
02730        marker.no_encoding = MBSTRG(current_internal_encoding);
02731        marker.val = NULL;
02732        marker.len = 0;
02733 
02734        if (ZEND_NUM_ARGS() == 5) {
02735               string.no_encoding = marker.no_encoding = mbfl_name2no_encoding(encoding);
02736               if (string.no_encoding == mbfl_no_encoding_invalid) {
02737                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding);
02738                      RETURN_FALSE;
02739               }
02740        }
02741 
02742        string.val = (unsigned char *)str;
02743        string.len = str_len;
02744 
02745        if (from < 0 || from > str_len) {
02746               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Start position is out of range");
02747               RETURN_FALSE;
02748        }
02749 
02750        if (width < 0) {
02751               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width is negative value");
02752               RETURN_FALSE;
02753        }
02754 
02755        if (ZEND_NUM_ARGS() >= 4) {
02756               marker.val = (unsigned char *)trimmarker;
02757               marker.len = trimmarker_len;
02758        }
02759 
02760        ret = mbfl_strimwidth(&string, &marker, &result, from, width);
02761 
02762        if (ret == NULL) {
02763               RETURN_FALSE;
02764        }
02765 
02766        RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */
02767 }
02768 /* }}} */
02769 
02770 /* {{{ MBSTRING_API char *php_mb_convert_encoding() */
02771 MBSTRING_API char * php_mb_convert_encoding(const char *input, size_t length, const char *_to_encoding, const char *_from_encodings, size_t *output_len TSRMLS_DC)
02772 {
02773        mbfl_string string, result, *ret;
02774        enum mbfl_no_encoding from_encoding, to_encoding;
02775        mbfl_buffer_converter *convd;
02776        int size, *list;
02777        char *output=NULL;
02778 
02779        if (output_len) {
02780               *output_len = 0;
02781        }
02782        if (!input) {
02783               return NULL;
02784        }
02785        /* new encoding */
02786        if (_to_encoding && strlen(_to_encoding)) {
02787               to_encoding = mbfl_name2no_encoding(_to_encoding);
02788               if (to_encoding == mbfl_no_encoding_invalid) {
02789                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", _to_encoding);
02790                      return NULL;
02791               }
02792        } else {
02793               to_encoding = MBSTRG(current_internal_encoding);
02794        }
02795 
02796        /* initialize string */
02797        mbfl_string_init(&string);
02798        mbfl_string_init(&result);
02799        from_encoding = MBSTRG(current_internal_encoding);
02800        string.no_encoding = from_encoding;
02801        string.no_language = MBSTRG(language);
02802        string.val = (unsigned char *)input;
02803        string.len = length;
02804 
02805        /* pre-conversion encoding */
02806        if (_from_encodings) {
02807               list = NULL;
02808               size = 0;
02809            php_mb_parse_encoding_list(_from_encodings, strlen(_from_encodings), &list, &size, 0 TSRMLS_CC);
02810               if (size == 1) {
02811                      from_encoding = *list;
02812                      string.no_encoding = from_encoding;
02813               } else if (size > 1) {
02814                      /* auto detect */
02815                      from_encoding = mbfl_identify_encoding_no(&string, list, size, MBSTRG(strict_detection));
02816                      if (from_encoding != mbfl_no_encoding_invalid) {
02817                             string.no_encoding = from_encoding;
02818                      } else {
02819                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to detect character encoding");
02820                             from_encoding = mbfl_no_encoding_pass;
02821                             to_encoding = from_encoding;
02822                             string.no_encoding = from_encoding;
02823                      }
02824               } else {
02825                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal character encoding specified");
02826               }
02827               if (list != NULL) {
02828                      efree((void *)list);
02829               }
02830        }
02831 
02832        /* initialize converter */
02833        convd = mbfl_buffer_converter_new(from_encoding, to_encoding, string.len);
02834        if (convd == NULL) {
02835               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create character encoding converter");
02836               return NULL;
02837        }
02838        mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
02839        mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
02840 
02841        /* do it */
02842        ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
02843        if (ret) {
02844               if (output_len) {
02845                      *output_len = ret->len;
02846               }
02847               output = (char *)ret->val;
02848        }
02849 
02850        MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
02851        mbfl_buffer_converter_delete(convd);
02852        return output;
02853 }
02854 /* }}} */
02855 
02856 /* {{{ proto string mb_convert_encoding(string str, string to-encoding [, mixed from-encoding])
02857    Returns converted string in desired encoding */
02858 PHP_FUNCTION(mb_convert_encoding)
02859 {
02860        char *arg_str, *arg_new;
02861        int str_len, new_len;
02862        zval *arg_old;
02863        int i;
02864        size_t size, l, n;
02865        char *_from_encodings = NULL, *ret, *s_free = NULL;
02866 
02867        zval **hash_entry;
02868        HashTable *target_hash;
02869 
02870        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|z", &arg_str, &str_len, &arg_new, &new_len, &arg_old) == FAILURE) {
02871               return;
02872        }
02873 
02874        if (ZEND_NUM_ARGS() == 3) {
02875               switch (Z_TYPE_P(arg_old)) {
02876               case IS_ARRAY:
02877                      target_hash = Z_ARRVAL_P(arg_old);
02878                      zend_hash_internal_pointer_reset(target_hash);
02879                      i = zend_hash_num_elements(target_hash);
02880                      _from_encodings = NULL;
02881 
02882                      while (i > 0) {
02883                             if (zend_hash_get_current_data(target_hash, (void **) &hash_entry) == FAILURE) {
02884                                    break;
02885                             }
02886 
02887                             convert_to_string_ex(hash_entry);
02888 
02889                             if ( _from_encodings) {
02890                                    l = strlen(_from_encodings);
02891                                    n = strlen(Z_STRVAL_PP(hash_entry));
02892                                    _from_encodings = erealloc(_from_encodings, l+n+2);
02893                                    strcpy(_from_encodings+l, ",");
02894                                    strcpy(_from_encodings+l+1, Z_STRVAL_PP(hash_entry));
02895                             } else {
02896                                    _from_encodings = estrdup(Z_STRVAL_PP(hash_entry));
02897                             }
02898 
02899                             zend_hash_move_forward(target_hash);
02900                             i--;
02901                      }
02902 
02903                      if (_from_encodings != NULL && !strlen(_from_encodings)) {
02904                             efree(_from_encodings);
02905                             _from_encodings = NULL;
02906                      }
02907                      s_free = _from_encodings;
02908                      break;
02909               default:
02910                      convert_to_string(arg_old);
02911                      _from_encodings = Z_STRVAL_P(arg_old);
02912                      break;
02913               }
02914        }
02915 
02916        /* new encoding */
02917        ret = php_mb_convert_encoding(arg_str, str_len, arg_new, _from_encodings, &size TSRMLS_CC);
02918        if (ret != NULL) {
02919               RETVAL_STRINGL(ret, size, 0);             /* the string is already strdup()'ed */
02920        } else {
02921               RETVAL_FALSE;
02922        }
02923 
02924        if ( s_free) {
02925               efree(s_free);
02926        }
02927 }
02928 /* }}} */
02929 
02930 /* {{{ proto string mb_convert_case(string sourcestring, int mode [, string encoding])
02931    Returns a case-folded version of sourcestring */
02932 PHP_FUNCTION(mb_convert_case)
02933 {
02934        char *str, *from_encoding = (char*)mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02935        int str_len, from_encoding_len;
02936        long case_mode = 0;
02937        char *newstr;
02938        size_t ret_len;
02939 
02940        RETVAL_FALSE;
02941        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|s!", &str, &str_len,
02942                             &case_mode, &from_encoding, &from_encoding_len) == FAILURE)
02943               RETURN_FALSE;
02944 
02945        newstr = php_unicode_convert_case(case_mode, str, (size_t) str_len, &ret_len, from_encoding TSRMLS_CC);
02946 
02947        if (newstr) {
02948               RETVAL_STRINGL(newstr, ret_len, 0);
02949        }      
02950 }
02951 /* }}} */
02952 
02953 /* {{{ proto string mb_strtoupper(string sourcestring [, string encoding])
02954  *  Returns a uppercased version of sourcestring
02955  */
02956 PHP_FUNCTION(mb_strtoupper)
02957 {
02958        char *str, *from_encoding = (char*)mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02959        int str_len, from_encoding_len;
02960        char *newstr;
02961        size_t ret_len;
02962 
02963        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &str, &str_len,
02964                             &from_encoding, &from_encoding_len) == FAILURE) {
02965               return;
02966        }
02967        newstr = php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, str, (size_t) str_len, &ret_len, from_encoding TSRMLS_CC);
02968 
02969        if (newstr) {
02970               RETURN_STRINGL(newstr, ret_len, 0);
02971        }
02972        RETURN_FALSE;
02973 }
02974 /* }}} */
02975 
02976 /* {{{ proto string mb_strtolower(string sourcestring [, string encoding])
02977  *  Returns a lowercased version of sourcestring
02978  */
02979 PHP_FUNCTION(mb_strtolower)
02980 {
02981        char *str, *from_encoding = (char*)mbfl_no2preferred_mime_name(MBSTRG(current_internal_encoding));
02982        int str_len, from_encoding_len;
02983        char *newstr;
02984        size_t ret_len;
02985 
02986        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &str, &str_len,
02987                             &from_encoding, &from_encoding_len) == FAILURE) {
02988               return;
02989        }
02990        newstr = php_unicode_convert_case(PHP_UNICODE_CASE_LOWER, str, (size_t) str_len, &ret_len, from_encoding TSRMLS_CC);
02991 
02992        if (newstr) {
02993               RETURN_STRINGL(newstr, ret_len, 0);
02994        }
02995        RETURN_FALSE;
02996 }
02997 /* }}} */
02998 
02999 /* {{{ proto string mb_detect_encoding(string str [, mixed encoding_list [, bool strict]])
03000    Encodings of the given string is returned (as a string) */
03001 PHP_FUNCTION(mb_detect_encoding)
03002 {
03003        char *str;
03004        int str_len;
03005        zend_bool strict=0;
03006        zval *encoding_list;
03007 
03008        mbfl_string string;
03009        const char *ret;
03010        enum mbfl_no_encoding *elist;
03011        int size, *list;
03012 
03013        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zb", &str, &str_len, &encoding_list, &strict) == FAILURE) {
03014               return;
03015        }
03016 
03017        /* make encoding list */
03018        list = NULL;
03019        size = 0;
03020        if (ZEND_NUM_ARGS() >= 2 && !ZVAL_IS_NULL(encoding_list)) {
03021               switch (Z_TYPE_P(encoding_list)) {
03022               case IS_ARRAY:
03023                      if (!php_mb_parse_encoding_array(encoding_list, &list, &size, 0 TSRMLS_CC)) {
03024                             if (list) {
03025                                    efree(list);
03026                                    list = NULL;
03027                                    size = 0;
03028                             }
03029                      }
03030                      break;
03031               default:
03032                      convert_to_string(encoding_list);
03033                      if (!php_mb_parse_encoding_list(Z_STRVAL_P(encoding_list), Z_STRLEN_P(encoding_list), &list, &size, 0 TSRMLS_CC)) {
03034                             if (list) {
03035                                    efree(list);
03036                                    list = NULL;
03037                                    size = 0;
03038                             }
03039                      }
03040                      break;
03041               }
03042               if (size <= 0) {
03043                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Illegal argument");
03044               }
03045        }
03046 
03047        if (ZEND_NUM_ARGS() < 3) {
03048               strict = (zend_bool)MBSTRG(strict_detection);
03049        }
03050 
03051        if (size > 0 && list != NULL) {
03052               elist = list;
03053        } else {
03054               elist = MBSTRG(current_detect_order_list);
03055               size = MBSTRG(current_detect_order_list_size);
03056        }
03057 
03058        mbfl_string_init(&string);
03059        string.no_language = MBSTRG(language);
03060        string.val = (unsigned char *)str;
03061        string.len = str_len;
03062        ret = mbfl_identify_encoding_name(&string, elist, size, strict);
03063 
03064        if (list != NULL) {
03065               efree((void *)list);
03066        }
03067 
03068        if (ret == NULL) {
03069               RETURN_FALSE;
03070        }
03071 
03072        RETVAL_STRING((char *)ret, 1);
03073 }
03074 /* }}} */
03075 
03076 /* {{{ proto mixed mb_list_encodings()
03077    Returns an array of all supported entity encodings */
03078 PHP_FUNCTION(mb_list_encodings)
03079 {
03080        const mbfl_encoding **encodings;
03081        const mbfl_encoding *encoding;
03082        int i;
03083 
03084        array_init(return_value);
03085        i = 0;
03086        encodings = mbfl_get_supported_encodings();
03087        while ((encoding = encodings[i++]) != NULL) {
03088               add_next_index_string(return_value, (char *) encoding->name, 1);
03089        }
03090 }
03091 /* }}} */
03092 
03093 /* {{{ proto array mb_encoding_aliases(string encoding)
03094    Returns an array of the aliases of a given encoding name */
03095 PHP_FUNCTION(mb_encoding_aliases)
03096 {
03097        const mbfl_encoding *encoding;
03098        char *name = NULL;
03099        int name_len;
03100 
03101        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
03102               RETURN_FALSE;
03103        }
03104 
03105        encoding = mbfl_name2encoding(name);
03106        if (!encoding) {
03107               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", name);
03108               RETURN_FALSE;
03109        }
03110 
03111        array_init(return_value);
03112        if (encoding->aliases != NULL) {
03113               const char **alias;
03114               for (alias = *encoding->aliases; *alias; ++alias) {
03115                      add_next_index_string(return_value, (char *)*alias, 1);
03116               }
03117        }
03118 }
03119 /* }}} */
03120 
03121 /* {{{ proto string mb_encode_mimeheader(string str [, string charset [, string transfer-encoding [, string linefeed [, int indent]]]])
03122    Converts the string to MIME "encoded-word" in the format of =?charset?(B|Q)?encoded_string?= */
03123 PHP_FUNCTION(mb_encode_mimeheader)
03124 {
03125        enum mbfl_no_encoding charset, transenc;
03126        mbfl_string  string, result, *ret;
03127        char *charset_name = NULL;
03128        int charset_name_len;
03129        char *trans_enc_name = NULL;
03130        int trans_enc_name_len;
03131        char *linefeed = "\r\n";
03132        int linefeed_len;
03133        long indent = 0;
03134 
03135        mbfl_string_init(&string);
03136        string.no_language = MBSTRG(language);
03137        string.no_encoding = MBSTRG(current_internal_encoding);
03138 
03139        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sssl", (char **)&string.val, &string.len, &charset_name, &charset_name_len, &trans_enc_name, &trans_enc_name_len, &linefeed, &linefeed_len, &indent) == FAILURE) {
03140               return;
03141        }
03142 
03143        charset = mbfl_no_encoding_pass;
03144        transenc = mbfl_no_encoding_base64;
03145 
03146        if (charset_name != NULL) {
03147               charset = mbfl_name2no_encoding(charset_name);
03148               if (charset == mbfl_no_encoding_invalid) {
03149                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", charset_name);
03150                      RETURN_FALSE;
03151               }
03152        } else {
03153               const mbfl_language *lang = mbfl_no2language(MBSTRG(language));
03154               if (lang != NULL) {
03155                      charset = lang->mail_charset;
03156                      transenc = lang->mail_header_encoding;
03157               }
03158        }
03159 
03160        if (trans_enc_name != NULL) {
03161               if (*trans_enc_name == 'B' || *trans_enc_name == 'b') {
03162                      transenc = mbfl_no_encoding_base64;
03163               } else if (*trans_enc_name == 'Q' || *trans_enc_name == 'q') {
03164                      transenc = mbfl_no_encoding_qprint;
03165               }
03166        }
03167 
03168        mbfl_string_init(&result);
03169        ret = mbfl_mime_header_encode(&string, &result, charset, transenc, linefeed, indent);
03170        if (ret != NULL) {
03171               RETVAL_STRINGL((char *)ret->val, ret->len, 0)    /* the string is already strdup()'ed */
03172        } else {
03173               RETVAL_FALSE;
03174        }
03175 }
03176 /* }}} */
03177 
03178 /* {{{ proto string mb_decode_mimeheader(string string)
03179    Decodes the MIME "encoded-word" in the string */
03180 PHP_FUNCTION(mb_decode_mimeheader)
03181 {
03182        mbfl_string string, result, *ret;
03183 
03184        mbfl_string_init(&string);
03185        string.no_language = MBSTRG(language);
03186        string.no_encoding = MBSTRG(current_internal_encoding);
03187 
03188        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", (char **)&string.val, &string.len) == FAILURE) {
03189               return;
03190        }
03191 
03192        mbfl_string_init(&result);
03193        ret = mbfl_mime_header_decode(&string, &result, MBSTRG(current_internal_encoding));
03194        if (ret != NULL) {
03195               RETVAL_STRINGL((char *)ret->val, ret->len, 0)    /* the string is already strdup()'ed */
03196        } else {
03197               RETVAL_FALSE;
03198        }
03199 }
03200 /* }}} */
03201 
03202 /* {{{ proto string mb_convert_kana(string str [, string option] [, string encoding])
03203    Conversion between full-width character and half-width character (Japanese) */
03204 PHP_FUNCTION(mb_convert_kana)
03205 {
03206        int opt, i;
03207        mbfl_string string, result, *ret;
03208        char *optstr = NULL;
03209        int optstr_len;
03210        char *encname = NULL;
03211        int encname_len;
03212 
03213        mbfl_string_init(&string);
03214        string.no_language = MBSTRG(language);
03215        string.no_encoding = MBSTRG(current_internal_encoding);
03216 
03217        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss", (char **)&string.val, &string.len, &optstr, &optstr_len, &encname, &encname_len) == FAILURE) {
03218               return;
03219        }
03220 
03221        /* option */
03222        if (optstr != NULL) {
03223               char *p = optstr;
03224               int n = optstr_len;
03225               i = 0;
03226               opt = 0;
03227               while (i < n) {
03228                      i++;
03229                      switch (*p++) {
03230                      case 'A':
03231                             opt |= 0x1;
03232                             break;
03233                      case 'a':
03234                             opt |= 0x10;
03235                             break;
03236                      case 'R':
03237                             opt |= 0x2;
03238                             break;
03239                      case 'r':
03240                             opt |= 0x20;
03241                             break;
03242                      case 'N':
03243                             opt |= 0x4;
03244                             break;
03245                      case 'n':
03246                             opt |= 0x40;
03247                             break;
03248                      case 'S':
03249                             opt |= 0x8;
03250                             break;
03251                      case 's':
03252                             opt |= 0x80;
03253                             break;
03254                      case 'K':
03255                             opt |= 0x100;
03256                             break;
03257                      case 'k':
03258                             opt |= 0x1000;
03259                             break;
03260                      case 'H':
03261                             opt |= 0x200;
03262                             break;
03263                      case 'h':
03264                             opt |= 0x2000;
03265                             break;
03266                      case 'V':
03267                             opt |= 0x800;
03268                             break;
03269                      case 'C':
03270                             opt |= 0x10000;
03271                             break;
03272                      case 'c':
03273                             opt |= 0x20000;
03274                             break;
03275                      case 'M':
03276                             opt |= 0x100000;
03277                             break;
03278                      case 'm':
03279                             opt |= 0x200000;
03280                             break;
03281                      }
03282               }
03283        } else {
03284               opt = 0x900;
03285        }
03286 
03287        /* encoding */
03288        if (encname != NULL) {
03289               string.no_encoding = mbfl_name2no_encoding(encname);
03290               if (string.no_encoding == mbfl_no_encoding_invalid) {
03291                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encname);
03292                      RETURN_FALSE;
03293               }
03294        }
03295 
03296        ret = mbfl_ja_jp_hantozen(&string, &result, opt);
03297        if (ret != NULL) {
03298               RETVAL_STRINGL((char *)ret->val, ret->len, 0);          /* the string is already strdup()'ed */
03299        } else {
03300               RETVAL_FALSE;
03301        }
03302 }
03303 /* }}} */
03304 
03305 #define PHP_MBSTR_STACK_BLOCK_SIZE 32
03306 
03307 /* {{{ proto string mb_convert_variables(string to-encoding, mixed from-encoding, mixed vars [, ...])
03308    Converts the string resource in variables to desired encoding */
03309 PHP_FUNCTION(mb_convert_variables)
03310 {
03311        zval ***args, ***stack, **var, **hash_entry, **zfrom_enc;
03312        HashTable *target_hash;
03313        mbfl_string string, result, *ret;
03314        enum mbfl_no_encoding from_encoding, to_encoding;
03315        mbfl_encoding_detector *identd;
03316        mbfl_buffer_converter *convd;
03317        int n, to_enc_len, argc, stack_level, stack_max, elistsz;
03318        enum mbfl_no_encoding *elist;
03319        char *name, *to_enc;
03320        void *ptmp;   
03321        
03322        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ+", &to_enc, &to_enc_len, &zfrom_enc, &args, &argc) == FAILURE) {
03323               return;
03324        }
03325 
03326        /* new encoding */
03327        to_encoding = mbfl_name2no_encoding(to_enc);
03328        if (to_encoding == mbfl_no_encoding_invalid) {
03329               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", to_enc);
03330               efree(args);
03331               RETURN_FALSE;
03332        }
03333 
03334        /* initialize string */
03335        mbfl_string_init(&string);
03336        mbfl_string_init(&result);
03337        from_encoding = MBSTRG(current_internal_encoding);
03338        string.no_encoding = from_encoding;
03339        string.no_language = MBSTRG(language);
03340 
03341        /* pre-conversion encoding */
03342        elist = NULL;
03343        elistsz = 0;
03344        switch (Z_TYPE_PP(zfrom_enc)) {
03345        case IS_ARRAY:
03346               php_mb_parse_encoding_array(*zfrom_enc, &elist, &elistsz, 0 TSRMLS_CC);
03347               break;
03348        default:
03349               convert_to_string_ex(zfrom_enc);
03350               php_mb_parse_encoding_list(Z_STRVAL_PP(zfrom_enc), Z_STRLEN_PP(zfrom_enc), &elist, &elistsz, 0 TSRMLS_CC);
03351               break;
03352        }
03353        if (elistsz <= 0) {
03354               from_encoding = mbfl_no_encoding_pass;
03355        } else if (elistsz == 1) {
03356               from_encoding = *elist;
03357        } else {
03358               /* auto detect */
03359               from_encoding = mbfl_no_encoding_invalid;
03360               stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
03361               stack = (zval ***)safe_emalloc(stack_max, sizeof(zval **), 0);
03362               stack_level = 0;
03363               identd = mbfl_encoding_detector_new(elist, elistsz, MBSTRG(strict_detection));
03364               if (identd != NULL) {
03365                      n = 0;
03366                      while (n < argc || stack_level > 0) {
03367                             if (stack_level <= 0) {
03368                                    var = args[n++];
03369                                    if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) {
03370                                           target_hash = HASH_OF(*var);
03371                                           if (target_hash != NULL) {
03372                                                  zend_hash_internal_pointer_reset(target_hash);
03373                                           }
03374                                    }
03375                             } else {
03376                                    stack_level--;
03377                                    var = stack[stack_level];
03378                             }
03379                             if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) {
03380                                    target_hash = HASH_OF(*var);
03381                                    if (target_hash != NULL) {
03382                                           while (zend_hash_get_current_data(target_hash, (void **) &hash_entry) != FAILURE) {
03383                                                  zend_hash_move_forward(target_hash);
03384                                                  if (Z_TYPE_PP(hash_entry) == IS_ARRAY || Z_TYPE_PP(hash_entry) == IS_OBJECT) {
03385                                                         if (stack_level >= stack_max) {
03386                                                                stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
03387                                                                ptmp = erealloc(stack, sizeof(zval **)*stack_max);
03388                                                                stack = (zval ***)ptmp;
03389                                                         }
03390                                                         stack[stack_level] = var;
03391                                                         stack_level++;
03392                                                         var = hash_entry;
03393                                                         target_hash = HASH_OF(*var);
03394                                                         if (target_hash != NULL) {
03395                                                                zend_hash_internal_pointer_reset(target_hash);
03396                                                                continue;
03397                                                         }
03398                                                  } else if (Z_TYPE_PP(hash_entry) == IS_STRING) {
03399                                                         string.val = (unsigned char *)Z_STRVAL_PP(hash_entry);
03400                                                         string.len = Z_STRLEN_PP(hash_entry);
03401                                                         if (mbfl_encoding_detector_feed(identd, &string)) {
03402                                                                goto detect_end;            /* complete detecting */
03403                                                         }
03404                                                  }
03405                                           }
03406                                    }
03407                             } else if (Z_TYPE_PP(var) == IS_STRING) {
03408                                    string.val = (unsigned char *)Z_STRVAL_PP(var);
03409                                    string.len = Z_STRLEN_PP(var);
03410                                    if (mbfl_encoding_detector_feed(identd, &string)) {
03411                                           goto detect_end;            /* complete detecting */
03412                                    }
03413                             }
03414                      }
03415 detect_end:
03416                      from_encoding = mbfl_encoding_detector_judge(identd);
03417                      mbfl_encoding_detector_delete(identd);
03418               }
03419               efree(stack);
03420 
03421               if (from_encoding == mbfl_no_encoding_invalid) {
03422                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to detect encoding");
03423                      from_encoding = mbfl_no_encoding_pass;
03424               }
03425        }
03426        if (elist != NULL) {
03427               efree((void *)elist);
03428        }
03429        /* create converter */
03430        convd = NULL;
03431        if (from_encoding != mbfl_no_encoding_pass) {
03432               convd = mbfl_buffer_converter_new(from_encoding, to_encoding, 0);
03433               if (convd == NULL) {
03434                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create converter");
03435                      RETURN_FALSE;
03436               }
03437               mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
03438               mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
03439        }
03440 
03441        /* convert */
03442        if (convd != NULL) {
03443               stack_max = PHP_MBSTR_STACK_BLOCK_SIZE;
03444               stack = (zval ***)safe_emalloc(stack_max, sizeof(zval **), 0);
03445               stack_level = 0;
03446               n = 0;
03447               while (n < argc || stack_level > 0) {
03448                      if (stack_level <= 0) {
03449                             var = args[n++];
03450                             if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) {
03451                                    target_hash = HASH_OF(*var);
03452                                    if (target_hash != NULL) {
03453                                           zend_hash_internal_pointer_reset(target_hash);
03454                                    }
03455                             }
03456                      } else {
03457                             stack_level--;
03458                             var = stack[stack_level];
03459                      }
03460                      if (Z_TYPE_PP(var) == IS_ARRAY || Z_TYPE_PP(var) == IS_OBJECT) {
03461                             target_hash = HASH_OF(*var);
03462                             if (target_hash != NULL) {
03463                                    while (zend_hash_get_current_data(target_hash, (void **) &hash_entry) != FAILURE) {
03464                                           zend_hash_move_forward(target_hash);
03465                                           if (Z_TYPE_PP(hash_entry) == IS_ARRAY || Z_TYPE_PP(hash_entry) == IS_OBJECT) {
03466                                                  if (stack_level >= stack_max) {
03467                                                         stack_max += PHP_MBSTR_STACK_BLOCK_SIZE;
03468                                                         ptmp = erealloc(stack, sizeof(zval **)*stack_max);
03469                                                         stack = (zval ***)ptmp;
03470                                                  }
03471                                                  stack[stack_level] = var;
03472                                                  stack_level++;
03473                                                  var = hash_entry;
03474                                                  SEPARATE_ZVAL(hash_entry);
03475                                                  target_hash = HASH_OF(*var);
03476                                                  if (target_hash != NULL) {
03477                                                         zend_hash_internal_pointer_reset(target_hash);
03478                                                         continue;
03479                                                  }
03480                                           } else if (Z_TYPE_PP(hash_entry) == IS_STRING) {
03481                                                  string.val = (unsigned char *)Z_STRVAL_PP(hash_entry);
03482                                                  string.len = Z_STRLEN_PP(hash_entry);
03483                                                  ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
03484                                                  if (ret != NULL) {
03485                                                         if (Z_REFCOUNT_PP(hash_entry) > 1) {
03486                                                                Z_DELREF_PP(hash_entry);
03487                                                                MAKE_STD_ZVAL(*hash_entry);
03488                                                         } else {
03489                                                                zval_dtor(*hash_entry);
03490                                                         }
03491                                                  ZVAL_STRINGL(*hash_entry, (char *)ret->val, ret->len, 0);
03492                                           }
03493                                    }
03494                             }
03495                      }
03496               } else if (Z_TYPE_PP(var) == IS_STRING) {
03497                      string.val = (unsigned char *)Z_STRVAL_PP(var);
03498                      string.len = Z_STRLEN_PP(var);
03499                      ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
03500                      if (ret != NULL) {
03501                             zval_dtor(*var);
03502                             ZVAL_STRINGL(*var, (char *)ret->val, ret->len, 0);
03503                             }
03504                      }
03505               }
03506               efree(stack);
03507 
03508               MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
03509               mbfl_buffer_converter_delete(convd);
03510        }
03511 
03512        efree(args);
03513 
03514        name = (char *)mbfl_no_encoding2name(from_encoding);
03515        if (name != NULL) {
03516               RETURN_STRING(name, 1);
03517        } else {
03518               RETURN_FALSE;
03519        }
03520 }
03521 /* }}} */
03522 
03523 /* {{{ HTML numeric entity */
03524 /* {{{ static void php_mb_numericentity_exec() */
03525 static void
03526 php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAMETERS, int type)
03527 {
03528        char *str, *encoding;
03529        int str_len, encoding_len;
03530        zval *zconvmap, **hash_entry;
03531        HashTable *target_hash;
03532        size_t argc = ZEND_NUM_ARGS();
03533        int i, *convmap, *mapelm, mapsize=0;
03534        mbfl_string string, result, *ret;
03535        enum mbfl_no_encoding no_encoding;
03536 
03537        if (zend_parse_parameters(argc TSRMLS_CC, "szs", &str, &str_len, &zconvmap, &encoding, &encoding_len) == FAILURE) {
03538               return;
03539        }
03540 
03541        mbfl_string_init(&string);
03542        string.no_language = MBSTRG(language);
03543        string.no_encoding = MBSTRG(current_internal_encoding);
03544        string.val = (unsigned char *)str;
03545        string.len = str_len;
03546 
03547        /* encoding */
03548        if (argc == 3) {
03549               no_encoding = mbfl_name2no_encoding(encoding);
03550               if (no_encoding == mbfl_no_encoding_invalid) {
03551                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", encoding);
03552                      RETURN_FALSE;
03553               } else {
03554                      string.no_encoding = no_encoding;
03555               }
03556        }
03557 
03558        /* conversion map */
03559        convmap = NULL;
03560        if (Z_TYPE_P(zconvmap) == IS_ARRAY) {
03561               target_hash = Z_ARRVAL_P(zconvmap);
03562               zend_hash_internal_pointer_reset(target_hash);
03563               i = zend_hash_num_elements(target_hash);
03564               if (i > 0) {
03565                      convmap = (int *)safe_emalloc(i, sizeof(int), 0);
03566                      mapelm = convmap;
03567                      mapsize = 0;
03568                      while (i > 0) {
03569                             if (zend_hash_get_current_data(target_hash, (void **) &hash_entry) == FAILURE) {
03570                                    break;
03571                             }
03572                             convert_to_long_ex(hash_entry);
03573                             *mapelm++ = Z_LVAL_PP(hash_entry);
03574                             mapsize++;
03575                             i--;
03576                             zend_hash_move_forward(target_hash);
03577                      }
03578               }
03579        }
03580        if (convmap == NULL) {
03581               RETURN_FALSE;
03582        }
03583        mapsize /= 4;
03584 
03585        ret = mbfl_html_numeric_entity(&string, &result, convmap, mapsize, type);
03586        if (ret != NULL) {
03587               RETVAL_STRINGL((char *)ret->val, ret->len, 0);
03588        } else {
03589               RETVAL_FALSE;
03590        }
03591        efree((void *)convmap);
03592 }
03593 /* }}} */
03594 
03595 /* {{{ proto string mb_encode_numericentity(string string, array convmap [, string encoding])
03596    Converts specified characters to HTML numeric entities */
03597 PHP_FUNCTION(mb_encode_numericentity)
03598 {
03599        php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
03600 }
03601 /* }}} */
03602 
03603 /* {{{ proto string mb_decode_numericentity(string string, array convmap [, string encoding])
03604    Converts HTML numeric entities to character code */
03605 PHP_FUNCTION(mb_decode_numericentity)
03606 {
03607        php_mb_numericentity_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
03608 }
03609 /* }}} */
03610 /* }}} */
03611 
03612 /* {{{ proto int mb_send_mail(string to, string subject, string message [, string additional_headers [, string additional_parameters]])
03613  *  Sends an email message with MIME scheme
03614  */
03615 
03616 #define SKIP_LONG_HEADER_SEP_MBSTRING(str, pos)                                                                 \
03617        if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) {  \
03618               pos += 2;                                                                           \
03619               while (str[pos + 1] == ' ' || str[pos + 1] == '\t') {                                             \
03620                      pos++;                                                                       \
03621               }                                                                                   \
03622               continue;                                                                           \
03623        }
03624 
03625 #define MAIL_ASCIIZ_CHECK_MBSTRING(str, len)                   \
03626        pp = str;                                 \
03627        ee = pp + len;                                   \
03628        while ((pp = memchr(pp, '\0', (ee - pp)))) {     \
03629               *pp = ' ';                         \
03630        }                                         \
03631 
03632 #define APPEND_ONE_CHAR(ch) do { \
03633        if (token.a > 0) { \
03634               smart_str_appendc(&token, ch); \
03635        } else {\
03636               token.len++; \
03637        } \
03638 } while (0)
03639 
03640 #define SEPARATE_SMART_STR(str) do {\
03641        if ((str)->a == 0) { \
03642               char *tmp_ptr; \
03643               (str)->a = 1; \
03644               while ((str)->a < (str)->len) { \
03645                      (str)->a <<= 1; \
03646               } \
03647               tmp_ptr = emalloc((str)->a + 1); \
03648               memcpy(tmp_ptr, (str)->c, (str)->len); \
03649               (str)->c = tmp_ptr; \
03650        } \
03651 } while (0)
03652 
03653 static void my_smart_str_dtor(smart_str *s)
03654 {
03655        if (s->a > 0) {
03656               smart_str_free(s);
03657        }
03658 }
03659 
03660 static int _php_mbstr_parse_mail_headers(HashTable *ht, const char *str, size_t str_len)
03661 {
03662        const char *ps;
03663        size_t icnt;
03664        int state = 0;
03665        int crlf_state = -1;
03666 
03667        smart_str token = { 0, 0, 0 };
03668        smart_str fld_name = { 0, 0, 0 }, fld_val = { 0, 0, 0 };
03669 
03670        ps = str;
03671        icnt = str_len;
03672 
03673        /*
03674         *             C o n t e n t - T y p e :   t e x t / h t m l \r\n
03675         *             ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^ ^^^^ 
03676         *      state  0            1           2          3          
03677         *
03678         *             C o n t e n t - T y p e :   t e x t / h t m l \r\n
03679         *             ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^ 
03680         * crlf_state -1                       0                     1 -1  
03681         *
03682         */
03683 
03684        while (icnt > 0) {
03685               switch (*ps) {
03686                      case ':':
03687                             if (crlf_state == 1) {
03688                                    APPEND_ONE_CHAR('\r');
03689                             }
03690 
03691                             if (state == 0 || state == 1) {
03692                                    fld_name = token;
03693 
03694                                    state = 2;
03695                             } else {
03696                                    APPEND_ONE_CHAR(*ps);
03697                             }
03698 
03699                             crlf_state = 0;
03700                             break;
03701 
03702                      case '\n':
03703                             if (crlf_state == -1) {
03704                                    goto out;
03705                             }
03706                             crlf_state = -1;
03707                             break;
03708 
03709                      case '\r':
03710                             if (crlf_state == 1) {
03711                                    APPEND_ONE_CHAR('\r');
03712                             } else {
03713                                    crlf_state = 1;
03714                             }
03715                             break;
03716 
03717                      case ' ': case '\t':
03718                             if (crlf_state == -1) {
03719                                    if (state == 3) {
03720                                           /* continuing from the previous line */
03721                                           SEPARATE_SMART_STR(&token);
03722                                           state = 4;
03723                                    } else {
03724                                           /* simply skipping this new line */
03725                                           state = 5;
03726                                    }
03727                             } else {
03728                                    if (crlf_state == 1) {
03729                                           APPEND_ONE_CHAR('\r');
03730                                    }
03731                                    if (state == 1 || state == 3) {
03732                                           APPEND_ONE_CHAR(*ps);
03733                                    }
03734                             }
03735                             crlf_state = 0;
03736                             break;
03737 
03738                      default:
03739                             switch (state) {
03740                                    case 0:
03741                                           token.c = (char *)ps;
03742                                           token.len = 0;
03743                                           token.a = 0;
03744                                           state = 1;
03745                                           break;
03746                                    
03747                                    case 2:
03748                                           if (crlf_state != -1) {
03749                                                  token.c = (char *)ps;
03750                                                  token.len = 0;
03751                                                  token.a = 0;
03752 
03753                                                  state = 3;
03754                                                  break;
03755                                           }
03756                                           /* break is missing intentionally */
03757 
03758                                    case 3:
03759                                           if (crlf_state == -1) {
03760                                                  fld_val = token;
03761 
03762                                                  if (fld_name.c != NULL && fld_val.c != NULL) {
03763                                                         char *dummy;
03764 
03765                                                         /* FIXME: some locale free implementation is
03766                                                          * really required here,,, */
03767                                                         SEPARATE_SMART_STR(&fld_name);
03768                                                         php_strtoupper(fld_name.c, fld_name.len);
03769 
03770                                                         zend_hash_update(ht, (char *)fld_name.c, fld_name.len, &fld_val, sizeof(smart_str), (void **)&dummy);
03771 
03772                                                         my_smart_str_dtor(&fld_name);
03773                                                  }
03774 
03775                                                  memset(&fld_name, 0, sizeof(smart_str));
03776                                                  memset(&fld_val, 0, sizeof(smart_str));
03777 
03778                                                  token.c = (char *)ps;
03779                                                  token.len = 0;
03780                                                  token.a = 0;
03781 
03782                                                  state = 1;
03783                                           }
03784                                           break;
03785 
03786                                    case 4:
03787                                           APPEND_ONE_CHAR(' ');
03788                                           state = 3;
03789                                           break;
03790                             }
03791 
03792                             if (crlf_state == 1) {
03793                                    APPEND_ONE_CHAR('\r');
03794                             }
03795 
03796                             APPEND_ONE_CHAR(*ps);
03797 
03798                             crlf_state = 0;
03799                             break;
03800               }
03801               ps++, icnt--;
03802        }
03803 out:
03804        if (state == 2) {
03805               token.c = "";
03806               token.len = 0;
03807               token.a = 0;
03808 
03809               state = 3;
03810        }
03811        if (state == 3) {
03812               fld_val = token;
03813 
03814               if (fld_name.c != NULL && fld_val.c != NULL) {
03815                      void *dummy;
03816 
03817                      /* FIXME: some locale free implementation is
03818                       * really required here,,, */
03819                      SEPARATE_SMART_STR(&fld_name);
03820                      php_strtoupper(fld_name.c, fld_name.len);
03821 
03822                      zend_hash_update(ht, (char *)fld_name.c, fld_name.len, &fld_val, sizeof(smart_str), (void **)&dummy);
03823 
03824                      my_smart_str_dtor(&fld_name);
03825               }
03826        }
03827        return state;
03828 }
03829 
03830 PHP_FUNCTION(mb_send_mail)
03831 {
03832        int n;
03833        char *to = NULL;
03834        int to_len;
03835        char *message = NULL;
03836        int message_len;
03837        char *headers = NULL;
03838        int headers_len;
03839        char *subject = NULL;
03840        int subject_len;
03841        char *extra_cmd = NULL;
03842        int extra_cmd_len;
03843        int i;
03844        char *to_r = NULL;
03845        char *force_extra_parameters = INI_STR("mail.force_extra_parameters");
03846        struct {
03847               int cnt_type:1;
03848               int cnt_trans_enc:1;
03849        } suppressed_hdrs = { 0, 0 };
03850 
03851        char *message_buf = NULL, *subject_buf = NULL, *p;
03852        mbfl_string orig_str, conv_str;
03853        mbfl_string *pstr;   /* pointer to mbfl string for return value */
03854        enum mbfl_no_encoding
03855            tran_cs,  /* transfar text charset */
03856            head_enc, /* header transfar encoding */
03857            body_enc; /* body transfar encoding */
03858        mbfl_memory_device device;  /* automatic allocateable buffer for additional header */
03859        const mbfl_language *lang;
03860        int err = 0;
03861        HashTable ht_headers;
03862        smart_str *s;
03863        extern void mbfl_memory_device_unput(mbfl_memory_device *device);
03864        char *pp, *ee;
03865     
03866        if (PG(safe_mode) && (ZEND_NUM_ARGS() == 5)) {
03867               php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect.  The fifth parameter is disabled in SAFE MODE.");
03868               RETURN_FALSE;
03869        }
03870     
03871        /* initialize */
03872        mbfl_memory_device_init(&device, 0, 0);
03873        mbfl_string_init(&orig_str);
03874        mbfl_string_init(&conv_str);
03875 
03876        /* character-set, transfer-encoding */
03877        tran_cs = mbfl_no_encoding_utf8;
03878        head_enc = mbfl_no_encoding_base64;
03879        body_enc = mbfl_no_encoding_base64;
03880        lang = mbfl_no2language(MBSTRG(language));
03881        if (lang != NULL) {
03882               tran_cs = lang->mail_charset;
03883               head_enc = lang->mail_header_encoding;
03884               body_enc = lang->mail_body_encoding;
03885        }
03886 
03887        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ss", &to, &to_len, &subject, &subject_len, &message, &message_len, &headers, &headers_len, &extra_cmd, &extra_cmd_len) == FAILURE) {
03888               return;
03889        }
03890 
03891        /* ASCIIZ check */
03892        MAIL_ASCIIZ_CHECK_MBSTRING(to, to_len);
03893        MAIL_ASCIIZ_CHECK_MBSTRING(subject, subject_len);
03894        MAIL_ASCIIZ_CHECK_MBSTRING(message, message_len);
03895        if (headers) {
03896               MAIL_ASCIIZ_CHECK_MBSTRING(headers, headers_len);
03897        }
03898        if (extra_cmd) {
03899               MAIL_ASCIIZ_CHECK_MBSTRING(extra_cmd, extra_cmd_len);
03900        }
03901 
03902        zend_hash_init(&ht_headers, 0, NULL, (dtor_func_t) my_smart_str_dtor, 0);
03903 
03904        if (headers != NULL) {
03905               _php_mbstr_parse_mail_headers(&ht_headers, headers, headers_len);
03906        }
03907 
03908        if (zend_hash_find(&ht_headers, "CONTENT-TYPE", sizeof("CONTENT-TYPE") - 1, (void **)&s) == SUCCESS) {
03909               char *tmp;
03910               char *param_name;
03911               char *charset = NULL;
03912 
03913               SEPARATE_SMART_STR(s);
03914               smart_str_0(s);
03915 
03916               p = strchr(s->c, ';');
03917 
03918               if (p != NULL) {
03919                      /* skipping the padded spaces */
03920                      do {
03921                             ++p;
03922                      } while (*p == ' ' || *p == '\t');
03923 
03924                      if (*p != '\0') {
03925                             if ((param_name = php_strtok_r(p, "= ", &tmp)) != NULL) {
03926                                    if (strcasecmp(param_name, "charset") == 0) {
03927                                           enum mbfl_no_encoding _tran_cs = tran_cs;
03928                                           
03929                                           charset = php_strtok_r(NULL, "= \"", &tmp);
03930                                           if (charset != NULL) {
03931                                                  _tran_cs = mbfl_name2no_encoding(charset);
03932                                           }
03933 
03934                                           if (_tran_cs == mbfl_no_encoding_invalid) {
03935                                                  php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported charset \"%s\" - will be regarded as ascii", charset); 
03936                                                  _tran_cs = mbfl_no_encoding_ascii;
03937                                           }
03938                                           tran_cs = _tran_cs;
03939                                    }
03940                             }
03941                      }
03942               }
03943               suppressed_hdrs.cnt_type = 1;
03944        }
03945 
03946        if (zend_hash_find(&ht_headers, "CONTENT-TRANSFER-ENCODING", sizeof("CONTENT-TRANSFER-ENCODING") - 1, (void **)&s) == SUCCESS) {
03947               enum mbfl_no_encoding _body_enc;
03948               SEPARATE_SMART_STR(s);
03949               smart_str_0(s);
03950 
03951               _body_enc = mbfl_name2no_encoding(s->c);
03952               switch (_body_enc) {
03953                      case mbfl_no_encoding_base64:
03954                      case mbfl_no_encoding_7bit:
03955                      case mbfl_no_encoding_8bit:
03956                             body_enc = _body_enc;
03957                             break;
03958 
03959                      default:
03960                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported transfer encoding \"%s\" - will be regarded as 8bit", s->c); 
03961                             body_enc =    mbfl_no_encoding_8bit;
03962                             break;
03963               }
03964               suppressed_hdrs.cnt_trans_enc = 1;
03965        }
03966 
03967        /* To: */
03968        if (to != NULL) {
03969         if (to_len > 0) {
03970             to_r = estrndup(to, to_len);
03971             for (; to_len; to_len--) {
03972                 if (!isspace((unsigned char) to_r[to_len - 1])) {
03973                     break;
03974                 }
03975                 to_r[to_len - 1] = '\0';
03976             }
03977             for (i = 0; to_r[i]; i++) {
03978                      if (iscntrl((unsigned char) to_r[i])) {
03979                             /* According to RFC 822, section 3.1.1 long headers may be separated into
03980                              * parts using CRLF followed at least one linear-white-space character ('\t' or ' ').
03981                              * To prevent these separators from being replaced with a space, we use the
03982                              * SKIP_LONG_HEADER_SEP_MBSTRING to skip over them.
03983                              */
03984                             SKIP_LONG_HEADER_SEP_MBSTRING(to_r, i);
03985                             to_r[i] = ' ';
03986                      }
03987             }
03988         } else {
03989             to_r = to;
03990         }
03991     } else {
03992               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing To: field");
03993               err = 1;
03994        }
03995 
03996        /* Subject: */
03997        if (subject != NULL && subject_len >= 0) {
03998               orig_str.no_language = MBSTRG(language);
03999               orig_str.val = (unsigned char *)subject;
04000               orig_str.len = subject_len;
04001               orig_str.no_encoding = MBSTRG(current_internal_encoding);
04002               if (orig_str.no_encoding == mbfl_no_encoding_invalid
04003                   || orig_str.no_encoding == mbfl_no_encoding_pass) {
04004                      orig_str.no_encoding = mbfl_identify_encoding_no(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection));
04005               }
04006               pstr = mbfl_mime_header_encode(&orig_str, &conv_str, tran_cs, head_enc, "\n", sizeof("Subject: [PHP-jp nnnnnnnn]"));
04007               if (pstr != NULL) {
04008                      subject_buf = subject = (char *)pstr->val;
04009               }
04010        } else {
04011               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing Subject: field");
04012               err = 1;
04013        }
04014 
04015        /* message body */
04016        if (message != NULL) {
04017               orig_str.no_language = MBSTRG(language);
04018               orig_str.val = (unsigned char *)message;
04019               orig_str.len = (unsigned int)message_len;
04020               orig_str.no_encoding = MBSTRG(current_internal_encoding);
04021 
04022               if (orig_str.no_encoding == mbfl_no_encoding_invalid
04023                   || orig_str.no_encoding == mbfl_no_encoding_pass) {
04024                      orig_str.no_encoding = mbfl_identify_encoding_no(&orig_str, MBSTRG(current_detect_order_list), MBSTRG(current_detect_order_list_size), MBSTRG(strict_detection));
04025               }
04026 
04027               pstr = NULL;
04028               {
04029                      mbfl_string tmpstr;
04030 
04031                      if (mbfl_convert_encoding(&orig_str, &tmpstr, tran_cs) != NULL) {
04032                             tmpstr.no_encoding=mbfl_no_encoding_8bit;
04033                             pstr = mbfl_convert_encoding(&tmpstr, &conv_str, body_enc);
04034                             efree(tmpstr.val);
04035                      }
04036               }
04037               if (pstr != NULL) {
04038                      message_buf = message = (char *)pstr->val;
04039               }
04040        } else {
04041               /* this is not really an error, so it is allowed. */
04042               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty message body");
04043               message = NULL;
04044        }
04045 
04046        /* other headers */
04047 #define PHP_MBSTR_MAIL_MIME_HEADER1 "MIME-Version: 1.0"
04048 #define PHP_MBSTR_MAIL_MIME_HEADER2 "Content-Type: text/plain"
04049 #define PHP_MBSTR_MAIL_MIME_HEADER3 "; charset="
04050 #define PHP_MBSTR_MAIL_MIME_HEADER4 "Content-Transfer-Encoding: "
04051        if (headers != NULL) {
04052               p = headers;
04053               n = headers_len;
04054               mbfl_memory_device_strncat(&device, p, n);
04055               if (n > 0 && p[n - 1] != '\n') {
04056                      mbfl_memory_device_strncat(&device, "\n", 1);
04057               }
04058        }
04059 
04060        if (!zend_hash_exists(&ht_headers, "MIME-VERSION", sizeof("MIME-VERSION") - 1)) {
04061               mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER1, sizeof(PHP_MBSTR_MAIL_MIME_HEADER1) - 1);
04062               mbfl_memory_device_strncat(&device, "\n", 1);
04063        }
04064 
04065        if (!suppressed_hdrs.cnt_type) {
04066               mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER2, sizeof(PHP_MBSTR_MAIL_MIME_HEADER2) - 1);
04067 
04068               p = (char *)mbfl_no2preferred_mime_name(tran_cs);
04069               if (p != NULL) {
04070                      mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER3, sizeof(PHP_MBSTR_MAIL_MIME_HEADER3) - 1);
04071                      mbfl_memory_device_strcat(&device, p);
04072               }
04073               mbfl_memory_device_strncat(&device, "\n", 1);
04074        }
04075        if (!suppressed_hdrs.cnt_trans_enc) {
04076               mbfl_memory_device_strncat(&device, PHP_MBSTR_MAIL_MIME_HEADER4, sizeof(PHP_MBSTR_MAIL_MIME_HEADER4) - 1);
04077               p = (char *)mbfl_no2preferred_mime_name(body_enc);
04078               if (p == NULL) {
04079                      p = "7bit";
04080               }
04081               mbfl_memory_device_strcat(&device, p);
04082               mbfl_memory_device_strncat(&device, "\n", 1);
04083        }
04084 
04085        mbfl_memory_device_unput(&device);
04086        mbfl_memory_device_output('\0', &device);
04087        headers = (char *)device.buffer;
04088 
04089        if (force_extra_parameters) {
04090               extra_cmd = php_escape_shell_cmd(force_extra_parameters);
04091        } else if (extra_cmd) {
04092               extra_cmd = php_escape_shell_cmd(extra_cmd);
04093        } 
04094 
04095        if (!err && php_mail(to_r, subject, message, headers, extra_cmd TSRMLS_CC)) {
04096               RETVAL_TRUE;
04097        } else {
04098               RETVAL_FALSE;
04099        }
04100 
04101        if (extra_cmd) {
04102               efree(extra_cmd);
04103        }
04104        if (to_r != to) {
04105               efree(to_r);
04106        }
04107        if (subject_buf) {
04108               efree((void *)subject_buf);
04109        }
04110        if (message_buf) {
04111               efree((void *)message_buf);
04112        }
04113        mbfl_memory_device_clear(&device);
04114        zend_hash_destroy(&ht_headers);
04115 }
04116 
04117 #undef SKIP_LONG_HEADER_SEP_MBSTRING
04118 #undef MAIL_ASCIIZ_CHECK_MBSTRING
04119 #undef APPEND_ONE_CHAR
04120 #undef SEPARATE_SMART_STR
04121 #undef PHP_MBSTR_MAIL_MIME_HEADER1
04122 #undef PHP_MBSTR_MAIL_MIME_HEADER2
04123 #undef PHP_MBSTR_MAIL_MIME_HEADER3
04124 #undef PHP_MBSTR_MAIL_MIME_HEADER4
04125 /* }}} */
04126 
04127 /* {{{ proto mixed mb_get_info([string type])
04128    Returns the current settings of mbstring */
04129 PHP_FUNCTION(mb_get_info)
04130 {
04131        char *typ = NULL;
04132        int typ_len, n;
04133        char *name;
04134        const struct mb_overload_def *over_func;
04135        zval *row1, *row2;
04136        const mbfl_language *lang = mbfl_no2language(MBSTRG(language));
04137        enum mbfl_no_encoding *entry;
04138 #ifdef ZEND_MULTIBYTE
04139        zval *row3;
04140 #endif /* ZEND_MULTIBYTE */
04141 
04142        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &typ, &typ_len) == FAILURE) {
04143               RETURN_FALSE;
04144        }
04145 
04146        if (!typ || !strcasecmp("all", typ)) {
04147               array_init(return_value);
04148               if ((name = (char *)mbfl_no_encoding2name(MBSTRG(current_internal_encoding))) != NULL) {
04149                      add_assoc_string(return_value, "internal_encoding", name, 1);
04150               }
04151               if ((name = (char *)mbfl_no_encoding2name(MBSTRG(http_input_identify))) != NULL) {
04152                      add_assoc_string(return_value, "http_input", name, 1);
04153               }
04154               if ((name = (char *)mbfl_no_encoding2name(MBSTRG(current_http_output_encoding))) != NULL) {
04155                      add_assoc_string(return_value, "http_output", name, 1);
04156               }
04157               if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes"), 0)) != NULL) {
04158                      add_assoc_string(return_value, "http_output_conv_mimetypes", name, 1);
04159               }
04160               add_assoc_long(return_value, "func_overload", MBSTRG(func_overload));
04161               if (MBSTRG(func_overload)){
04162                      over_func = &(mb_ovld[0]);
04163                      MAKE_STD_ZVAL(row1);
04164                      array_init(row1);
04165                      while (over_func->type > 0) {
04166                             if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) {
04167                                    add_assoc_string(row1, over_func->orig_func, over_func->ovld_func, 1);
04168                             }
04169                             over_func++;
04170                      }
04171                      add_assoc_zval(return_value, "func_overload_list", row1);
04172               } else {
04173                      add_assoc_string(return_value, "func_overload_list", "no overload", 1);
04174               }
04175               if (lang != NULL) {
04176                      if ((name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) {
04177                             add_assoc_string(return_value, "mail_charset", name, 1);
04178                      }
04179                      if ((name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) {
04180                             add_assoc_string(return_value, "mail_header_encoding", name, 1);
04181                      }
04182                      if ((name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) {
04183                             add_assoc_string(return_value, "mail_body_encoding", name, 1);
04184                      }
04185               }
04186               add_assoc_long(return_value, "illegal_chars", MBSTRG(illegalchars));
04187               if (MBSTRG(encoding_translation)) {
04188                      add_assoc_string(return_value, "encoding_translation", "On", 1);
04189               } else {
04190                      add_assoc_string(return_value, "encoding_translation", "Off", 1);
04191               }
04192               if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) {
04193                      add_assoc_string(return_value, "language", name, 1);
04194               }             
04195               n = MBSTRG(current_detect_order_list_size);
04196               entry = MBSTRG(current_detect_order_list);
04197               if(n > 0) {
04198                      MAKE_STD_ZVAL(row2);
04199                      array_init(row2);
04200                      while (n > 0) {
04201                             if ((name = (char *)mbfl_no_encoding2name(*entry)) != NULL) {
04202                                    add_next_index_string(row2, name, 1);
04203                             }
04204                             entry++;
04205                             n--;
04206                      }
04207                      add_assoc_zval(return_value, "detect_order", row2);
04208               }
04209               if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
04210                      add_assoc_string(return_value, "substitute_character", "none", 1);
04211               } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
04212                      add_assoc_string(return_value, "substitute_character", "long", 1);
04213               } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
04214                      add_assoc_string(return_value, "substitute_character", "entity", 1);
04215               } else {
04216                      add_assoc_long(return_value, "substitute_character", MBSTRG(current_filter_illegal_substchar));
04217               }
04218               if (MBSTRG(strict_detection)) {
04219                      add_assoc_string(return_value, "strict_detection", "On", 1);
04220               } else {
04221                      add_assoc_string(return_value, "strict_detection", "Off", 1);
04222               }
04223 #ifdef ZEND_MULTIBYTE
04224               entry = MBSTRG(script_encoding_list);
04225               n = MBSTRG(script_encoding_list_size);
04226               if(n > 0) {
04227                      MAKE_STD_ZVAL(row3);
04228                      array_init(row3);
04229                      while (n > 0) {
04230                             if ((name = (char *)mbfl_no_encoding2name(*entry)) != NULL) {
04231                                    add_next_index_string(row3, name, 1);
04232                             }
04233                             entry++;
04234                             n--;
04235                      }
04236                      add_assoc_zval(return_value, "script_encoding", row3);
04237               }
04238 #endif /* ZEND_MULTIBYTE */
04239        } else if (!strcasecmp("internal_encoding", typ)) {
04240               if ((name = (char *)mbfl_no_encoding2name(MBSTRG(current_internal_encoding))) != NULL) {
04241                      RETVAL_STRING(name, 1);
04242               }             
04243        } else if (!strcasecmp("http_input", typ)) {
04244               if ((name = (char *)mbfl_no_encoding2name(MBSTRG(http_input_identify))) != NULL) {
04245                      RETVAL_STRING(name, 1);
04246               }             
04247        } else if (!strcasecmp("http_output", typ)) {
04248               if ((name = (char *)mbfl_no_encoding2name(MBSTRG(current_http_output_encoding))) != NULL) {
04249                      RETVAL_STRING(name, 1);
04250               }             
04251        } else if (!strcasecmp("http_output_conv_mimetypes", typ)) {
04252               if ((name = (char *)zend_ini_string("mbstring.http_output_conv_mimetypes", sizeof("mbstring.http_output_conv_mimetypes"), 0)) != NULL) {
04253                      RETVAL_STRING(name, 1);
04254               }
04255        } else if (!strcasecmp("func_overload", typ)) {
04256               RETVAL_LONG(MBSTRG(func_overload));
04257        } else if (!strcasecmp("func_overload_list", typ)) {
04258               if (MBSTRG(func_overload)){
04259                             over_func = &(mb_ovld[0]);
04260                             array_init(return_value);
04261                             while (over_func->type > 0) {
04262                                    if ((MBSTRG(func_overload) & over_func->type) == over_func->type ) {
04263                                           add_assoc_string(return_value, over_func->orig_func, over_func->ovld_func, 1);
04264                                    }
04265                                    over_func++;
04266                             }
04267               } else {
04268                      RETVAL_STRING("no overload", 1);
04269               }
04270        } else if (!strcasecmp("mail_charset", typ)) {
04271               if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_charset)) != NULL) {
04272                      RETVAL_STRING(name, 1);
04273               }
04274        } else if (!strcasecmp("mail_header_encoding", typ)) {
04275               if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_header_encoding)) != NULL) {
04276                      RETVAL_STRING(name, 1);
04277               }
04278        } else if (!strcasecmp("mail_body_encoding", typ)) {
04279               if (lang != NULL && (name = (char *)mbfl_no_encoding2name(lang->mail_body_encoding)) != NULL) {
04280                      RETVAL_STRING(name, 1);
04281               }
04282        } else if (!strcasecmp("illegal_chars", typ)) {
04283               RETVAL_LONG(MBSTRG(illegalchars));
04284        } else if (!strcasecmp("encoding_translation", typ)) {
04285               if (MBSTRG(encoding_translation)) {
04286                      RETVAL_STRING("On", 1);
04287               } else {
04288                      RETVAL_STRING("Off", 1);
04289               }
04290        } else if (!strcasecmp("language", typ)) {
04291               if ((name = (char *)mbfl_no_language2name(MBSTRG(language))) != NULL) {
04292                      RETVAL_STRING(name, 1);
04293               }             
04294        } else if (!strcasecmp("detect_order", typ)) {
04295               n = MBSTRG(current_detect_order_list_size);
04296               entry = MBSTRG(current_detect_order_list);
04297               if(n > 0) {
04298                      array_init(return_value);
04299                      while (n > 0) {
04300                             name = (char *)mbfl_no_encoding2name(*entry);
04301                             if (name) {
04302                                    add_next_index_string(return_value, name, 1);
04303                             }
04304                             entry++;
04305                             n--;
04306                      }
04307               }
04308        } else if (!strcasecmp("substitute_character", typ)) {
04309               if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) {
04310                      RETVAL_STRING("none", 1);
04311               } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG) {
04312                      RETVAL_STRING("long", 1);
04313               } else if (MBSTRG(current_filter_illegal_mode) == MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY) {
04314                      RETVAL_STRING("entity", 1);
04315               } else {
04316                      RETVAL_LONG(MBSTRG(current_filter_illegal_substchar));
04317               }
04318        } else if (!strcasecmp("strict_detection", typ)) {
04319               if (MBSTRG(strict_detection)) {
04320                      RETVAL_STRING("On", 1);
04321               } else {
04322                      RETVAL_STRING("Off", 1);
04323               }
04324        } else {
04325 #ifdef ZEND_MULTIBYTE
04326        if (!strcasecmp("script_encoding", typ)) {
04327               entry = MBSTRG(script_encoding_list);
04328               n = MBSTRG(script_encoding_list_size);
04329               if(n > 0) {
04330                      array_init(return_value);
04331                      while (n > 0) {
04332                             name = (char *)mbfl_no_encoding2name(*entry);
04333                             if (name) {
04334                                    add_next_index_string(return_value, name, 1);
04335                             }
04336                             entry++;
04337                             n--;
04338                      }
04339               }
04340               return;
04341        }
04342 #endif /* ZEND_MULTIBYTE */
04343               RETURN_FALSE;
04344        }
04345 }
04346 /* }}} */
04347 
04348 /* {{{ proto bool mb_check_encoding([string var[, string encoding]])
04349    Check if the string is valid for the specified encoding */
04350 PHP_FUNCTION(mb_check_encoding)
04351 {
04352        char *var = NULL;
04353        int var_len;
04354        char *enc = NULL;
04355        int enc_len;
04356        mbfl_buffer_converter *convd;
04357        enum mbfl_no_encoding no_encoding = MBSTRG(current_internal_encoding);
04358        mbfl_string string, result, *ret = NULL;
04359        long illegalchars = 0;
04360 
04361        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &var, &var_len, &enc, &enc_len) == FAILURE) {
04362               RETURN_FALSE;
04363        }
04364 
04365        if (var == NULL) {
04366               RETURN_BOOL(MBSTRG(illegalchars) == 0);
04367        }
04368 
04369        if (enc != NULL) {
04370               no_encoding = mbfl_name2no_encoding(enc);
04371               if (no_encoding == mbfl_no_encoding_invalid || no_encoding == mbfl_no_encoding_pass) {
04372                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid encoding \"%s\"", enc);
04373                      RETURN_FALSE;
04374               }
04375        }
04376        
04377        convd = mbfl_buffer_converter_new(no_encoding, no_encoding, 0);
04378        if (convd == NULL) {
04379               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create converter");
04380               RETURN_FALSE;
04381        }      
04382        mbfl_buffer_converter_illegal_mode(convd, MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE);
04383        mbfl_buffer_converter_illegal_substchar(convd, 0);      
04384        
04385        /* initialize string */
04386        mbfl_string_init_set(&string, mbfl_no_language_neutral, no_encoding);
04387        mbfl_string_init(&result);
04388 
04389        string.val = (unsigned char *)var;
04390        string.len = var_len;
04391        ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
04392        illegalchars = mbfl_buffer_illegalchars(convd);
04393        mbfl_buffer_converter_delete(convd);
04394 
04395        RETVAL_FALSE;
04396        if (ret != NULL) {
04397               if (illegalchars == 0 && string.len == result.len && memcmp(string.val, result.val, string.len) == 0) {
04398                      RETVAL_TRUE;
04399               }
04400               mbfl_string_clear(&result);
04401        }
04402 }
04403 /* }}} */
04404 
04405 /* {{{ MBSTRING_API int php_mb_encoding_translation() */
04406 MBSTRING_API int php_mb_encoding_translation(TSRMLS_D) 
04407 {
04408        return MBSTRG(encoding_translation);
04409 }
04410 /* }}} */
04411 
04412 /* {{{ MBSTRING_API size_t php_mb_mbchar_bytes_ex() */
04413 MBSTRING_API size_t php_mb_mbchar_bytes_ex(const char *s, const mbfl_encoding *enc)
04414 {
04415        if (enc != NULL) {
04416               if (enc->flag & MBFL_ENCTYPE_MBCS) {
04417                      if (enc->mblen_table != NULL) {
04418                             if (s != NULL) return enc->mblen_table[*(unsigned char *)s];
04419                      }
04420               } else if (enc->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) {
04421                      return 2;
04422               } else if (enc->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {
04423                      return 4;
04424               }
04425        }
04426        return 1;
04427 }
04428 /* }}} */
04429 
04430 /* {{{ MBSTRING_API size_t php_mb_mbchar_bytes() */
04431 MBSTRING_API size_t php_mb_mbchar_bytes(const char *s TSRMLS_DC)
04432 {
04433        return php_mb_mbchar_bytes_ex(s,
04434               mbfl_no2encoding(MBSTRG(internal_encoding)));
04435 }
04436 /* }}} */
04437 
04438 /* {{{ MBSTRING_API char *php_mb_safe_strrchr_ex() */
04439 MBSTRING_API char *php_mb_safe_strrchr_ex(const char *s, unsigned int c, size_t nbytes, const mbfl_encoding *enc)
04440 {
04441        register const char *p = s;
04442        char *last=NULL;
04443 
04444        if (nbytes == (size_t)-1) {
04445               size_t nb = 0;
04446 
04447               while (*p != '\0') {
04448                      if (nb == 0) {
04449                             if ((unsigned char)*p == (unsigned char)c) {
04450                                    last = (char *)p;
04451                             }
04452                             nb = php_mb_mbchar_bytes_ex(p, enc);
04453                             if (nb == 0) {
04454                                    return NULL; /* something is going wrong! */
04455                             }
04456                      }
04457                      --nb;
04458                      ++p;
04459               }
04460        } else {
04461               register size_t bcnt = nbytes;
04462               register size_t nbytes_char;
04463               while (bcnt > 0) {
04464                      if ((unsigned char)*p == (unsigned char)c) {
04465                             last = (char *)p;
04466                      }
04467                      nbytes_char = php_mb_mbchar_bytes_ex(p, enc);
04468                      if (bcnt < nbytes_char) {
04469                             return NULL;
04470                      }
04471                      p += nbytes_char;
04472                      bcnt -= nbytes_char;
04473               }
04474        }
04475        return last;
04476 }
04477 /* }}} */
04478 
04479 /* {{{ MBSTRING_API char *php_mb_safe_strrchr() */
04480 MBSTRING_API char *php_mb_safe_strrchr(const char *s, unsigned int c, size_t nbytes TSRMLS_DC)
04481 {
04482        return php_mb_safe_strrchr_ex(s, c, nbytes,
04483               mbfl_no2encoding(MBSTRG(internal_encoding)));
04484 }
04485 /* }}} */
04486 
04487 /* {{{ MBSTRING_API char *php_mb_strrchr() */
04488 MBSTRING_API char *php_mb_strrchr(const char *s, char c TSRMLS_DC)
04489 {
04490        return php_mb_safe_strrchr(s, c, -1 TSRMLS_CC);
04491 }
04492 /* }}} */
04493 
04494 /* {{{ MBSTRING_API size_t php_mb_gpc_mbchar_bytes() */
04495 MBSTRING_API size_t php_mb_gpc_mbchar_bytes(const char *s TSRMLS_DC)
04496 {
04497 
04498        if (MBSTRG(http_input_identify) != mbfl_no_encoding_invalid){
04499               return php_mb_mbchar_bytes_ex(s,
04500               mbfl_no2encoding(MBSTRG(http_input_identify)));
04501        } else {
04502               return php_mb_mbchar_bytes_ex(s,
04503               mbfl_no2encoding(MBSTRG(internal_encoding)));
04504        }
04505 }
04506 /* }}} */
04507 
04508 /*     {{{ MBSTRING_API int php_mb_gpc_encoding_converter() */
04509 MBSTRING_API int php_mb_gpc_encoding_converter(char **str, int *len, int num, const char *encoding_to, const char *encoding_from TSRMLS_DC)
04510 {
04511        int i;
04512        mbfl_string string, result, *ret = NULL;
04513        enum mbfl_no_encoding from_encoding, to_encoding;
04514        mbfl_buffer_converter *convd;
04515 
04516        if (encoding_to) {
04517               /* new encoding */
04518               to_encoding = mbfl_name2no_encoding(encoding_to);
04519               if (to_encoding == mbfl_no_encoding_invalid) {
04520                      return -1;
04521               }
04522        } else {
04523               to_encoding = MBSTRG(current_internal_encoding);
04524        }      
04525        if (encoding_from) {
04526               /* old encoding */
04527               from_encoding = mbfl_name2no_encoding(encoding_from);
04528               if (from_encoding == mbfl_no_encoding_invalid) {
04529                      return -1;
04530               }
04531        } else {
04532               from_encoding = MBSTRG(http_input_identify);
04533        }
04534 
04535        if (from_encoding == mbfl_no_encoding_pass) {
04536               return 0;
04537        }
04538 
04539        /* initialize string */
04540        mbfl_string_init(&string);
04541        mbfl_string_init(&result);
04542        string.no_encoding = from_encoding;
04543        string.no_language = MBSTRG(language);
04544 
04545        for (i=0; i<num; i++){
04546               string.val = (unsigned char *)str[i];
04547               string.len = len[i];
04548 
04549               /* initialize converter */
04550               convd = mbfl_buffer_converter_new(from_encoding, to_encoding, string.len);
04551               if (convd == NULL) {
04552                      return -1;
04553               }
04554               mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
04555               mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
04556               
04557               /* do it */
04558               ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
04559               if (ret != NULL) {
04560                      efree(str[i]);
04561                      str[i] = (char *)ret->val;
04562                      len[i] = (int)ret->len;
04563               }
04564               
04565               MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
04566               mbfl_buffer_converter_delete(convd);
04567        }
04568 
04569        return ret ? 0 : -1;
04570 }
04571 /* }}} */
04572 
04573 /* {{{ MBSTRING_API int php_mb_gpc_encoding_detector()
04574  */
04575 MBSTRING_API int php_mb_gpc_encoding_detector(char **arg_string, int *arg_length, int num, char *arg_list TSRMLS_DC)
04576 {
04577        mbfl_string string;
04578        enum mbfl_no_encoding *elist;
04579        enum mbfl_no_encoding encoding = mbfl_no_encoding_invalid;
04580        mbfl_encoding_detector *identd = NULL; 
04581 
04582        int size;
04583        enum mbfl_no_encoding *list;
04584 
04585        if (MBSTRG(http_input_list_size) == 1 && 
04586               MBSTRG(http_input_list)[0] == mbfl_no_encoding_pass) {
04587               MBSTRG(http_input_identify) = mbfl_no_encoding_pass;
04588               return SUCCESS;
04589        }
04590 
04591        if (MBSTRG(http_input_list_size) == 1 && 
04592               MBSTRG(http_input_list)[0] != mbfl_no_encoding_auto &&
04593               mbfl_no_encoding2name(MBSTRG(http_input_list)[0]) != NULL) {
04594               MBSTRG(http_input_identify) = MBSTRG(http_input_list)[0];
04595               return SUCCESS;
04596        }
04597 
04598        if (arg_list && strlen(arg_list)>0) {
04599               /* make encoding list */
04600               list = NULL;
04601               size = 0;
04602               php_mb_parse_encoding_list(arg_list, strlen(arg_list), &list, &size, 0 TSRMLS_CC);
04603               
04604               if (size > 0 && list != NULL) {
04605                      elist = list;
04606               } else {
04607                      elist = MBSTRG(current_detect_order_list);
04608                      size = MBSTRG(current_detect_order_list_size);
04609                      if (size <= 0){
04610                             elist = MBSTRG(default_detect_order_list);
04611                             size = MBSTRG(default_detect_order_list_size);
04612                      }
04613               }
04614        } else {
04615               elist = MBSTRG(current_detect_order_list);
04616               size = MBSTRG(current_detect_order_list_size);
04617               if (size <= 0){
04618                      elist = MBSTRG(default_detect_order_list);
04619                      size = MBSTRG(default_detect_order_list_size);
04620               }
04621        }
04622 
04623        mbfl_string_init(&string);
04624        string.no_language = MBSTRG(language);
04625 
04626        identd = mbfl_encoding_detector_new(elist, size, MBSTRG(strict_detection));
04627 
04628        if (identd) {
04629               int n = 0;
04630               while(n < num){
04631                      string.val = (unsigned char *)arg_string[n];
04632                      string.len = arg_length[n];
04633                      if (mbfl_encoding_detector_feed(identd, &string)) {
04634                             break;
04635                      }
04636                      n++;
04637               }
04638               encoding = mbfl_encoding_detector_judge(identd);
04639               mbfl_encoding_detector_delete(identd);
04640        }
04641 
04642        if (encoding != mbfl_no_encoding_invalid) {
04643               MBSTRG(http_input_identify) = encoding;
04644               return SUCCESS;
04645        } else {
04646               return FAILURE;
04647        }
04648 }
04649 /* }}} */
04650 
04651 /* {{{ MBSTRING_API int php_mb_stripos()
04652  */
04653 MBSTRING_API int php_mb_stripos(int mode, const char *old_haystack, unsigned int old_haystack_len, const char *old_needle, unsigned int old_needle_len, long offset, const char *from_encoding TSRMLS_DC)
04654 {
04655        int n;
04656        mbfl_string haystack, needle;
04657        n = -1;
04658 
04659        mbfl_string_init(&haystack);
04660        mbfl_string_init(&needle);
04661        haystack.no_language = MBSTRG(language);
04662        haystack.no_encoding = MBSTRG(current_internal_encoding);
04663        needle.no_language = MBSTRG(language);
04664        needle.no_encoding = MBSTRG(current_internal_encoding);
04665 
04666        do {
04667               size_t len = 0;
04668               haystack.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_haystack, old_haystack_len, &len, from_encoding TSRMLS_CC);
04669               haystack.len = len;
04670 
04671               if (!haystack.val) {
04672                      break;
04673               }
04674 
04675               if (haystack.len <= 0) {
04676                      break;
04677               }
04678 
04679               needle.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, (char *)old_needle, old_needle_len, &len, from_encoding TSRMLS_CC);
04680               needle.len = len;
04681 
04682               if (!needle.val) {
04683                      break;
04684               }
04685 
04686               if (needle.len <= 0) {
04687                      break;
04688               }
04689 
04690               haystack.no_encoding = needle.no_encoding = mbfl_name2no_encoding(from_encoding);
04691               if (haystack.no_encoding == mbfl_no_encoding_invalid) {
04692                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", from_encoding);
04693                      break;
04694               }
04695 
04696               {
04697                      int haystack_char_len = mbfl_strlen(&haystack);
04698  
04699                      if (mode) {
04700                             if ((offset > 0 && offset > haystack_char_len) ||
04701                                    (offset < 0 && -offset > haystack_char_len)) {
04702                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
04703                                    break;
04704                             }
04705                      } else {
04706                             if (offset < 0 || offset > haystack_char_len) {
04707                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
04708                                    break;
04709                             }
04710                      }
04711               }
04712 
04713               n = mbfl_strpos(&haystack, &needle, offset, mode);
04714        } while(0);
04715 
04716        if (haystack.val) {
04717               efree(haystack.val);
04718        }
04719 
04720        if (needle.val) {
04721               efree(needle.val);
04722        }
04723 
04724        return n;
04725 }
04726 /* }}} */
04727 
04728 #ifdef ZEND_MULTIBYTE
04729 /* {{{ php_mb_set_zend_encoding() */
04730 static int php_mb_set_zend_encoding(TSRMLS_D)
04731 {
04732        /* 'd better use mbfl_memory_device? */
04733        char *name, *list = NULL;
04734        int n, *entry, list_size = 0;
04735        zend_encoding_detector encoding_detector;
04736        zend_encoding_converter encoding_converter;
04737        zend_encoding_oddlen encoding_oddlen;
04738 
04739        /* notify script encoding to Zend Engine */
04740        entry = MBSTRG(script_encoding_list);
04741        n = MBSTRG(script_encoding_list_size);
04742        while (n > 0) {
04743               name = (char *)mbfl_no_encoding2name(*entry);
04744               if (name) {
04745                      list_size += strlen(name) + 1;
04746                      if (!list) {
04747                             list = (char*)emalloc(list_size);
04748                             *list = '\0';
04749                      } else {
04750                             list = (char*)erealloc(list, list_size);
04751                             strcat(list, ",");
04752                      }
04753                      strcat(list, name);
04754               }
04755               entry++;
04756               n--;
04757        }
04758        zend_multibyte_set_script_encoding(list, (list ? strlen(list) : 0) TSRMLS_CC);
04759        if (list) {
04760               efree(list);
04761        }
04762        encoding_detector = php_mb_encoding_detector;
04763        encoding_converter = php_mb_encoding_converter;
04764        encoding_oddlen = php_mb_oddlen;
04765 
04766        /* TODO: make independent from mbstring.encoding_translation? */
04767        if (MBSTRG(encoding_translation)) {
04768               /* notify internal encoding to Zend Engine */
04769               name = (char*)mbfl_no_encoding2name(MBSTRG(current_internal_encoding));
04770               zend_multibyte_set_internal_encoding(name TSRMLS_CC);
04771        }
04772 
04773        zend_multibyte_set_functions(encoding_detector, encoding_converter, encoding_oddlen TSRMLS_CC);
04774 
04775        return 0;
04776 }
04777 /* }}} */
04778 
04779 /* {{{ char *php_mb_encoding_detector()
04780  * Interface for Zend Engine
04781  */
04782 static char* php_mb_encoding_detector(const unsigned char *arg_string, size_t arg_length, char *arg_list TSRMLS_DC)
04783 {
04784        mbfl_string string;
04785        const char *ret;
04786        enum mbfl_no_encoding *elist;
04787        int size, *list;
04788 
04789        /* make encoding list */
04790        list = NULL;
04791        size = 0;
04792        php_mb_parse_encoding_list(arg_list, strlen(arg_list), &list, &size, 0 TSRMLS_CC);
04793        if (size <= 0) {
04794               return NULL;
04795        }
04796        if (size > 0 && list != NULL) {
04797               elist = list;
04798        } else {
04799               elist = MBSTRG(current_detect_order_list);
04800               size = MBSTRG(current_detect_order_list_size);
04801        }
04802 
04803        mbfl_string_init(&string);
04804        string.no_language = MBSTRG(language);
04805        string.val = (unsigned char *)arg_string;
04806        string.len = arg_length;
04807        ret = mbfl_identify_encoding_name(&string, elist, size, 0);
04808        if (list != NULL) {
04809               efree((void *)list);
04810        }
04811        if (ret != NULL) {
04812               return estrdup(ret);
04813        } else {
04814               return NULL;
04815        }
04816 }
04817 /* }}} */
04818 
04819 /*     {{{ int php_mb_encoding_converter() */
04820 static int php_mb_encoding_converter(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length, const char *encoding_to, const char *encoding_from TSRMLS_DC)
04821 {
04822        mbfl_string string, result, *ret;
04823        enum mbfl_no_encoding from_encoding, to_encoding;
04824        mbfl_buffer_converter *convd;
04825 
04826        /* new encoding */
04827        to_encoding = mbfl_name2no_encoding(encoding_to);
04828        if (to_encoding == mbfl_no_encoding_invalid) {
04829               return -1;
04830        }      
04831        /* old encoding */
04832        from_encoding = mbfl_name2no_encoding(encoding_from);
04833        if (from_encoding == mbfl_no_encoding_invalid) {
04834               return -1;
04835        }
04836        /* initialize string */
04837        mbfl_string_init(&string);
04838        mbfl_string_init(&result);
04839        string.no_encoding = from_encoding;
04840        string.no_language = MBSTRG(language);
04841        string.val = (unsigned char*)from;
04842        string.len = from_length;
04843 
04844        /* initialize converter */
04845        convd = mbfl_buffer_converter_new(from_encoding, to_encoding, string.len);
04846        if (convd == NULL) {
04847               return -1;
04848        }
04849        mbfl_buffer_converter_illegal_mode(convd, MBSTRG(current_filter_illegal_mode));
04850        mbfl_buffer_converter_illegal_substchar(convd, MBSTRG(current_filter_illegal_substchar));
04851 
04852        /* do it */
04853        ret = mbfl_buffer_converter_feed_result(convd, &string, &result);
04854        if (ret != NULL) {
04855               *to = ret->val;
04856               *to_length = ret->len;
04857        }
04858 
04859        MBSTRG(illegalchars) += mbfl_buffer_illegalchars(convd);
04860        mbfl_buffer_converter_delete(convd);
04861 
04862        return ret ? 0 : -1;
04863 }
04864 /* }}} */
04865 
04866 /* {{{ int php_mb_oddlen()
04867  *     returns number of odd (e.g. appears only first byte of multibyte
04868  *     character) chars
04869  */
04870 static size_t php_mb_oddlen(const unsigned char *string, size_t length, const char *encoding TSRMLS_DC)
04871 {
04872        mbfl_string mb_string;
04873 
04874        mbfl_string_init(&mb_string);
04875        mb_string.no_language = MBSTRG(language);
04876        mb_string.no_encoding = mbfl_name2no_encoding(encoding);
04877        mb_string.val = (unsigned char *)string;
04878        mb_string.len = length;
04879 
04880        if (mb_string.no_encoding == mbfl_no_encoding_invalid) {
04881               return 0;
04882        }
04883        return mbfl_oddlen(&mb_string);
04884 }
04885 /* }}} */
04886 #endif /* ZEND_MULTIBYTE */
04887 
04888 #endif /* HAVE_MBSTRING */
04889 
04890 /*
04891  * Local variables:
04892  * tab-width: 4
04893  * c-basic-offset: 4
04894  * End:
04895  * vim600: fdm=marker
04896  * vim: noet sw=4 ts=4
04897  */