1 /* xmbsrtowcs.c -- replacement function for mbsrtowcs */
3 /* Copyright (C) 2002-2013 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 /* Ask for GNU extensions to get extern declaration for mbsnrtowcs if
22 available via glibc. */
24 # define _GNU_SOURCE 1
31 /* <wchar.h>, <wctype.h> and <stdlib.h> are included in "shmbutil.h".
32 If <wchar.h>, <wctype.h>, mbsrtowcs(), exist, HANDLE_MULTIBYTE
41 # define FREE(x) do { if (x) free (x); } while (0)
45 extern char *strchrnul __P((const char *, int));
48 /* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>.
49 So, this function is made for converting 0x5c to U<0x5c>. */
51 static mbstate_t local_state;
52 static int local_state_use = 0;
55 xmbsrtowcs (dest, src, len, pstate)
62 size_t mblength, wclength, n;
69 memset (&local_state, '\0', sizeof(mbstate_t));
83 /* It doesn't matter if malloc fails here, since mbsrtowcs should do
84 the right thing with a NULL first argument. */
85 wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
89 wclength = mbsrtowcs (wsbuf, &mbs, n, &psbuf);
96 for (wclength = 0; wclength < len; wclength++, dest++)
106 else if (**src == '\\')
112 mblength = mbrtowc(dest, *src, n, ps);
115 mblength = mbrtowc(dest, *src, n, ps);
117 /* Cannot convert multibyte character to wide character. */
118 if (mblength == (size_t)-1 || mblength == (size_t)-2)
124 /* The multibyte string has been completely converted,
125 including the terminating '\0'. */
137 /* Convert a multibyte string to a wide character string. Memory for the
138 new wide character string is obtained with malloc.
140 Fast multiple-character version of xdupmbstowcs used when the indices are
141 not required and mbsnrtowcs is available. */
144 xdupmbstowcs2 (destp, src)
145 wchar_t **destp; /* Store the pointer to the wide character string */
146 const char *src; /* Multibyte character string */
148 const char *p; /* Conversion start position of src */
149 wchar_t *wsbuf; /* Buffer for wide characters. */
150 size_t wsbuf_size; /* Size of WSBUF */
151 size_t wcnum; /* Number of wide characters in WSBUF */
152 mbstate_t state; /* Conversion State */
153 size_t n, wcslength; /* Number of wide characters produced by the conversion. */
154 const char *end_or_backslash;
155 size_t nms; /* Number of multibyte characters to convert at one time. */
159 memset (&state, '\0', sizeof(mbstate_t));
168 end_or_backslash = strchrnul(p, '\\');
169 nms = end_or_backslash - p;
170 if (*end_or_backslash == '\0')
173 /* Compute the number of produced wide-characters. */
177 if (nms == 0 && *p == '\\') /* special initial case */
180 wcslength = mbsnrtowcs (NULL, &tmp_p, nms, 0, &tmp_state);
184 tmp_p = p; /* will need below */
186 wcslength = 1; /* take a single byte */
189 /* Conversion failed. */
190 if (wcslength == (size_t)-1)
197 /* Resize the buffer if it is not large enough. */
198 if (wsbuf_size < wcnum+wcslength+1) /* 1 for the L'\0' or the potential L'\\' */
202 while (wsbuf_size < wcnum+wcslength+1) /* 1 for the L'\0' or the potential L'\\' */
203 wsbuf_size += WSBUF_INC;
205 wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
215 /* Perform the conversion. This is assumed to return 'wcslength'.
216 It may set 'p' to NULL. */
217 n = mbsnrtowcs(wsbuf+wcnum, &p, nms, wsbuf_size-wcnum, &state);
219 if (n == 0 && p == 0)
221 wsbuf[wcnum] = L'\0';
225 /* Compensate for taking single byte on wcs conversion failure above. */
226 if (wcslength == 1 && (n == 0 || n == (size_t)-1))
241 if (mbsinit (&state) && (p != NULL) && (*p == '\\'))
243 wsbuf[wcnum++] = L'\\';
251 /* Return the length of the wide character string, not including `\0'. */
254 #endif /* HAVE_MBSNRTOWCS */
256 /* Convert a multibyte string to a wide character string. Memory for the
257 new wide character string is obtained with malloc.
259 The return value is the length of the wide character string. Returns a
260 pointer to the wide character string in DESTP. If INDICESP is not NULL,
261 INDICESP stores the pointer to the pointer array. Each pointer is to
262 the first byte of each multibyte character. Memory for the pointer array
263 is obtained with malloc, too.
264 If conversion is failed, the return value is (size_t)-1 and the values
265 of DESTP and INDICESP are NULL. */
268 xdupmbstowcs (destp, indicesp, src)
269 wchar_t **destp; /* Store the pointer to the wide character string */
270 char ***indicesp; /* Store the pointer to the pointer array. */
271 const char *src; /* Multibyte character string */
273 const char *p; /* Conversion start position of src */
274 wchar_t wc; /* Created wide character by conversion */
275 wchar_t *wsbuf; /* Buffer for wide characters. */
276 char **indices; /* Buffer for indices. */
277 size_t wsbuf_size; /* Size of WSBUF */
278 size_t wcnum; /* Number of wide characters in WSBUF */
279 mbstate_t state; /* Conversion State */
281 /* In case SRC or DESP is NULL, conversion doesn't take place. */
282 if (src == NULL || destp == NULL)
292 if (indicesp == NULL)
293 return (xdupmbstowcs2 (destp, src));
296 memset (&state, '\0', sizeof(mbstate_t));
297 wsbuf_size = WSBUF_INC;
299 wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t));
311 indices = (char **) malloc (wsbuf_size * sizeof(char *));
325 size_t mblength; /* Byte length of one multibyte character. */
327 if (mbsinit (&state))
340 mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
343 mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
345 /* Conversion failed. */
346 if (MB_INVALIDCH (mblength))
358 /* Resize buffers when they are not large enough. */
359 if (wsbuf_size < wcnum)
364 wsbuf_size += WSBUF_INC;
366 wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
380 idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char *));
394 wsbuf[wcnum - 1] = wc;
396 indices[wcnum - 1] = (char *)p;
399 while (MB_NULLWCH (wc) == 0);
401 /* Return the length of the wide character string, not including `\0'. */
403 if (indicesp != NULL)
409 #endif /* HANDLE_MULTIBYTE */