Merge CRT changes from cmake branch (mainly MSVC compilation fixes)
[reactos.git] / reactos / lib / sdk / crt / string / wcs.c
1 /*
2 * PROJECT: ReactOS CRT library
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: lib/sdk/crt/string/wcs.c
5 * PURPOSE: wcs* CRT functions
6 * PROGRAMMERS: Wine team
7 * Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /*
11 * msvcrt.dll wide-char functions
12 *
13 * Copyright 1999 Alexandre Julliard
14 * Copyright 2000 Jon Griffiths
15 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 */
30 #include <precomp.h>
31 #include <assert.h>
32
33 #ifndef _LIBCNT_
34 #include <internal/wine/msvcrt.h>
35 #endif
36
37 #include "wine/unicode.h"
38 //#include "wine/debug.h"
39
40
41 //WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
42
43 #undef sprintf
44 #undef wsprintf
45 #undef snprintf
46 #undef vsnprintf
47 #undef vprintf
48 #undef vwprintf
49
50 #ifdef _MSC_VER
51 #pragma function(_wcsset)
52 #endif
53
54 #ifndef _LIBCNT_
55 /*********************************************************************
56 * _wcsdup (MSVCRT.@)
57 */
58 wchar_t* CDECL _wcsdup( const wchar_t* str )
59 {
60 wchar_t* ret = NULL;
61 if (str)
62 {
63 int size = (strlenW(str) + 1) * sizeof(wchar_t);
64 ret = malloc( size );
65 if (ret) memcpy( ret, str, size );
66 }
67 return ret;
68 }
69 /*********************************************************************
70 * _wcsicoll (MSVCRT.@)
71 */
72 INT CDECL _wcsicoll( const wchar_t* str1, const wchar_t* str2 )
73 {
74 /* FIXME: handle collates */
75 return strcmpiW( str1, str2 );
76 }
77 #endif
78
79 /*********************************************************************
80 * _wcsnset (MSVCRT.@)
81 */
82 wchar_t* CDECL _wcsnset( wchar_t* str, wchar_t c, size_t n )
83 {
84 wchar_t* ret = str;
85 while ((n-- > 0) && *str) *str++ = c;
86 return ret;
87 }
88
89 /*********************************************************************
90 * _wcsrev (MSVCRT.@)
91 */
92 wchar_t* CDECL _wcsrev( wchar_t* str )
93 {
94 wchar_t* ret = str;
95 wchar_t* end = str + strlenW(str) - 1;
96 while (end > str)
97 {
98 wchar_t t = *end;
99 *end-- = *str;
100 *str++ = t;
101 }
102 return ret;
103 }
104
105 #ifndef _LIBCNT_
106 /*********************************************************************
107 * _wcsset (MSVCRT.@)
108 */
109 wchar_t* CDECL _wcsset( wchar_t* str, wchar_t c )
110 {
111 wchar_t* ret = str;
112 while (*str) *str++ = c;
113 return ret;
114 }
115
116 /******************************************************************
117 * _wcsupr_s (MSVCRT.@)
118 *
119 */
120 INT CDECL _wcsupr_s( wchar_t* str, size_t n )
121 {
122 wchar_t* ptr = str;
123
124 if (!str || !n)
125 {
126 if (str) *str = '\0';
127 __set_errno(EINVAL);
128 return EINVAL;
129 }
130
131 while (n--)
132 {
133 if (!*ptr) return 0;
134 *ptr = toupperW(*ptr);
135 ptr++;
136 }
137
138 /* MSDN claims that the function should return and set errno to
139 * ERANGE, which doesn't seem to be true based on the tests. */
140 *str = '\0';
141 __set_errno(EINVAL);
142 return EINVAL;
143 }
144
145 /*********************************************************************
146 * wcstod (MSVCRT.@)
147 */
148 double CDECL wcstod(const wchar_t* lpszStr, wchar_t** end)
149 {
150 const wchar_t* str = lpszStr;
151 int negative = 0;
152 double ret = 0, divisor = 10.0;
153
154 TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end);
155
156 /* FIXME:
157 * - Should set errno on failure
158 * - Should fail on overflow
159 * - Need to check which input formats are allowed
160 */
161 while (isspaceW(*str))
162 str++;
163
164 if (*str == '-')
165 {
166 negative = 1;
167 str++;
168 }
169
170 while (isdigitW(*str))
171 {
172 ret = ret * 10.0 + (*str - '0');
173 str++;
174 }
175 if (*str == '.')
176 str++;
177 while (isdigitW(*str))
178 {
179 ret = ret + (*str - '0') / divisor;
180 divisor *= 10;
181 str++;
182 }
183
184 if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd')
185 {
186 int negativeExponent = 0;
187 int exponent = 0;
188 if (*(++str) == '-')
189 {
190 negativeExponent = 1;
191 str++;
192 }
193 while (isdigitW(*str))
194 {
195 exponent = exponent * 10 + (*str - '0');
196 str++;
197 }
198 if (exponent != 0)
199 {
200 if (negativeExponent)
201 ret = ret / pow(10.0, exponent);
202 else
203 ret = ret * pow(10.0, exponent);
204 }
205 }
206
207 if (negative)
208 ret = -ret;
209
210 if (end)
211 *end = (wchar_t*)str;
212
213 TRACE("returning %g\n", ret);
214 return ret;
215 }
216 #endif
217
218 /*********************************************************************
219 * wcscoll (MSVCRT.@)
220 */
221 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 )
222 {
223 /* FIXME: handle collates */
224 return strcmpW( str1, str2 );
225 }
226
227 /*********************************************************************
228 * wcspbrk (MSVCRT.@)
229 */
230 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
231 {
232 const wchar_t* p;
233 while (*str)
234 {
235 for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str;
236 str++;
237 }
238 return NULL;
239 }
240
241 #ifndef _LIBCNT_
242 /*********************************************************************
243 * wcstok (MSVCRT.@)
244 */
245 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim )
246 {
247 MSVCRT_thread_data *data = msvcrt_get_thread_data();
248 wchar_t *ret;
249
250 if (!str)
251 if (!(str = data->wcstok_next)) return NULL;
252
253 while (*str && strchrW( delim, *str )) str++;
254 if (!*str) return NULL;
255 ret = str++;
256 while (*str && !strchrW( delim, *str )) str++;
257 if (*str) *str++ = 0;
258 data->wcstok_next = str;
259 return ret;
260 }
261
262 /*********************************************************************
263 * wctomb (MSVCRT.@)
264 */
265 INT CDECL wctomb(char *mbchar, wchar_t wchar)
266 {
267 BOOL bUsedDefaultChar;
268 char chMultiByte[MB_LEN_MAX];
269 int nBytes;
270
271 /* At least one parameter needs to be given, the length of a null character cannot be queried (verified by tests under WinXP SP2) */
272 if(!mbchar && !wchar)
273 return 0;
274
275 /* Use WideCharToMultiByte for doing the conversion using the codepage currently set with setlocale() */
276 nBytes = WideCharToMultiByte(MSVCRT___lc_codepage, 0, &wchar, 1, chMultiByte, MB_LEN_MAX, NULL, &bUsedDefaultChar);
277
278 /* Only copy the character if an 'mbchar' pointer was given.
279
280 The "C" locale is emulated with codepage 1252 here. This codepage has a default character "?", but the "C" locale doesn't have one.
281 Therefore don't copy the character in this case. */
282 if(mbchar && !(MSVCRT_current_lc_all[0] == 'C' && !MSVCRT_current_lc_all[1] && bUsedDefaultChar))
283 memcpy(mbchar, chMultiByte, nBytes);
284
285 /* If the default character was used, set errno to EILSEQ and return -1. */
286 if(bUsedDefaultChar)
287 {
288 __set_errno(EILSEQ);
289 return -1;
290 }
291
292 /* Otherwise return the number of bytes this character occupies. */
293 return nBytes;
294 }
295
296 size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)
297 {
298 BOOL bUsedDefaultChar;
299 char* p = mbstr;
300 int nResult;
301
302 /* Does the caller query for output buffer size? */
303 if(!mbstr)
304 {
305 int nLength;
306
307 /* If we currently use the "C" locale, the length of the input string is returned (verified by tests under WinXP SP2) */
308 if(MSVCRT_current_lc_all[0] == 'C' && !MSVCRT_current_lc_all[1])
309 return wcslen(wcstr);
310
311 /* Otherwise check the length each character needs and build a final return value out of this */
312 count = wcslen(wcstr);
313 nLength = 0;
314
315 while((int)(--count) >= 0 && *wcstr)
316 {
317 /* Get the length of this character */
318 nResult = wctomb(NULL, *wcstr++);
319
320 /* If this character is not convertible in the current locale, the end result will be -1 */
321 if(nResult == -1)
322 return -1;
323
324 nLength += nResult;
325 }
326
327 /* Return the final length */
328 return nLength;
329 }
330
331 /* Convert the string then */
332 bUsedDefaultChar = FALSE;
333
334 for(;;)
335 {
336 char chMultiByte[MB_LEN_MAX];
337 UINT uLength;
338
339 /* Are we at the terminating null character? */
340 if(!*wcstr)
341 {
342 /* Set the null character, but don't increment the pointer as the returned length never includes the terminating null character */
343 *p = 0;
344 break;
345 }
346
347 /* Convert this character into the temporary chMultiByte variable */
348 ZeroMemory(chMultiByte, MB_LEN_MAX);
349 nResult = wctomb(chMultiByte, *wcstr++);
350
351 /* Check if this was an invalid character */
352 if(nResult == -1)
353 bUsedDefaultChar = TRUE;
354
355 /* If we got no character, stop the conversion process here */
356 if(!chMultiByte[0])
357 break;
358
359 /* Determine whether this is a double-byte or a single-byte character */
360 if(chMultiByte[1])
361 uLength = 2;
362 else
363 uLength = 1;
364
365 /* Decrease 'count' by the character length and check if the buffer can still hold the full character */
366 count -= uLength;
367
368 if((int)count < 0)
369 break;
370
371 /* It can, so copy it and move the pointer forward */
372 memcpy(p, chMultiByte, uLength);
373 p += uLength;
374 }
375
376 if(bUsedDefaultChar)
377 return -1;
378
379 /* Return the length in bytes of the copied characters (without the terminating null character) */
380 return p - mbstr;
381 }
382 #endif
383
384 /*********************************************************************
385 * wcscpy_s (MSVCRT.@)
386 */
387 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc)
388 {
389 INT size = 0;
390
391 if(!wcDest || !numElement)
392 return EINVAL;
393
394 wcDest[0] = 0;
395
396 if(!wcSrc)
397 {
398 return EINVAL;
399 }
400
401 size = strlenW(wcSrc) + 1;
402
403 if(size > numElement)
404 {
405 return ERANGE;
406 }
407
408 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
409
410 return 0;
411 }
412
413 /******************************************************************
414 * wcsncpy_s (MSVCRT.@)
415 */
416 INT CDECL wcsncpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc,
417 size_t count )
418 {
419 size_t size = 0;
420
421 if (!wcDest || !numElement)
422 return EINVAL;
423
424 wcDest[0] = 0;
425
426 if (!wcSrc)
427 {
428 return EINVAL;
429 }
430
431 size = min(strlenW(wcSrc), count);
432
433 if (size >= numElement)
434 {
435 return ERANGE;
436 }
437
438 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
439 wcDest[size] = '\0';
440
441 return 0;
442 }
443
444