blob: 9c35c462d83253c281e482467d4ccd5e052466d1 [file] [log] [blame]
Jon Griffiths1db20bf2001-01-10 23:59:25 +00001/*
2 * msvcrt.dll wide-char functions
3 *
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00006 *
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
Jon Griffiths1db20bf2001-01-10 23:59:25 +000020 */
Jon Griffiths34c786b2001-01-22 02:21:54 +000021#include <limits.h>
22#include <stdio.h>
Dave Belanger9a05e1f2004-04-08 19:48:19 +000023#include <math.h>
Mike McCormack2cc5f1e2005-02-14 20:53:42 +000024#include <assert.h>
Jon Griffiths1db20bf2001-01-10 23:59:25 +000025#include "msvcrt.h"
26#include "winnls.h"
27#include "wine/unicode.h"
Alexandre Julliardbd1689e2002-01-22 00:57:16 +000028#include "wine/debug.h"
29
30WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
Jon Griffiths1db20bf2001-01-10 23:59:25 +000031
Jon Griffiths34c786b2001-01-22 02:21:54 +000032
Jon Griffiths1db20bf2001-01-10 23:59:25 +000033/* INTERNAL: MSVCRT_malloc() based wstrndup */
Alexandre Julliard5f31b322002-12-19 04:21:30 +000034MSVCRT_wchar_t* msvcrt_wstrndup(const MSVCRT_wchar_t *buf, unsigned int size)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000035{
Alexandre Julliard5f31b322002-12-19 04:21:30 +000036 MSVCRT_wchar_t* ret;
Jon Griffiths1db20bf2001-01-10 23:59:25 +000037 unsigned int len = strlenW(buf), max_len;
38
39 max_len = size <= len? size : len + 1;
40
Alexandre Julliard5f31b322002-12-19 04:21:30 +000041 ret = MSVCRT_malloc(max_len * sizeof (MSVCRT_wchar_t));
Jon Griffiths1db20bf2001-01-10 23:59:25 +000042 if (ret)
43 {
Alexandre Julliard5f31b322002-12-19 04:21:30 +000044 memcpy(ret,buf,max_len * sizeof (MSVCRT_wchar_t));
Jon Griffiths1db20bf2001-01-10 23:59:25 +000045 ret[max_len] = 0;
46 }
47 return ret;
48}
49
50/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +000051 * _wcsdup (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000052 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +000053MSVCRT_wchar_t* _wcsdup( const MSVCRT_wchar_t* str )
Jon Griffiths1db20bf2001-01-10 23:59:25 +000054{
Alexandre Julliard5f31b322002-12-19 04:21:30 +000055 MSVCRT_wchar_t* ret = NULL;
Jon Griffiths1db20bf2001-01-10 23:59:25 +000056 if (str)
57 {
Alexandre Julliard5f31b322002-12-19 04:21:30 +000058 int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
Jon Griffiths1db20bf2001-01-10 23:59:25 +000059 ret = MSVCRT_malloc( size );
60 if (ret) memcpy( ret, str, size );
61 }
62 return ret;
63}
64
65/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +000066 * _wcsicoll (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000067 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +000068INT _wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
Jon Griffiths1db20bf2001-01-10 23:59:25 +000069{
70 /* FIXME: handle collates */
71 return strcmpiW( str1, str2 );
72}
73
74/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +000075 * _wcsnset (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000076 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +000077MSVCRT_wchar_t* _wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
Jon Griffiths1db20bf2001-01-10 23:59:25 +000078{
Alexandre Julliard5f31b322002-12-19 04:21:30 +000079 MSVCRT_wchar_t* ret = str;
Jon Griffiths1db20bf2001-01-10 23:59:25 +000080 while ((n-- > 0) && *str) *str++ = c;
81 return ret;
82}
83
84/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +000085 * _wcsrev (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000086 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +000087MSVCRT_wchar_t* _wcsrev( MSVCRT_wchar_t* str )
Jon Griffiths1db20bf2001-01-10 23:59:25 +000088{
Alexandre Julliard5f31b322002-12-19 04:21:30 +000089 MSVCRT_wchar_t* ret = str;
90 MSVCRT_wchar_t* end = str + strlenW(str) - 1;
Jon Griffiths1db20bf2001-01-10 23:59:25 +000091 while (end > str)
92 {
Alexandre Julliard5f31b322002-12-19 04:21:30 +000093 MSVCRT_wchar_t t = *end;
Jon Griffiths1db20bf2001-01-10 23:59:25 +000094 *end-- = *str;
95 *str++ = t;
96 }
97 return ret;
98}
99
100/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000101 * _wcsset (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000102 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000103MSVCRT_wchar_t* _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000104{
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000105 MSVCRT_wchar_t* ret = str;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000106 while (*str) *str++ = c;
107 return ret;
108}
109
110/*********************************************************************
Jon Griffithsd051a952003-09-23 22:50:30 +0000111 * wcstod (MSVCRT.@)
112 */
113double MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
114{
115 const MSVCRT_wchar_t* str = lpszStr;
116 int negative = 0;
117 double ret = 0, divisor = 10.0;
118
119 TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end);
120
121 /* FIXME:
122 * - Should set errno on failure
123 * - Should fail on overflow
124 * - Need to check which input formats are allowed
125 */
126 while (isspaceW(*str))
127 str++;
128
129 if (*str == '-')
130 {
131 negative = 1;
132 str++;
133 }
134
135 while (isdigitW(*str))
136 {
137 ret = ret * 10.0 + (*str - '0');
138 str++;
139 }
140 if (*str == '.')
141 str++;
142 while (isdigitW(*str))
143 {
144 ret = ret + (*str - '0') / divisor;
145 divisor *= 10;
146 str++;
147 }
148
Dave Belanger9a05e1f2004-04-08 19:48:19 +0000149 if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd')
150 {
151 int negativeExponent = 0;
152 int exponent = 0;
153 if (*(++str) == '-')
154 {
155 negativeExponent = 1;
156 str++;
157 }
158 while (isdigitW(*str))
159 {
160 exponent = exponent * 10 + (*str - '0');
161 str++;
162 }
163 if (exponent != 0)
164 {
165 if (negativeExponent)
166 ret = ret / pow(10.0, exponent);
167 else
168 ret = ret * pow(10.0, exponent);
169 }
170 }
171
172 if (negative)
173 ret = -ret;
174
Jon Griffithsd051a952003-09-23 22:50:30 +0000175 if (end)
176 *end = (MSVCRT_wchar_t*)str;
177
178 TRACE("returning %g\n", ret);
179 return ret;
180}
181
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000182
183typedef struct pf_output_t
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000184{
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000185 int used;
186 int len;
187 BOOL unicode;
188 union {
189 LPWSTR W;
190 LPSTR A;
191 } buf;
192} pf_output;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000193
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000194typedef struct pf_flags_t
195{
196 char Sign, LeftAlign, Alternate, PadZero;
Mike McCormack990e5372005-10-27 10:20:08 +0000197 int FieldLength, Precision;
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000198 char IntegerLength, IntegerDouble;
199 char WideString;
200 char Format;
201} pf_flags;
202
203/*
204 * writes a string of characters to the output
205 * returns -1 if the string doesn't fit in the output buffer
206 * return the length of the string if all characters were written
207 */
208static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len )
209{
210 int space = out->len - out->used;
211
212 if( len < 0 )
213 len = strlenW( str );
214 if( out->unicode )
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000215 {
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000216 LPWSTR p = out->buf.W + out->used;
217
218 if( space >= len )
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000219 {
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000220 memcpy( p, str, len*sizeof(WCHAR) );
221 out->used += len;
222 return len;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000223 }
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000224 if( space > 0 )
225 memcpy( p, str, space*sizeof(WCHAR) );
226 out->used += len;
227 }
228 else
229 {
230 int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL );
231 LPSTR p = out->buf.A + out->used;
232
233 if( space >= n )
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000234 {
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000235 WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL );
236 out->used += n;
237 return len;
238 }
239 if( space > 0 )
240 WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL );
241 out->used += n;
242 }
243 return -1;
244}
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000245
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000246static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len )
247{
248 int space = out->len - out->used;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000249
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000250 if( len < 0 )
251 len = strlen( str );
252 if( !out->unicode )
253 {
254 LPSTR p = out->buf.A + out->used;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000255
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000256 if( space >= len )
257 {
258 memcpy( p, str, len );
259 out->used += len;
260 return len;
261 }
262 if( space > 0 )
263 memcpy( p, str, space );
264 out->used += len;
265 }
266 else
267 {
268 int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 );
269 LPWSTR p = out->buf.W + out->used;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000270
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000271 if( space >= n )
272 {
273 MultiByteToWideChar( CP_ACP, 0, str, len, p, n );
274 out->used += n;
275 return len;
276 }
277 if( space > 0 )
278 MultiByteToWideChar( CP_ACP, 0, str, len, p, space );
279 out->used += n;
280 }
281 return -1;
282}
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000283
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000284static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left )
285{
286 int i, r = 0;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000287
Jesse Allen419d4932005-12-26 13:01:38 +0100288 if( flags->Sign && !( flags->Format == 'd' || flags->Format == 'i' ) )
289 flags->Sign = 0;
290
291 if( left && flags->Sign )
292 {
293 flags->FieldLength--;
294 if( flags->PadZero )
295 r = pf_output_stringA( out, &flags->Sign, 1 );
296 }
297
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000298 if( ( !left && flags->LeftAlign ) ||
Jesse Allen39b725b2005-12-20 11:49:05 +0100299 ( left && !flags->LeftAlign ))
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000300 {
301 for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ )
302 {
Jesse Allen39b725b2005-12-20 11:49:05 +0100303 if( left && flags->PadZero )
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000304 r = pf_output_stringA( out, "0", 1 );
305 else
306 r = pf_output_stringA( out, " ", 1 );
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000307 }
308 }
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000309
Jesse Allen419d4932005-12-26 13:01:38 +0100310 if( left && flags->Sign && !flags->PadZero )
311 r = pf_output_stringA( out, &flags->Sign, 1 );
312
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000313 return r;
314}
315
316static inline int pf_output_format_W( pf_output *out, LPCWSTR str,
317 int len, pf_flags *flags )
318{
319 int r = 0;
320
321 if( len < 0 )
322 len = strlenW( str );
323
Mike McCormack990e5372005-10-27 10:20:08 +0000324 if (flags->Precision >= 0 && flags->Precision < len)
325 len = flags->Precision;
Uwe Bonnes0fb9ef62005-02-25 19:16:46 +0000326
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000327 r = pf_fill( out, len, flags, 1 );
328
329 if( r>=0 )
330 r = pf_output_stringW( out, str, len );
331
332 if( r>=0 )
333 r = pf_fill( out, len, flags, 0 );
334
335 return r;
336}
337
338static inline int pf_output_format_A( pf_output *out, LPCSTR str,
339 int len, pf_flags *flags )
340{
341 int r = 0;
342
343 if( len < 0 )
344 len = strlen( str );
345
Mike McCormack990e5372005-10-27 10:20:08 +0000346 if (flags->Precision >= 0 && flags->Precision < len)
347 len = flags->Precision;
Uwe Bonnes0fb9ef62005-02-25 19:16:46 +0000348
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000349 r = pf_fill( out, len, flags, 1 );
350
351 if( r>=0 )
352 r = pf_output_stringA( out, str, len );
353
354 if( r>=0 )
355 r = pf_fill( out, len, flags, 0 );
356
357 return r;
358}
359
Jesse Allen419d4932005-12-26 13:01:38 +0100360static inline BOOL pf_is_integer_format( char fmt )
361{
362 static const char float_fmts[] = "diouxX";
363 if (!fmt)
364 return FALSE;
365 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
366}
367
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000368static inline BOOL pf_is_double_format( char fmt )
369{
Jesse Allen5c631162005-12-19 21:26:46 +0100370 static const char float_fmts[] = "aeEfgG";
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000371 if (!fmt)
372 return FALSE;
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000373 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
374}
375
376static inline BOOL pf_is_valid_format( char fmt )
377{
Jesse Allen5c631162005-12-19 21:26:46 +0100378 static const char float_fmts[] = "acCdeEfgGinouxX";
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000379 if (!fmt)
380 return FALSE;
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000381 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
382}
383
384static void pf_rebuild_format_string( char *p, pf_flags *flags )
385{
386 *p++ = '%';
387 if( flags->Sign )
388 *p++ = flags->Sign;
389 if( flags->LeftAlign )
390 *p++ = flags->LeftAlign;
391 if( flags->Alternate )
392 *p++ = flags->Alternate;
393 if( flags->PadZero )
394 *p++ = flags->PadZero;
395 if( flags->FieldLength )
396 {
397 sprintf(p, "%d", flags->FieldLength);
398 p += strlen(p);
399 }
Mike McCormack990e5372005-10-27 10:20:08 +0000400 if( flags->Precision >= 0 )
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000401 {
402 sprintf(p, ".%d", flags->Precision);
403 p += strlen(p);
404 }
405 *p++ = flags->Format;
406 *p++ = 0;
407}
408
Jesse Allen419d4932005-12-26 13:01:38 +0100409/* pf_integer_conv: prints x to buf, including alternate formats,
410 but not the sign */
411static void pf_integer_conv( char *buf, pf_flags *flags, LONGLONG x )
412{
413 unsigned int base;
414 char *digits;
415
416 int i, j, k;
417 char tmp[40];
418
419 base = 10;
420 if( flags->Format == 'o' )
421 base = 8;
422 else if( flags->Format == 'x' || flags->Format == 'X' )
423 base = 16;
424
425 if( flags->Format == 'X' )
426 digits = "0123456789ABCDEFX";
427 else
428 digits = "0123456789abcdefx";
429
430 if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
431 {
432 x = -x;
433 flags->Sign = '-';
434 }
435
436 /* Do conversion (backwards) */
437 i = 0;
438 if( x == 0 && flags->Precision )
439 tmp[i++] = '0';
440 else
441 while( x != 0 )
442 {
443 j = (ULONGLONG) x % base;
444 x = (ULONGLONG) x / base;
445 tmp[i++] = digits[j];
446 }
447 k = flags->Precision - i;
448 while( k-- > 0 )
449 tmp[i++] = '0';
450 if( flags->Alternate )
451 {
452 if( base == 16 )
453 {
454 tmp[i++] = digits[16];
455 tmp[i++] = '0';
456 }
457 else if( base == 8 && tmp[i-1] != '0' )
458 tmp[i++] = '0';
459 }
460
461 /* Reverse for buf */
462 j = 0;
463 while( i-- > 0 )
464 buf[j++] = tmp[i];
465 buf[j] = '\0';
466
467 /* Adjust precision so pf_fill won't truncate the number later */
468 flags->Precision = strlen( buf );
469
470 return;
471}
472
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000473/*********************************************************************
474 * pf_vsnprintf (INTERNAL)
475 *
476 * implements both A and W vsnprintf functions
477 */
478static int pf_vsnprintf( pf_output *out, const WCHAR *format, va_list valist )
479{
480 int r;
481 LPCWSTR q, p = format;
482 pf_flags flags;
483
Rein Klazesb6d331d2005-04-14 11:32:53 +0000484 TRACE("format is %s\n",debugstr_w(format));
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000485 while (*p)
486 {
487 q = strchrW( p, '%' );
488
489 /* there's no % characters left, output the rest of the string */
490 if( !q )
491 {
492 r = pf_output_stringW(out, p, -1);
493 if( r<0 )
494 return r;
495 p += r;
496 continue;
497 }
498
499 /* there's characters before the %, output them */
500 if( q != p )
501 {
502 r = pf_output_stringW(out, p, q - p);
503 if( r<0 )
504 return r;
505 p = q;
506 }
507
508 /* we must be at a % now, skip over it */
509 assert( *p == '%' );
510 p++;
511
512 /* output a single % character */
513 if( *p == '%' )
514 {
f4380562005-05-10 08:27:38 +0000515 r = pf_output_stringW(out, p++, 1);
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000516 if( r<0 )
517 return r;
518 continue;
519 }
520
521 /* parse the flags */
522 memset( &flags, 0, sizeof flags );
523 while (*p)
524 {
525 if( *p == '+' || *p == ' ' )
Jesse Allen180326b2005-12-21 20:07:03 +0100526 {
527 if ( flags.Sign != '+' )
528 flags.Sign = *p;
529 }
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000530 else if( *p == '-' )
531 flags.LeftAlign = *p;
532 else if( *p == '0' )
533 flags.PadZero = *p;
534 else if( *p == '#' )
535 flags.Alternate = *p;
536 else
537 break;
538 p++;
539 }
540
541 /* deal with the field width specifier */
542 flags.FieldLength = 0;
Rein Klazesb6d331d2005-04-14 11:32:53 +0000543 if( *p == '*' )
544 {
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000545 flags.FieldLength = va_arg( valist, int );
Rein Klazesb6d331d2005-04-14 11:32:53 +0000546 p++;
547 }
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000548 else while( isdigit(*p) )
549 {
550 flags.FieldLength *= 10;
551 flags.FieldLength += *p++ - '0';
552 }
553
554 /* deal with precision */
Mike McCormack990e5372005-10-27 10:20:08 +0000555 flags.Precision = -1;
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000556 if( *p == '.' )
557 {
Mike McCormack990e5372005-10-27 10:20:08 +0000558 flags.Precision = 0;
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000559 p++;
560 if( *p == '*' )
Uwe Bonnes0fb9ef62005-02-25 19:16:46 +0000561 {
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000562 flags.Precision = va_arg( valist, int );
Uwe Bonnes0fb9ef62005-02-25 19:16:46 +0000563 p++;
564 }
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000565 else while( isdigit(*p) )
566 {
567 flags.Precision *= 10;
568 flags.Precision += *p++ - '0';
569 }
570 }
571
572 /* deal with integer width modifier */
573 while( *p )
574 {
575 if( *p == 'h' || *p == 'l' || *p == 'L' )
576 {
Jesse Allenee058ed2005-12-26 13:00:35 +0100577 flags.IntegerLength = *p;
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000578 p++;
579 }
Jesse Allen6c709422005-12-26 13:00:01 +0100580 else if( *p == 'I' )
581 {
582 if( *(p+1) == '6' && *(p+2) == '4' )
583 {
584 flags.IntegerDouble++;
585 p += 3;
586 }
587 else if( *(p+1) == '3' && *(p+2) == '2' )
588 p += 3;
589 else if( isdigit(*(p+1)) || *(p+1) == 0 )
590 break;
591 else
592 p++;
593 }
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000594 else if( *p == 'w' )
595 flags.WideString = *p++;
Mike McCormack5b432752005-03-04 10:47:27 +0000596 else if( *p == 'F' )
597 p++; /* ignore */
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000598 else
599 break;
600 }
601
602 flags.Format = *p;
603 r = 0;
604
605 /* output a unicode string */
Mike McCormack5def7dd2005-03-05 10:46:46 +0000606 if( ( flags.Format == 's' && (flags.WideString || flags.IntegerLength == 'l' )) ||
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000607 ( !out->unicode && flags.Format == 'S' ) ||
608 ( out->unicode && flags.Format == 's' ) )
609 {
610 LPCWSTR str = va_arg( valist, const WCHAR * );
611
612 if( str )
613 r = pf_output_format_W( out, str, -1, &flags );
614 else
615 r = pf_output_format_A( out, "(null)", -1, &flags );
616 }
617
618 /* output a ASCII string */
619 else if( ( flags.Format == 's' && flags.IntegerLength == 'h' ) ||
620 ( out->unicode && flags.Format == 'S' ) ||
621 ( !out->unicode && flags.Format == 's' ) )
622 {
623 LPCSTR str = va_arg( valist, const CHAR * );
624
625 if( str )
626 r = pf_output_format_A( out, str, -1, &flags );
627 else
628 r = pf_output_format_A( out, "(null)", -1, &flags );
629 }
630
631 /* output a single wide character */
632 else if( ( flags.Format == 'c' && flags.IntegerLength == 'w' ) ||
633 ( out->unicode && flags.Format == 'c' ) ||
634 ( !out->unicode && flags.Format == 'C' ) )
635 {
636 WCHAR ch = va_arg( valist, int );
637
638 r = pf_output_format_W( out, &ch, 1, &flags );
639 }
640
641 /* output a single ascii character */
642 else if( ( flags.Format == 'c' && flags.IntegerLength == 'h' ) ||
643 ( out->unicode && flags.Format == 'C' ) ||
644 ( !out->unicode && flags.Format == 'c' ) )
645 {
646 CHAR ch = va_arg( valist, int );
647
648 r = pf_output_format_A( out, &ch, 1, &flags );
649 }
650
651 /* output a pointer */
652 else if( flags.Format == 'p' )
653 {
Marcus Meissner222d74a2005-07-03 11:19:29 +0000654 char pointer[11];
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000655
656 flags.PadZero = 0;
657 if( flags.Alternate )
658 sprintf(pointer, "0X%08lX", va_arg(valist, long));
659 else
660 sprintf(pointer, "%08lX", va_arg(valist, long));
661 r = pf_output_format_A( out, pointer, -1, &flags );
662 }
663
664 /* deal with %n */
665 else if( flags.Format == 'n' )
666 {
667 int *x = va_arg(valist, int *);
668 *x = out->used;
669 }
670
Jesse Allen419d4932005-12-26 13:01:38 +0100671 /* deal with 64-bit integers */
672 else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble )
673 {
674 char number[40], *x = number;
675
676 if( flags.FieldLength >= sizeof number )
677 x = HeapAlloc( GetProcessHeap(), 0, flags.FieldLength+1 );
678
679 pf_integer_conv( x, &flags, va_arg(valist, LONGLONG) );
680
681 r = pf_output_format_A( out, x, -1, &flags );
682 if( x != number )
683 HeapFree( GetProcessHeap(), 0, number );
684 }
685
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000686 /* deal with integers and floats using libc's printf */
687 else if( pf_is_valid_format( flags.Format ) )
688 {
689 char fmt[20], number[40], *x = number;
690
691 if( flags.FieldLength >= sizeof number )
692 x = HeapAlloc( GetProcessHeap(), 0, flags.FieldLength+1 );
693
694 pf_rebuild_format_string( fmt, &flags );
695
696 if( pf_is_double_format( flags.Format ) )
Mike McCormackcbe3fb62005-10-28 09:40:16 +0000697 sprintf( x, fmt, va_arg(valist, double) );
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000698 else
Mike McCormackcbe3fb62005-10-28 09:40:16 +0000699 sprintf( x, fmt, va_arg(valist, int) );
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000700
Mike McCormackcbe3fb62005-10-28 09:40:16 +0000701 r = pf_output_stringA( out, x, -1 );
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000702 if( x != number )
703 HeapFree( GetProcessHeap(), 0, number );
704 }
705 else
706 continue;
707
708 if( r<0 )
709 return r;
710 p++;
711 }
712
713 /* check we reached the end, and null terminate the string */
714 assert( *p == 0 );
Alexandre Julliardee603ce2006-01-14 17:30:02 +0100715 pf_output_stringW( out, p, 1 );
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000716
717 return out->used - 1;
718}
719
720/*********************************************************************
721 * _vsnprintf (MSVCRT.@)
722 */
723int MSVCRT_vsnprintf( char *str, unsigned int len,
724 const char *format, va_list valist )
725{
726 DWORD sz;
727 LPWSTR formatW = NULL;
728 pf_output out;
729 int r;
730
731 out.unicode = FALSE;
732 out.buf.A = str;
733 out.used = 0;
734 out.len = len;
735
736 if( format )
737 {
738 sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
739 formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
740 MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
741 }
742
743 r = pf_vsnprintf( &out, formatW, valist );
744
745 HeapFree( GetProcessHeap(), 0, formatW );
746
747 return r;
748}
749
750/*********************************************************************
Alexandre Julliardee603ce2006-01-14 17:30:02 +0100751 * _snprintf (MSVCRT.@)
752 */
753int MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
754{
755 int retval;
756 va_list valist;
757 va_start(valist, format);
758 retval = MSVCRT_vsnprintf(str, len, format, valist);
759 va_end(valist);
760 return retval;
761}
762
763/*********************************************************************
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000764 * _vsnwsprintf (MSVCRT.@)
765 */
766int MSVCRT_vsnwprintf( MSVCRT_wchar_t *str, unsigned int len,
Alexandre Julliarda17b2c12006-01-24 12:21:58 +0100767 const MSVCRT_wchar_t *format, va_list valist )
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000768{
769 pf_output out;
770
771 out.unicode = TRUE;
772 out.buf.W = str;
773 out.used = 0;
774 out.len = len;
775
776 return pf_vsnprintf( &out, format, valist );
777}
778
779/*********************************************************************
Alexandre Julliardee603ce2006-01-14 17:30:02 +0100780 * _snwprintf (MSVCRT.@)
781 */
782int MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
783{
784 int retval;
785 va_list valist;
786 va_start(valist, format);
787 retval = MSVCRT_vsnwprintf(str, len, format, valist);
788 va_end(valist);
789 return retval;
790}
791
792/*********************************************************************
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000793 * sprintf (MSVCRT.@)
794 */
795int MSVCRT_sprintf( char *str, const char *format, ... )
796{
797 va_list ap;
798 int r;
799
800 va_start( ap, format );
801 r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
802 va_end( ap );
803 return r;
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000804}
805
806/*********************************************************************
807 * swprintf (MSVCRT.@)
808 */
809int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
810{
811 va_list ap;
812 int r;
813
814 va_start( ap, format );
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000815 r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
Mike McCormackdb0d0bb2004-06-02 00:35:09 +0000816 va_end( ap );
817 return r;
818}
819
Jon Griffithsd051a952003-09-23 22:50:30 +0000820/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000821 * vswprintf (MSVCRT.@)
822 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000823int MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
Jon Griffiths34c786b2001-01-22 02:21:54 +0000824{
Mike McCormack2cc5f1e2005-02-14 20:53:42 +0000825 return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
Jon Griffiths34c786b2001-01-22 02:21:54 +0000826}
827
828/*********************************************************************
829 * wcscoll (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000830 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000831int MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000832{
833 /* FIXME: handle collates */
834 return strcmpW( str1, str2 );
835}
836
837/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000838 * wcspbrk (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000839 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000840MSVCRT_wchar_t* MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000841{
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000842 const MSVCRT_wchar_t* p;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000843 while (*str)
844 {
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000845 for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000846 str++;
847 }
848 return NULL;
849}
850
851/*********************************************************************
Alexandre Julliard2ec3b962006-01-14 17:24:49 +0100852 * wcstok (MSVCRT.@)
853 */
854MSVCRT_wchar_t *MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
855{
856 thread_data_t *data = msvcrt_get_thread_data();
857 MSVCRT_wchar_t *ret;
858
859 if (!str)
860 if (!(str = data->wcstok_next)) return NULL;
861
862 while (*str && strchrW( delim, *str )) str++;
863 if (!*str) return NULL;
864 ret = str++;
865 while (*str && !strchrW( delim, *str )) str++;
866 if (*str) *str++ = 0;
867 data->wcstok_next = str;
868 return ret;
869}
870
871
872/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000873 * wctomb (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000874 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000875INT MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000876{
877 return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
878}
879
880/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000881 * iswalnum (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000882 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000883INT MSVCRT_iswalnum( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000884{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000885 return isalnumW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000886}
887
888/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000889 * iswalpha (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000890 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000891INT MSVCRT_iswalpha( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000892{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000893 return isalphaW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000894}
895
896/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000897 * iswcntrl (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000898 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000899INT MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000900{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000901 return iscntrlW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000902}
903
904/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000905 * iswdigit (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000906 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000907INT MSVCRT_iswdigit( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000908{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000909 return isdigitW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000910}
911
912/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000913 * iswgraph (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000914 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000915INT MSVCRT_iswgraph( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000916{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000917 return isgraphW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000918}
919
920/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000921 * iswlower (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000922 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000923INT MSVCRT_iswlower( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000924{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000925 return islowerW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000926}
927
928/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000929 * iswprint (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000930 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000931INT MSVCRT_iswprint( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000932{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000933 return isprintW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000934}
935
936/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000937 * iswpunct (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000938 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000939INT MSVCRT_iswpunct( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000940{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000941 return ispunctW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000942}
943
944/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000945 * iswspace (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000946 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000947INT MSVCRT_iswspace( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000948{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000949 return isspaceW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000950}
951
952/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000953 * iswupper (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000954 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000955INT MSVCRT_iswupper( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000956{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000957 return isupperW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000958}
959
960/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000961 * iswxdigit (MSVCRT.@)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000962 */
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000963INT MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000964{
Alexandre Julliard22c2ac72001-11-08 19:16:34 +0000965 return isxdigitW( wc );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000966}