Fix warnings generated with -Wsign-compare.
[wine] / dlls / msvcrt / wcs.c
1 /*
2  * msvcrt.dll wide-char functions
3  *
4  * Copyright 1999 Alexandre Julliard
5  * Copyright 2000 Jon Griffiths
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include <limits.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include "msvcrt.h"
25 #include "winnls.h"
26 #include "wine/unicode.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
30
31
32 /* INTERNAL: MSVCRT_malloc() based wstrndup */
33 MSVCRT_wchar_t* msvcrt_wstrndup(const MSVCRT_wchar_t *buf, unsigned int size)
34 {
35   MSVCRT_wchar_t* ret;
36   unsigned int len = strlenW(buf), max_len;
37
38   max_len = size <= len? size : len + 1;
39
40   ret = MSVCRT_malloc(max_len * sizeof (MSVCRT_wchar_t));
41   if (ret)
42   {
43     memcpy(ret,buf,max_len * sizeof (MSVCRT_wchar_t));
44     ret[max_len] = 0;
45   }
46   return ret;
47 }
48
49 /*********************************************************************
50  *              _wcsdup (MSVCRT.@)
51  */
52 MSVCRT_wchar_t* _wcsdup( const MSVCRT_wchar_t* str )
53 {
54   MSVCRT_wchar_t* ret = NULL;
55   if (str)
56   {
57     int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
58     ret = MSVCRT_malloc( size );
59     if (ret) memcpy( ret, str, size );
60   }
61   return ret;
62 }
63
64 /*********************************************************************
65  *              _wcsicoll (MSVCRT.@)
66  */
67 INT _wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
68 {
69   /* FIXME: handle collates */
70   return strcmpiW( str1, str2 );
71 }
72
73 /*********************************************************************
74  *              _wcsnset (MSVCRT.@)
75  */
76 MSVCRT_wchar_t* _wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
77 {
78   MSVCRT_wchar_t* ret = str;
79   while ((n-- > 0) && *str) *str++ = c;
80   return ret;
81 }
82
83 /*********************************************************************
84  *              _wcsrev (MSVCRT.@)
85  */
86 MSVCRT_wchar_t* _wcsrev( MSVCRT_wchar_t* str )
87 {
88   MSVCRT_wchar_t* ret = str;
89   MSVCRT_wchar_t* end = str + strlenW(str) - 1;
90   while (end > str)
91   {
92     MSVCRT_wchar_t t = *end;
93     *end--  = *str;
94     *str++  = t;
95   }
96   return ret;
97 }
98
99 /*********************************************************************
100  *              _wcsset (MSVCRT.@)
101  */
102 MSVCRT_wchar_t* _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
103 {
104   MSVCRT_wchar_t* ret = str;
105   while (*str) *str++ = c;
106   return ret;
107 }
108
109 /*********************************************************************
110  *              wcstod (MSVCRT.@)
111  */
112 double MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
113 {
114   const MSVCRT_wchar_t* str = lpszStr;
115   int negative = 0;
116   double ret = 0, divisor = 10.0;
117
118   TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end);
119
120   /* FIXME:
121    * - Should set errno on failure
122    * - Should fail on overflow
123    * - Need to check which input formats are allowed
124    */
125   while (isspaceW(*str))
126     str++;
127
128   if (*str == '-')
129   {
130     negative = 1;
131     str++;
132   }
133
134   while (isdigitW(*str))
135   {
136     ret = ret * 10.0 + (*str - '0');
137     str++;
138   }
139   if (*str == '.')
140     str++;
141   while (isdigitW(*str))
142   {
143     ret = ret + (*str - '0') / divisor;
144     divisor *= 10;
145     str++;
146   }
147
148   if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd')
149   {
150     int negativeExponent = 0;
151     int exponent = 0;
152     if (*(++str) == '-')
153     {
154       negativeExponent = 1;
155       str++;
156     }
157     while (isdigitW(*str))
158     {
159       exponent = exponent * 10 + (*str - '0');
160       str++;
161     }
162     if (exponent != 0)
163     {
164       if (negativeExponent)
165         ret = ret / pow(10.0, exponent);
166       else
167         ret = ret * pow(10.0, exponent);
168     }
169   }
170
171   if (negative)
172     ret = -ret;
173
174   if (end)
175     *end = (MSVCRT_wchar_t*)str;
176
177   TRACE("returning %g\n", ret);
178   return ret;
179 }
180
181 static int MSVCRT_vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist)
182 {
183     unsigned int written = 0;
184     const WCHAR *iter = format;
185     char bufa[256], fmtbufa[64], *fmta;
186
187     while (*iter)
188     {
189         while (*iter && *iter != '%')
190         {
191             if (written++ >= len)
192                 return -1;
193             *str++ = *iter++;
194         }
195         if (*iter == '%')
196         {
197             if (iter[1] == '%')
198             {
199                 if (written++ >= len)
200                     return -1;
201                 *str++ = '%'; /* "%%"->'%' */
202                 iter += 2;
203                 continue;
204             }
205
206             fmta = fmtbufa;
207             *fmta++ = *iter++;
208             while (*iter == '0' ||
209                    *iter == '+' ||
210                    *iter == '-' ||
211                    *iter == ' ' ||
212                    *iter == '*' ||
213                    *iter == '#')
214             {
215                 if (*iter == '*')
216                 {
217                     char *buffiter = bufa;
218                     int fieldlen = va_arg(valist, int);
219                     sprintf(buffiter, "%d", fieldlen);
220                     while (*buffiter)
221                         *fmta++ = *buffiter++;
222                 }
223                 else
224                     *fmta++ = *iter;
225                 iter++;
226             }
227
228             while (isdigit(*iter))
229                 *fmta++ = *iter++;
230
231             if (*iter == '.')
232             {
233                 *fmta++ = *iter++;
234                 if (*iter == '*')
235                 {
236                     char *buffiter = bufa;
237                     int fieldlen = va_arg(valist, int);
238                     sprintf(buffiter, "%d", fieldlen);
239                     while (*buffiter)
240                         *fmta++ = *buffiter++;
241                 }
242                 else
243                     while (isdigit(*iter))
244                         *fmta++ = *iter++;
245             }
246             if (*iter == 'h' || *iter == 'l')
247                 *fmta++ = *iter++;
248
249             switch (*iter)
250             {
251             case 'S':
252             {
253                 static const char *none = "(null)";
254                 const char *astr = va_arg(valist, const char *);
255                 const char *striter = astr ? astr : none;
256                 int r, n;
257                 while (*striter)
258                 {
259                     if (written >= len)
260                         return -1;
261                     n = 1;
262                     if( IsDBCSLeadByte( *striter ) )
263                         n++;
264                     r = MultiByteToWideChar( CP_ACP, 0,
265                                striter, n, str, len - written );
266                     striter += n;
267                     str += r;
268                     written += r;
269                 }
270                 iter++;
271                 break;
272             }
273
274             case 's':
275             {
276                 static const WCHAR none[] = { '(','n','u','l','l',')',0 };
277                 const WCHAR *wstr = va_arg(valist, const WCHAR *);
278                 const WCHAR *striter = wstr ? wstr : none;
279                 while (*striter)
280                 {
281                     if (written++ >= len)
282                         return -1;
283                     *str++ = *striter++;
284                 }
285                 iter++;
286                 break;
287             }
288
289             case 'c':
290                 if (written++ >= len)
291                     return -1;
292                 *str++ = (WCHAR)va_arg(valist, int);
293                 iter++;
294                 break;
295
296             default:
297             {
298                 /* For non wc types, use system sprintf and append to wide char output */
299                 /* FIXME: for unrecognised types, should ignore % when printing */
300                 char *bufaiter = bufa;
301                 if (*iter == 'p')
302                     sprintf(bufaiter, "%08lX", va_arg(valist, long));
303                 else
304                 {
305                     *fmta++ = *iter;
306                     *fmta = '\0';
307                     if (*iter == 'a' || *iter == 'A' ||
308                         *iter == 'e' || *iter == 'E' ||
309                         *iter == 'f' || *iter == 'F' || 
310                         *iter == 'g' || *iter == 'G')
311                         sprintf(bufaiter, fmtbufa, va_arg(valist, double));
312                     else
313                     {
314                         /* FIXME: On 32 bit systems this doesn't handle int 64's.
315                          *        on 64 bit systems this doesn't work for 32 bit types
316                          */
317                         sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
318                     }
319                 }
320                 while (*bufaiter)
321                 {
322                     if (written++ >= len)
323                         return -1;
324                     *str++ = *bufaiter++;
325                 }
326                 iter++;
327                 break;
328             }
329             }
330         }
331     }
332     if (written >= len)
333         return -1;
334     *str++ = 0;
335     return (int)written;
336 }
337
338 /*********************************************************************
339  *              swprintf (MSVCRT.@)
340  */
341 int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
342 {
343     va_list ap;
344     int r;
345
346     va_start( ap, format );
347     r = MSVCRT_vsnprintfW( str, INT_MAX, format, ap );
348     va_end( ap );
349     return r;
350 }
351
352 /*********************************************************************
353  *              _vsnwprintf (MSVCRT.@)
354  */
355 int _vsnwprintf(MSVCRT_wchar_t *str, unsigned int len,
356                 const MSVCRT_wchar_t *format, va_list valist)
357 {
358     return MSVCRT_vsnprintfW(str, len, format, valist);
359 }
360
361 /*********************************************************************
362  *              vswprintf (MSVCRT.@)
363  */
364 int MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
365 {
366     return MSVCRT_vsnprintfW( str, INT_MAX, format, args );
367 }
368
369 /*********************************************************************
370  *              wcscoll (MSVCRT.@)
371  */
372 int MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
373 {
374   /* FIXME: handle collates */
375   return strcmpW( str1, str2 );
376 }
377
378 /*********************************************************************
379  *              wcspbrk (MSVCRT.@)
380  */
381 MSVCRT_wchar_t* MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
382 {
383   const MSVCRT_wchar_t* p;
384   while (*str)
385   {
386     for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
387       str++;
388   }
389   return NULL;
390 }
391
392 /*********************************************************************
393  *              wctomb (MSVCRT.@)
394  */
395 INT MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
396 {
397   return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
398 }
399
400 /*********************************************************************
401  *              iswalnum (MSVCRT.@)
402  */
403 INT MSVCRT_iswalnum( MSVCRT_wchar_t wc )
404 {
405     return isalnumW( wc );
406 }
407
408 /*********************************************************************
409  *              iswalpha (MSVCRT.@)
410  */
411 INT MSVCRT_iswalpha( MSVCRT_wchar_t wc )
412 {
413     return isalphaW( wc );
414 }
415
416 /*********************************************************************
417  *              iswcntrl (MSVCRT.@)
418  */
419 INT MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
420 {
421     return iscntrlW( wc );
422 }
423
424 /*********************************************************************
425  *              iswdigit (MSVCRT.@)
426  */
427 INT MSVCRT_iswdigit( MSVCRT_wchar_t wc )
428 {
429     return isdigitW( wc );
430 }
431
432 /*********************************************************************
433  *              iswgraph (MSVCRT.@)
434  */
435 INT MSVCRT_iswgraph( MSVCRT_wchar_t wc )
436 {
437     return isgraphW( wc );
438 }
439
440 /*********************************************************************
441  *              iswlower (MSVCRT.@)
442  */
443 INT MSVCRT_iswlower( MSVCRT_wchar_t wc )
444 {
445     return islowerW( wc );
446 }
447
448 /*********************************************************************
449  *              iswprint (MSVCRT.@)
450  */
451 INT MSVCRT_iswprint( MSVCRT_wchar_t wc )
452 {
453     return isprintW( wc );
454 }
455
456 /*********************************************************************
457  *              iswpunct (MSVCRT.@)
458  */
459 INT MSVCRT_iswpunct( MSVCRT_wchar_t wc )
460 {
461     return ispunctW( wc );
462 }
463
464 /*********************************************************************
465  *              iswspace (MSVCRT.@)
466  */
467 INT MSVCRT_iswspace( MSVCRT_wchar_t wc )
468 {
469     return isspaceW( wc );
470 }
471
472 /*********************************************************************
473  *              iswupper (MSVCRT.@)
474  */
475 INT MSVCRT_iswupper( MSVCRT_wchar_t wc )
476 {
477     return isupperW( wc );
478 }
479
480 /*********************************************************************
481  *              iswxdigit (MSVCRT.@)
482  */
483 INT MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
484 {
485     return isxdigitW( wc );
486 }