f1703bccf99b7f8b3594b57697b07b2c507c0761
[platform/upstream/bash.git] / lib / glob / xmbsrtowcs.c
1 /* xmbsrtowcs.c -- replacement function for mbsrtowcs */
2
3 /* Copyright (C) 2002 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software; you can redistribute it and/or modify it under
8    the terms of the GNU General Public License as published by the Free
9    Software Foundation; either version 2, or (at your option) any later
10    version.
11
12    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13    WARRANTY; without even the implied warranty of MERCHANTABILITY or
14    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15    for more details.
16
17    You should have received a copy of the GNU General Public License along
18    with Bash; see the file COPYING.  If not, write to the Free Software
19    Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20 #include <config.h>
21
22 #include <bashansi.h>
23
24 /* <wchar.h>, <wctype.h> and <stdlib.h> are included in "shmbutil.h".
25    If <wchar.h>, <wctype.h>, mbsrtowcs(), exist, HANDLE_MULTIBYTE
26    is defined as 1. */
27 #include <shmbutil.h>
28
29 #if HANDLE_MULTIBYTE
30 /* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>.
31    So, this function is made for converting 0x5c to U<0x5c>. */
32
33 static mbstate_t local_state;
34 static int local_state_use = 0;
35
36 size_t
37 xmbsrtowcs (dest, src, len, pstate)
38     wchar_t *dest;
39     const char **src;
40     size_t len;
41     mbstate_t *pstate;
42 {
43   mbstate_t *ps;
44   size_t mblength, wclength, n;
45
46   ps = pstate;
47   if (pstate == NULL)
48     {
49       if (!local_state_use)
50         {
51           memset (&local_state, '\0', sizeof(mbstate_t));
52           local_state_use = 1;
53         }
54       ps = &local_state;
55     }
56
57   n = strlen(*src);
58
59   if (dest == NULL)
60     {
61       wchar_t *wsbuf;
62       const char *mbs;
63       mbstate_t psbuf;
64
65       wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
66       mbs = *src;
67       psbuf = *ps;
68
69       wclength = mbsrtowcs (wsbuf, &mbs, n, &psbuf);
70
71       free (wsbuf);
72       return wclength;
73     }
74       
75   for (wclength = 0; wclength < len; wclength++, dest++)
76     {
77       if(mbsinit(ps))
78         {
79           if (**src == '\0')
80             {
81               *dest = L'\0';
82               *src = NULL;
83               return (wclength);
84             }
85           else if (**src == '\\')
86             {
87               *dest = L'\\';
88               mblength = 1;
89             }
90           else
91             mblength = mbrtowc(dest, *src, n, ps);
92         }
93       else
94         mblength = mbrtowc(dest, *src, n, ps);
95
96       /* Cannot convert multibyte character to wide character. */
97       if (mblength == (size_t)-1 || mblength == (size_t)-2)
98         return (size_t)-1;
99
100       *src += mblength;
101       n -= mblength;
102
103       /* The multibyte string  has  been  completely  converted,
104          including  the terminating '\0'. */
105       if (*dest == L'\0')
106         {
107           *src = NULL;
108           break;
109         }
110     }
111
112     return (wclength);
113 }
114
115 /* Convert a multibyte string to a wide character string. Memory for the
116    new wide character string is obtained with malloc.
117
118    The return value is the length of the wide character string. Returns a
119    pointer to the wide character string in DESTP. If INDICESP is not NULL,
120    INDICESP stores the pointer to the pointer array. Each pointer is to
121    the first byte of each multibyte character. Memory for the pointer array
122    is obtained with malloc, too.
123    If conversion is failed, the return value is (size_t)-1 and the values
124    of DESTP and INDICESP are NULL. */
125
126 #define WSBUF_INC 32
127
128 size_t
129 xdupmbstowcs (destp, indicesp, src)
130     wchar_t **destp;    /* Store the pointer to the wide character string */
131     char ***indicesp;   /* Store the pointer to the pointer array. */
132     const char *src;    /* Multibyte character string */
133 {
134   const char *p;        /* Conversion start position of src */
135   wchar_t wc;           /* Created wide character by conversion */
136   wchar_t *wsbuf;       /* Buffer for wide characters. */
137   char **indices;       /* Buffer for indices. */
138   size_t wsbuf_size;    /* Size of WSBUF */
139   size_t wcnum;         /* Number of wide characters in WSBUF */
140   mbstate_t state;      /* Conversion State */
141
142   /* In case SRC or DESP is NULL, conversion doesn't take place. */
143   if (src == NULL || destp == NULL)
144     {
145       *destp = NULL;
146       return (size_t)-1;
147     }
148
149   memset (&state, '\0', sizeof(mbstate_t));
150   wsbuf_size = WSBUF_INC;
151
152   wsbuf = (wchar_t *) malloc (wsbuf_size * sizeof(wchar_t));
153   if (wsbuf == NULL)
154     {
155       *destp = NULL;
156       return (size_t)-1;
157     }
158
159   indices = (char **) malloc (wsbuf_size * sizeof(char *));
160   if (indices == NULL)
161     {
162       free (wsbuf);
163       *destp = NULL;
164       return (size_t)-1;
165     }
166
167   p = src;
168   wcnum = 0;
169   do {
170       size_t mblength;  /* Byte length of one multibyte character. */
171
172       if(mbsinit (&state))
173         {
174           if (*p == '\0')
175             {
176               wc = L'\0';
177               mblength = 1;
178             }
179           else if (*p == '\\')
180             {
181               wc = L'\\';
182               mblength = 1;
183             }
184           else
185             mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
186         }
187       else
188         mblength = mbrtowc(&wc, p, MB_LEN_MAX, &state);
189
190       /* Conversion failed. */
191       if (MB_INVALIDCH (mblength))
192         {
193           free (wsbuf);
194           free (indices);
195           *destp = NULL;
196           return (size_t)-1;
197         }
198
199       ++wcnum;
200
201       /* Resize buffers when they are not large enough. */
202       if (wsbuf_size < wcnum)
203         {
204           wchar_t *wstmp;
205           char **idxtmp;
206
207           wsbuf_size += WSBUF_INC;
208
209           wstmp = (wchar_t *) realloc (wsbuf, wsbuf_size * sizeof (wchar_t));
210           if (wstmp == NULL)
211             {
212               free (wsbuf);
213               free (indices);
214               *destp = NULL;
215               return (size_t)-1;
216             }
217           wsbuf = wstmp;
218
219           idxtmp = (char **) realloc (indices, wsbuf_size * sizeof (char **));
220           if (idxtmp == NULL)
221             {
222               free (wsbuf);
223               free (indices);
224               *destp = NULL;
225               return (size_t)-1;
226             }
227           indices = idxtmp;
228         }
229
230       wsbuf[wcnum - 1] = wc;
231       indices[wcnum - 1] = (char *)p;
232       p += mblength;
233   } while (MB_NULLWCH (wc) == 0);
234
235   /* Return the length of the wide character string, not including `\0'. */
236   *destp = wsbuf;
237   if (indicesp != NULL)
238     *indicesp = indices;
239   else
240     free (indices);
241
242   return (wcnum - 1);
243 }
244
245 #endif /* HANDLE_MULTIBYTE */