]> granicus.if.org Git - php/commitdiff
Fix #16069. Patch by Moriyoshi Koizumi <readjust@deneb.freemail.ne.jp>
authorYasuo Ohgaki <yohgaki@php.net>
Thu, 11 Jul 2002 03:37:28 +0000 (03:37 +0000)
committerYasuo Ohgaki <yohgaki@php.net>
Thu, 11 Jul 2002 03:37:28 +0000 (03:37 +0000)
@ Made iconv() work well with libiconv or libgconv. (Moriyoshi, Yasuo)

ext/iconv/config.m4
ext/iconv/iconv.c

index 12e14d7ad8756d50cec44a7eab031b1fcee26fff..61b3998bb042310368c3aead0ad32576f71abcef 100644 (file)
@@ -8,6 +8,41 @@ PHP_ARG_WITH(iconv, for iconv support,
 if test "$PHP_ICONV" != "no"; then
 
   PHP_SETUP_ICONV(ICONV_SHARED_LIBADD, [
+       AC_MSG_CHECKING([if iconv supports errno])
+       AC_TRY_RUN([
+#define LIBICONV_PLUG
+#include <iconv.h>
+#include <errno.h>
+#if defined(_LIBICONV_H)
+#define icv_open(a, b) libiconv_open(a, b)
+#define icv_close(a) libiconv_close(a)
+#define icv(a, b, c, d, e) libiconv(a, b, c, d, e)
+#else
+#define icv_open(a, b) iconv_open(a, b)
+#define icv_close(a) iconv_close(a)
+#define icv(a, b, c, d, e) iconv(a, b, c, d, e)
+#endif
+
+int main() {
+       iconv_t cd;
+       cd = icv_open( "*blahblah*", "*blahblah*" );
+       if( cd == (iconv_t)(-1) ) {
+               if( errno == EINVAL ) {
+                       return 0;
+               } else {
+                       return 1;
+               }
+       }
+       icv_close( cd );
+       return 2;
+}
+],[
+       AC_MSG_RESULT(yes)
+       PHP_DEFINE(ICONV_SUPPORTS_ERRNO)
+],[
+       AC_MSG_RESULT(no)
+])
+
     PHP_NEW_EXTENSION(iconv, iconv.c, $ext_shared)
     PHP_SUBST(ICONV_SHARED_LIBADD)
   ], [
index 305004c2840c4a001909cf3cb1fc51887e0b56c9..87d21fd514a6d28373bc8cc9146a8e8bafd3d47f 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef PHP_ATOM_INC
 #include "php_have_iconv.h"
 #include "php_have_libiconv.h"
+#include "php_iconv_supports_errno.h"
 #endif
 
 #if HAVE_ICONV
@@ -49,6 +50,7 @@
 
 
 #if HAVE_LIBICONV
+#define LIBICONV_PLUG
 #define icv_open(a, b) libiconv_open(a, b)
 #define icv_close(a) libiconv_close(a)
 #define icv(a, b, c, d, e) libiconv(a, b, c, d, e)
@@ -145,8 +147,7 @@ static int php_iconv_string(const char *in_p, size_t in_len,
                                                        char **out, size_t *out_len,
                                                        const char *in_charset, const char *out_charset, int *err TSRMLS_DC)
 {
-#if HAVE_LIBICONV
-       /* No errno for libiconv(?) */
+#if !defined(ICONV_SUPPORTS_ERRNO)
        unsigned int in_size, out_size, out_left;
        char *out_buffer, *out_p;
        iconv_t cd;
@@ -163,9 +164,9 @@ static int php_iconv_string(const char *in_p, size_t in_len,
          a single char can be more than 4 bytes.
          I added 15 extra bytes for safety. <yohgaki@php.net>
        */
-       out_size = in_len * sizeof(ucs4_t) + 16;
-       out_buffer = (char *) emalloc(out_size);
-       
+       out_size = in_len * sizeof(ucs4_t) + 15;
+       out_buffer = (char *) emalloc(out_size + 1);
+
        *out = out_buffer;
        out_p = out_buffer;
        out_left = out_size;
@@ -197,71 +198,78 @@ static int php_iconv_string(const char *in_p, size_t in_len,
 
 #else
        /*
-         libc iconv should support errno. Handle it better way.
+         iconv supports errno. Handle it better way.
        */
        iconv_t cd;
        size_t in_left, out_size, out_left;
        char *out_p, *out_buf, *tmp_buf;
-       size_t i, bsz, result;
+       size_t bsz, result;
 
        *err = 0;
-       cd = iconv_open(out_charset, in_charset);
+       cd = icv_open(out_charset, in_charset);
+
        if (cd == (iconv_t)(-1)) {
                if (errno == EINVAL) {
                        *err = PHP_ICONV_WRONG_CHARSET;
-                       php_error(E_NOTICE, "%s() wrong charset, cannot convert from `%s' to `%s'",
+                       php_error(E_NOTICE, "%s(): wrong charset, cannot convert from `%s' to `%s'",
                                          get_active_function_name(TSRMLS_C), in_charset, out_charset);
-               }
-               else {
+               } else {
                        *err = PHP_ICONV_CONVERTER;
-                       php_error(E_NOTICE, "%s() cannot open converter",
+                       php_error(E_NOTICE, "%s(): cannot open converter",
                                          get_active_function_name(TSRMLS_C));
                }
                return FAILURE;
        }
-       
        in_left= in_len;
        out_left = in_len + 32; /* Avoid realloc() most cases */ 
+       out_size = 0;
        bsz = out_left;
        out_buf = (char *) emalloc(bsz+1); 
        out_p = out_buf;
-       result = iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left);
-       out_size = bsz - out_left;
-       for (i = 2;in_left > 0 && errno == E2BIG; i++) {
-               /* converted string is longer than out buffer */
-               tmp_buf = (char*)erealloc(out_buf, bsz*i+1);
-               if (tmp_buf == NULL) {
-                       break;
+
+       while(in_left > 0) {
+               result = icv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left);
+               out_size = bsz - out_left;
+               if( result == (size_t)(-1) ) {
+                       if( errno == E2BIG && in_left > 0 ) {
+                               /* converted string is longer than out buffer */
+                               bsz += in_len;
+
+                               tmp_buf = (char*) erealloc(out_buf, bsz+1);
+
+                               if (tmp_buf != NULL) {
+                                       out_p = out_buf = tmp_buf;
+                                       out_p += out_size;
+                                       out_left = bsz - out_size;
+                                       continue;       
+                               }
+                       }
                }
-               out_buf = tmp_buf;
-               out_p = tmp_buf;
-               out_p += out_size;
-               out_left = bsz;
-               result = iconv(cd, (char **)&in_p, &in_left, &out_p, &out_left);
-               out_size += bsz - out_left;
+               break;
        }
-       iconv_close(cd);
+       icv_close(cd);
+
        if (result == (size_t)(-1)) {
                switch (errno) {
                        case EINVAL:
-                               php_error(E_NOTICE, "%s() detected incomplete character in input string",
+                               php_error(E_NOTICE, "%s(): detected incomplete character in input string",
                                                  get_active_function_name(TSRMLS_C));
                                *err = PHP_ICONV_ILLEGAL_CHAR;
                                break;
                        case EILSEQ:
-                               php_error(E_NOTICE, "%s() detected illegal character in input string",
+                               php_error(E_NOTICE, "%s(): detected illegal character in input string",
                                                  get_active_function_name(TSRMLS_C));
                                *err = PHP_ICONV_ILLEGAL_SEQ;
                                break;
                        case E2BIG:
                                /* should not happen */
-                               php_error(E_WARNING, "%s() run out buffer",
+                               php_error(E_WARNING, "%s(): run out buffer",
                                                  get_active_function_name(TSRMLS_C));
                                *err = PHP_ICONV_TOO_BIG;
                                break;
                        default:
                                /* other error */
-                               php_error(E_NOTICE, "%s() unknown error (%d)",
+                               php_error(E_NOTICE, "%s(): unknown error (%d)",
                                                  get_active_function_name(TSRMLS_C), errno);
                                *err = PHP_ICONV_UNKNOWN;
                                efree(out_buf);