annotate lib/striconv.c @ 17363:5a51fb7777a9

sys_select, sys_time: port 2013-01-30 Solaris 2.6 fix to Cygwin Problem reported by Marco Atzeri in <http://lists.gnu.org/archive/html/bug-gnulib/2013-03/msg00000.html>. * lib/sys_select.in.h [HAVE_SYS_SELECT_H && _CYGWIN_SYS_TIME_H]: Simply delegate to the system <sys/select.h> in this case too. Also, pay attention to _GL_SYS_SELECT_H_REDIRECT_FROM_SYS_TIME_H only if OSF/1, since otherwise Cygwin breaks, and it doesn't seem to be needed on Solaris either. * lib/sys_time.in.h [_CYGWIN_SYS_TIME_H]: Simply delgate to the system <sys/time.h> in this case.
author Paul Eggert <eggert@cs.ucla.edu>
date Tue, 19 Mar 2013 09:08:47 -0700
parents e542fd46ad6f
children 344018b6e5d7
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
1 /* Charset conversion.
17249
e542fd46ad6f maint: update all copyright year number ranges
Eric Blake <eblake@redhat.com>
parents: 16366
diff changeset
2 Copyright (C) 2001-2007, 2010-2013 Free Software Foundation, Inc.
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
3 Written by Bruno Haible and Simon Josefsson.
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
4
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
5 This program is free software; you can redistribute it and/or modify
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
6 it under the terms of the GNU General Public License as published by
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
7 the Free Software Foundation; either version 2, or (at your option)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
8 any later version.
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
10 This program is distributed in the hope that it will be useful,
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13 GNU General Public License for more details.
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
14
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
15 You should have received a copy of the GNU General Public License
16366
bb182ee4a09d maint: replace FSF snail-mail addresses with URLs
Paul Eggert <eggert@cs.ucla.edu>
parents: 16201
diff changeset
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
17
7304
1c4ed7637c24 Include <config.h> unconditionally.
Bruno Haible <bruno@clisp.org>
parents: 7261
diff changeset
18 #include <config.h>
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
19
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
20 /* Specification. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
21 #include "striconv.h"
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
22
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
23 #include <errno.h>
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
24 #include <stdlib.h>
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
25 #include <string.h>
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
26
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
27 #if HAVE_ICONV
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
28 # include <iconv.h>
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
29 /* Get MB_LEN_MAX, CHAR_BIT. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
30 # include <limits.h>
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
31 #endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
32
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
33 #include "c-strcase.h"
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
34
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
35 #ifndef SIZE_MAX
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
36 # define SIZE_MAX ((size_t) -1)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
37 #endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
38
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
39
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
40 #if HAVE_ICONV
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
41
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
42 int
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
43 mem_cd_iconv (const char *src, size_t srclen, iconv_t cd,
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
44 char **resultp, size_t *lengthp)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
45 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
46 # define tmpbufsize 4096
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
47 size_t length;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
48 char *result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
49
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
50 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
51 # if defined _LIBICONV_VERSION \
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
52 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
53 || defined __sun)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
54 /* Set to the initial state. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
55 iconv (cd, NULL, NULL, NULL, NULL);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
56 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
57
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
58 /* Determine the length we need. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
59 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
60 size_t count = 0;
7861
28688a13afbc Align the temporary buffer.
Bruno Haible <bruno@clisp.org>
parents: 7586
diff changeset
61 /* The alignment is needed when converting e.g. to glibc's WCHAR_T or
28688a13afbc Align the temporary buffer.
Bruno Haible <bruno@clisp.org>
parents: 7586
diff changeset
62 libiconv's UCS-4-INTERNAL encoding. */
28688a13afbc Align the temporary buffer.
Bruno Haible <bruno@clisp.org>
parents: 7586
diff changeset
63 union { unsigned int align; char buf[tmpbufsize]; } tmp;
28688a13afbc Align the temporary buffer.
Bruno Haible <bruno@clisp.org>
parents: 7586
diff changeset
64 # define tmpbuf tmp.buf
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
65 const char *inptr = src;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
66 size_t insize = srclen;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
67
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
68 while (insize > 0)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
69 {
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
70 char *outptr = tmpbuf;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
71 size_t outsize = tmpbufsize;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
72 size_t res = iconv (cd,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
73 (ICONV_CONST char **) &inptr, &insize,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
74 &outptr, &outsize);
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
75
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
76 if (res == (size_t)(-1))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
77 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
78 if (errno == E2BIG)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
79 ;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
80 else if (errno == EINVAL)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
81 break;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
82 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
83 return -1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
84 }
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
85 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
86 /* Irix iconv() inserts a NUL byte if it cannot convert.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
87 NetBSD iconv() inserts a question mark if it cannot convert.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
88 Only GNU libiconv and GNU libc are known to prefer to fail rather
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
89 than doing a lossy conversion. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
90 else if (res > 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
91 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
92 errno = EILSEQ;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
93 return -1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
94 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
95 # endif
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
96 count += outptr - tmpbuf;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
97 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
98 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
99 # if defined _LIBICONV_VERSION \
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
100 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
101 || defined __sun)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
102 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
103 char *outptr = tmpbuf;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
104 size_t outsize = tmpbufsize;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
105 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
106
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
107 if (res == (size_t)(-1))
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
108 return -1;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
109 count += outptr - tmpbuf;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
110 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
111 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
112 length = count;
7861
28688a13afbc Align the temporary buffer.
Bruno Haible <bruno@clisp.org>
parents: 7586
diff changeset
113 # undef tmpbuf
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
114 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
115
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
116 if (length == 0)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
117 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
118 *lengthp = 0;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
119 return 0;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
120 }
7912
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
121 if (*resultp != NULL && *lengthp >= length)
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
122 result = *resultp;
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
123 else
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
124 {
7912
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
125 result = (char *) malloc (length);
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
126 if (result == NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
127 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
128 errno = ENOMEM;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
129 return -1;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
130 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
131 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
132
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
133 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
134 # if defined _LIBICONV_VERSION \
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
135 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
136 || defined __sun)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
137 /* Return to the initial state. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
138 iconv (cd, NULL, NULL, NULL, NULL);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
139 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
140
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
141 /* Do the conversion for real. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
142 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
143 const char *inptr = src;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
144 size_t insize = srclen;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
145 char *outptr = result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
146 size_t outsize = length;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
147
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
148 while (insize > 0)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
149 {
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
150 size_t res = iconv (cd,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
151 (ICONV_CONST char **) &inptr, &insize,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
152 &outptr, &outsize);
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
153
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
154 if (res == (size_t)(-1))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
155 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
156 if (errno == EINVAL)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
157 break;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
158 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
159 goto fail;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
160 }
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
161 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
162 /* Irix iconv() inserts a NUL byte if it cannot convert.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
163 NetBSD iconv() inserts a question mark if it cannot convert.
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
164 Only GNU libiconv and GNU libc are known to prefer to fail rather
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
165 than doing a lossy conversion. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
166 else if (res > 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
167 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
168 errno = EILSEQ;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
169 goto fail;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
170 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
171 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
172 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
173 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
174 # if defined _LIBICONV_VERSION \
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
175 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
176 || defined __sun)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
177 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
178 size_t res = iconv (cd, NULL, NULL, &outptr, &outsize);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
179
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
180 if (res == (size_t)(-1))
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
181 goto fail;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
182 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
183 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
184 if (outsize != 0)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
185 abort ();
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
186 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
187
7912
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
188 *resultp = result;
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
189 *lengthp = length;
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
190
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
191 return 0;
7912
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
192
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
193 fail:
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
194 {
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
195 if (result != *resultp)
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
196 {
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
197 int saved_errno = errno;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
198 free (result);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
199 errno = saved_errno;
7912
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
200 }
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
201 return -1;
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
202 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
203 # undef tmpbufsize
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
204 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
205
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
206 char *
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
207 str_cd_iconv (const char *src, iconv_t cd)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
208 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
209 /* For most encodings, a trailing NUL byte in the input will be converted
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
210 to a trailing NUL byte in the output. But not for UTF-7. So that this
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
211 function is usable for UTF-7, we have to exclude the NUL byte from the
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
212 conversion and add it by hand afterwards. */
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
213 # if !defined _LIBICONV_VERSION && !(defined __GLIBC__ && !defined __UCLIBC__)
7881
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
214 /* Irix iconv() inserts a NUL byte if it cannot convert.
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
215 NetBSD iconv() inserts a question mark if it cannot convert.
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
216 Only GNU libiconv and GNU libc are known to prefer to fail rather
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
217 than doing a lossy conversion. For other iconv() implementations,
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
218 we have to look at the number of irreversible conversions returned;
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
219 but this information is lost when iconv() returns for an E2BIG reason.
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
220 Therefore we cannot use the second, faster algorithm. */
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
221
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
222 char *result = NULL;
7912
57ae1482adc0 Make the API of mem_cd_iconv more useful.
Bruno Haible <bruno@clisp.org>
parents: 7881
diff changeset
223 size_t length = 0;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
224 int retval = mem_cd_iconv (src, strlen (src), cd, &result, &length);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
225 char *final_result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
226
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
227 if (retval < 0)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
228 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
229 if (result != NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
230 abort ();
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
231 return NULL;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
232 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
233
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
234 /* Add the terminating NUL byte. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
235 final_result =
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
236 (result != NULL ? realloc (result, length + 1) : malloc (length + 1));
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
237 if (final_result == NULL)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
238 {
12737
d49b651c4fd8 lib/striconv.c (str_cd_iconv): Avoid if before free.
Simon Josefsson <simon@josefsson.org>
parents: 12559
diff changeset
239 free (result);
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
240 errno = ENOMEM;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
241 return NULL;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
242 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
243 final_result[length] = '\0';
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
244
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
245 return final_result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
246
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
247 # else
7881
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
248 /* This algorithm is likely faster than the one above. But it may produce
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
249 iconv() returns for an E2BIG reason, when the output size guess is too
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
250 small. Therefore it can only be used when we don't need the number of
6b561fb10325 (str_cd_iconv): Use the first algorithm if iconv is not from GNU libiconv or
Bruno Haible <bruno@clisp.org>
parents: 7862
diff changeset
251 irreversible conversions performed. */
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
252 char *result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
253 size_t result_size;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
254 size_t length;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
255 const char *inptr = src;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
256 size_t inbytes_remaining = strlen (src);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
257
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
258 /* Make a guess for the worst-case output size, in order to avoid a
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
259 realloc. It's OK if the guess is wrong as long as it is not zero and
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
260 doesn't lead to an integer overflow. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
261 result_size = inbytes_remaining;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
262 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
263 size_t approx_sqrt_SIZE_MAX = SIZE_MAX >> (sizeof (size_t) * CHAR_BIT / 2);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
264 if (result_size <= approx_sqrt_SIZE_MAX / MB_LEN_MAX)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
265 result_size *= MB_LEN_MAX;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
266 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
267 result_size += 1; /* for the terminating NUL */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
268
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
269 result = (char *) malloc (result_size);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
270 if (result == NULL)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
271 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
272 errno = ENOMEM;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
273 return NULL;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
274 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
275
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
276 /* Avoid glibc-2.1 bug and Solaris 2.7-2.9 bug. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
277 # if defined _LIBICONV_VERSION \
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
278 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
279 || defined __sun)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
280 /* Set to the initial state. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
281 iconv (cd, NULL, NULL, NULL, NULL);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
282 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
283
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
284 /* Do the conversion. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
285 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
286 char *outptr = result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
287 size_t outbytes_remaining = result_size - 1;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
288
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
289 for (;;)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
290 {
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
291 /* Here inptr + inbytes_remaining = src + strlen (src),
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
292 outptr + outbytes_remaining = result + result_size - 1. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
293 size_t res = iconv (cd,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
294 (ICONV_CONST char **) &inptr, &inbytes_remaining,
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
295 &outptr, &outbytes_remaining);
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
296
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
297 if (res == (size_t)(-1))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
298 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
299 if (errno == EINVAL)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
300 break;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
301 else if (errno == E2BIG)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
302 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
303 size_t used = outptr - result;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
304 size_t newsize = result_size * 2;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
305 char *newresult;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
306
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
307 if (!(newsize > result_size))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
308 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
309 errno = ENOMEM;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
310 goto failed;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
311 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
312 newresult = (char *) realloc (result, newsize);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
313 if (newresult == NULL)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
314 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
315 errno = ENOMEM;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
316 goto failed;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
317 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
318 result = newresult;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
319 result_size = newsize;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
320 outptr = result + used;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
321 outbytes_remaining = result_size - 1 - used;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
322 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
323 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
324 goto failed;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
325 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
326 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
327 break;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
328 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
329 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
330 # if defined _LIBICONV_VERSION \
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
331 || !(((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
332 || defined __sun)
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
333 for (;;)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
334 {
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
335 /* Here outptr + outbytes_remaining = result + result_size - 1. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
336 size_t res = iconv (cd, NULL, NULL, &outptr, &outbytes_remaining);
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
337
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
338 if (res == (size_t)(-1))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
339 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
340 if (errno == E2BIG)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
341 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
342 size_t used = outptr - result;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
343 size_t newsize = result_size * 2;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
344 char *newresult;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
345
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
346 if (!(newsize > result_size))
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
347 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
348 errno = ENOMEM;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
349 goto failed;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
350 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
351 newresult = (char *) realloc (result, newsize);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
352 if (newresult == NULL)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
353 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
354 errno = ENOMEM;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
355 goto failed;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
356 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
357 result = newresult;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
358 result_size = newsize;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
359 outptr = result + used;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
360 outbytes_remaining = result_size - 1 - used;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
361 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
362 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
363 goto failed;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
364 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
365 else
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
366 break;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
367 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
368 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
369
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
370 /* Add the terminating NUL byte. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
371 *outptr++ = '\0';
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
372
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
373 length = outptr - result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
374 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
375
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
376 /* Give away unused memory. */
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
377 if (length < result_size)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
378 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
379 char *smaller_result = (char *) realloc (result, length);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
380
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
381 if (smaller_result != NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
382 result = smaller_result;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
383 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
384
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
385 return result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
386
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
387 failed:
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
388 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
389 int saved_errno = errno;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
390 free (result);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
391 errno = saved_errno;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
392 return NULL;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
393 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
394
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
395 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
396 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
397
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
398 #endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
399
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
400 char *
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
401 str_iconv (const char *src, const char *from_codeset, const char *to_codeset)
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
402 {
7919
b7b7885895a6 New module 'striconveha'.
Bruno Haible <bruno@clisp.org>
parents: 7917
diff changeset
403 if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0)
7917
0b6b5a675452 Ensure errno when strdup fails.
Bruno Haible <bruno@clisp.org>
parents: 7912
diff changeset
404 {
0b6b5a675452 Ensure errno when strdup fails.
Bruno Haible <bruno@clisp.org>
parents: 7912
diff changeset
405 char *result = strdup (src);
0b6b5a675452 Ensure errno when strdup fails.
Bruno Haible <bruno@clisp.org>
parents: 7912
diff changeset
406
0b6b5a675452 Ensure errno when strdup fails.
Bruno Haible <bruno@clisp.org>
parents: 7912
diff changeset
407 if (result == NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
408 errno = ENOMEM;
7917
0b6b5a675452 Ensure errno when strdup fails.
Bruno Haible <bruno@clisp.org>
parents: 7912
diff changeset
409 return result;
0b6b5a675452 Ensure errno when strdup fails.
Bruno Haible <bruno@clisp.org>
parents: 7912
diff changeset
410 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
411 else
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
412 {
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
413 #if HAVE_ICONV
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
414 iconv_t cd;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
415 char *result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
416
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
417 /* Avoid glibc-2.1 bug with EUC-KR. */
13885
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
418 # if ((__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1) && !defined __UCLIBC__) \
87a95303747f Port to uClibc.
Bruno Haible <bruno@clisp.org>
parents: 12737
diff changeset
419 && !defined _LIBICONV_VERSION
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
420 if (c_strcasecmp (from_codeset, "EUC-KR") == 0
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
421 || c_strcasecmp (to_codeset, "EUC-KR") == 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
422 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
423 errno = EINVAL;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
424 return NULL;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
425 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
426 # endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
427 cd = iconv_open (to_codeset, from_codeset);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
428 if (cd == (iconv_t) -1)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
429 return NULL;
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
430
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
431 result = str_cd_iconv (src, cd);
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
432
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
433 if (result == NULL)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
434 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
435 /* Close cd, but preserve the errno from str_cd_iconv. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
436 int saved_errno = errno;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
437 iconv_close (cd);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
438 errno = saved_errno;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
439 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
440 else
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
441 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
442 if (iconv_close (cd) < 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
443 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
444 /* Return NULL, but free the allocated memory, and while doing
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
445 that, preserve the errno from iconv_close. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
446 int saved_errno = errno;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
447 free (result);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
448 errno = saved_errno;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
449 return NULL;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
450 }
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
451 }
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
452 return result;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
453 #else
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
454 /* This is a different error code than if iconv_open existed but didn't
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
455 support from_codeset and to_codeset, so that the caller can emit
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
456 an error message such as
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
457 "iconv() is not supported. Installing GNU libiconv and
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 7944
diff changeset
458 then reinstalling this package would fix this." */
7261
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
459 errno = ENOSYS;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
460 return NULL;
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
461 #endif
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
462 }
f75588924b8c New module 'striconv'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
463 }