]> git.ipfire.org Git - thirdparty/glibc.git/blame - iconv/gconv_open.c
support: Fix typo in xgetsockname error message
[thirdparty/glibc.git] / iconv / gconv_open.c
CommitLineData
6973fc01 1/* Find matching transformation algorithms and initialize steps.
dff8da6b 2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
6973fc01 3 This file is part of the GNU C Library.
6973fc01
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
6973fc01
UD
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
6973fc01 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
6973fc01
UD
18
19#include <errno.h>
5db91571 20#include <locale.h>
e0e86ccb 21#include "../locale/localeinfo.h"
6973fc01 22#include <stdlib.h>
fd19ed3d 23#include <string.h>
6973fc01 24
e62c19f1
UD
25#include <gconv_int.h>
26
6973fc01 27
335a3b0a
AS
28/* How many character should be converted in one call? */
29#define GCONV_NCHAR_GOAL 8160
30
31
6973fc01 32int
91927b7c 33__gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle,
c90a2db6 34 int flags)
6973fc01 35{
d64b6ad0 36 struct __gconv_step *steps;
6973fc01 37 size_t nsteps;
d64b6ad0 38 __gconv_t result = NULL;
6973fc01
UD
39 size_t cnt = 0;
40 int res;
306eeae5 41 int conv_flags = 0;
ba7b4d29 42 bool translit = false;
91927b7c 43 char *tocode, *fromcode;
85830c4c 44
55985355 45 /* Find out whether any error handling method is specified. */
91927b7c 46 translit = conv_spec->translit;
85830c4c 47
91927b7c
AS
48 if (conv_spec->ignore)
49 conv_flags |= __GCONV_IGNORE_ERRORS;
55985355 50
91927b7c
AS
51 tocode = conv_spec->tocode;
52 fromcode = conv_spec->fromcode;
323fb88d 53
e0e86ccb
UD
54 /* If the string is empty define this to mean the charset of the
55 currently selected locale. */
91927b7c 56 if (strcmp (tocode, "//") == 0)
e0e86ccb
UD
57 {
58 const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
59 size_t len = strlen (codeset);
60 char *dest;
91927b7c 61 tocode = dest = (char *) alloca (len + 3);
e0e86ccb
UD
62 memcpy (__mempcpy (dest, codeset, len), "//", 3);
63 }
91927b7c 64 if (strcmp (fromcode, "//") == 0)
e0e86ccb
UD
65 {
66 const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
67 size_t len = strlen (codeset);
68 char *dest;
91927b7c 69 fromcode = dest = (char *) alloca (len + 3);
e0e86ccb
UD
70 memcpy (__mempcpy (dest, codeset, len), "//", 3);
71 }
72
91927b7c 73 res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags);
d64b6ad0 74 if (res == __GCONV_OK)
6973fc01
UD
75 {
76 /* Allocate room for handle. */
d64b6ad0
UD
77 result = (__gconv_t) malloc (sizeof (struct __gconv_info)
78 + (nsteps
79 * sizeof (struct __gconv_step_data)));
6973fc01 80 if (result == NULL)
d64b6ad0 81 res = __GCONV_NOMEM;
6973fc01
UD
82 else
83 {
84 /* Remember the list of steps. */
d64b6ad0
UD
85 result->__steps = steps;
86 result->__nsteps = nsteps;
6973fc01 87
390500b1 88 /* Clear the array for the step data. */
d64b6ad0
UD
89 memset (result->__data, '\0',
90 nsteps * sizeof (struct __gconv_step_data));
6973fc01 91
390500b1 92 /* Call all initialization functions for the transformation
49c091e5 93 step implementations. */
405b8c60 94 for (cnt = 0; cnt < nsteps; ++cnt)
6973fc01 95 {
0aece08d
UD
96 size_t size;
97
8b682b99
UD
98 /* Would have to be done if we would not clear the whole
99 array above. */
85830c4c 100#if 0
390500b1 101 /* Reset the counter. */
d64b6ad0 102 result->__data[cnt].__invocation_counter = 0;
6973fc01 103
390500b1 104 /* It's a regular use. */
d64b6ad0 105 result->__data[cnt].__internal_use = 0;
85830c4c 106#endif
e3e0a182 107
390500b1 108 /* We use the `mbstate_t' member in DATA. */
d64b6ad0 109 result->__data[cnt].__statep = &result->__data[cnt].__state;
e3e0a182 110
ba7b4d29
FW
111 /* The builtin transliteration handling only
112 supports the internal encoding. */
113 if (translit
114 && __strcasecmp_l (steps[cnt].__from_name,
115 "INTERNAL", _nl_C_locobj_ptr) == 0)
116 conv_flags |= __GCONV_TRANSLIT;
0aece08d 117
405b8c60
UD
118 /* If this is the last step we must not allocate an
119 output buffer. */
120 if (cnt < nsteps - 1)
d6204268 121 {
306eeae5 122 result->__data[cnt].__flags = conv_flags;
d6204268 123
405b8c60
UD
124 /* Allocate the buffer. */
125 size = (GCONV_NCHAR_GOAL * steps[cnt].__max_needed_to);
d6204268 126
9cfe5381 127 result->__data[cnt].__outbuf = malloc (size);
405b8c60 128 if (result->__data[cnt].__outbuf == NULL)
67aacae6
UD
129 {
130 res = __GCONV_NOMEM;
131 goto bail;
132 }
d6204268 133
405b8c60
UD
134 result->__data[cnt].__outbufend =
135 result->__data[cnt].__outbuf + size;
136 }
137 else
138 {
139 /* Handle the last entry. */
306eeae5 140 result->__data[cnt].__flags = conv_flags | __GCONV_IS_LAST;
7039a4c9 141
d6204268
UD
142 break;
143 }
405b8c60 144 }
6973fc01 145 }
6973fc01 146
45eca4d1 147 if (res != __GCONV_OK)
6973fc01 148 {
45eca4d1 149 /* Something went wrong. Free all the resources. */
d6204268
UD
150 int serrno;
151 bail:
152 serrno = errno;
6973fc01 153
45eca4d1
UD
154 if (result != NULL)
155 {
156 while (cnt-- > 0)
ba7b4d29 157 free (result->__data[cnt].__outbuf);
45eca4d1
UD
158
159 free (result);
160 result = NULL;
161 }
6973fc01 162
45eca4d1 163 __gconv_close_transform (steps, nsteps);
6973fc01 164
45eca4d1
UD
165 __set_errno (serrno);
166 }
6973fc01
UD
167 }
168
169 *handle = result;
170 return res;
171}
91927b7c 172libc_hidden_def (__gconv_open)