X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=charset.cpkg;h=89905b8ed4b11b6b1abbb8576815c06a6f2cf171;hp=a58b013b53abd4271b8d441adacafcd0a807b6d0;hb=db3bd72d8b48f1f9b49899da081ffbec4ce2c1c6;hpb=07066d3ea19865d08c4a8fd98b5e87eeace810da diff --git a/charset.cpkg b/charset.cpkg index a58b013..89905b8 100644 --- a/charset.cpkg +++ b/charset.cpkg @@ -226,41 +226,117 @@ iconv_t mutt_iconv_open(const char *tocode, const char *fromcode, int flags) charset_canonicalize(from1, sizeof(from1), fromcode); } - m_strcat(to1, sizeof(to1), "//TRANSLIT"); if ((cd = iconv_open(to1, from1)) != MUTT_ICONV_ERROR) return cd; if (rx_list_match2(iconv_hooks, to1, to2, sizeof(to2)) - && rx_list_match2(iconv_hooks, from1, from2, sizeof(from2))) { - m_strcat(to2, sizeof(to2), "//TRANSLIT"); + && rx_list_match2(iconv_hooks, from1, from2, sizeof(from2))) return iconv_open(to2, from2); - } return MUTT_ICONV_ERROR; } +/* Like iconv, but keeps going even when the input is invalid + If you're supplying inrepls, the source charset should be stateless; + if you're supplying an outrepl, the target charset should be. */ +/* XXX: MC: I do not understand what it does yet */ +ssize_t mutt_iconv(iconv_t cd, + const char **inbuf, ssize_t *inbytesleft, + char **outbuf, ssize_t *outbytesleft, + const char **inrepls, const char *outrepl) +{ + ssize_t ret = 0, ret1; + const char *ib = *inbuf; + ssize_t ibl = *inbytesleft; + char *ob = *outbuf; + ssize_t obl = *outbytesleft; + + for (;;) { + ret1 = my_iconv(cd, &ib, &ibl, &ob, &obl); + if (ret1 != -1) + ret += ret1; + + if (ibl && obl && errno == EILSEQ) { + if (inrepls) { + /* Try replacing the input */ + const char **t; + + for (t = inrepls; *t; t++) { + const char *ib1 = *t; + ssize_t ibl1 = m_strlen(*t); + char *ob1 = ob; + ssize_t obl1 = obl; + + my_iconv(cd, &ib1, &ibl1, &ob1, &obl1); + if (!ibl1) { + ++ib, --ibl; + ob = ob1, obl = obl1; + ++ret; + break; + } + } + if (*t) + continue; + } + /* Replace the output */ + if (!outrepl) + outrepl = "?"; + my_iconv(cd, 0, 0, &ob, &obl); + if (obl) { + ssize_t n = m_strlen(outrepl); + + if (n > obl) { + outrepl = "?"; + n = 1; + } + memcpy(ob, outrepl, n); + ++ib, --ibl; + ob += n, obl -= n; + ++ret; + my_iconv(cd, 0, 0, 0, 0); /* for good measure */ + continue; + } + } + *inbuf = ib, *inbytesleft = ibl; + *outbuf = ob, *outbytesleft = obl; + return ret; + } +} + /* Convert a string */ int mutt_convert_string(char **ps, const char *from, const char *to, int flags) { iconv_t cd; + const char *repls[] = { "\357\277\275", "?", 0 }; + if (m_strisempty(*ps)) return 0; cd = mutt_iconv_open(to, from, flags); if (cd != MUTT_ICONV_ERROR) { + const char **inrepls = NULL; + const char *outrepl = NULL; const char *ib; char *buf, *ob; ssize_t ibl, obl; + if (charset_is_utf8(to)) + outrepl = "\357\277\275"; + else + if (charset_is_utf8(from)) + inrepls = repls; + else + outrepl = "?"; + ibl = m_strlen(*ps) + 1; ib = *ps; obl = MB_LEN_MAX * ibl; ob = buf = p_new(char, obl + 1); - mutt_iconv(cd, &ib, &ibl, &ob, &obl); + mutt_iconv(cd, &ib, &ibl, &ob, &obl, inrepls, outrepl); iconv_close(cd); *ob = '\0'; @@ -288,9 +364,9 @@ static ssize_t convert_string(const char *f, ssize_t flen, obl = 4 * flen + 1; ob = buf = p_new(char, obl); - n = mutt_iconv(cd, &f, &flen, &ob, &obl); + n = my_iconv(cd, &f, &flen, &ob, &obl); - if (n < 0 || mutt_iconv(cd, 0, 0, &ob, &obl) < 0) { + if (n < 0 || my_iconv(cd, 0, 0, &ob, &obl) < 0) { e = errno; p_delete(&buf); iconv_close(cd); @@ -352,11 +428,14 @@ struct fgetconv_t { char *ob; char *ib; ssize_t ibl; + const char **inrepls; }; fgetconv_t * fgetconv_open(FILE *file, const char *from, const char *to, int flags) { + static const char *repls[] = { "\357\277\275", "?", 0 }; + struct fgetconv_t *fc = p_new(struct fgetconv_t, 1); fc->file = file; @@ -368,6 +447,7 @@ fgetconv_open(FILE *file, const char *from, const char *to, int flags) fc->p = fc->ob = fc->bufo; fc->ib = fc->bufi; fc->ibl = 0; + fc->inrepls = repls + charset_is_utf8(to); } return fc; } @@ -377,7 +457,7 @@ void fgetconv_close(fgetconv_t **fcp) struct fgetconv_t *fc = *fcp; if (fc->cd != MUTT_ICONV_ERROR) - iconv_close(fc->cd); + iconv_close (fc->cd); p_delete(fcp); } @@ -400,7 +480,7 @@ int fgetconv(fgetconv_t *fc) if (fc->ibl) { ssize_t obl = ssizeof(fc->bufo); - mutt_iconv(fc->cd, (const char **)&fc->ib, &fc->ibl, &fc->ob, &obl); + my_iconv(fc->cd, (const char **)&fc->ib, &fc->ibl, &fc->ob, &obl); if (fc->p < fc->ob) return (unsigned char)*(fc->p)++; } @@ -426,7 +506,8 @@ int fgetconv(fgetconv_t *fc) if (fc->ibl) { ssize_t obl = ssizeof(fc->bufo); - mutt_iconv(fc->cd, (const char **)&fc->ib, &fc->ibl, &fc->ob, &obl); + mutt_iconv(fc->cd, (const char **)&fc->ib, &fc->ibl, &fc->ob, &obl, + fc->inrepls, 0); if (fc->p < fc->ob) { return (unsigned char)*(fc->p)++; }