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 #undef sprintf
39 #undef wsprintf
40 #undef snprintf
41 #undef vsnprintf
42 #undef vprintf
43 #undef vwprintf
44
45 #ifdef _MSC_VER
46 #pragma function(_wcsset)
47 #endif
48
49 #ifndef _LIBCNT_
50 /*********************************************************************
51 * _wcsdup (MSVCRT.@)
52 */
_wcsdup(const wchar_t * str)53 wchar_t* CDECL _wcsdup( const wchar_t* str )
54 {
55 wchar_t* ret = NULL;
56 if (str)
57 {
58 size_t size = (strlenW(str) + 1) * sizeof(wchar_t);
59 ret = malloc( size );
60 if (ret) memcpy( ret, str, size );
61 }
62 return ret;
63 }
64 /*********************************************************************
65 * _wcsicoll (MSVCRT.@)
66 */
_wcsicoll(const wchar_t * str1,const wchar_t * str2)67 INT CDECL _wcsicoll( const wchar_t* str1, const wchar_t* str2 )
68 {
69 /* FIXME: handle collates */
70 return strcmpiW( str1, str2 );
71 }
72 #endif
73
74 /*********************************************************************
75 * _wcsnset (MSVCRT.@)
76 */
_wcsnset(wchar_t * str,wchar_t c,size_t n)77 wchar_t* CDECL _wcsnset( wchar_t* str, wchar_t c, size_t n )
78 {
79 wchar_t* ret = str;
80 while ((n-- > 0) && *str) *str++ = c;
81 return ret;
82 }
83
84 /*********************************************************************
85 * _wcsrev (MSVCRT.@)
86 */
_wcsrev(wchar_t * str)87 wchar_t* CDECL _wcsrev( wchar_t* str )
88 {
89 wchar_t* ret = str;
90 wchar_t* end = str + strlenW(str) - 1;
91 while (end > str)
92 {
93 wchar_t t = *end;
94 *end-- = *str;
95 *str++ = t;
96 }
97 return ret;
98 }
99
100 #ifndef _LIBCNT_
101 /*********************************************************************
102 * _wcsset (MSVCRT.@)
103 */
_wcsset(wchar_t * str,wchar_t c)104 wchar_t* CDECL _wcsset( wchar_t* str, wchar_t c )
105 {
106 wchar_t* ret = str;
107 while (*str) *str++ = c;
108 return ret;
109 }
110
111 /******************************************************************
112 * _wcsupr_s (MSVCRT.@)
113 *
114 */
_wcsupr_s(wchar_t * str,size_t n)115 INT CDECL _wcsupr_s( wchar_t* str, size_t n )
116 {
117 wchar_t* ptr = str;
118
119 if (!str || !n)
120 {
121 if (str) *str = '\0';
122 _set_errno(EINVAL);
123 return EINVAL;
124 }
125
126 while (n--)
127 {
128 if (!*ptr) return 0;
129 *ptr = toupperW(*ptr);
130 ptr++;
131 }
132
133 /* MSDN claims that the function should return and set errno to
134 * ERANGE, which doesn't seem to be true based on the tests. */
135 *str = '\0';
136 _set_errno(EINVAL);
137 return EINVAL;
138 }
139
140 /*********************************************************************
141 * wcstod (MSVCRT.@)
142 */
wcstod(const wchar_t * lpszStr,wchar_t ** end)143 double CDECL wcstod(const wchar_t* lpszStr, wchar_t** end)
144 {
145 const wchar_t* str = lpszStr;
146 int negative = 0;
147 double ret = 0, divisor = 10.0;
148
149 TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end);
150
151 /* FIXME:
152 * - Should set errno on failure
153 * - Should fail on overflow
154 * - Need to check which input formats are allowed
155 */
156 while (isspaceW(*str))
157 str++;
158
159 if (*str == '-')
160 {
161 negative = 1;
162 str++;
163 }
164
165 while (isdigitW(*str))
166 {
167 ret = ret * 10.0 + (*str - '0');
168 str++;
169 }
170 if (*str == '.')
171 str++;
172 while (isdigitW(*str))
173 {
174 ret = ret + (*str - '0') / divisor;
175 divisor *= 10;
176 str++;
177 }
178
179 if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd')
180 {
181 int negativeExponent = 0;
182 int exponent = 0;
183 if (*(++str) == '-')
184 {
185 negativeExponent = 1;
186 str++;
187 }
188 while (isdigitW(*str))
189 {
190 exponent = exponent * 10 + (*str - '0');
191 str++;
192 }
193 if (exponent != 0)
194 {
195 if (negativeExponent)
196 ret = ret / pow(10.0, exponent);
197 else
198 ret = ret * pow(10.0, exponent);
199 }
200 }
201
202 if (negative)
203 ret = -ret;
204
205 if (end)
206 *end = (wchar_t*)str;
207
208 TRACE("returning %g\n", ret);
209 return ret;
210 }
211 #endif
212
213 /*********************************************************************
214 * wcscoll (MSVCRT.@)
215 */
wcscoll(const wchar_t * str1,const wchar_t * str2)216 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 )
217 {
218 /* FIXME: handle collates */
219 return strcmpW( str1, str2 );
220 }
221
222 /*********************************************************************
223 * wcspbrk (MSVCRT.@)
224 */
wcspbrk(const wchar_t * str,const wchar_t * accept)225 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
226 {
227 const wchar_t* p;
228 while (*str)
229 {
230 for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str;
231 str++;
232 }
233 return NULL;
234 }
235
236 #ifndef _LIBCNT_
237
238 /*********************************************************************
239 * wctomb (MSVCRT.@)
240 */
241 /*********************************************************************
242 * wctomb (MSVCRT.@)
243 */
wctomb(char * dst,wchar_t ch)244 INT CDECL wctomb( char *dst, wchar_t ch )
245 {
246 BOOL error;
247 INT size;
248
249 size = WideCharToMultiByte(get_locinfo()->lc_codepage, 0, &ch, 1, dst, dst ? 6 : 0, NULL, &error);
250 if(!size || error) {
251 *_errno() = EINVAL;
252 return EOF;
253 }
254 return size;
255 }
256
257 /*********************************************************************
258 * wcsrtombs_l (INTERNAL)
259 */
wcsrtombs_l(char * mbstr,const wchar_t ** wcstr,size_t count,_locale_t locale)260 static size_t CDECL wcsrtombs_l(char *mbstr, const wchar_t **wcstr,
261 size_t count, _locale_t locale)
262 {
263 MSVCRT_pthreadlocinfo locinfo;
264 size_t tmp = 0;
265 BOOL used_default;
266
267 if(!locale)
268 locinfo = get_locinfo();
269 else
270 locinfo = ((MSVCRT__locale_t)locale)->locinfo;
271
272 if(!locinfo->lc_codepage) {
273 size_t i;
274
275 if(!mbstr)
276 return strlenW(*wcstr);
277
278 for(i=0; i<count; i++) {
279 if((*wcstr)[i] > 255) {
280 _set_errno(EILSEQ);
281 return -1;
282 }
283
284 mbstr[i] = (*wcstr)[i];
285 if(!(*wcstr)[i]) break;
286 }
287 return i;
288 }
289
290 if(!mbstr) {
291 tmp = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
292 *wcstr, -1, NULL, 0, NULL, &used_default);
293 if(!tmp || used_default) {
294 _set_errno(EILSEQ);
295 return -1;
296 }
297 return tmp-1;
298 }
299
300 while(**wcstr) {
301 char buf[3];
302 size_t i, size;
303
304 size = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
305 *wcstr, 1, buf, 3, NULL, &used_default);
306 if(!size || used_default) {
307 _set_errno(EILSEQ);
308 return -1;
309 }
310 if(tmp+size > count)
311 return tmp;
312
313 for(i=0; i<size; i++)
314 mbstr[tmp++] = buf[i];
315 (*wcstr)++;
316 }
317
318 if(tmp < count) {
319 mbstr[tmp] = '\0';
320 *wcstr = NULL;
321 }
322 return tmp;
323 }
324
325 /*********************************************************************
326 * _wcstombs_l (MSVCRT.@)
327 */
_wcstombs_l(char * mbstr,const wchar_t * wcstr,size_t count,_locale_t locale)328 size_t CDECL _wcstombs_l(char *mbstr, const wchar_t *wcstr, size_t count, _locale_t locale)
329 {
330 return wcsrtombs_l(mbstr, &wcstr, count, locale);
331 }
332
333 /*********************************************************************
334 * wcstombs (MSVCRT.@)
335 */
wcstombs(char * mbstr,const wchar_t * wcstr,size_t count)336 size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)
337 {
338 return wcsrtombs_l(mbstr, &wcstr, count, NULL);
339 }
340 #endif
341
342 /*********************************************************************
343 * wcscpy_s (MSVCRT.@)
344 */
wcscpy_s(wchar_t * wcDest,size_t numElement,const wchar_t * wcSrc)345 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc)
346 {
347 size_t size = 0;
348
349 if(!wcDest || !numElement)
350 return EINVAL;
351
352 wcDest[0] = 0;
353
354 if(!wcSrc)
355 {
356 return EINVAL;
357 }
358
359 size = strlenW(wcSrc) + 1;
360
361 if(size > numElement)
362 {
363 return ERANGE;
364 }
365
366 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
367
368 return 0;
369 }
370
371 /******************************************************************
372 * wcsncpy_s (MSVCRT.@)
373 */
wcsncpy_s(wchar_t * wcDest,size_t numElement,const wchar_t * wcSrc,size_t count)374 INT CDECL wcsncpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc,
375 size_t count )
376 {
377 size_t size = 0;
378
379 if (!wcDest || !numElement)
380 return EINVAL;
381
382 wcDest[0] = 0;
383
384 if (!wcSrc)
385 {
386 return EINVAL;
387 }
388
389 size = min(strlenW(wcSrc), count);
390
391 if (size >= numElement)
392 {
393 return ERANGE;
394 }
395
396 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
397 wcDest[size] = '\0';
398
399 return 0;
400 }
401
402 /******************************************************************
403 * wcscat_s (MSVCRT.@)
404 *
405 */
wcscat_s(wchar_t * dst,size_t elem,const wchar_t * src)406 INT CDECL wcscat_s(wchar_t* dst, size_t elem, const wchar_t* src)
407 {
408 wchar_t* ptr = dst;
409
410 if (!dst || elem == 0) return EINVAL;
411 if (!src)
412 {
413 dst[0] = '\0';
414 return EINVAL;
415 }
416
417 /* seek to end of dst string (or elem if no end of string is found */
418 while (ptr < dst + elem && *ptr != '\0') ptr++;
419 while (ptr < dst + elem)
420 {
421 if ((*ptr++ = *src++) == '\0') return 0;
422 }
423 /* not enough space */
424 dst[0] = '\0';
425 return ERANGE;
426 }
427
428 /*********************************************************************
429 * wcsncat_s (MSVCRT.@)
430 *
431 */
wcsncat_s(wchar_t * dst,size_t elem,const wchar_t * src,size_t count)432 INT CDECL wcsncat_s(wchar_t *dst, size_t elem,
433 const wchar_t *src, size_t count)
434 {
435 size_t srclen;
436 wchar_t dststart;
437 INT ret = 0;
438
439 if (!MSVCRT_CHECK_PMT(dst != NULL) || !MSVCRT_CHECK_PMT(elem > 0))
440 {
441 #ifndef _LIBCNT_
442 _set_errno(EINVAL);
443 #endif
444 return EINVAL;
445 }
446 if (!MSVCRT_CHECK_PMT(src != NULL || count == 0))
447 return EINVAL;
448 if (count == 0)
449 return 0;
450
451 for (dststart = 0; dststart < elem; dststart++)
452 {
453 if (dst[dststart] == '\0')
454 break;
455 }
456 if (dststart == elem)
457 {
458 MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL);
459 return EINVAL;
460 }
461
462 if (count == _TRUNCATE)
463 {
464 srclen = strlenW(src);
465 if (srclen >= (elem - dststart))
466 {
467 srclen = elem - dststart - 1;
468 ret = STRUNCATE;
469 }
470 }
471 else
472 srclen = min(strlenW(src), count);
473 if (srclen < (elem - dststart))
474 {
475 memcpy(&dst[dststart], src, srclen*sizeof(wchar_t));
476 dst[dststart+srclen] = '\0';
477 return ret;
478 }
479 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
480 dst[0] = '\0';
481 return ERANGE;
482 }
483
484