Implement new versions of wctomb and wcstombs, which consider =

Colin Finck mail at colinfinck.de
Sun Jul 27 16:52:31 CDT 2008


the language set by setlocale() and work according to all behaviours I =
could find when testing under WinXP SP2.=0A=
=0A=
---=0A=
 dlls/msvcrt/locale.c    |    5 +-=0A=
 dlls/msvcrt/msvcrt.h    |    3 +=0A=
 dlls/msvcrt/msvcrt.spec |    2 +-=0A=
 dlls/msvcrt/wcs.c       |  120 =
++++++++++++++++++++++++++++++++++++++++++++++-=0A=
 4 files changed, 124 insertions(+), 6 deletions(-)=0A=
=0A=
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c=0A=
index 6447436..d2dd5e6 100644=0A=
--- a/dlls/msvcrt/locale.c=0A=
+++ b/dlls/msvcrt/locale.c=0A=
@@ -42,7 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);=0A=
  * string to produce lc_all.=0A=
  */=0A=
 #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */=0A=
-#define MAX_LOCALE_LENGTH 256=0A=
 char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH] =3D { 0 };=0A=
 LCID MSVCRT_current_lc_all_lcid =3D 0;=0A=
 int MSVCRT___lc_codepage =3D 0;=0A=
@@ -344,8 +343,8 @@ char* CDECL MSVCRT_setlocale(int category, const =
char* locale)=0A=
   {=0A=
     MSVCRT_current_lc_all[0] =3D 'C';=0A=
     MSVCRT_current_lc_all[1] =3D '\0';=0A=
-    MSVCRT___lc_codepage =3D GetACP();=0A=
-    MSVCRT___lc_collate_cp =3D GetACP();=0A=
+    MSVCRT___lc_codepage =3D 1252;=0A=
+    MSVCRT___lc_collate_cp =3D 1252;=0A=
 =0A=
     switch (category) {=0A=
     case MSVCRT_LC_ALL:=0A=
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h=0A=
index b9aea53..6ac5c19 100644=0A=
--- a/dlls/msvcrt/msvcrt.h=0A=
+++ b/dlls/msvcrt/msvcrt.h=0A=
@@ -112,6 +112,8 @@ typedef struct __thread_data thread_data_t;=0A=
 =0A=
 extern thread_data_t *msvcrt_get_thread_data(void);=0A=
 =0A=
+#define MAX_LOCALE_LENGTH 256=0A=
+extern char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH];=0A=
 extern int MSVCRT___lc_codepage;=0A=
 =0A=
 void   msvcrt_set_errno(int);=0A=
@@ -576,6 +578,7 @@ struct MSVCRT__stat64 {=0A=
 #define MSVCRT__PC_64         0x00000000=0A=
 =0A=
 #define MSVCRT_CLOCKS_PER_SEC 1000=0A=
+#define MSVCRT_MB_LEN_MAX 2=0A=
 =0A=
 /* signals */=0A=
 #define MSVCRT_SIGINT   2=0A=
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec=0A=
index ecdce4f..8a8b5f2 100644=0A=
--- a/dlls/msvcrt/msvcrt.spec=0A=
+++ b/dlls/msvcrt/msvcrt.spec=0A=
@@ -779,7 +779,7 @@=0A=
 @ cdecl wcstod(wstr ptr) MSVCRT_wcstod=0A=
 @ cdecl wcstok(wstr wstr) MSVCRT_wcstok=0A=
 @ cdecl wcstol(wstr ptr long) ntdll.wcstol=0A=
-@ cdecl wcstombs(ptr ptr long) ntdll.wcstombs=0A=
+@ cdecl wcstombs(ptr ptr long) MSVCRT_wcstombs=0A=
 @ cdecl wcstoul(wstr ptr long) ntdll.wcstoul=0A=
 @ stub wcsxfrm #(ptr wstr long) MSVCRT_wcsxfrm=0A=
 @ cdecl wctomb(ptr long) MSVCRT_wctomb=0A=
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c=0A=
index 8eccb39..1e859ff 100644=0A=
--- a/dlls/msvcrt/wcs.c=0A=
+++ b/dlls/msvcrt/wcs.c=0A=
@@ -922,9 +922,125 @@ MSVCRT_wchar_t * CDECL MSVCRT_wcstok( =
MSVCRT_wchar_t *str, const MSVCRT_wchar_t=0A=
 /*********************************************************************=0A=
  *		wctomb (MSVCRT.@)=0A=
  */=0A=
-INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )=0A=
+INT CDECL MSVCRT_wctomb(char *mbchar, MSVCRT_wchar_t wchar)=0A=
 {=0A=
-  return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );=0A=
+    BOOL bUsedDefaultChar;=0A=
+    char chMultiByte[MSVCRT_MB_LEN_MAX];=0A=
+    int nBytes;=0A=
+=0A=
+    /* At least one parameter needs to be given, the length of a null =
character cannot be queried (verified by tests under WinXP SP2) */=0A=
+    if(!mbchar && !wchar)=0A=
+        return 0;=0A=
+=0A=
+    /* Use WideCharToMultiByte for doing the conversion using the =
codepage currently set with setlocale() */=0A=
+    nBytes =3D WideCharToMultiByte(MSVCRT___lc_codepage, 0, &wchar, 1, =
chMultiByte, MSVCRT_MB_LEN_MAX, NULL, &bUsedDefaultChar);=0A=
+=0A=
+    /* Only copy the character if an 'mbchar' pointer was given.=0A=
+=0A=
+       The "C" locale is emulated with codepage 1252 here. This =
codepage has a default character "?", but the "C" locale doesn't have =
one.=0A=
+       Therefore don't copy the character in this case. */=0A=
+    if(mbchar && !(MSVCRT_current_lc_all[0] =3D=3D 'C' && =
!MSVCRT_current_lc_all[1] && bUsedDefaultChar))=0A=
+        memcpy(mbchar, chMultiByte, nBytes);=0A=
+=0A=
+    /* If the default character was used, set errno to EILSEQ and =
return -1. */=0A=
+    if(bUsedDefaultChar)=0A=
+    {=0A=
+        *MSVCRT__errno() =3D MSVCRT_EILSEQ;=0A=
+        return -1;=0A=
+    }=0A=
+=0A=
+    /* Otherwise return the number of bytes this character occupies. */=0A=
+    return nBytes;=0A=
+}=0A=
+=0A=
+/*********************************************************************=0A=
+ *		wcstombs (MSVCRT.@)=0A=
+ */=0A=
+size_t CDECL MSVCRT_wcstombs(char *mbstr, const MSVCRT_wchar_t *wcstr, =
size_t count)=0A=
+{=0A=
+    BOOL bUsedDefaultChar;=0A=
+    char* p =3D mbstr;=0A=
+    int nResult;=0A=
+=0A=
+    /* Does the caller query for output buffer size? */=0A=
+    if(!mbstr)=0A=
+    {=0A=
+        int nLength;=0A=
+=0A=
+        /* If we currently use the "C" locale, the length of the input =
string is returned (verified by tests under WinXP SP2) */=0A=
+        if(MSVCRT_current_lc_all[0] =3D=3D 'C' && =
!MSVCRT_current_lc_all[1])=0A=
+            return strlenW(wcstr);=0A=
+=0A=
+        /* Otherwise check the length each character needs and build a =
final return value out of this */=0A=
+        count =3D strlenW(wcstr);=0A=
+        nLength =3D 0;=0A=
+=0A=
+        while((int)(--count) >=3D 0 && *wcstr)=0A=
+        {=0A=
+            /* Get the length of this character */=0A=
+            nResult =3D MSVCRT_wctomb(NULL, *wcstr++);=0A=
+=0A=
+            /* If this character is not convertible in the current =
locale, the end result will be -1 */=0A=
+            if(nResult =3D=3D -1)=0A=
+                return -1;=0A=
+=0A=
+            nLength +=3D nResult;=0A=
+        }=0A=
+=0A=
+        /* Return the final length */=0A=
+        return nLength;=0A=
+    }=0A=
+=0A=
+    /* Convert the string then */=0A=
+    bUsedDefaultChar =3D FALSE;=0A=
+=0A=
+    for(;;)=0A=
+    {=0A=
+        char chMultiByte[MSVCRT_MB_LEN_MAX];=0A=
+        UINT uLength;=0A=
+=0A=
+        /* Are we at the terminating null character? */=0A=
+        if(!*wcstr)=0A=
+        {=0A=
+            /* Set the null character, but don't increment the pointer =
as the returned length never includes the terminating null character */=0A=
+            *p =3D 0;=0A=
+            break;=0A=
+        }=0A=
+=0A=
+        /* Convert this character into the temporary chMultiByte =
variable */=0A=
+        ZeroMemory(chMultiByte, MSVCRT_MB_LEN_MAX);=0A=
+        nResult =3D MSVCRT_wctomb(chMultiByte, *wcstr++);=0A=
+=0A=
+        /* Check if this was an invalid character */=0A=
+        if(nResult =3D=3D -1)=0A=
+            bUsedDefaultChar =3D TRUE;=0A=
+=0A=
+        /* If we got no character, stop the conversion process here */=0A=
+        if(!chMultiByte[0])=0A=
+            break;=0A=
+=0A=
+        /* Determine whether this is a double-byte or a single-byte =
character */=0A=
+        if(chMultiByte[1])=0A=
+            uLength =3D 2;=0A=
+        else=0A=
+            uLength =3D 1;=0A=
+=0A=
+        /* Decrease 'count' by the character length and check if the =
buffer can still hold the full character */=0A=
+        count -=3D uLength;=0A=
+=0A=
+        if((int)count < 0)=0A=
+            break;=0A=
+=0A=
+        /* It can, so copy it and move the pointer forward */=0A=
+        memcpy(p, chMultiByte, uLength);=0A=
+        p +=3D uLength;=0A=
+    }=0A=
+=0A=
+    if(bUsedDefaultChar)=0A=
+        return -1;=0A=
+=0A=
+    /* Return the length in bytes of the copied characters (without the =
terminating null character) */=0A=
+    return p - mbstr;=0A=
 }=0A=
 =0A=
 /*********************************************************************=0A=
-- =0A=
1.5.6.1.1071.g76fb=0A=
=0A=

------=_NextPart_000_001B_01C8F043.5AB474B0--




More information about the wine-patches mailing list