X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fstriconveha.c;h=fdb84216547da155db5832a678ec01beae6239d9;hb=ccd54782ae73477aa3f3987ab04db9e6fde025d6;hp=9da18c93ef8e5ff07a10ca7632bfce623922cd27;hpb=36a6f6825953d52a32710a6c38d3ef3a5870d3ac;p=gnulib.git diff --git a/lib/striconveha.c b/lib/striconveha.c index 9da18c93e..fdb842165 100644 --- a/lib/striconveha.c +++ b/lib/striconveha.c @@ -25,6 +25,9 @@ #include #include +#include "allocsa.h" +#include "c-strcase.h" + #define SIZEOF(a) (sizeof(a)/sizeof(a[0])) @@ -143,14 +146,16 @@ uniconv_register_autodetect (const char *name, } } -int -mem_iconveha (const char *src, size_t srclen, - const char *from_codeset, const char *to_codeset, - enum iconv_ilseq_handler handler, - char **resultp, size_t *lengthp) +/* Like mem_iconveha, except no handling of transliteration. */ +static int +mem_iconveha_notranslit (const char *src, size_t srclen, + const char *from_codeset, const char *to_codeset, + enum iconv_ilseq_handler handler, + size_t *offsets, + char **resultp, size_t *lengthp) { int retval = mem_iconveh (src, srclen, from_codeset, to_codeset, handler, - resultp, lengthp); + offsets, resultp, lengthp); if (retval >= 0 || errno != EINVAL) return retval; else @@ -162,13 +167,32 @@ mem_iconveha (const char *src, size_t srclen, for (alias = autodetect_list; alias != NULL; alias = alias->next) if (strcmp (from_codeset, alias->name) == 0) { - const char * const *encodings = alias->encodings_to_try; + const char * const *encodings; + if (handler != iconveh_error) + { + /* First try all encodings without any forgiving. */ + encodings = alias->encodings_to_try; + do + { + retval = mem_iconveha_notranslit (src, srclen, + *encodings, to_codeset, + iconveh_error, offsets, + resultp, lengthp); + if (!(retval < 0 && errno == EILSEQ)) + return retval; + encodings++; + } + while (*encodings != NULL); + } + + encodings = alias->encodings_to_try; do { - retval = mem_iconveha (src, srclen, - from_codeset, to_codeset, handler, - resultp, lengthp); + retval = mem_iconveha_notranslit (src, srclen, + *encodings, to_codeset, + handler, offsets, + resultp, lengthp); if (!(retval < 0 && errno == EILSEQ)) return retval; encodings++; @@ -185,10 +209,52 @@ mem_iconveha (const char *src, size_t srclen, } } -char * -str_iconveha (const char *src, +int +mem_iconveha (const char *src, size_t srclen, const char *from_codeset, const char *to_codeset, - enum iconv_ilseq_handler handler) + bool transliterate, + enum iconv_ilseq_handler handler, + size_t *offsets, + char **resultp, size_t *lengthp) +{ + if (srclen == 0) + { + /* Nothing to convert. */ + *lengthp = 0; + return 0; + } + + /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, + we want to use transliteration. */ +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105 + if (transliterate) + { + int retval; + size_t len = strlen (to_codeset); + char *to_codeset_suffixed = (char *) allocsa (len + 10 + 1); + memcpy (to_codeset_suffixed, to_codeset, len); + memcpy (to_codeset_suffixed + len, "//TRANSLIT", 10 + 1); + + retval = mem_iconveha_notranslit (src, srclen, + from_codeset, to_codeset_suffixed, + handler, offsets, resultp, lengthp); + + freesa (to_codeset_suffixed); + + return retval; + } + else +#endif + return mem_iconveha_notranslit (src, srclen, + from_codeset, to_codeset, + handler, offsets, resultp, lengthp); +} + +/* Like str_iconveha, except no handling of transliteration. */ +static char * +str_iconveha_notranslit (const char *src, + const char *from_codeset, const char *to_codeset, + enum iconv_ilseq_handler handler) { char *result = str_iconveh (src, from_codeset, to_codeset, handler); @@ -203,11 +269,30 @@ str_iconveha (const char *src, for (alias = autodetect_list; alias != NULL; alias = alias->next) if (strcmp (from_codeset, alias->name) == 0) { - const char * const *encodings = alias->encodings_to_try; + const char * const *encodings; + + if (handler != iconveh_error) + { + /* First try all encodings without any forgiving. */ + encodings = alias->encodings_to_try; + do + { + result = str_iconveha_notranslit (src, + *encodings, to_codeset, + iconveh_error); + if (!(result == NULL && errno == EILSEQ)) + return result; + encodings++; + } + while (*encodings != NULL); + } + encodings = alias->encodings_to_try; do { - result = str_iconveha (src, *encodings, to_codeset, handler); + result = str_iconveha_notranslit (src, + *encodings, to_codeset, + handler); if (!(result == NULL && errno == EILSEQ)) return result; encodings++; @@ -223,3 +308,41 @@ str_iconveha (const char *src, return NULL; } } + +char * +str_iconveha (const char *src, + const char *from_codeset, const char *to_codeset, + bool transliterate, + enum iconv_ilseq_handler handler) +{ + if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0) + { + char *result = strdup (src); + + if (result == NULL) + errno = ENOMEM; + return result; + } + + /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, + we want to use transliteration. */ +#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 || _LIBICONV_VERSION >= 0x0105 + if (transliterate) + { + char *result; + size_t len = strlen (to_codeset); + char *to_codeset_suffixed = (char *) allocsa (len + 10 + 1); + memcpy (to_codeset_suffixed, to_codeset, len); + memcpy (to_codeset_suffixed + len, "//TRANSLIT", 10 + 1); + + result = str_iconveha_notranslit (src, from_codeset, to_codeset_suffixed, + handler); + + freesa (to_codeset_suffixed); + + return result; + } + else +#endif + return str_iconveha_notranslit (src, from_codeset, to_codeset, handler); +}