xref: /reactos/sdk/lib/crt/string/wcs.c (revision 8a978a17)
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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