From 2cc5f1e469485d385127c82dd157981f2716bbec Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Mon, 14 Feb 2005 20:53:42 +0000 Subject: [PATCH] Add handling of %ws, %S and %C to _vns(w)printf, improve sprintf tests. --- dlls/msvcrt/msvcrt.spec | 6 +- dlls/msvcrt/tests/printf.c | 254 ++++++++++++--- dlls/msvcrt/wcs.c | 611 ++++++++++++++++++++++++++++--------- 3 files changed, 669 insertions(+), 202 deletions(-) diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 4a12c6e2b43..5b80001ceba 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -484,8 +484,8 @@ @ cdecl _unloaddll(long) @ cdecl _unlock(long) @ cdecl _utime(str ptr) -@ cdecl _vsnprintf(ptr long ptr ptr) vsnprintf -@ cdecl _vsnwprintf(ptr long wstr long) +@ cdecl _vsnprintf(ptr long ptr ptr) MSVCRT_vsnprintf +@ cdecl _vsnwprintf(ptr long wstr long) MSVCRT_vsnwprintf @ cdecl _waccess(wstr long) @ stub _wasctime #(ptr) MSVCRT__wasctime @ cdecl _wchdir(wstr) @@ -693,7 +693,7 @@ @ cdecl signal(long long) MSVCRT_signal @ cdecl sin(double) @ cdecl sinh(double) -@ varargs sprintf(ptr str) +@ varargs sprintf(ptr str) MSVCRT_sprintf @ cdecl sqrt(double) @ cdecl srand(long) @ varargs sscanf(str str) MSVCRT_sscanf diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c index 2cfc502de96..74c838cd4e7 100644 --- a/dlls/msvcrt/tests/printf.c +++ b/dlls/msvcrt/tests/printf.c @@ -3,6 +3,7 @@ * * Copyright 2002 Uwe Bonnes * Copyright 2004 Aneurin Price + * Copyright 2005 Mike McCormack * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,54 +27,213 @@ static void test_sprintf( void ) { char buffer[100]; - const char *I64d = "%I64d"; - const char *O4c = "%04c"; - const char *O4s = "%04s"; - const char *hash012p = "%#012p"; + const char *format; double pnumber=789456123; -/** WCHAR widestring[]={'w','i','d','e','s','t','r','i','n','g',0};**/ - sprintf(buffer,"%+#23.15e",pnumber); - todo_wine - { - ok(strstr(buffer,"e+008") != 0,"Sprintf different \"%s\"\n",buffer); - } - sprintf(buffer,I64d,((ULONGLONG)0xffffffff)*0xffffffff); - todo_wine - { - ok(strlen(buffer) == 11,"Problem with long long \"%s\"\n",buffer); - } - sprintf(buffer,"%lld",((ULONGLONG)0xffffffff)*0xffffffff); - todo_wine - { - ok(strlen(buffer) == 1,"Problem with \"ll\" interpretation \"%s\"\n",buffer); - } -/** This one actually crashes WINE at the moment, when using builtin msvcrt.dll. - sprintf(buffer,"%S",widestring); - todo_wine - { - ok(strlen(buffer) == 10,"Problem with \"%%S\" interpretation \"%s\"\n",buffer); - } - **/ - sprintf(buffer,O4c,'1'); - todo_wine - { - ok(!strcmp(buffer,"0001"),"Character not zero-prefixed \"%s\"\n",buffer); - } - sprintf(buffer,"%p",(void *)57); - todo_wine - { - ok(!strcmp(buffer,"00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); - } - sprintf(buffer,hash012p,(void *)57); - todo_wine - { - ok(!strcmp(buffer," 0X00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); - } - sprintf(buffer,O4s,"foo");/**Warning again**/ - todo_wine - { - ok(!strcmp(buffer,"0foo"),"String not zero-prefixed \"%s\"\n",buffer); - } + int x, r; + WCHAR wide[] = { 'w','i','d','e',0}; + + format = "%+#23.15e"; + r = sprintf(buffer,format,pnumber); + todo_wine { + ok(!strcmp(buffer,"+7.894561230000000e+008"),"exponent format incorrect\n"); + } + ok( r==23, "return count wrong\n"); + + todo_wine { + format = "%I64d"; + r = sprintf(buffer,format,((ULONGLONG)0xffffffff)*0xffffffff); + ok(!strcmp(buffer,"-8589934591"),"Problem with long long\n"); + ok( r==11, "return count wrong\n"); + } + + format = "%lld"; + r = sprintf(buffer,format,((ULONGLONG)0xffffffff)*0xffffffff); + ok(!strcmp(buffer, "1"), "Problem with \"ll\" interpretation\n"); + ok( r==1, "return count wrong\n"); + + format = "%S"; + r = sprintf(buffer,format,wide); + ok(!strcmp(buffer,"wide"),"Problem with wide string format\n"); + ok( r==4, "return count wrong\n"); + + format = "%04c"; + r = sprintf(buffer,format,'1'); + ok(!strcmp(buffer,"0001"),"Character not zero-prefixed \"%s\"\n",buffer); + ok( r==4, "return count wrong\n"); + + format = "%p"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer,"00000039"),"Pointer formatted incorrectly \"%s\"\n",buffer); + ok( r==8, "return count wrong\n"); + + format = "%#012p"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer," 0X00000039"),"Pointer formatted incorrectly\n"); + ok( r==12, "return count wrong\n"); + + format = "%04s"; + r = sprintf(buffer,format,"foo"); + ok(!strcmp(buffer,"0foo"),"String not zero-prefixed \"%s\"\n",buffer); + ok( r==4, "return count wrong\n"); + + format = "%#-012p"; + r = sprintf(buffer,format,(void *)57); + ok(!strcmp(buffer,"0X00000039 "),"Pointer formatted incorrectly\n"); + ok( r==12, "return count wrong\n"); + + format = "hello"; + r = sprintf(buffer, format); + ok(!strcmp(buffer,"hello"), "failed\n"); + ok( r==5, "return count wrong\n"); + + format = "%ws"; + r = sprintf(buffer, format, wide); + ok(!strcmp(buffer,"wide"), "failed\n"); + ok( r==4, "return count wrong\n"); + + format = "%-10ws"; + r = sprintf(buffer, format, wide ); + ok(!strcmp(buffer,"wide "), "failed\n"); + ok( r==10, "return count wrong\n"); + + format = "%10ws"; + r = sprintf(buffer, format, wide ); + ok(!strcmp(buffer," wide"), "failed\n"); + ok( r==10, "return count wrong\n"); + + format = "%#+ -03whlls"; + r = sprintf(buffer, format, wide ); + ok(!strcmp(buffer,"wide"), "failed\n"); + ok( r==4, "return count wrong\n"); + + format = "%w0s"; + r = sprintf(buffer, format, wide ); + ok(!strcmp(buffer,"0s"), "failed\n"); + ok( r==2, "return count wrong\n"); + + format = "%w-s"; + r = sprintf(buffer, format, wide ); + ok(!strcmp(buffer,"-s"), "failed\n"); + ok( r==2, "return count wrong\n"); + + format = "%b"; + r = sprintf(buffer, format); + ok(!strcmp(buffer,"b"), "failed\n"); + ok( r==1, "return count wrong\n"); + + format = "%3c"; + r = sprintf(buffer, format,'a'); + ok(!strcmp(buffer," a"), "failed\n"); + ok( r==3, "return count wrong\n"); + + format = "%3d"; + r = sprintf(buffer, format,1234); + ok(!strcmp(buffer,"1234"), "failed\n"); + ok( r==4, "return count wrong\n"); + + format = "%3h"; + r = sprintf(buffer, format); + ok(!strcmp(buffer,""), "failed\n"); + ok( r==0, "return count wrong\n"); + + format = "%j%k%m%q%r%t%v%y%z"; + r = sprintf(buffer, format); + ok(!strcmp(buffer,"jkmqrtvyz"), "failed\n"); + ok( r==9, "return count wrong\n"); + + format = "asdf%n"; + x = 0; + r = sprintf(buffer, format, &x ); + ok(x == 4, "should write to x\n"); + ok(!strcmp(buffer,"asdf"), "failed\n"); + ok( r==4, "return count wrong\n"); + + format = "%-1d"; + r = sprintf(buffer, format,2); + ok(!strcmp(buffer,"2"), "failed\n"); + ok( r==1, "return count wrong\n"); + + format = "%2.4f"; + r = sprintf(buffer, format,8.6); + ok(!strcmp(buffer,"8.6000"), "failed\n"); + ok( r==6, "return count wrong\n"); + + todo_wine { + format = "%2.4e"; + r = sprintf(buffer, format,8.6); + ok(!strcmp(buffer,"8.6000e+000"), "failed\n"); + ok( r==11, "return count wrong\n"); + } + + format = "%2.4g"; + r = sprintf(buffer, format,8.6); + ok(!strcmp(buffer,"8.6"), "failed\n"); + ok( r==3, "return count wrong\n"); + + format = "%-i"; + r = sprintf(buffer, format,-1); + ok(!strcmp(buffer,"-1"), "failed\n"); + ok( r==2, "return count wrong\n"); + + format = "%-i"; + r = sprintf(buffer, format,1); + ok(!strcmp(buffer,"1"), "failed\n"); + ok( r==1, "return count wrong\n"); + + format = "%+i"; + r = sprintf(buffer, format,1); + ok(!strcmp(buffer,"+1"), "failed\n"); + ok( r==2, "return count wrong\n"); + + format = "%o"; + r = sprintf(buffer, format,10); + ok(!strcmp(buffer,"12"), "failed\n"); + ok( r==2, "return count wrong\n"); + + format = "%p"; + r = sprintf(buffer, format,0); + ok(!strcmp(buffer,"00000000"), "failed\n"); + ok( r==8, "return count wrong\n"); + + format = "%s"; + r = sprintf(buffer, format,0); + ok(!strcmp(buffer,"(null)"), "failed\n"); + ok( r==6, "return count wrong\n"); + + format = "%s"; + r = sprintf(buffer, format,"%%%%"); + ok(!strcmp(buffer,"%%%%"), "failed\n"); + ok( r==4, "return count wrong\n"); + + format = "%u"; + r = sprintf(buffer, format,-1); + ok(!strcmp(buffer,"4294967295"), "failed\n"); + ok( r==10, "return count wrong\n"); + + format = "%w"; + r = sprintf(buffer, format,-1); + ok(!strcmp(buffer,""), "failed\n"); + ok( r==0, "return count wrong\n"); + + format = "%h"; + r = sprintf(buffer, format,-1); + ok(!strcmp(buffer,""), "failed\n"); + ok( r==0, "return count wrong\n"); + + format = "%z"; + r = sprintf(buffer, format,-1); + ok(!strcmp(buffer,"z"), "failed\n"); + ok( r==1, "return count wrong\n"); + + format = "%j"; + r = sprintf(buffer, format,-1); + ok(!strcmp(buffer,"j"), "failed\n"); + ok( r==1, "return count wrong\n"); + + format = "x%cx"; + r = sprintf(buffer, format, 0x100+'X'); + ok(!strcmp(buffer,"xXx"), "failed\n"); + ok( r==3, "return count wrong\n"); } static void test_swprintf( void ) diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c index bae0d7f3bd9..9eb1f9a75c5 100644 --- a/dlls/msvcrt/wcs.c +++ b/dlls/msvcrt/wcs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "msvcrt.h" #include "winnls.h" #include "wine/unicode.h" @@ -178,161 +179,476 @@ double MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end) return ret; } -static int MSVCRT_vsnprintfW(WCHAR *str, size_t len, const WCHAR *format, va_list valist) + +typedef struct pf_output_t { - unsigned int written = 0; - const WCHAR *iter = format; - char bufa[256], fmtbufa[64], *fmta; + int used; + int len; + BOOL unicode; + union { + LPWSTR W; + LPSTR A; + } buf; +} pf_output; - while (*iter) +typedef struct pf_flags_t +{ + char Sign, LeftAlign, Alternate, PadZero; + char FieldLength, Precision; + char IntegerLength, IntegerDouble; + char WideString; + char Format; +} pf_flags; + +/* + * writes a string of characters to the output + * returns -1 if the string doesn't fit in the output buffer + * return the length of the string if all characters were written + */ +static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len ) +{ + int space = out->len - out->used; + + if( len < 0 ) + len = strlenW( str ); + if( out->unicode ) { - while (*iter && *iter != '%') + LPWSTR p = out->buf.W + out->used; + + if( space >= len ) { - if (written++ >= len) - return -1; - *str++ = *iter++; + memcpy( p, str, len*sizeof(WCHAR) ); + out->used += len; + return len; } - if (*iter == '%') + if( space > 0 ) + memcpy( p, str, space*sizeof(WCHAR) ); + out->used += len; + } + else + { + int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL ); + LPSTR p = out->buf.A + out->used; + + if( space >= n ) { - if (iter[1] == '%') - { - if (written++ >= len) - return -1; - *str++ = '%'; /* "%%"->'%' */ - iter += 2; - continue; - } + WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL ); + out->used += n; + return len; + } + if( space > 0 ) + WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL ); + out->used += n; + } + return -1; +} - fmta = fmtbufa; - *fmta++ = *iter++; - while (*iter == '0' || - *iter == '+' || - *iter == '-' || - *iter == ' ' || - *iter == '*' || - *iter == '#') - { - if (*iter == '*') - { - char *buffiter = bufa; - int fieldlen = va_arg(valist, int); - sprintf(buffiter, "%d", fieldlen); - while (*buffiter) - *fmta++ = *buffiter++; - } - else - *fmta++ = *iter; - iter++; - } +static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len ) +{ + int space = out->len - out->used; - while (isdigit(*iter)) - *fmta++ = *iter++; + if( len < 0 ) + len = strlen( str ); + if( !out->unicode ) + { + LPSTR p = out->buf.A + out->used; - if (*iter == '.') - { - *fmta++ = *iter++; - if (*iter == '*') - { - char *buffiter = bufa; - int fieldlen = va_arg(valist, int); - sprintf(buffiter, "%d", fieldlen); - while (*buffiter) - *fmta++ = *buffiter++; - } - else - while (isdigit(*iter)) - *fmta++ = *iter++; - } - if (*iter == 'h' || *iter == 'l') - *fmta++ = *iter++; + if( space >= len ) + { + memcpy( p, str, len ); + out->used += len; + return len; + } + if( space > 0 ) + memcpy( p, str, space ); + out->used += len; + } + else + { + int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 ); + LPWSTR p = out->buf.W + out->used; - switch (*iter) - { - case 'S': - { - static const char *none = "(null)"; - const char *astr = va_arg(valist, const char *); - const char *striter = astr ? astr : none; - int r, n; - while (*striter) - { - if (written >= len) - return -1; - n = 1; - if( IsDBCSLeadByte( *striter ) ) - n++; - r = MultiByteToWideChar( CP_ACP, 0, - striter, n, str, len - written ); - striter += n; - str += r; - written += r; - } - iter++; - break; - } + if( space >= n ) + { + MultiByteToWideChar( CP_ACP, 0, str, len, p, n ); + out->used += n; + return len; + } + if( space > 0 ) + MultiByteToWideChar( CP_ACP, 0, str, len, p, space ); + out->used += n; + } + return -1; +} - case 's': - { - static const WCHAR none[] = { '(','n','u','l','l',')',0 }; - const WCHAR *wstr = va_arg(valist, const WCHAR *); - const WCHAR *striter = wstr ? wstr : none; - while (*striter) - { - if (written++ >= len) - return -1; - *str++ = *striter++; - } - iter++; - break; - } +static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left ) +{ + int i, r = 0; - case 'c': - if (written++ >= len) - return -1; - *str++ = (WCHAR)va_arg(valist, int); - iter++; - break; - - default: - { - /* For non wc types, use system sprintf and append to wide char output */ - /* FIXME: for unrecognised types, should ignore % when printing */ - char *bufaiter = bufa; - if (*iter == 'p') - sprintf(bufaiter, "%08lX", va_arg(valist, long)); - else - { - *fmta++ = *iter; - *fmta = '\0'; - if (*iter == 'a' || *iter == 'A' || - *iter == 'e' || *iter == 'E' || - *iter == 'f' || *iter == 'F' || - *iter == 'g' || *iter == 'G') - sprintf(bufaiter, fmtbufa, va_arg(valist, double)); - else - { - /* FIXME: On 32 bit systems this doesn't handle int 64's. - * on 64 bit systems this doesn't work for 32 bit types - */ - sprintf(bufaiter, fmtbufa, va_arg(valist, void *)); - } - } - while (*bufaiter) - { - if (written++ >= len) - return -1; - *str++ = *bufaiter++; - } - iter++; - break; - } - } + if( ( !left && flags->LeftAlign ) || + ( left && !flags->LeftAlign ) || + ( left && flags->PadZero ) ) + { + for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ ) + { + if( flags->PadZero ) + r = pf_output_stringA( out, "0", 1 ); + else + r = pf_output_stringA( out, " ", 1 ); } } - if (written >= len) - return -1; - *str++ = 0; - return (int)written; + + return r; +} + +static inline int pf_output_format_W( pf_output *out, LPCWSTR str, + int len, pf_flags *flags ) +{ + int r = 0; + + if( len < 0 ) + len = strlenW( str ); + + r = pf_fill( out, len, flags, 1 ); + + if( r>=0 ) + r = pf_output_stringW( out, str, len ); + + if( r>=0 ) + r = pf_fill( out, len, flags, 0 ); + + return r; +} + +static inline int pf_output_format_A( pf_output *out, LPCSTR str, + int len, pf_flags *flags ) +{ + int r = 0; + + if( len < 0 ) + len = strlen( str ); + + r = pf_fill( out, len, flags, 1 ); + + if( r>=0 ) + r = pf_output_stringA( out, str, len ); + + if( r>=0 ) + r = pf_fill( out, len, flags, 0 ); + + return r; +} + +static inline BOOL pf_is_double_format( char fmt ) +{ + char float_fmts[] = "aefg"; + if (!fmt) + return FALSE; + fmt = tolower( fmt ); + return strchr( float_fmts, fmt ) ? TRUE : FALSE; +} + +static inline BOOL pf_is_valid_format( char fmt ) +{ + char float_fmts[] = "acdefginoux"; + if (!fmt) + return FALSE; + fmt = tolower( fmt ); + return strchr( float_fmts, fmt ) ? TRUE : FALSE; +} + +static void pf_rebuild_format_string( char *p, pf_flags *flags ) +{ + *p++ = '%'; + if( flags->Sign ) + *p++ = flags->Sign; + if( flags->LeftAlign ) + *p++ = flags->LeftAlign; + if( flags->Alternate ) + *p++ = flags->Alternate; + if( flags->PadZero ) + *p++ = flags->PadZero; + if( flags->FieldLength ) + { + sprintf(p, "%d", flags->FieldLength); + p += strlen(p); + } + if( flags->Precision ) + { + sprintf(p, ".%d", flags->Precision); + p += strlen(p); + } + *p++ = flags->Format; + *p++ = 0; +} + +/********************************************************************* + * pf_vsnprintf (INTERNAL) + * + * implements both A and W vsnprintf functions + */ +static int pf_vsnprintf( pf_output *out, const WCHAR *format, va_list valist ) +{ + int r; + LPCWSTR q, p = format; + pf_flags flags; + + while (*p) + { + q = strchrW( p, '%' ); + + /* there's no % characters left, output the rest of the string */ + if( !q ) + { + r = pf_output_stringW(out, p, -1); + if( r<0 ) + return r; + p += r; + continue; + } + + /* there's characters before the %, output them */ + if( q != p ) + { + r = pf_output_stringW(out, p, q - p); + if( r<0 ) + return r; + p = q; + } + + /* we must be at a % now, skip over it */ + assert( *p == '%' ); + p++; + + /* output a single % character */ + if( *p == '%' ) + { + r = pf_output_stringW(out, p, 1); + if( r<0 ) + return r; + continue; + } + + /* parse the flags */ + memset( &flags, 0, sizeof flags ); + while (*p) + { + if( *p == '+' || *p == ' ' ) + flags.Sign = '+'; + else if( *p == '-' ) + flags.LeftAlign = *p; + else if( *p == '0' ) + flags.PadZero = *p; + else if( *p == '#' ) + flags.Alternate = *p; + else + break; + p++; + } + + /* deal with the field width specifier */ + flags.FieldLength = 0; + if( *p == '*' ) + flags.FieldLength = va_arg( valist, int ); + else while( isdigit(*p) ) + { + flags.FieldLength *= 10; + flags.FieldLength += *p++ - '0'; + } + + /* deal with precision */ + if( *p == '.' ) + { + p++; + if( *p == '*' ) + flags.Precision = va_arg( valist, int ); + else while( isdigit(*p) ) + { + flags.Precision *= 10; + flags.Precision += *p++ - '0'; + } + } + + /* deal with integer width modifier */ + while( *p ) + { + if( *p == 'h' || *p == 'l' || *p == 'L' ) + { + if( flags.IntegerLength == *p ) /* FIXME: this is wrong */ + flags.IntegerDouble++; + else + flags.IntegerLength = *p; + p++; + } + else if( *p == 'w' ) + flags.WideString = *p++; + else + break; + } + + flags.Format = *p; + r = 0; + + /* output a unicode string */ + if( ( flags.Format == 's' && flags.WideString ) || + ( !out->unicode && flags.Format == 'S' ) || + ( out->unicode && flags.Format == 's' ) ) + { + LPCWSTR str = va_arg( valist, const WCHAR * ); + + if( str ) + r = pf_output_format_W( out, str, -1, &flags ); + else + r = pf_output_format_A( out, "(null)", -1, &flags ); + } + + /* output a ASCII string */ + else if( ( flags.Format == 's' && flags.IntegerLength == 'h' ) || + ( out->unicode && flags.Format == 'S' ) || + ( !out->unicode && flags.Format == 's' ) ) + { + LPCSTR str = va_arg( valist, const CHAR * ); + + if( str ) + r = pf_output_format_A( out, str, -1, &flags ); + else + r = pf_output_format_A( out, "(null)", -1, &flags ); + } + + /* output a single wide character */ + else if( ( flags.Format == 'c' && flags.IntegerLength == 'w' ) || + ( out->unicode && flags.Format == 'c' ) || + ( !out->unicode && flags.Format == 'C' ) ) + { + WCHAR ch = va_arg( valist, int ); + + r = pf_output_format_W( out, &ch, 1, &flags ); + } + + /* output a single ascii character */ + else if( ( flags.Format == 'c' && flags.IntegerLength == 'h' ) || + ( out->unicode && flags.Format == 'C' ) || + ( !out->unicode && flags.Format == 'c' ) ) + { + CHAR ch = va_arg( valist, int ); + + r = pf_output_format_A( out, &ch, 1, &flags ); + } + + /* output a pointer */ + else if( flags.Format == 'p' ) + { + char pointer[10]; + + flags.PadZero = 0; + if( flags.Alternate ) + sprintf(pointer, "0X%08lX", va_arg(valist, long)); + else + sprintf(pointer, "%08lX", va_arg(valist, long)); + r = pf_output_format_A( out, pointer, -1, &flags ); + } + + /* deal with %n */ + else if( flags.Format == 'n' ) + { + int *x = va_arg(valist, int *); + *x = out->used; + } + + /* deal with integers and floats using libc's printf */ + else if( pf_is_valid_format( flags.Format ) ) + { + char fmt[20], number[40], *x = number; + + if( flags.FieldLength >= sizeof number ) + x = HeapAlloc( GetProcessHeap(), 0, flags.FieldLength+1 ); + + pf_rebuild_format_string( fmt, &flags ); + + if( pf_is_double_format( flags.Format ) ) + sprintf( number, fmt, va_arg(valist, double) ); + else + sprintf( number, fmt, va_arg(valist, int) ); + + r = pf_output_stringA( out, number, -1 ); + if( x != number ) + HeapFree( GetProcessHeap(), 0, number ); + } + else + continue; + + if( r<0 ) + return r; + p++; + } + + /* check we reached the end, and null terminate the string */ + assert( *p == 0 ); + r = pf_output_stringW( out, p, 1 ); + if( r<0 ) + return r; + + return out->used - 1; +} + +/********************************************************************* + * _vsnprintf (MSVCRT.@) + */ +int MSVCRT_vsnprintf( char *str, unsigned int len, + const char *format, va_list valist ) +{ + DWORD sz; + LPWSTR formatW = NULL; + pf_output out; + int r; + + out.unicode = FALSE; + out.buf.A = str; + out.used = 0; + out.len = len; + + if( format ) + { + sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 ); + formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz ); + } + + r = pf_vsnprintf( &out, formatW, valist ); + + HeapFree( GetProcessHeap(), 0, formatW ); + + return r; +} + +/********************************************************************* + * _vsnwsprintf (MSVCRT.@) + */ +int MSVCRT_vsnwprintf( MSVCRT_wchar_t *str, unsigned int len, + const WCHAR *format, va_list valist ) +{ + pf_output out; + + out.unicode = TRUE; + out.buf.W = str; + out.used = 0; + out.len = len; + + return pf_vsnprintf( &out, format, valist ); +} + +/********************************************************************* + * sprintf (MSVCRT.@) + */ +int MSVCRT_sprintf( char *str, const char *format, ... ) +{ + va_list ap; + int r; + + va_start( ap, format ); + r = MSVCRT_vsnprintf( str, INT_MAX, format, ap ); + va_end( ap ); + return r; } /********************************************************************* @@ -344,26 +660,17 @@ int MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... ) int r; va_start( ap, format ); - r = MSVCRT_vsnprintfW( str, INT_MAX, format, ap ); + r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap ); va_end( ap ); return r; } -/********************************************************************* - * _vsnwprintf (MSVCRT.@) - */ -int _vsnwprintf(MSVCRT_wchar_t *str, unsigned int len, - const MSVCRT_wchar_t *format, va_list valist) -{ - return MSVCRT_vsnprintfW(str, len, format, valist); -} - /********************************************************************* * vswprintf (MSVCRT.@) */ int MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args ) { - return MSVCRT_vsnprintfW( str, INT_MAX, format, args ); + return MSVCRT_vsnwprintf( str, INT_MAX, format, args ); } /*********************************************************************