Patch-ID: bash40-030
[bash.git] / lib / glob / xmbsrtowcs.c
blob23fcd8e7123adaf84a9701d186ae4ed06a525557
1 /* xmbsrtowcs.c -- replacement function for mbsrtowcs */
3 /* Copyright (C) 2002-2004 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 #include <bashansi.h>
25 /* <wchar.h>, <wctype.h> and <stdlib.h> are included in "shmbutil.h".
26 If <wchar.h>, <wctype.h>, mbsrtowcs(), exist, HANDLE_MULTIBYTE
27 is defined as 1. */
28 #include <shmbutil.h>
30 #if HANDLE_MULTIBYTE
32 #ifndef FREE
33 # define FREE(x) do { if (x) free (x); } while (0)
34 #endif
35 /* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>.
36 So, this function is made for converting 0x5c to U<0x5c>. */
38 static mbstate_t local_state;
39 static int local_state_use = 0;
41 size_t
42 xmbsrtowcs (dest, src, len, pstate)
43 wchar_t *dest;
44 const char **src;
45 size_t len;
46 mbstate_t *pstate;
48 mbstate_t *ps;
49 size_t mblength, wclength, n;
51 ps = pstate;
52 if (pstate == NULL)
54 if (!local_state_use)
56 memset (&local_state, '\0', sizeof(mbstate_t));
57 local_state_use = 1;
59 ps = &local_state;
62 n = strlen (*src);
64 if (dest == NULL)
66 wchar_t *wsbuf;
67 const char *mbs;
68 mbstate_t psbuf;
70 /* It doesn't matter if malloc fails here, since mbsrtowcs should do
71 the right thing with a NULL first argument. */
72 wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
73 mbs = *src;
74 psbuf = *ps;
76 wclength = mbsrtowcs (wsbuf, &mbs, n, &psbuf);
78 if (wsbuf)
79 free (wsbuf);
80 return wclength;
83 for (wclength = 0; wclength < len; wclength++, dest++)
85 if (mbsinit(ps))
87 if (**src == '\0')
89 *dest = L'\0';
90 *src = NULL;
91 return (wclength);
93 else if (**src == '\\')
95 *dest = L'\\';
96 mblength = 1;
98 else
99 mblength = mbrtowc(dest, *src, n, ps);
101 else
102 mblength = mbrtowc(dest, *src, n, ps);
104 /* Cannot convert multibyte character to wide character. */
105 if (mblength == (size_t)-1 || mblength == (size_t)-2)
106 return (size_t)-1;
108 *src += mblength;
109 n -= mblength;
111 /* The multibyte string has been completely converted,
112 including the terminating '\0'. */
113 if (*dest == L'\0')
115 *src = NULL;
116 break;
120 return (wclength);
123 /* Convert a multibyte string to a wide character string. Memory for the
124 new wide character string is obtained with malloc.
126 The return value is the length of the wide character string. Returns a
127 pointer to the wide character string in DESTP. If INDICESP is not NULL,
128 INDICESP stores the pointer to the pointer array. Each pointer is to
129 the first byte of each multibyte character. Memory for the pointer array
130 is obtained with malloc, too.
131 If conversion is failed, the return value is (size_t)-1 and the values
132 of DESTP and INDICESP are NULL. */
134 #define WSBUF_INC 32
136 size_t
137 xdupmbstowcs (destp, indicesp, src)
138 wchar_t **destp; /* Store the pointer to the wide character string */
139 char ***indicesp; /* Store the pointer to the pointer array. */
140 const char *src; /* Multibyte character string */
142 const char *p; /* Conversion start position of src */
143 wchar_t wc; /* Created wide character by conversion */
144 wchar_t *wsbuf; /* Buffer for wide characters. */
145 char **indices; /* Buffer for indices. */
146 size_t wsbuf_size; /* Size of WSBUF */
147 size_t wcnum; /* Number of wide characters in WSBUF */
148 mbstate_t state; /* Conversion State */
150 /* In case SRC or DESP is NULL, conversion doesn't take place. */
151 if (src == NULL || destp == NULL)
153 if (destp)
154 *destp = NULL;
155 return (size_t)-1;
158 memset (&state, '\0', sizeof(mbstate_t));
159 wsbuf_size = WSBUF_INC;
161 wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t));
162 if (wsbuf == NULL)
164 *destp = NULL;
165 return (size_t)-1;
168 indices = NULL;
169 if (indicesp)
171 indices = (char **) malloc (wsbuf_size * sizeof(char *));
172 if (indices == NULL)
174 free (wsbuf);
175 *destp = NULL;
176 return (size_t)-1;
180 p = src;
181 wcnum = 0;
184 size_t mblength; /* Byte length of one multibyte character. */
186 if (mbsinit (&state))
188 if (*p == '\0')
190 wc = L'\0';
191 mblength = 1;
193 else if (*p == '\\')
195 wc = L'\\';
196 mblength = 1;
198 else
199 mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
201 else
202 mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
204 /* Conversion failed. */
205 if (MB_INVALIDCH (mblength))
207 free (wsbuf);
208 FREE (indices);
209 *destp = NULL;
210 return (size_t)-1;
213 ++wcnum;
215 /* Resize buffers when they are not large enough. */
216 if (wsbuf_size < wcnum)
218 wchar_t *wstmp;
219 char **idxtmp;
221 wsbuf_size += WSBUF_INC;
223 wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
224 if (wstmp == NULL)
226 free (wsbuf);
227 FREE (indices);
228 *destp = NULL;
229 return (size_t)-1;
231 wsbuf = wstmp;
233 if (indicesp)
235 idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **));
236 if (idxtmp == NULL)
238 free (wsbuf);
239 free (indices);
240 *destp = NULL;
241 return (size_t)-1;
243 indices = idxtmp;
247 wsbuf[wcnum - 1] = wc;
248 if (indices)
249 indices[wcnum - 1] = (char *)p;
250 p += mblength;
252 while (MB_NULLWCH (wc) == 0);
254 /* Return the length of the wide character string, not including `\0'. */
255 *destp = wsbuf;
256 if (indicesp != NULL)
257 *indicesp = indices;
259 return (wcnum - 1);
262 #endif /* HANDLE_MULTIBYTE */