From 1caf9135115db922238f1a9e9e52759e251454a3 Mon Sep 17 00:00:00 2001 From: Simon Josefsson Date: Wed, 23 Feb 2005 23:30:10 +0000 Subject: [PATCH] 2005-02-22 Simon Josefsson * iconvme.h, iconvme.c: New files, from libc. --- lib/ChangeLog | 4 ++ lib/iconvme.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/iconvme.h | 25 +++++++++ lib/size_max.h | 27 ++++++++++ 4 files changed, 221 insertions(+) create mode 100644 lib/iconvme.c create mode 100644 lib/iconvme.h create mode 100644 lib/size_max.h diff --git a/lib/ChangeLog b/lib/ChangeLog index 2b55302e2..c82fdf59f 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,7 @@ +2005-02-22 Simon Josefsson + + * iconvme.h, iconvme.c: New files, from libc. + 2005-02-20 Neil Conway * xgethostname.c (xgethostname): Check for ENOMEM, which is diff --git a/lib/iconvme.c b/lib/iconvme.c new file mode 100644 index 000000000..6905b8b31 --- /dev/null +++ b/lib/iconvme.c @@ -0,0 +1,165 @@ +/* Recode strings between character sets, using iconv. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Get prototype. */ +#include "iconvme.h" + +/* Get malloc. */ +#include + +/* Get strcmp. */ +#include + +/* Get errno. */ +#include + +#ifdef _LIBC +# define HAVE_ICONV 1 +#else +/* Get strdup. */ +# include "strdup.h" +#endif + +#if HAVE_ICONV +/* Get iconv etc. */ +# include +/* Get MB_LEN_MAX. */ +# include +#endif + +/* Convert a zero-terminated string STR from the FROM_CODSET code set + to the TO_CODESET code set. The returned string is allocated using + malloc, and must be dellocated by the caller using free. On + failure, NULL is returned and errno holds the error reason. Note + that if TO_CODESET uses \0 for anything but to terminate the + string, the caller of this function may have difficulties finding + out the length of the output string. */ +char * +iconv_string (const char *str, const char *from_codeset, + const char *to_codeset) +{ + char *dest = NULL; +#if HAVE_ICONV + iconv_t cd; + char *outp; + char *p = (char *) str; + size_t inbytes_remaining = strlen (p); + /* Guess the maximum length the output string can have. */ + size_t outbuf_size = (inbytes_remaining + 1) * MB_LEN_MAX; + size_t outbytes_remaining = outbuf_size - 1; /* -1 for NUL */ + size_t err; + int have_error = 0; + + if (1 < MB_LEN_MAX && SIZE_MAX / MB_LEN_MAX <= inbytes_remaining) + { + errno = ENOMEM; + return NULL; + } +#endif + + if (strcmp (to_codeset, from_codeset) == 0) + return strdup (str); + +#if HAVE_ICONV + cd = iconv_open (to_codeset, from_codeset); + if (cd == (iconv_t) -1) + return NULL; + + outp = dest = (char *) malloc (outbuf_size); + if (dest == NULL) + goto out; + +again: + err = iconv (cd, &p, &inbytes_remaining, &outp, &outbytes_remaining); + + if (err == (size_t) - 1) + { + switch (errno) + { + case EINVAL: + /* Incomplete text, do not report an error */ + break; + + case E2BIG: + { + size_t used = outp - dest; + size_t newsize = outbuf_size * 2; + char *newdest; + + if (newsize <= outbuf_size) + { + errno = ENOMEM; + have_error = 1; + goto out; + } + newdest = (char *) realloc (dest, newsize); + if (newdest == NULL) + { + have_error = 1; + goto out; + } + dest = newdest; + outbuf_size = newsize; + + outp = dest + used; + outbytes_remaining = outbuf_size - used - 1; /* -1 for NUL */ + + goto again; + } + break; + + case EILSEQ: + have_error = 1; + break; + + default: + have_error = 1; + break; + } + } + + *outp = '\0'; + +out: + { + int save_errno = errno; + + if (iconv_close (cd) < 0 && !have_error) + { + /* If we didn't have a real error before, make sure we restore + the iconv_close error below. */ + save_errno = errno; + have_error = 1; + } + + if (have_error && dest) + { + free (dest); + dest = NULL; + errno = save_errno; + } + } +#else + errno = ENOSYS; +#endif + + return dest; +} diff --git a/lib/iconvme.h b/lib/iconvme.h new file mode 100644 index 000000000..3eb9b32b4 --- /dev/null +++ b/lib/iconvme.h @@ -0,0 +1,25 @@ +/* Recode strings between character sets, using iconv. + Copyright (C) 2004 Free Software Foundation, Inc. + Written by Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef ICONVME_H +# define ICONVME_H + +extern char *iconv_string (const char *string, const char *from_code, + const char *to_code); + +#endif /* ICONVME_H */ diff --git a/lib/size_max.h b/lib/size_max.h new file mode 100644 index 000000000..dcce48efc --- /dev/null +++ b/lib/size_max.h @@ -0,0 +1,27 @@ +/* size_max.h -- declare SIZE_MAX through system headers + Copyright (C) 2005 Free Software Foundation, Inc. + Written by Simon Josefsson. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GNULIB_SIZE_MAX_H +#define GNULIB_SIZE_MAX_H + +# include +# if HAVE_STDINT_H +# include +# endif + +#endif /* GNULIB_SIZE_MAX_H */ -- 2.11.0