]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/iconv/bsd_iconv.c
unbound: Import upstream 0ee44ef3 when ENOBUFS is returned
[FreeBSD/FreeBSD.git] / lib / libc / iconv / bsd_iconv.c
1 /* $NetBSD: iconv.c,v 1.11 2009/03/03 16:22:33 explorer Exp $ */
2
3 /*-
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2003 Citrus Project,
7  * Copyright (c) 2009, 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 #include <sys/queue.h>
34 #include <sys/types.h>
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <iconv.h>
39 #include <limits.h>
40 #include <paths.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include "citrus_types.h"
46 #include "citrus_module.h"
47 #include "citrus_esdb.h"
48 #include "citrus_hash.h"
49 #include "citrus_iconv.h"
50
51 #include "iconv-internal.h"
52
53 #define ISBADF(_h_)     (!(_h_) || (_h_) == (iconv_t)-1)
54
55 static iconv_t
56 __bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle)
57 {
58         int ret;
59
60         /*
61          * Remove anything following a //, as these are options (like
62          * //ignore, //translate, etc) and we just don't handle them.
63          * This is for compatibility with software that uses these
64          * blindly.
65          */
66         ret = _citrus_iconv_open(&handle, in, out);
67         if (ret) {
68                 errno = ret == ENOENT ? EINVAL : ret;
69                 return ((iconv_t)-1);
70         }
71
72         handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE");
73
74         return ((iconv_t)(void *)handle);
75 }
76
77 iconv_t
78 __bsd_iconv_open(const char *out, const char *in)
79 {
80
81         return (__bsd___iconv_open(out, in, NULL));
82 }
83
84 int
85 __bsd_iconv_open_into(const char *out, const char *in, iconv_allocation_t *ptr)
86 {
87         struct _citrus_iconv *handle;
88
89         handle = (struct _citrus_iconv *)ptr;
90         return ((__bsd___iconv_open(out, in, handle) == (iconv_t)-1) ? -1 : 0);
91 }
92
93 int
94 __bsd_iconv_close(iconv_t handle)
95 {
96
97         if (ISBADF(handle)) {
98                 errno = EBADF;
99                 return (-1);
100         }
101
102         _citrus_iconv_close((struct _citrus_iconv *)(void *)handle);
103
104         return (0);
105 }
106
107 size_t
108 __bsd_iconv(iconv_t handle, char **in, size_t *szin, char **out, size_t *szout)
109 {
110         size_t ret;
111         int err;
112
113         if (ISBADF(handle)) {
114                 errno = EBADF;
115                 return ((size_t)-1);
116         }
117
118         err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
119             in, szin, out, szout, 0, &ret);
120         if (err) {
121                 errno = err;
122                 ret = (size_t)-1;
123         }
124
125         return (ret);
126 }
127
128 size_t
129 __bsd___iconv(iconv_t handle, char **in, size_t *szin, char **out,
130     size_t *szout, uint32_t flags, size_t *invalids)
131 {
132         size_t ret;
133         int err;
134
135         if (ISBADF(handle)) {
136                 errno = EBADF;
137                 return ((size_t)-1);
138         }
139
140         err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
141             in, szin, out, szout, flags, &ret);
142         if (invalids)
143                 *invalids = ret;
144         if (err) {
145                 errno = err;
146                 ret = (size_t)-1;
147         }
148
149         return (ret);
150 }
151
152 int
153 __bsd___iconv_get_list(char ***rlist, size_t *rsz, bool sorted)
154 {
155         int ret;
156
157         ret = _citrus_esdb_get_list(rlist, rsz, sorted);
158         if (ret) {
159                 errno = ret;
160                 return (-1);
161         }
162
163         return (0);
164 }
165
166 void
167 __bsd___iconv_free_list(char **list, size_t sz)
168 {
169
170         _citrus_esdb_free_list(list, sz);
171 }
172
173 /*
174  * GNU-compatibile non-standard interfaces.
175  */
176 static int
177 qsort_helper(const void *first, const void *second)
178 {
179         const char * const *s1;
180         const char * const *s2;
181
182         s1 = first;
183         s2 = second;
184         return (strcmp(*s1, *s2));
185 }
186
187 void
188 __bsd_iconvlist(int (*do_one) (unsigned int, const char * const *,
189     void *), void *data)
190 {
191         char **list, **names;
192         const char * const *np;
193         char *curitem, *curkey, *slashpos;
194         size_t sz;
195         unsigned int i, j, n;
196
197         i = 0;
198         names = NULL;
199
200         if (__bsd___iconv_get_list(&list, &sz, true)) {
201                 list = NULL;
202                 goto out;
203         }
204         qsort((void *)list, sz, sizeof(char *), qsort_helper);
205         while (i < sz) {
206                 j = 0;
207                 slashpos = strchr(list[i], '/');
208                 names = malloc(sz * sizeof(char *));
209                 if (names == NULL)
210                         goto out;
211                 curkey = strndup(list[i], slashpos - list[i]);
212                 if (curkey == NULL)
213                         goto out;
214                 names[j++] = curkey;
215                 for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) {
216                         slashpos = strchr(list[i], '/');
217                         if (strcmp(curkey, &slashpos[1]) == 0)
218                                 continue;
219                         curitem = strdup(&slashpos[1]);
220                         if (curitem == NULL)
221                                 goto out;
222                         names[j++] = curitem;
223                 }
224                 np = (const char * const *)names;
225                 do_one(j, np, data);
226                 for (n = 0; n < j; n++)
227                         free(names[n]);
228                 free(names);
229                 names = NULL;
230         }
231
232 out:
233         if (names != NULL) {
234                 for (n = 0; n < j; n++)
235                         free(names[n]);
236                 free(names);
237         }
238         if (list != NULL)
239                 __bsd___iconv_free_list(list, sz);
240 }
241
242 __inline const char *
243 __bsd_iconv_canonicalize(const char *name)
244 {
245
246         return (_citrus_iconv_canonicalize(name));
247 }
248
249 int
250 __bsd_iconvctl(iconv_t cd, int request, void *argument)
251 {
252         struct _citrus_iconv *cv;
253         struct iconv_hooks *hooks;
254         const char *convname;
255         char *dst;
256         int *i;
257         size_t srclen;
258
259         cv = (struct _citrus_iconv *)(void *)cd;
260         hooks = (struct iconv_hooks *)argument;
261         i = (int *)argument;
262
263         if (ISBADF(cd)) {
264                 errno = EBADF;
265                 return (-1);
266         }
267
268         switch (request) {
269         case ICONV_TRIVIALP:
270                 convname = cv->cv_shared->ci_convname;
271                 dst = strchr(convname, '/');
272                 srclen = dst - convname;
273                 dst++;
274                 *i = (srclen == strlen(dst)) && !memcmp(convname, dst, srclen);
275                 return (0);
276         case ICONV_GET_TRANSLITERATE:
277                 *i = 1;
278                 return (0);
279         case ICONV_SET_TRANSLITERATE:
280                 return  ((*i == 1) ? 0 : -1);
281         case ICONV_GET_DISCARD_ILSEQ:
282                 *i = cv->cv_shared->ci_discard_ilseq ? 1 : 0;
283                 return (0);
284         case ICONV_SET_DISCARD_ILSEQ:
285                 cv->cv_shared->ci_discard_ilseq = *i;
286                 return (0);
287         case ICONV_SET_HOOKS:
288                 cv->cv_shared->ci_hooks = hooks;
289                 return (0);
290         case ICONV_SET_FALLBACKS:
291                 errno = EOPNOTSUPP;
292                 return (-1);
293         case ICONV_GET_ILSEQ_INVALID:
294                 *i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0;
295                 return (0);
296         case ICONV_SET_ILSEQ_INVALID:
297                 cv->cv_shared->ci_ilseq_invalid = *i;
298                 return (0);
299         default:
300                 errno = EINVAL;
301                 return (-1);
302         }
303 }
304
305 void
306 __bsd_iconv_set_relocation_prefix(const char *orig_prefix __unused,
307     const char *curr_prefix __unused)
308 {
309
310 }