mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[MSVCRT]
- Massive update to go towards a proper localization implementation Based on wine code svn path=/trunk/; revision=57833
This commit is contained in:
parent
359c37fdf9
commit
b588451fcf
14 changed files with 2026 additions and 904 deletions
|
@ -77,17 +77,11 @@ DllMain(PVOID hinstDll, ULONG dwReason, PVOID reserved)
|
|||
|
||||
/* Initialization of the WINE code */
|
||||
msvcrt_init_mt_locks();
|
||||
//if(!msvcrt_init_locale()) {
|
||||
// msvcrt_free_mt_locks();
|
||||
// msvcrt_free_tls_mem();
|
||||
// return FALSE;
|
||||
//}
|
||||
//msvcrt_init_math();
|
||||
msvcrt_init_io();
|
||||
//msvcrt_init_console();
|
||||
//msvcrt_init_args();
|
||||
//msvcrt_init_signals();
|
||||
_setmbcp(_MB_CP_LOCALE);
|
||||
TRACE("Attach done\n");
|
||||
break;
|
||||
|
||||
|
@ -110,7 +104,8 @@ DllMain(PVOID hinstDll, ULONG dwReason, PVOID reserved)
|
|||
msvcrt_free_tls_mem();
|
||||
if (!msvcrt_free_tls())
|
||||
return FALSE;
|
||||
//MSVCRT__free_locale(MSVCRT_locale);
|
||||
if(global_locale)
|
||||
MSVCRT__free_locale(global_locale);
|
||||
|
||||
if (__winitenv && __winitenv != _wenviron)
|
||||
FreeEnvironment((char**)__winitenv);
|
||||
|
|
|
@ -1042,7 +1042,7 @@
|
|||
@ cdecl _wcstoi64(wstr ptr long)
|
||||
# @ cdecl _wcstoi64_l(wstr ptr long ptr)
|
||||
# stub _wcstol_l
|
||||
# stub _wcstombs_l
|
||||
@ cdecl _wcstombs_l(ptr ptr long ptr)
|
||||
# @ cdecl _wcstombs_s_l(ptr ptr long wstr long ptr)
|
||||
@ cdecl _wcstoui64(wstr ptr long)
|
||||
# @ cdecl _wcstoui64_l(wstr ptr long ptr)
|
||||
|
|
|
@ -61,6 +61,7 @@ list(APPEND CRT_SOURCE
|
|||
math/sinf.c
|
||||
math/sinh.c
|
||||
math/tanh.c
|
||||
mbstring/_setmbcp.c
|
||||
mbstring/hanzen.c
|
||||
mbstring/ischira.c
|
||||
mbstring/iskana.c
|
||||
|
@ -323,7 +324,6 @@ list(APPEND CRT_SOURCE
|
|||
time/utime64.c
|
||||
time/utime.c
|
||||
time/wasctime.c
|
||||
time/wcsftime.c
|
||||
time/wctime32.c
|
||||
time/wctime64.c
|
||||
time/wctime.c
|
||||
|
|
32
reactos/lib/sdk/crt/include/internal/locale.h
Normal file
32
reactos/lib/sdk/crt/include/internal/locale.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef __CRT_INTERNAL_LOCALE_H
|
||||
#define __CRT_INTERNAL_LOCALE_H
|
||||
|
||||
typedef struct MSVCRT_threadmbcinfostruct *MSVCRT_pthreadmbcinfo;
|
||||
|
||||
typedef struct __lc_time_data {
|
||||
union {
|
||||
char *str[43];
|
||||
struct {
|
||||
char *short_wday[7];
|
||||
char *wday[7];
|
||||
char *short_mon[12];
|
||||
char *mon[12];
|
||||
char *am;
|
||||
char *pm;
|
||||
char *short_date;
|
||||
char *date;
|
||||
char *time;
|
||||
} names;
|
||||
} str;
|
||||
LCID lcid;
|
||||
int unk[2];
|
||||
wchar_t *wstr[43];
|
||||
char data[1];
|
||||
} MSVCRT___lc_time_data;
|
||||
|
||||
int _setmbcp_l(int, LCID, MSVCRT_pthreadmbcinfo) DECLSPEC_HIDDEN;
|
||||
MSVCRT_pthreadmbcinfo get_mbcinfo(void) DECLSPEC_HIDDEN;
|
||||
LCID MSVCRT_locale_to_LCID(const char *locale) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif //__CRT_INTERNAL_LOCALE_H
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
#define MAX_LOCALE_LENGTH 256
|
||||
extern unsigned char _mbctype[257];
|
||||
extern int MSVCRT___lc_codepage;
|
||||
extern unsigned int MSVCRT___lc_codepage;
|
||||
extern char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH];
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <internal/wine/eh.h>
|
||||
|
||||
typedef struct MSVCRT_threadlocaleinfostruct {
|
||||
int refcount;
|
||||
LONG refcount;
|
||||
unsigned int lc_codepage;
|
||||
unsigned int lc_collate_cp;
|
||||
unsigned long lc_handle[6];
|
||||
|
@ -36,14 +36,14 @@ typedef struct MSVCRT_threadlocaleinfostruct {
|
|||
struct MSVCRT_lconv *lconv;
|
||||
int *ctype1_refcount;
|
||||
unsigned short *ctype1;
|
||||
unsigned short *pctype;
|
||||
const unsigned short *pctype;
|
||||
unsigned char *pclmap;
|
||||
unsigned char *pcumap;
|
||||
struct __lc_time_data *lc_time_curr;
|
||||
} MSVCRT_threadlocinfo;
|
||||
|
||||
typedef struct MSVCRT_threadmbcinfostruct {
|
||||
int refcount;
|
||||
LONG refcount;
|
||||
int mbcodepage;
|
||||
int ismbcodepage;
|
||||
int mblcid;
|
||||
|
@ -130,7 +130,16 @@ extern inline void msvcrt_free_tls_mem(void);
|
|||
#define MSVCRT_ENABLE_PER_THREAD_LOCALE 1
|
||||
#define MSVCRT_DISABLE_PER_THREAD_LOCALE 2
|
||||
|
||||
extern MSVCRT__locale_t MSVCRT_locale;
|
||||
void __init_global_locale();
|
||||
extern MSVCRT__locale_t global_locale;
|
||||
#define MSVCRT_locale __get_MSVCRT_locale()
|
||||
extern inline MSVCRT__locale_t __get_MSVCRT_locale()
|
||||
{
|
||||
if(!global_locale)
|
||||
__init_global_locale();
|
||||
return global_locale;
|
||||
}
|
||||
|
||||
MSVCRT_pthreadlocinfo get_locinfo(void);
|
||||
void __cdecl MSVCRT__free_locale(MSVCRT__locale_t);
|
||||
void free_locinfo(MSVCRT_pthreadlocinfo);
|
||||
|
|
File diff suppressed because it is too large
Load diff
222
reactos/lib/sdk/crt/mbstring/_setmbcp.c
Normal file
222
reactos/lib/sdk/crt/mbstring/_setmbcp.c
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* msvcrt.dll mbcs functions
|
||||
*
|
||||
* Copyright 1999 Alexandre Julliard
|
||||
* Copyright 2000 Jon Griffths
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
* FIXME
|
||||
* Not currently binary compatible with win32. MSVCRT_mbctype must be
|
||||
* populated correctly and the ismb* functions should reference it.
|
||||
*/
|
||||
|
||||
#include <precomp.h>
|
||||
|
||||
#include <mbctype.h>
|
||||
|
||||
/* It seems that the data about valid trail bytes is not available from kernel32
|
||||
* so we have to store is here. The format is the same as for lead bytes in CPINFO */
|
||||
struct cp_extra_info_t
|
||||
{
|
||||
int cp;
|
||||
BYTE TrailBytes[MAX_LEADBYTES];
|
||||
};
|
||||
|
||||
static struct cp_extra_info_t g_cpextrainfo[] =
|
||||
{
|
||||
{932, {0x40, 0x7e, 0x80, 0xfc, 0, 0}},
|
||||
{936, {0x40, 0xfe, 0, 0}},
|
||||
{949, {0x41, 0xfe, 0, 0}},
|
||||
{950, {0x40, 0x7e, 0xa1, 0xfe, 0, 0}},
|
||||
{1361, {0x31, 0x7e, 0x81, 0xfe, 0, 0}},
|
||||
{20932, {1, 255, 0, 0}}, /* seems to give different results on different systems */
|
||||
{0, {1, 255, 0, 0}} /* match all with FIXME */
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
* INTERNAL: _setmbcp_l
|
||||
*/
|
||||
int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo)
|
||||
{
|
||||
const char format[] = ".%d";
|
||||
|
||||
int newcp;
|
||||
CPINFO cpi;
|
||||
BYTE *bytes;
|
||||
WORD chartypes[256];
|
||||
char bufA[256];
|
||||
WCHAR bufW[256];
|
||||
int charcount;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if(!mbcinfo)
|
||||
mbcinfo = get_mbcinfo();
|
||||
|
||||
switch (cp)
|
||||
{
|
||||
case _MB_CP_ANSI:
|
||||
newcp = GetACP();
|
||||
break;
|
||||
case _MB_CP_OEM:
|
||||
newcp = GetOEMCP();
|
||||
break;
|
||||
case _MB_CP_LOCALE:
|
||||
newcp = get_locinfo()->lc_codepage;
|
||||
if(newcp)
|
||||
break;
|
||||
/* fall through (C locale) */
|
||||
case _MB_CP_SBCS:
|
||||
newcp = 20127; /* ASCII */
|
||||
break;
|
||||
default:
|
||||
newcp = cp;
|
||||
break;
|
||||
}
|
||||
|
||||
if(lcid == -1) {
|
||||
sprintf(bufA, format, newcp);
|
||||
mbcinfo->mblcid = MSVCRT_locale_to_LCID(bufA);
|
||||
} else {
|
||||
mbcinfo->mblcid = lcid;
|
||||
}
|
||||
|
||||
if(mbcinfo->mblcid == -1)
|
||||
{
|
||||
WARN("Can't assign LCID to codepage (%d)\n", mbcinfo->mblcid);
|
||||
mbcinfo->mblcid = 0;
|
||||
}
|
||||
|
||||
if (!GetCPInfo(newcp, &cpi))
|
||||
{
|
||||
WARN("Codepage %d not found\n", newcp);
|
||||
*_errno() = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* setup the _mbctype */
|
||||
memset(mbcinfo->mbctype, 0, sizeof(unsigned char[257]));
|
||||
memset(mbcinfo->mbcasemap, 0, sizeof(unsigned char[256]));
|
||||
|
||||
bytes = cpi.LeadByte;
|
||||
while (bytes[0] || bytes[1])
|
||||
{
|
||||
for (i = bytes[0]; i <= bytes[1]; i++)
|
||||
mbcinfo->mbctype[i + 1] |= _M1;
|
||||
bytes += 2;
|
||||
}
|
||||
|
||||
if (cpi.MaxCharSize > 1)
|
||||
{
|
||||
/* trail bytes not available through kernel32 but stored in a structure in msvcrt */
|
||||
struct cp_extra_info_t *cpextra = g_cpextrainfo;
|
||||
|
||||
mbcinfo->ismbcodepage = 1;
|
||||
while (TRUE)
|
||||
{
|
||||
if (cpextra->cp == 0 || cpextra->cp == newcp)
|
||||
{
|
||||
if (cpextra->cp == 0)
|
||||
FIXME("trail bytes data not available for DBCS codepage %d - assuming all bytes\n", newcp);
|
||||
|
||||
bytes = cpextra->TrailBytes;
|
||||
while (bytes[0] || bytes[1])
|
||||
{
|
||||
for (i = bytes[0]; i <= bytes[1]; i++)
|
||||
mbcinfo->mbctype[i + 1] |= _M2;
|
||||
bytes += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
cpextra++;
|
||||
}
|
||||
}
|
||||
else
|
||||
mbcinfo->ismbcodepage = 0;
|
||||
|
||||
/* we can't use GetStringTypeA directly because we don't have a locale - only a code page
|
||||
*/
|
||||
charcount = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (!(mbcinfo->mbctype[i + 1] & _M1))
|
||||
bufA[charcount++] = i;
|
||||
|
||||
ret = MultiByteToWideChar(newcp, 0, bufA, charcount, bufW, charcount);
|
||||
if (ret != charcount)
|
||||
ERR("MultiByteToWideChar of chars failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
|
||||
|
||||
GetStringTypeW(CT_CTYPE1, bufW, charcount, chartypes);
|
||||
|
||||
charcount = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (!(mbcinfo->mbctype[i + 1] & _M1))
|
||||
{
|
||||
if (chartypes[charcount] & C1_UPPER)
|
||||
{
|
||||
mbcinfo->mbctype[i + 1] |= _SBUP;
|
||||
bufW[charcount] = tolowerW(bufW[charcount]);
|
||||
}
|
||||
else if (chartypes[charcount] & C1_LOWER)
|
||||
{
|
||||
mbcinfo->mbctype[i + 1] |= _SBLOW;
|
||||
bufW[charcount] = toupperW(bufW[charcount]);
|
||||
}
|
||||
charcount++;
|
||||
}
|
||||
|
||||
ret = WideCharToMultiByte(newcp, 0, bufW, charcount, bufA, charcount, NULL, NULL);
|
||||
if (ret != charcount)
|
||||
ERR("WideCharToMultiByte failed for cp %d, ret=%d (exp %d), error=%d\n", newcp, ret, charcount, GetLastError());
|
||||
|
||||
charcount = 0;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if(!(mbcinfo->mbctype[i + 1] & _M1))
|
||||
{
|
||||
if(mbcinfo->mbctype[i] & (C1_UPPER|C1_LOWER))
|
||||
mbcinfo->mbcasemap[i] = bufA[charcount];
|
||||
charcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (newcp == 932) /* CP932 only - set _MP and _MS */
|
||||
{
|
||||
/* On Windows it's possible to calculate the _MP and _MS from CT_CTYPE1
|
||||
* and CT_CTYPE3. But as of Wine 0.9.43 we return wrong values what makes
|
||||
* it hard. As this is set only for codepage 932 we hardcode it what gives
|
||||
* also faster execution.
|
||||
*/
|
||||
for (i = 161; i <= 165; i++)
|
||||
mbcinfo->mbctype[i + 1] |= _MP;
|
||||
for (i = 166; i <= 223; i++)
|
||||
mbcinfo->mbctype[i + 1] |= _MS;
|
||||
}
|
||||
|
||||
mbcinfo->mbcodepage = newcp;
|
||||
if(MSVCRT_locale && mbcinfo == MSVCRT_locale->mbcinfo)
|
||||
memcpy(_mbctype, MSVCRT_locale->mbcinfo->mbctype, sizeof(_mbctype));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _setmbcp (MSVCRT.@)
|
||||
*/
|
||||
int CDECL _setmbcp(int cp)
|
||||
{
|
||||
return _setmbcp_l(cp, -1, NULL);
|
||||
}
|
||||
|
|
@ -13,17 +13,18 @@
|
|||
#include <precomp.h>
|
||||
#include <mbstring.h>
|
||||
|
||||
extern int g_mbcp_is_multibyte;
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
/*********************************************************************
|
||||
* _mbsncpy(MSVCRT.@)
|
||||
* REMARKS
|
||||
* The parameter n is the number or characters to copy, not the size of
|
||||
* the buffer. Use _mbsnbcpy for a function analogical to strncpy
|
||||
*/
|
||||
unsigned char* _mbsncpy(unsigned char *dst, const unsigned char *src, size_t n)
|
||||
unsigned char* CDECL _mbsncpy(unsigned char* dst, const unsigned char* src, size_t n)
|
||||
{
|
||||
unsigned char* ret = dst;
|
||||
if(!n)
|
||||
return dst;
|
||||
if (g_mbcp_is_multibyte)
|
||||
if (get_mbcinfo()->ismbcodepage)
|
||||
{
|
||||
while (*src && n)
|
||||
{
|
||||
|
@ -55,48 +56,12 @@ unsigned char* _mbsncpy(unsigned char *dst, const unsigned char *src, size_t n)
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The _mbsnbcpy function copies count bytes from src to dest. If src is shorter
|
||||
* than dest, the string is padded with null characters. If dest is less than or
|
||||
* equal to count it is not terminated with a null character.
|
||||
*
|
||||
* @implemented
|
||||
*/
|
||||
unsigned char * _mbsnbcpy(unsigned char *dst, const unsigned char *src, size_t n)
|
||||
{
|
||||
unsigned char* ret = dst;
|
||||
if(!n)
|
||||
return dst;
|
||||
if(g_mbcp_is_multibyte)
|
||||
{
|
||||
int is_lead = 0;
|
||||
while (*src && n)
|
||||
{
|
||||
is_lead = (!is_lead && _ismbblead(*src));
|
||||
n--;
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
if (is_lead) /* if string ends with a lead, remove it */
|
||||
*(dst - 1) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (n)
|
||||
{
|
||||
n--;
|
||||
if (!(*dst++ = *src++)) break;
|
||||
}
|
||||
}
|
||||
while (n--) *dst++ = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
/*********************************************************************
|
||||
* _mbsnbcpy_s(MSVCRT.@)
|
||||
* REMARKS
|
||||
* Unlike _mbsnbcpy this function does not pad the rest of the dest
|
||||
* string with 0
|
||||
*/
|
||||
*/
|
||||
int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src, size_t n)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
@ -111,7 +76,7 @@ int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src,
|
|||
if(!n)
|
||||
return 0;
|
||||
|
||||
if(g_mbcp_is_multibyte)
|
||||
if(get_mbcinfo()->ismbcodepage)
|
||||
{
|
||||
int is_lead = 0;
|
||||
while (*src && n)
|
||||
|
@ -155,3 +120,40 @@ int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _mbsnbcpy(MSVCRT.@)
|
||||
* REMARKS
|
||||
* Like strncpy this function doesn't enforce the string to be
|
||||
* NUL-terminated
|
||||
*/
|
||||
unsigned char* CDECL _mbsnbcpy(unsigned char* dst, const unsigned char* src, size_t n)
|
||||
{
|
||||
unsigned char* ret = dst;
|
||||
if(!n)
|
||||
return dst;
|
||||
if(get_mbcinfo()->ismbcodepage)
|
||||
{
|
||||
int is_lead = 0;
|
||||
while (*src && n)
|
||||
{
|
||||
is_lead = (!is_lead && _ismbblead(*src));
|
||||
n--;
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
if (is_lead) /* if string ends with a lead, remove it */
|
||||
*(dst - 1) = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (n)
|
||||
{
|
||||
n--;
|
||||
if (!(*dst++ = *src++)) break;
|
||||
}
|
||||
}
|
||||
while (n--) *dst++ = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@ thread_data_t *msvcrt_get_thread_data(void)
|
|||
ptr->tid = GetCurrentThreadId();
|
||||
ptr->handle = INVALID_HANDLE_VALUE;
|
||||
ptr->random_seed = 1;
|
||||
//ptr->locinfo = MSVCRT_locale->locinfo;
|
||||
//ptr->mbcinfo = MSVCRT_locale->mbcinfo;
|
||||
ptr->locinfo = MSVCRT_locale->locinfo;
|
||||
ptr->mbcinfo = MSVCRT_locale->mbcinfo;
|
||||
}
|
||||
SetLastError( err );
|
||||
return ptr;
|
||||
|
|
|
@ -57,6 +57,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
|||
#include <internal/atexit.h>
|
||||
#include <internal/console.h>
|
||||
#include <internal/ieee.h>
|
||||
#include <internal/locale.h>
|
||||
#include <internal/math.h>
|
||||
#include <internal/mbstring.h>
|
||||
#include <internal/mtdll.h>
|
||||
|
|
|
@ -548,24 +548,12 @@ const unsigned short _wctype[] = {
|
|||
0x0100 | _LOWER, /* 0xfe */
|
||||
0x0100 | _LOWER /* 0xff */
|
||||
};
|
||||
|
||||
const unsigned short *_pctype = _ctype + 1;
|
||||
const unsigned short *_pwctype = _wctype + 1;
|
||||
|
||||
extern const unsigned short wine_wctype_table[];
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
const unsigned short **__p__pctype(void)
|
||||
{
|
||||
return &_pctype;
|
||||
}
|
||||
|
||||
const unsigned short* __cdecl __pctype_func(void)
|
||||
{
|
||||
return _pctype;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
|
|
@ -238,122 +238,81 @@ wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
|
|||
/*********************************************************************
|
||||
* wctomb (MSVCRT.@)
|
||||
*/
|
||||
INT CDECL wctomb(char *mbchar, wchar_t wchar)
|
||||
/*********************************************************************
|
||||
* wctomb (MSVCRT.@)
|
||||
*/
|
||||
INT CDECL wctomb( char *dst, wchar_t ch )
|
||||
{
|
||||
BOOL bUsedDefaultChar;
|
||||
char chMultiByte[MB_LEN_MAX];
|
||||
int nBytes;
|
||||
BOOL error;
|
||||
INT size;
|
||||
|
||||
/* At least one parameter needs to be given, the length of a null character cannot be queried (verified by tests under WinXP SP2) */
|
||||
if(!mbchar && !wchar)
|
||||
return 0;
|
||||
|
||||
/* Use WideCharToMultiByte for doing the conversion using the codepage currently set with setlocale() */
|
||||
nBytes = WideCharToMultiByte(MSVCRT___lc_codepage, 0, &wchar, 1, chMultiByte, MB_LEN_MAX, NULL, &bUsedDefaultChar);
|
||||
|
||||
/* Only copy the character if an 'mbchar' pointer was given.
|
||||
|
||||
The "C" locale is emulated with codepage 1252 here. This codepage has a default character "?", but the "C" locale doesn't have one.
|
||||
Therefore don't copy the character in this case. */
|
||||
if(mbchar && !(MSVCRT_current_lc_all[0] == 'C' && !MSVCRT_current_lc_all[1] && bUsedDefaultChar))
|
||||
memcpy(mbchar, chMultiByte, nBytes);
|
||||
|
||||
/* If the default character was used, set errno to EILSEQ and return -1. */
|
||||
if(bUsedDefaultChar)
|
||||
{
|
||||
_set_errno(EILSEQ);
|
||||
return -1;
|
||||
size = WideCharToMultiByte(get_locinfo()->lc_codepage, 0, &ch, 1, dst, dst ? 6 : 0, NULL, &error);
|
||||
if(!size || error) {
|
||||
*_errno() = EINVAL;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* Otherwise return the number of bytes this character occupies. */
|
||||
return nBytes;
|
||||
return size;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* wcsrtombs_l (INTERNAL)
|
||||
*/
|
||||
static size_t CDECL wcsrtombs_l(char *mbstr, const wchar_t **wcstr, size_t count, _locale_t locale)
|
||||
{
|
||||
MSVCRT_pthreadlocinfo locinfo;
|
||||
size_t tmp = 0;
|
||||
BOOL used_default;
|
||||
|
||||
if(!locale)
|
||||
locinfo = get_locinfo();
|
||||
else
|
||||
locinfo = ((MSVCRT__locale_t)locale)->locinfo;
|
||||
|
||||
if(!mbstr) {
|
||||
tmp = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
|
||||
*wcstr, -1, NULL, 0, NULL, &used_default)-1;
|
||||
if(used_default)
|
||||
return -1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
while(**wcstr) {
|
||||
char buf[3];
|
||||
size_t i, size;
|
||||
|
||||
size = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
|
||||
*wcstr, 1, buf, 3, NULL, &used_default);
|
||||
if(used_default)
|
||||
return -1;
|
||||
if(tmp+size > count)
|
||||
return tmp;
|
||||
|
||||
for(i=0; i<size; i++)
|
||||
mbstr[tmp++] = buf[i];
|
||||
(*wcstr)++;
|
||||
}
|
||||
|
||||
if(tmp < count) {
|
||||
mbstr[tmp] = '\0';
|
||||
*wcstr = NULL;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _wcstombs_l (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL _wcstombs_l(char *mbstr, const wchar_t *wcstr, size_t count, _locale_t locale)
|
||||
{
|
||||
return wcsrtombs_l(mbstr, &wcstr, count, locale);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* wcstombs (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)
|
||||
{
|
||||
BOOL bUsedDefaultChar;
|
||||
char* p = mbstr;
|
||||
int nResult;
|
||||
|
||||
/* Does the caller query for output buffer size? */
|
||||
if(!mbstr)
|
||||
{
|
||||
int nLength;
|
||||
|
||||
/* If we currently use the "C" locale, the length of the input string is returned (verified by tests under WinXP SP2) */
|
||||
if(MSVCRT_current_lc_all[0] == 'C' && !MSVCRT_current_lc_all[1])
|
||||
return wcslen(wcstr);
|
||||
|
||||
/* Otherwise check the length each character needs and build a final return value out of this */
|
||||
count = wcslen(wcstr);
|
||||
nLength = 0;
|
||||
|
||||
while((int)(--count) >= 0 && *wcstr)
|
||||
{
|
||||
/* Get the length of this character */
|
||||
nResult = wctomb(NULL, *wcstr++);
|
||||
|
||||
/* If this character is not convertible in the current locale, the end result will be -1 */
|
||||
if(nResult == -1)
|
||||
return -1;
|
||||
|
||||
nLength += nResult;
|
||||
}
|
||||
|
||||
/* Return the final length */
|
||||
return nLength;
|
||||
}
|
||||
|
||||
/* Convert the string then */
|
||||
bUsedDefaultChar = FALSE;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char chMultiByte[MB_LEN_MAX];
|
||||
UINT uLength;
|
||||
|
||||
/* Are we at the terminating null character? */
|
||||
if(!*wcstr)
|
||||
{
|
||||
/* Set the null character, but don't increment the pointer as the returned length never includes the terminating null character */
|
||||
*p = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Convert this character into the temporary chMultiByte variable */
|
||||
ZeroMemory(chMultiByte, MB_LEN_MAX);
|
||||
nResult = wctomb(chMultiByte, *wcstr++);
|
||||
|
||||
/* Check if this was an invalid character */
|
||||
if(nResult == -1)
|
||||
bUsedDefaultChar = TRUE;
|
||||
|
||||
/* If we got no character, stop the conversion process here */
|
||||
if(!chMultiByte[0])
|
||||
break;
|
||||
|
||||
/* Determine whether this is a double-byte or a single-byte character */
|
||||
if(chMultiByte[1])
|
||||
uLength = 2;
|
||||
else
|
||||
uLength = 1;
|
||||
|
||||
/* Decrease 'count' by the character length and check if the buffer can still hold the full character */
|
||||
count -= uLength;
|
||||
|
||||
if((int)count < 0)
|
||||
break;
|
||||
|
||||
/* It can, so copy it and move the pointer forward */
|
||||
memcpy(p, chMultiByte, uLength);
|
||||
p += uLength;
|
||||
}
|
||||
|
||||
if(bUsedDefaultChar)
|
||||
return -1;
|
||||
|
||||
/* Return the length in bytes of the copied characters (without the terminating null character) */
|
||||
return p - mbstr;
|
||||
return wcsrtombs_l(mbstr, &wcstr, count, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -6,14 +6,320 @@
|
|||
* PROGRAMER:
|
||||
*/
|
||||
#include <precomp.h>
|
||||
#include <tchar.h>
|
||||
|
||||
size_t
|
||||
_tcsftime(_TCHAR *strDest,
|
||||
size_t maxsize,
|
||||
const _TCHAR *format,
|
||||
const struct tm *timeptr)
|
||||
static inline BOOL strftime_date(char *str, size_t *pos, size_t max,
|
||||
BOOL alternate, const struct tm *mstm, MSVCRT___lc_time_data *time_data)
|
||||
{
|
||||
char *format;
|
||||
SYSTEMTIME st;
|
||||
size_t ret;
|
||||
|
||||
st.wYear = mstm->tm_year + 1900;
|
||||
st.wMonth = mstm->tm_mon + 1;
|
||||
st.wDayOfWeek = mstm->tm_wday;
|
||||
st.wDay = mstm->tm_mday;
|
||||
st.wHour = mstm->tm_hour;
|
||||
st.wMinute = mstm->tm_min;
|
||||
st.wSecond = mstm->tm_sec;
|
||||
st.wMilliseconds = 0;
|
||||
|
||||
format = alternate ? time_data->str.names.date : time_data->str.names.short_date;
|
||||
ret = GetDateFormatA(time_data->lcid, 0, &st, format, NULL, 0);
|
||||
if(ret && ret<max-*pos)
|
||||
ret = GetDateFormatA(time_data->lcid, 0, &st, format, str+*pos, max-*pos);
|
||||
if(!ret) {
|
||||
*str = 0;
|
||||
*_errno() = EINVAL;
|
||||
return FALSE;
|
||||
}else if(ret > max-*pos) {
|
||||
*str = 0;
|
||||
*_errno() = ERANGE;
|
||||
return FALSE;
|
||||
}
|
||||
*pos += ret-1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOL strftime_time(char *str, size_t *pos, size_t max,
|
||||
const struct tm *mstm, MSVCRT___lc_time_data *time_data)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
size_t ret;
|
||||
|
||||
st.wYear = mstm->tm_year + 1900;
|
||||
st.wMonth = mstm->tm_mon + 1;
|
||||
st.wDayOfWeek = mstm->tm_wday;
|
||||
st.wDay = mstm->tm_mday;
|
||||
st.wHour = mstm->tm_hour;
|
||||
st.wMinute = mstm->tm_min;
|
||||
st.wSecond = mstm->tm_sec;
|
||||
st.wMilliseconds = 0;
|
||||
|
||||
ret = GetTimeFormatA(time_data->lcid, 0, &st, time_data->str.names.time, NULL, 0);
|
||||
if(ret && ret<max-*pos)
|
||||
ret = GetTimeFormatA(time_data->lcid, 0, &st, time_data->str.names.time,
|
||||
str+*pos, max-*pos);
|
||||
if(!ret) {
|
||||
*str = 0;
|
||||
*_errno() = EINVAL;
|
||||
return FALSE;
|
||||
}else if(ret > max-*pos) {
|
||||
*str = 0;
|
||||
*_errno() = ERANGE;
|
||||
return FALSE;
|
||||
}
|
||||
*pos += ret-1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOL strftime_str(char *str, size_t *pos, size_t max, char *src)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
if(len > max-*pos) {
|
||||
*str = 0;
|
||||
*_errno() = ERANGE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(str+*pos, src, len);
|
||||
*pos += len;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline BOOL strftime_int(char *str, size_t *pos, size_t max,
|
||||
int src, int prec, int l, int h)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if(src<l || src>h) {
|
||||
*str = 0;
|
||||
*_errno() = EINVAL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
len = _snprintf(str+*pos, max-*pos, "%0*d", prec, src);
|
||||
if(len == -1) {
|
||||
*str = 0;
|
||||
*_errno() = ERANGE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pos += len;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* _Strftime (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL _Strftime(char *str, size_t max, const char *format,
|
||||
const struct tm *mstm, MSVCRT___lc_time_data *time_data)
|
||||
{
|
||||
size_t ret, tmp;
|
||||
BOOL alternate;
|
||||
|
||||
TRACE("(%p %ld %s %p %p)\n", str, max, format, mstm, time_data);
|
||||
|
||||
if(!str || !format) {
|
||||
if(str && max)
|
||||
*str = 0;
|
||||
*_errno() = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!time_data)
|
||||
time_data = get_locinfo()->lc_time_curr;
|
||||
|
||||
for(ret=0; *format && ret<max; format++) {
|
||||
if(*format != '%') {
|
||||
str[ret++] = *format;
|
||||
continue;
|
||||
}
|
||||
|
||||
format++;
|
||||
if(*format == '#') {
|
||||
alternate = TRUE;
|
||||
format++;
|
||||
}else {
|
||||
alternate = FALSE;
|
||||
}
|
||||
|
||||
if(!mstm)
|
||||
goto einval_error;
|
||||
|
||||
switch(*format) {
|
||||
case 'c':
|
||||
if(!strftime_date(str, &ret, max, alternate, mstm, time_data))
|
||||
return 0;
|
||||
if(ret < max)
|
||||
str[ret++] = ' ';
|
||||
if(!strftime_time(str, &ret, max, mstm, time_data))
|
||||
return 0;
|
||||
break;
|
||||
case 'x':
|
||||
if(!strftime_date(str, &ret, max, alternate, mstm, time_data))
|
||||
return 0;
|
||||
break;
|
||||
case 'X':
|
||||
if(!strftime_time(str, &ret, max, mstm, time_data))
|
||||
return 0;
|
||||
break;
|
||||
case 'a':
|
||||
if(mstm->tm_wday<0 || mstm->tm_wday>6)
|
||||
goto einval_error;
|
||||
if(!strftime_str(str, &ret, max, time_data->str.names.short_wday[mstm->tm_wday]))
|
||||
return 0;
|
||||
break;
|
||||
case 'A':
|
||||
if(mstm->tm_wday<0 || mstm->tm_wday>6)
|
||||
goto einval_error;
|
||||
if(!strftime_str(str, &ret, max, time_data->str.names.wday[mstm->tm_wday]))
|
||||
return 0;
|
||||
break;
|
||||
case 'b':
|
||||
if(mstm->tm_mon<0 || mstm->tm_mon>11)
|
||||
goto einval_error;
|
||||
if(!strftime_str(str, &ret, max, time_data->str.names.short_mon[mstm->tm_mon]))
|
||||
return 0;
|
||||
break;
|
||||
case 'B':
|
||||
if(mstm->tm_mon<0 || mstm->tm_mon>11)
|
||||
goto einval_error;
|
||||
if(!strftime_str(str, &ret, max, time_data->str.names.mon[mstm->tm_mon]))
|
||||
return 0;
|
||||
break;
|
||||
case 'd':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_mday, alternate ? 0 : 2, 0, 31))
|
||||
return 0;
|
||||
break;
|
||||
case 'H':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_hour, alternate ? 0 : 2, 0, 23))
|
||||
return 0;
|
||||
break;
|
||||
case 'I':
|
||||
tmp = mstm->tm_hour;
|
||||
if(tmp > 12)
|
||||
tmp -= 12;
|
||||
else if(!tmp)
|
||||
tmp = 12;
|
||||
if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 1, 12))
|
||||
return 0;
|
||||
break;
|
||||
case 'j':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_yday+1, alternate ? 0 : 3, 1, 366))
|
||||
return 0;
|
||||
break;
|
||||
case 'm':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_mon+1, alternate ? 0 : 2, 1, 12))
|
||||
return 0;
|
||||
break;
|
||||
case 'M':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_min, alternate ? 0 : 2, 0, 59))
|
||||
return 0;
|
||||
break;
|
||||
case 'p':
|
||||
if(mstm->tm_hour<0 || mstm->tm_hour>23)
|
||||
goto einval_error;
|
||||
if(!strftime_str(str, &ret, max, mstm->tm_hour<12 ?
|
||||
time_data->str.names.am : time_data->str.names.pm))
|
||||
return 0;
|
||||
break;
|
||||
case 'S':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_sec, alternate ? 0 : 2, 0, 59))
|
||||
return 0;
|
||||
break;
|
||||
case 'w':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_wday, 0, 0, 6))
|
||||
return 0;
|
||||
break;
|
||||
case 'y':
|
||||
if(!strftime_int(str, &ret, max, mstm->tm_year%100, alternate ? 0 : 2, 0, 99))
|
||||
return 0;
|
||||
break;
|
||||
case 'Y':
|
||||
tmp = 1900+mstm->tm_year;
|
||||
if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 4, 0, 9999))
|
||||
return 0;
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
_tzset();
|
||||
if(_get_tzname(&tmp, str+ret, max-ret, mstm->tm_isdst ? 1 : 0))
|
||||
return 0;
|
||||
ret += tmp;
|
||||
break;
|
||||
case 'U':
|
||||
case 'W':
|
||||
if(mstm->tm_wday<0 || mstm->tm_wday>6 || mstm->tm_yday<0 || mstm->tm_yday>365)
|
||||
goto einval_error;
|
||||
if(*format == 'U')
|
||||
tmp = mstm->tm_wday;
|
||||
else if(!mstm->tm_wday)
|
||||
tmp = 6;
|
||||
else
|
||||
tmp = mstm->tm_wday-1;
|
||||
|
||||
tmp = mstm->tm_yday/7 + (tmp<=mstm->tm_yday%7);
|
||||
if(!strftime_int(str, &ret, max, tmp, alternate ? 0 : 2, 0, 53))
|
||||
return 0;
|
||||
break;
|
||||
case '%':
|
||||
str[ret++] = '%';
|
||||
break;
|
||||
default:
|
||||
WARN("unknown format %c\n", *format);
|
||||
goto einval_error;
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == max) {
|
||||
if(max)
|
||||
*str = 0;
|
||||
*_errno() = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
str[ret] = 0;
|
||||
return ret;
|
||||
|
||||
einval_error:
|
||||
*str = 0;
|
||||
*_errno() = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* strftime (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL strftime( char *str, size_t max, const char *format,
|
||||
const struct tm *mstm )
|
||||
{
|
||||
return _Strftime(str, max, format, mstm, NULL);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* wcsftime (MSVCRT.@)
|
||||
*/
|
||||
size_t CDECL wcsftime( wchar_t *str, size_t max,
|
||||
const wchar_t *format, const struct tm *mstm )
|
||||
{
|
||||
char *s, *fmt;
|
||||
size_t len;
|
||||
|
||||
TRACE("%p %ld %s %p\n", str, max, debugstr_w(format), mstm );
|
||||
|
||||
len = WideCharToMultiByte( CP_ACP, 0, format, -1, NULL, 0, NULL, NULL );
|
||||
if (!(fmt = malloc( len ))) return 0;
|
||||
WideCharToMultiByte( CP_ACP, 0, format, -1, fmt, len, NULL, NULL );
|
||||
|
||||
if ((s = malloc( max*4 )))
|
||||
{
|
||||
if (!strftime( s, max*4, fmt, mstm )) s[0] = 0;
|
||||
len = MultiByteToWideChar( CP_ACP, 0, s, -1, str, max );
|
||||
if (len) len--;
|
||||
free( s );
|
||||
}
|
||||
else len = 0;
|
||||
|
||||
free( fmt );
|
||||
return len;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue