update for HEAD-2003091401
[reactos.git] / lib / user32 / misc / sprintf.c
index 6ddd417..978b57d 100644 (file)
@@ -1,19 +1,41 @@
-/* $Id$
- *
- * user32.dll
- *
+/*
  * wsprintf functions
  *
  * Copyright 1996 Alexandre Julliard
  *
- * 1999-05-01 (Emanuele Aliberti)
- *     Adapted from Wine to ReactOS
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * NOTE:
+ * This code is duplicated in shlwapi. If you change something here make sure
+ * to change it in shlwapi too.
+ */
+/*
+ * COPYRIGHT:        See COPYING in the top level directory
+ * PROJECT:          ReactOS User32
+ * PURPOSE:          [w]sprintf functions
+ * FILE:             lib/user32/sprintf.c
+ * PROGRAMER:        Steven Edwards 
+ * REVISION HISTORY: 2003/07/13 Merged from wine user/wsprintf.c
+ * NOTES:            Adapted from Wine
  */
 
 #include <stdarg.h>
 #include <string.h>
 #include <stdio.h>
 #include <windows.h>
+#include "strpool.h"
 
 #define WPRINTF_LEFTALIGN   0x0001  /* Align output on the left ('-' prefix) */
 #define WPRINTF_PREFIX_HEX  0x0002  /* Prefix hex with 0x ('#' prefix) */
 
 typedef enum
 {
-       WPR_UNKNOWN,
-       WPR_CHAR,
-       WPR_WCHAR,
-       WPR_STRING,
-       WPR_WSTRING,
-       WPR_SIGNED,
-       WPR_UNSIGNED,
-       WPR_HEXA
-               
+    WPR_UNKNOWN,
+    WPR_CHAR,
+    WPR_WCHAR,
+    WPR_STRING,
+    WPR_WSTRING,
+    WPR_SIGNED,
+    WPR_UNSIGNED,
+    WPR_HEXA
 } WPRINTF_TYPE;
 
-
 typedef struct
 {
-       UINT            flags;
-       UINT            width;
-       UINT            precision;
-       WPRINTF_TYPE    type;
-       
+    UINT         flags;
+    UINT         width;
+    UINT         precision;
+    WPRINTF_TYPE   type;
 } WPRINTF_FORMAT;
 
+typedef union {
+    WCHAR   wchar_view;
+    CHAR    char_view;
+    LPCSTR  lpcstr_view;
+    LPCWSTR lpcwstr_view;
+    INT     int_view;
+} WPRINTF_DATA;
 
-static const LPSTR     null_stringA = "(null)";
-static const LPWSTR    null_stringW = L"(null)";
-
-
-/* === COMMON === */
-
+static const CHAR null_stringA[] = "(null)";
+static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
 
 /***********************************************************************
- * NAME                                                                PRIVATE
- *     WPRINTF_GetLen
+ *           WPRINTF_ParseFormatA
  *
- * DESCRIPTION
- *     ?
+ * Parse a format specification. A format specification has the form:
  *
- * ARGUMENTS
- *     format
- *             ?
- *     arg
- *             ?
- *     number
- *             ?
- *     maxlen
- *             ?
+ * [-][#][0][width][.precision]type
  *
- * RETURN VALUE
- *     ?
+ * Return value is the length of the format specification in characters.
  */
-static
-UINT
-WPRINTF_GetLen(
-       WPRINTF_FORMAT  *format,
-       LPCVOID         arg,
-       LPSTR           number,
-       UINT            maxlen
-       )
+static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
 {
-       UINT len;
-
-       if (format->flags & WPRINTF_LEFTALIGN)
-       {
-               format->flags &= ~WPRINTF_ZEROPAD;
-       }
-       if (format->width > maxlen)
-       {
-               format->width = maxlen;
-       }
-       switch(format->type)
-       {
-       case WPR_CHAR:
-       case WPR_WCHAR:
-               return (format->precision = 1);
-               
-       case WPR_STRING:
-               if (!*(LPCSTR *)arg)
-               {
-                       *(LPCSTR *)arg = null_stringA;
-               }
-               for (   len = 0;
-                       (!format->precision || (len < format->precision));
-                       len++
-                       )
-               {
-                       if (!*(*(LPCSTR *)arg + len))
-                       {
-                               break;
-                       }
-               }
-               if (len > maxlen)
-               {
-                       len = maxlen;
-               }
-               return (format->precision = len);
-
-       case WPR_WSTRING:
-               if (!*(LPCWSTR *)arg)
-               {
-                       *(LPCWSTR *)arg = null_stringW;
-               }
-               for (   len = 0;
-                       (!format->precision || (len < format->precision));
-                       len++
-                       )
-               {
-                   if (!*(*(LPCWSTR *)arg + len))
-                           break;
-               }
-               if (len > maxlen)
-               {
-                       len = maxlen;
-               }
-               return (format->precision = len);
-               
-       case WPR_SIGNED:
-               len = sprintf(
-                       number,
-                       "%d",
-                       *(INT *) arg
-                       );
-               break;
-               
-       case WPR_UNSIGNED:
-               len = sprintf(
-                       number,
-                       "%u",
-                       *(UINT *) arg
-                       );
-               break;
-               
-       case WPR_HEXA:
-               len = sprintf(
-                       number,
-                        ((format->flags & WPRINTF_UPPER_HEX)
-                               ? "%X"
-                               : "%x"),
-                        *(UINT *) arg
-                       );
-               if (format->flags & WPRINTF_PREFIX_HEX)
-               {
-                       len += 2;
-               }
-               break;
-       
-       default:
-               return 0;
-       }
-       if (len > maxlen)
-       {
-               len = maxlen;
-       }
-       if (format->precision < len)
-       {
-               format->precision = len;
-       }
-       if (format->precision > maxlen)
-       {
-               format->precision = maxlen;
-       }
-       if (    (format->flags & WPRINTF_ZEROPAD)
-               && (format->width > format->precision)
-               )
-       {
-               format->precision = format->width;
-       }
-       return len;
+    LPCSTR p = format;
+
+    res->flags = 0;
+    res->width = 0;
+    res->precision = 0;
+    if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
+    if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
+    if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
+    while ((*p >= '0') && (*p <= '9'))  /* width field */
+    {
+        res->width = res->width * 10 + *p - '0';
+        p++;
+    }
+    if (*p == '.')  /* precision field */
+    {
+        p++;
+        while ((*p >= '0') && (*p <= '9'))
+        {
+            res->precision = res->precision * 10 + *p - '0';
+            p++;
+        }
+    }
+    if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
+    else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
+    else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
+    switch(*p)
+    {
+    case 'c':
+        res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
+        break;
+    case 'C':
+        res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
+        break;
+    case 'd':
+    case 'i':
+        res->type = WPR_SIGNED;
+        break;
+    case 's':
+        res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
+        break;
+    case 'S':
+        res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
+        break;
+    case 'u':
+        res->type = WPR_UNSIGNED;
+        break;
+    case 'p':
+        res->width = 8;
+        res->flags |= WPRINTF_ZEROPAD;
+        /* fall through */
+    case 'X':
+        res->flags |= WPRINTF_UPPER_HEX;
+        /* fall through */
+    case 'x':
+        res->type = WPR_HEXA;
+        break;
+    default: /* unknown format char */
+        res->type = WPR_UNKNOWN;
+        p--;  /* print format as normal char */
+        break;
+    }
+    return (INT)(p - format) + 1;
 }
 
 
-/* === ANSI VERSION === */
-
-
 /***********************************************************************
- * NAME                                                                PRIVATE
- *     WPRINTF_ParseFormatA
- *
- * DESCRIPTION
- *     Parse a format specification. A format specification has the
- *     form:
+ *           WPRINTF_ParseFormatW
  *
- *     [-][#][0][width][.precision]type
+ * Parse a format specification. A format specification has the form:
  *
- * ARGUMENTS
- *     format
- *             ?
- *     res
- *             ?
+ * [-][#][0][width][.precision]type
  *
- * RETURN VALUE
- *     The length of the format specification in characters.
+ * Return value is the length of the format specification in characters.
  */
-static
-INT
-WPRINTF_ParseFormatA(
-       LPCSTR          format,
-       WPRINTF_FORMAT  *res
-       )
+static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
 {
-       LPCSTR p = format;
-
-       res->flags = 0;
-       res->width = 0;
-       res->precision = 0;
-       if (*p == '-')
-       {
-               res->flags |= WPRINTF_LEFTALIGN;
-               p++;
-       }
-       if (*p == '#')
-       {
-               res->flags |= WPRINTF_PREFIX_HEX;
-               p++;
-       }
-       if (*p == '0')
-       {
-               res->flags |= WPRINTF_ZEROPAD;
-               p++;
-       }
-       while ((*p >= '0') && (*p <= '9'))  /* width field */
-       {
-               res->width =
-                       (res->width * 10)
-                       + (*p - '0');
-               p++;
-       }
-       if (*p == '.')  /* precision field */
-       {
-               p++;
-               while ((*p >= '0') && (*p <= '9'))
-               {
-                       res->precision =
-                               (res->precision * 10)
-                               + (*p - '0');
-                       p++;
-               }
-       }
-       if (*p == 'l')
-       {
-               res->flags |= WPRINTF_LONG;
-               p++;
-       }
-       else if (*p == 'h')
-       {
-               res->flags |= WPRINTF_SHORT;
-               p++;
-       }
-       else if (*p == 'w')
-       {
-               res->flags |= WPRINTF_WIDE;
-               p++;
-       }
-       
-       switch (*p)
-       {
-       case 'c':
-               res->type =
-                       (res->flags & WPRINTF_LONG)
-                               ? WPR_WCHAR
-                               : WPR_CHAR;
-               break;
-               
-       case 'C':
-               res->type =
-                       (res->flags & WPRINTF_SHORT)
-                               ? WPR_CHAR
-                               : WPR_WCHAR;
-               break;
-               
-       case 'd':
-       case 'i':
-               res->type = WPR_SIGNED;
-               break;
-               
-       case 's':
-               res->type =
-                       (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) 
-                               ? WPR_WSTRING
-                               : WPR_STRING;
-               break;
-               
-       case 'S':
-               res->type =
-                       (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE))
-                               ? WPR_STRING
-                               : WPR_WSTRING;
-               break;
-               
-       case 'u':
-               res->type = WPR_UNSIGNED;
-               break;
-               
-       case 'X':
-               res->flags |= WPRINTF_UPPER_HEX;
-               /* fall through */
-               
-       case 'x':
-               res->type = WPR_HEXA;
-               break;
-               
-       default: /* unknown format char */
-               res->type = WPR_UNKNOWN;
-               p--;  /* print format as normal char */
-               break;
-
-       } /* switch */
-       
-       return (INT) (p - format) + 1;
+    LPCWSTR p = format;
+
+    res->flags = 0;
+    res->width = 0;
+    res->precision = 0;
+    if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
+    if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
+    if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
+    while ((*p >= '0') && (*p <= '9'))  /* width field */
+    {
+        res->width = res->width * 10 + *p - '0';
+        p++;
+    }
+    if (*p == '.')  /* precision field */
+    {
+        p++;
+        while ((*p >= '0') && (*p <= '9'))
+        {
+            res->precision = res->precision * 10 + *p - '0';
+            p++;
+        }
+    }
+    if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
+    else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
+    else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
+    switch((CHAR)*p)
+    {
+    case 'c':
+        res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
+        break;
+    case 'C':
+        res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
+        break;
+    case 'd':
+    case 'i':
+        res->type = WPR_SIGNED;
+        break;
+    case 's':
+        res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
+        break;
+    case 'S':
+        res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
+        break;
+    case 'u':
+        res->type = WPR_UNSIGNED;
+        break;
+    case 'p':
+        res->width = 8;
+        res->flags |= WPRINTF_ZEROPAD;
+        /* fall through */
+    case 'X':
+        res->flags |= WPRINTF_UPPER_HEX;
+        /* fall through */
+    case 'x':
+        res->type = WPR_HEXA;
+        break;
+    default:
+        res->type = WPR_UNKNOWN;
+        p--;  /* print format as normal char */
+        break;
+    }
+    return (INT)(p - format) + 1;
 }
 
 
 /***********************************************************************
- * NAME                                                                PRIVATE
- *     wvsnprintfA   (Not a Windows API)
+ *           WPRINTF_GetLen
  */
-INT
-STDCALL
-wvsnprintfA(
-       LPSTR   buffer,
-       UINT    maxlen,
-       LPCSTR  spec,
-       va_list args
-       )
+static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg,
+                              LPSTR number, UINT maxlen )
 {
-       WPRINTF_FORMAT  format;
-       LPSTR           p = buffer;
-       UINT            i;
-       UINT            len;
-       CHAR            number [20];
+    UINT len;
+
+    if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
+    if (format->width > maxlen) format->width = maxlen;
+    switch(format->type)
+    {
+    case WPR_CHAR:
+    case WPR_WCHAR:
+        return (format->precision = 1);
+    case WPR_STRING:
+        if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA;
+        for (len = 0; !format->precision || (len < format->precision); len++)
+            if (!*(arg->lpcstr_view + len)) break;
+        if (len > maxlen) len = maxlen;
+        return (format->precision = len);
+    case WPR_WSTRING:
+        if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW;
+        for (len = 0; !format->precision || (len < format->precision); len++)
+            if (!*(arg->lpcwstr_view + len)) break;
+        if (len > maxlen) len = maxlen;
+        return (format->precision = len);
+    case WPR_SIGNED:
+        len = sprintf( number, "%d", arg->int_view );
+        break;
+    case WPR_UNSIGNED:
+        len = sprintf( number, "%u", (UINT)arg->int_view );
+        break;
+    case WPR_HEXA:
+        len = sprintf( number,
+                       (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x",
+                       (UINT)arg->int_view);
+        break;
+    default:
+        return 0;
+    }
+    if (len > maxlen) len = maxlen;
+    if (format->precision < len) format->precision = len;
+    if (format->precision > maxlen) format->precision = maxlen;
+    if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision))
+        format->precision = format->width;
+    if (format->flags & WPRINTF_PREFIX_HEX) len += 2;
+    return len;
+}
 
-       while (*spec && (maxlen > 1))
-       {
-               if (*spec != '%')
-               {
-                       *p++ = *spec++;
-                       maxlen--;
-                       continue;
-               }
-               spec++;
-               if (*spec == '%')
-               {
-                       *p++ = *spec++;
-                       maxlen--;
-                       continue;
-               }
-               spec += WPRINTF_ParseFormatA(
-                               spec,
-                               & format
-                               );
-               len = WPRINTF_GetLen(
-                               & format,
-                               args,
-                               number,
-                               (maxlen - 1)
-                               );
-               if (!(format.flags & WPRINTF_LEFTALIGN))
-               {
-                       for (   i = format.precision;
-                               (i < format.width);
-                               i++, maxlen--
-                               )
-                       {
-                               *p++ = ' ';
-                       }
-               }
-               switch (format.type)
-               {
-               case WPR_WCHAR:
-                       if ((*p = (CHAR) (WCHAR) va_arg( args, int)))
-                       {
-                               p++;
-                       }
-                       else if (format.width > 1)
-                       {
-                               *p++ = ' ';
-                       }
-                       else
-                       {
-                               len = 0;
-                       }
-                       break;
-                       
-               case WPR_CHAR:
-                       if ((*p = (CHAR) va_arg( args, int )))
-                       {
-                               p++;
-                       }
-                       else if (format.width > 1)
-                       {
-                               *p++ = ' ';
-                       }
-                       else
-                       {
-                               len = 0;
-                       }
-                       break;
-                       
-               case WPR_STRING:
-                       memcpy(
-                               p,
-                               va_arg( args, LPCSTR ),
-                               len
-                               );
-                       p += len;
-                       break;
-                       
-               case WPR_WSTRING:
-               {
-                       LPCWSTR ptr = va_arg( args, LPCWSTR );
-                       
-                       for (   i = 0;
-                               (i < len);
-                               i++
-                               )
-                       {
-                               *p++ = (CHAR) *ptr++;
-                       }
-               }
-                       break;
-               
-               case WPR_HEXA:
-                       if (    (format.flags & WPRINTF_PREFIX_HEX)
-                               && (maxlen > 3)
-                               )
-                       {
-                               *p++ = '0';
-                               *p++ = (format.flags & WPRINTF_UPPER_HEX)
-                                       ? 'X'
-                                       : 'x';
-                               maxlen -= 2;
-                               len -= 2;
-                               format.precision -= 2;
-                               format.width -= 2;
-                       }
-                       /* fall through */
-                       
-               case WPR_SIGNED:
-               case WPR_UNSIGNED:
-                       for (   i = len;
-                               (i < format.precision);
-                               i++, maxlen--
-                               )
-                       {
-                               *p++ = '0';
-                       }
-                       memcpy(
-                               p,
-                               number,
-                               len
-                               );
-                       p += len;
-                       (void) va_arg( args, INT ); /* Go to the next arg */
-                       break;
-                       
-               case WPR_UNKNOWN:
-                       continue;
-               } /* switch */
-               
-               if (format.flags & WPRINTF_LEFTALIGN)
-               {
-                       for (   i = format.precision;
-                               (i < format.width);
-                               i++, maxlen--
-                               )
-                       {
-                               *p++ = ' ';
-                       }
-               }
-               maxlen -= len;
-       } /* while */
-       
-       *p = '\0';
-       return (maxlen > 1)
-               ? (INT) (p - buffer)
-               : -1;
+/***********************************************************************
+ *           wvsnprintfA   (internal)
+ */
+static INT wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, va_list args )
+{
+    WPRINTF_FORMAT format;
+    LPSTR p = buffer;
+    UINT i, len, sign;
+    CHAR number[20];
+    WPRINTF_DATA argData;
+
+    //TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec));
+
+    while (*spec && (maxlen > 1))
+    {
+        if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
+        spec++;
+        if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
+        spec += WPRINTF_ParseFormatA( spec, &format );
+
+        switch(format.type)
+        {
+        case WPR_WCHAR:
+            argData.wchar_view = (WCHAR)va_arg( args, int );
+            break;
+        case WPR_CHAR:
+            argData.char_view = (CHAR)va_arg( args, int );
+            break;
+        case WPR_STRING:
+            argData.lpcstr_view = va_arg( args, LPCSTR );
+            break;
+        case WPR_WSTRING:
+            argData.lpcwstr_view = va_arg( args, LPCWSTR );
+            break;
+        case WPR_HEXA:
+        case WPR_SIGNED:
+        case WPR_UNSIGNED:
+            argData.int_view = va_arg( args, INT );
+            break;
+        default:
+            argData.wchar_view = 0;
+            break;
+        }
+
+        len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
+        sign = 0;
+        if (!(format.flags & WPRINTF_LEFTALIGN))
+            for (i = format.precision; i < format.width; i++, maxlen--)
+                *p++ = ' ';
+        switch(format.type)
+        {
+        case WPR_WCHAR:
+            *p++ = argData.wchar_view;
+            break;
+        case WPR_CHAR:
+            *p++ = argData.char_view;
+            break;
+        case WPR_STRING:
+            memcpy( p, argData.lpcstr_view, len );
+            p += len;
+            break;
+        case WPR_WSTRING:
+            {
+                LPCWSTR ptr = argData.lpcwstr_view;
+                for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
+            }
+            break;
+        case WPR_HEXA:
+            if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
+            {
+                *p++ = '0';
+                *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
+                maxlen -= 2;
+                len -= 2;
+            }
+            /* fall through */
+        case WPR_SIGNED:
+            /* Transfer the sign now, just in case it will be zero-padded*/
+            if (number[0] == '-')
+            {
+                *p++ = '-';
+                sign = 1;
+            }
+            /* fall through */
+        case WPR_UNSIGNED:
+            for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
+            memcpy( p, number + sign, len - sign  );
+            p += len - sign;
+            break;
+        case WPR_UNKNOWN:
+            continue;
+        }
+        if (format.flags & WPRINTF_LEFTALIGN)
+            for (i = format.precision; i < format.width; i++, maxlen--)
+                *p++ = ' ';
+        maxlen -= len;
+    }
+    *p = 0;
+    //TRACE("%s\n",debugstr_a(buffer));
+    return (maxlen > 1) ? (INT)(p - buffer) : -1;
 }
 
 
 /***********************************************************************
- * NAME                                                                PUBLIC
- *     wsprintfA   (USER32.585)
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
+ *           wvsnprintfW   (internal)
  */
-INT
-CDECL
-wsprintfA(
-       LPSTR   buffer,
-       LPCSTR  spec,
-       ...
-       )
+static INT wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, va_list args )
 {
-       va_list valist;
-       INT     res;
-
-       va_start( valist, spec );
-       res = wvsnprintfA(
-                       buffer,
-                       0xffffffff,
-                       spec,
-                       valist
-                       );
-       va_end( valist );
-       return res;
+    WPRINTF_FORMAT format;
+    LPWSTR p = buffer;
+    UINT i, len, sign;
+    CHAR number[20];
+    WPRINTF_DATA argData;
+
+    //TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec));
+
+    while (*spec && (maxlen > 1))
+    {
+        if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
+        spec++;
+        if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
+        spec += WPRINTF_ParseFormatW( spec, &format );
+
+        switch(format.type)
+        {
+        case WPR_WCHAR:
+            argData.wchar_view = (WCHAR)va_arg( args, int );
+            break;
+        case WPR_CHAR:
+            argData.char_view = (CHAR)va_arg( args, int );
+            break;
+        case WPR_STRING:
+            argData.lpcstr_view = va_arg( args, LPCSTR );
+            break;
+        case WPR_WSTRING:
+            argData.lpcwstr_view = va_arg( args, LPCWSTR );
+            break;
+        case WPR_HEXA:
+        case WPR_SIGNED:
+        case WPR_UNSIGNED:
+            argData.int_view = va_arg( args, INT );
+            break;
+        default:
+            argData.wchar_view = 0;
+            break;
+        }
+
+        len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
+        sign = 0;
+        if (!(format.flags & WPRINTF_LEFTALIGN))
+            for (i = format.precision; i < format.width; i++, maxlen--)
+                *p++ = ' ';
+        switch(format.type)
+        {
+        case WPR_WCHAR:
+            *p++ = argData.wchar_view;
+            break;
+        case WPR_CHAR:
+            *p++ = argData.char_view;
+            break;
+        case WPR_STRING:
+            {
+                LPCSTR ptr = argData.lpcstr_view;
+                for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
+            }
+            break;
+        case WPR_WSTRING:
+            if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) );
+            p += len;
+            break;
+        case WPR_HEXA:
+            if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
+            {
+                *p++ = '0';
+                *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
+                maxlen -= 2;
+                len -= 2;
+            }
+            /* fall through */
+        case WPR_SIGNED:
+            /* Transfer the sign now, just in case it will be zero-padded*/
+            if (number[0] == '-')
+            {
+                *p++ = '-';
+                sign = 1;
+            }
+            /* fall through */
+        case WPR_UNSIGNED:
+            for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
+            for (i = sign; i < len; i++) *p++ = (WCHAR)number[i];
+            break;
+        case WPR_UNKNOWN:
+            continue;
+        }
+        if (format.flags & WPRINTF_LEFTALIGN)
+            for (i = format.precision; i < format.width; i++, maxlen--)
+                *p++ = ' ';
+        maxlen -= len;
+    }
+    *p = 0;
+    //TRACE("%s\n",debugstr_w(buffer));
+    return (maxlen > 1) ? (INT)(p - buffer) : -1;
 }
 
-
 /***********************************************************************
- * NAME                                                                PUBLIC
- *     wvsprintfA   (USER32.587)
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
+ *           wvsprintfA   (USER32.@)
+ * @implemented
  */
-INT
-STDCALL
-wvsprintfA(
-       LPSTR   buffer,
-       LPCSTR  spec,
-       va_list args
-       )
+INT STDCALL wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
 {
-       return wvsnprintfA(
-                       buffer,
-                       0xffffffff,
-                       spec,
-                       args
-                       );
+    INT res = wvsnprintfA( buffer, 1024, spec, args );
+    return ( res == -1 ) ? 1024 : res;
 }
 
 
-/* === UNICODE VERSION === */
+/***********************************************************************
+ *           wvsprintfW   (USER32.@)
+ * @implemented
+ */
+INT STDCALL wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
+{
+    INT res = wvsnprintfW( buffer, 1024, spec, args );
+    return ( res == -1 ) ? 1024 : res;
+}
+
+/***********************************************************************
+ *           wsprintfA   (USER32.@)
+ * @implemented
+ */
+INT CDECL wsprintfA( LPSTR buffer, LPCSTR spec, ... )
+{
+    va_list valist;
+    INT res;
 
+    va_start( valist, spec );
+    res = wvsnprintfA( buffer, 1024, spec, valist );
+    va_end( valist );
+    return ( res == -1 ) ? 1024 : res;
+}
 
 /***********************************************************************
- * NAME                                                                PRIVATE
- *     WPRINTF_ParseFormatW
- *
- * DESCRIPTION
- *     Parse a format specification. A format specification has
- *     the form:
- *
- *     [-][#][0][width][.precision]type
- *
- * ARGUMENTS
- *     format
- *             ?
- *     res
- *             ?
- *
- * RETURN VALUE
- *     The length of the format specification in characters.
+ *           wsprintfW   (USER32.@)
+ * @implemented
  */
-static
-INT
-WPRINTF_ParseFormatW(
-       LPCWSTR         format,
-       WPRINTF_FORMAT  *res
-       )
+INT CDECL wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
 {
-       LPCWSTR p = format;
+    va_list valist;
+    INT res;
 
-       res->flags = 0;
-       res->width = 0;
-       res->precision = 0;
-       if (*p == L'-')
-       {
-               res->flags |= WPRINTF_LEFTALIGN;
-               p++;
-       }
-       if (*p == L'#')
-       {
-               res->flags |= WPRINTF_PREFIX_HEX;
-               p++;
-       }
-       if (*p == L'0')
-       {
-               res->flags |= WPRINTF_ZEROPAD;
-               p++;
-       }
-       
-       while ((*p >= L'0') && (*p <= L'9'))  /* width field */
+    va_start( valist, spec );
+    res = wvsnprintfW( buffer, 1024, spec, valist );
+    va_end( valist );
+    return ( res == -1 ) ? 1024 : res;
+}
+/*
+ * @implemented
+ */
+DWORD STDCALL WCSToMBEx(WORD CodePage,LPWSTR UnicodeString,LONG UnicodeSize,LPSTR *MBString,LONG MBSize,BOOL Allocate)
+{
+       DWORD Size;
+       if (UnicodeSize == -1)
        {
-               res->width = 
-                       (res->width * 10)
-                       + (*p - L'0');
-               p++;
+               UnicodeSize = wcslen(UnicodeString)+1;
        }
-
-       if (*p == L'.')  /* precision field */
+       if (MBSize == -1)
        {
-               p++;
-               while ((*p >= L'0') && (*p <= L'9'))
+               if (!Allocate)
                {
-                       res->precision =
-                               (res->precision * 10)
-                               + (*p - '0');
-                       p++;
+                       return 0;
                }
+               MBSize = UnicodeSize * 2;
        }
-       if (*p == L'l')
+       if (Allocate)
        {
-               res->flags |= WPRINTF_LONG;
-               p++;
+               *MBString = HEAP_alloc(MBSize);
        }
-       else if (*p == L'h')
+       if ((CodePage == 0) || (CodePage == NLS_ANSI_CODE_PAGE))
        {
-               res->flags |= WPRINTF_SHORT;
-               p++;
+               RtlUnicodeToMultiByteN(*MBString,MBSize,&Size,UnicodeString,UnicodeSize);
        }
-       else if (*p == L'w')
+       else
        {
-               res->flags |= WPRINTF_WIDE;
-               p++;
+               WideCharToMultiByte(CodePage,0,UnicodeString,UnicodeSize,*MBString,MBSize,0,0);
        }
-       
-       switch ((CHAR)*p)
-       {
-       case L'c':
-               res->type =
-                       (res->flags & WPRINTF_SHORT)
-                               ? WPR_CHAR
-                               : WPR_WCHAR;
-               break;
-               
-       case L'C':
-               res->type =
-                       (res->flags & WPRINTF_LONG)
-                               ? WPR_WCHAR
-                               : WPR_CHAR;
-               break;
-               
-       case L'd':
-       case L'i':
-               res->type = WPR_SIGNED;
-               break;
-               
-       case L's':
-               res->type =
-                       ((res->flags & WPRINTF_SHORT)
-                        && !(res->flags & WPRINTF_WIDE)
-                       )
-                               ? WPR_STRING
-                               : WPR_WSTRING;
-               break;
-               
-       case L'S':
-               res->type =
-                       (res->flags & (WPRINTF_LONG | WPRINTF_WIDE))
-                               ? WPR_WSTRING
-                               : WPR_STRING;
-               break;
-               
-       case L'u':
-               res->type = WPR_UNSIGNED;
-               break;
-               
-       case L'X':
-               res->flags |= WPRINTF_UPPER_HEX;
-               /* fall through */
-               
-       case L'x':
-               res->type = WPR_HEXA;
-               break;
-               
-       default:
-               res->type = WPR_UNKNOWN;
-               p--;  /* print format as normal char */
-               break;
-       } /* switch */
-       
-       return (INT) (p - format) + 1;
+       return UnicodeSize;
 }
-
-
-/***********************************************************************
- * NAME                                                                PRIVATE
- *           wvsnprintfW   (Not a Windows API)
+/*
+ * @implemented
  */
-INT
-wvsnprintfW(
-       LPWSTR  buffer,
-       UINT    maxlen,
-       LPCWSTR spec,
-       va_list args
-       )
+DWORD STDCALL MBToWCSEx(WORD CodePage,LPSTR MBString,LONG MBSize,LPWSTR *UnicodeString,LONG UnicodeSize,BOOL Allocate)
 {
-       WPRINTF_FORMAT  format;
-       LPWSTR          p = buffer;
-       UINT            i;
-       UINT            len;
-       CHAR            number [20];
-
-       while (*spec && (maxlen > 1))
+       DWORD Size;
+       if (MBSize == -1)
        {
-               if (*spec != L'%')
-               {
-                       *p++ = *spec++;
-                       maxlen--;
-                       continue;
-               }
-               spec++;
-               if (*spec == L'%')
-               {
-                       *p++ = *spec++;
-                       maxlen--;
-                       continue;
-               }
-               spec += WPRINTF_ParseFormatW(
-                               spec,
-                               & format
-                               );
-               len = WPRINTF_GetLen(
-                               & format,
-                               args,
-                               number,
-                               (maxlen - 1)
-                               );
-               if (!(format.flags & WPRINTF_LEFTALIGN))
-               {
-                       for (   i = format.precision;
-                               (i < format.width);
-                               i++, maxlen--
-                               )
-                       {
-                               *p++ = L' ';
-                       }
-               }
-               switch (format.type)
-               {
-               case WPR_WCHAR:
-                       if ((*p = (WCHAR) va_arg( args, int)))
-                       {
-                               p++;
-                       }
-                       else if (format.width > 1)
-                       {
-                               *p++ = L' ';
-                       }
-                       else
-                       {
-                               len = 0;
-                       }
-                       break;
-                       
-               case WPR_CHAR:
-                       if ((*p = (WCHAR)(CHAR) va_arg( args, int )))
-                       {
-                               p++;
-                       }
-                       else if (format.width > 1)
-                       {
-                               *p++ = L' ';
-                       }
-                       else
-                       {
-                               len = 0;
-                       }
-                       break;
-                       
-               case WPR_STRING:
-               {
-                       LPCSTR ptr = va_arg( args, LPCSTR );
-                       
-                       for (   i = 0;
-                               (i < len);
-                               i++
-                               )
-                       {
-                               *p++ = (WCHAR) *ptr++;
-                       }
-               }
-                       break;
-                       
-               case WPR_WSTRING:
-                       if (len)
-                       {
-                               memcpy(
-                                       p,
-                                       va_arg( args, LPCWSTR ),
-                                       (len * sizeof (WCHAR))
-                                       );
-                       }
-                       p += len;
-                       break;
-                       
-               case WPR_HEXA:
-                       if (    (format.flags & WPRINTF_PREFIX_HEX)
-                               && (maxlen > 3)
-                               )
-                       {
-                               *p++ = L'0';
-                               *p++ = (format.flags & WPRINTF_UPPER_HEX)
-                                       ? L'X'
-                                       : L'x';
-                               maxlen -= 2;
-                               len -= 2;
-                               format.precision -= 2;
-                               format.width -= 2;
-                       }
-                       /* fall through */
-                       
-               case WPR_SIGNED:
-               case WPR_UNSIGNED:
-                       for (   i = len;
-                               (i < format.precision);
-                               i++, maxlen--
-                               )
-                       {
-                               *p++ = L'0';
-                       }
-                       for (   i = 0;
-                               (i < len);
-                               i++
-                               )
-                       {
-                               *p++ = (WCHAR) number[i];
-                       }
-                       (void) va_arg( args, INT ); /* Go to the next arg */
-                       break;
-                       
-               case WPR_UNKNOWN:
-                       continue;
-               } /* switch */
-
-               if (format.flags & WPRINTF_LEFTALIGN)
+               MBSize = strlen(MBString)+1;
+       }
+       if (UnicodeSize == -1)
+       {
+               if (!Allocate)
                {
-                       for (   i = format.precision;
-                               (i < format.width);
-                               i++, maxlen--
-                               )
-                       {
-                               *p++ = L' ';
-                       }
+                       return 0;
                }
-               maxlen -= len;
-       } /* while */
-       
-       *p = L'\0';
-       return (maxlen > 1)
-               ? (INT) (p - buffer)
-               : -1;
-}
-
-
-/***********************************************************************
- * NAME                                                                PUBLIC
- *     wsprintfW   (USER32.586)
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- */
-INT
-CDECL
-wsprintfW(
-       LPWSTR  buffer,
-       LPCWSTR spec,
-       ...
-       )
-{
-       va_list valist;
-       INT     res;
-
-       va_start( valist, spec );
-       res = wvsnprintfW(
-                       buffer,
-                       0xffffffff,
-                       spec,
-                       valist
-                       );
-       va_end( valist );
-       return res;
+               UnicodeSize = MBSize;
+       }
+       if (Allocate)
+       {
+               *UnicodeString = HEAP_alloc(UnicodeSize);
+       }
+       UnicodeSize *= sizeof(WCHAR);
+       if ((CodePage == 0) || (CodePage == NLS_ANSI_CODE_PAGE))
+       {
+               RtlMultiByteToUnicodeN(*UnicodeString,UnicodeSize,&Size,MBString,MBSize);
+       }
+       else
+       {
+               Size = MultiByteToWideChar(CodePage,0,MBString,MBSize,*UnicodeString,UnicodeSize);
+       }
+       return Size;
 }
-
-
-/***********************************************************************
- * NAME                                                                PUBLIC
- *           wvsprintfW   (USER32.588)
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
+const LPWSTR strings[14] = {L"OK",L"Cancel",L"&Abort",L"&Retry",L"&Ignore",L"&Yes",L"&No",L"&Close",L"Help",L"&Try Again",L"&Continue"};
+/*
+ * @implemented
  */
-INT
-STDCALL
-wvsprintfW(
-       LPWSTR  buffer,
-       LPCWSTR spec,
-       va_list args
-       )
+LPWSTR STDCALL MB_GetString(DWORD string)
 {
-       return wvsnprintfW(
-                       buffer,
-                       0xffffffff,
-                       spec,
-                       args
-                       );
+       return heap_string_poolW(strings[string],wcslen(strings[string]));
 }
-
-
-/* EOF */
-