Code

Move encoding conversion routine out of mailinfo to utf8.c
authorJunio C Hamano <junkio@cox.net>
Sun, 24 Dec 2006 07:36:55 +0000 (23:36 -0800)
committerJunio C Hamano <junkio@cox.net>
Tue, 26 Dec 2006 08:22:39 +0000 (00:22 -0800)
This moves the body of convert_to_utf8() routine used in mailinfo
to the utf8.c i18n library.

Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-mailinfo.c
utf8.c
utf8.h

index e6472293d47611d415276f6057227d9c93788f63..507b93f6a707a2e44ee5f5b2abc55f0e6b096367 100644 (file)
@@ -4,6 +4,7 @@
  */
 #include "cache.h"
 #include "builtin.h"
+#include "utf8.h"
 
 static FILE *cmitmsg, *patchfile, *fin, *fout;
 
@@ -510,40 +511,18 @@ static int decode_b_segment(char *in, char *ot, char *ep)
 
 static void convert_to_utf8(char *line, char *charset)
 {
-#ifndef NO_ICONV
-       char *in, *out;
-       size_t insize, outsize, nrc;
-       char outbuf[4096]; /* cheat */
        static char latin_one[] = "latin1";
        char *input_charset = *charset ? charset : latin_one;
-       iconv_t conv = iconv_open(metainfo_charset, input_charset);
-
-       if (conv == (iconv_t) -1) {
-               static int warned_latin1_once = 0;
-               if (input_charset != latin_one) {
-                       fprintf(stderr, "cannot convert from %s to %s\n",
-                               input_charset, metainfo_charset);
-                       *charset = 0;
-               }
-               else if (!warned_latin1_once) {
-                       warned_latin1_once = 1;
-                       fprintf(stderr, "tried to convert from %s to %s, "
-                               "but your iconv does not work with it.\n",
-                               input_charset, metainfo_charset);
-               }
+       char *out = reencode_string(line, metainfo_charset, input_charset);
+
+       if (!out) {
+               fprintf(stderr, "cannot convert from %s to %s\n",
+                       input_charset, metainfo_charset);
+               *charset = 0;
                return;
        }
-       in = line;
-       insize = strlen(in);
-       out = outbuf;
-       outsize = sizeof(outbuf);
-       nrc = iconv(conv, &in, &insize, &out, &outsize);
-       iconv_close(conv);
-       if (nrc == (size_t) -1)
-               return;
-       *out = 0;
-       strcpy(line, outbuf);
-#endif
+       strcpy(line, out);
+       free(out);
 }
 
 static int decode_header_bq(char *it)
diff --git a/utf8.c b/utf8.c
index 8fa62571aa959897275e694a4370e99c46cccd6a..1eedd8b61aeed9867366df0b70ac849cdef985b9 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -276,3 +276,57 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width)
                }
        }
 }
+
+/*
+ * Given a buffer and its encoding, return it re-encoded
+ * with iconv.  If the conversion fails, returns NULL.
+ */
+#ifndef NO_ICONV
+char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
+{
+       iconv_t conv;
+       size_t insz, outsz, outalloc;
+       char *out, *outpos, *cp;
+
+       if (!in_encoding)
+               return NULL;
+       conv = iconv_open(out_encoding, in_encoding);
+       if (conv == (iconv_t) -1)
+               return NULL;
+       insz = strlen(in);
+       outsz = insz;
+       outalloc = outsz + 1; /* for terminating NUL */
+       out = xmalloc(outalloc);
+       outpos = out;
+       cp = (char *)in;
+
+       while (1) {
+               size_t cnt = iconv(conv, &cp, &insz, &outpos, &outsz);
+
+               if (cnt == -1) {
+                       size_t sofar;
+                       if (errno != E2BIG) {
+                               free(out);
+                               iconv_close(conv);
+                               return NULL;
+                       }
+                       /* insz has remaining number of bytes.
+                        * since we started outsz the same as insz,
+                        * it is likely that insz is not enough for
+                        * converting the rest.
+                        */
+                       sofar = outpos - out;
+                       outalloc = sofar + insz * 2 + 32;
+                       out = xrealloc(out, outalloc);
+                       outpos = out + sofar;
+                       outsz = outalloc - sofar - 1;
+               }
+               else {
+                       *outpos = '\0';
+                       break;
+               }
+       }
+       iconv_close(conv);
+       return out;
+}
+#endif
diff --git a/utf8.h b/utf8.h
index a0d7f591adc3d86e5c813d79059c7c0335b32dc3..cae2a8e665c2cbe7bf31a49deed84250eaa37a33 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -5,4 +5,10 @@ int utf8_width(const char **start);
 int is_utf8(const char *text);
 void print_wrapped_text(const char *text, int indent, int indent2, int len);
 
+#ifndef NO_ICONV
+char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
+#else
+#define reencode_string(a,b,c) NULL
+#endif
+
 #endif