1 /* xmbsrtowcs.c -- replacement function for mbsrtowcs */
3 /* Copyright (C) 2002-2010 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
39 # define FREE(x) do { if (x) free (x); } while (0)
43 extern char *strchrnul __P((const char *, int));
46 /* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>.
47 So, this function is made for converting 0x5c to U<0x5c>. */
49 static mbstate_t local_state;
50 static int local_state_use = 0;
53 xmbsrtowcs (dest, src, len, pstate)
60 size_t mblength, wclength, n;
67 memset (&local_state, '\0', sizeof(mbstate_t));
81 /* It doesn't matter if malloc fails here, since mbsrtowcs should do
82 the right thing with a NULL first argument. */
83 wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
87 wclength = mbsrtowcs (wsbuf, &mbs, n, &psbuf);
94 for (wclength = 0; wclength < len; wclength++, dest++)
104 else if (**src == '\\')
110 mblength = mbrtowc(dest, *src, n, ps);
113 mblength = mbrtowc(dest, *src, n, ps);
115 /* Cannot convert multibyte character to wide character. */
116 if (mblength == (size_t)-1 || mblength == (size_t)-2)
122 /* The multibyte string has been completely converted,
123 including the terminating '\0'. */
135 /* Convert a multibyte string to a wide character string. Memory for the
136 new wide character string is obtained with malloc.
138 Fast multiple-character version of xdupmbstowcs used when the indices are
139 not required and mbsnrtowcs is available. */
142 xdupmbstowcs2 (destp, src)
143 wchar_t **destp; /* Store the pointer to the wide character string */
144 const char *src; /* Multibyte character string */
146 const char *p; /* Conversion start position of src */
147 wchar_t *wsbuf; /* Buffer for wide characters. */
148 size_t wsbuf_size; /* Size of WSBUF */
149 size_t wcnum; /* Number of wide characters in WSBUF */
150 mbstate_t state; /* Conversion State */
151 size_t wcslength; /* Number of wide characters produced by the conversion. */
152 const char *end_or_backslash;
153 size_t nms; /* Number of multibyte characters to convert at one time. */
157 memset (&state, '\0', sizeof(mbstate_t));
166 end_or_backslash = strchrnul(p, '\\');
167 nms = (end_or_backslash - p);
168 if (*end_or_backslash == '\0')
171 /* Compute the number of produced wide-characters. */
174 wcslength = mbsnrtowcs(NULL, &tmp_p, nms, 0, &tmp_state);
176 /* Conversion failed. */
177 if (wcslength == (size_t)-1)
184 /* Resize the buffer if it is not large enough. */
185 if (wsbuf_size < wcnum+wcslength+1) /* 1 for the L'\0' or the potential L'\\' */
189 wsbuf_size = wcnum+wcslength+1; /* 1 for the L'\0' or the potential L'\\' */
191 wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
201 /* Perform the conversion. This is assumed to return 'wcslength'.
202 * It may set 'p' to NULL. */
203 mbsnrtowcs(wsbuf+wcnum, &p, nms, wsbuf_size-wcnum, &state);
207 if (mbsinit (&state) && (p != NULL) && (*p == '\\'))
209 wsbuf[wcnum++] = L'\\';
217 /* Return the length of the wide character string, not including `\0'. */
220 #endif /* HAVE_MBSNRTOWCS */
222 /* Convert a multibyte string to a wide character string. Memory for the
223 new wide character string is obtained with malloc.
225 The return value is the length of the wide character string. Returns a
226 pointer to the wide character string in DESTP. If INDICESP is not NULL,
227 INDICESP stores the pointer to the pointer array. Each pointer is to
228 the first byte of each multibyte character. Memory for the pointer array
229 is obtained with malloc, too.
230 If conversion is failed, the return value is (size_t)-1 and the values
231 of DESTP and INDICESP are NULL. */
236 xdupmbstowcs (destp, indicesp, src)
237 wchar_t **destp; /* Store the pointer to the wide character string */
238 char ***indicesp; /* Store the pointer to the pointer array. */
239 const char *src; /* Multibyte character string */
241 const char *p; /* Conversion start position of src */
242 wchar_t wc; /* Created wide character by conversion */
243 wchar_t *wsbuf; /* Buffer for wide characters. */
244 char **indices; /* Buffer for indices. */
245 size_t wsbuf_size; /* Size of WSBUF */
246 size_t wcnum; /* Number of wide characters in WSBUF */
247 mbstate_t state; /* Conversion State */
249 /* In case SRC or DESP is NULL, conversion doesn't take place. */
250 if (src == NULL || destp == NULL)
258 if (indicesp == NULL)
259 return (xdupmbstowcs2 (destp, src));
262 memset (&state, '\0', sizeof(mbstate_t));
263 wsbuf_size = WSBUF_INC;
265 wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t));
275 indices = (char **) malloc (wsbuf_size * sizeof(char *));
288 size_t mblength; /* Byte length of one multibyte character. */
290 if (mbsinit (&state))
303 mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
306 mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
308 /* Conversion failed. */
309 if (MB_INVALIDCH (mblength))
319 /* Resize buffers when they are not large enough. */
320 if (wsbuf_size < wcnum)
325 wsbuf_size += WSBUF_INC;
327 wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
339 idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **));
351 wsbuf[wcnum - 1] = wc;
353 indices[wcnum - 1] = (char *)p;
356 while (MB_NULLWCH (wc) == 0);
358 /* Return the length of the wide character string, not including `\0'. */
360 if (indicesp != NULL)
366 #endif /* HANDLE_MULTIBYTE */