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