mirror of
https://github.com/reactos/reactos.git
synced 2024-08-12 14:16:30 +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
|
@ -77,17 +77,11 @@ DllMain(PVOID hinstDll, ULONG dwReason, PVOID reserved)
|
||||||
|
|
||||||
/* Initialization of the WINE code */
|
/* Initialization of the WINE code */
|
||||||
msvcrt_init_mt_locks();
|
msvcrt_init_mt_locks();
|
||||||
//if(!msvcrt_init_locale()) {
|
|
||||||
// msvcrt_free_mt_locks();
|
|
||||||
// msvcrt_free_tls_mem();
|
|
||||||
// return FALSE;
|
|
||||||
//}
|
|
||||||
//msvcrt_init_math();
|
//msvcrt_init_math();
|
||||||
msvcrt_init_io();
|
msvcrt_init_io();
|
||||||
//msvcrt_init_console();
|
//msvcrt_init_console();
|
||||||
//msvcrt_init_args();
|
//msvcrt_init_args();
|
||||||
//msvcrt_init_signals();
|
//msvcrt_init_signals();
|
||||||
_setmbcp(_MB_CP_LOCALE);
|
|
||||||
TRACE("Attach done\n");
|
TRACE("Attach done\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -110,7 +104,8 @@ DllMain(PVOID hinstDll, ULONG dwReason, PVOID reserved)
|
||||||
msvcrt_free_tls_mem();
|
msvcrt_free_tls_mem();
|
||||||
if (!msvcrt_free_tls())
|
if (!msvcrt_free_tls())
|
||||||
return FALSE;
|
return FALSE;
|
||||||
//MSVCRT__free_locale(MSVCRT_locale);
|
if(global_locale)
|
||||||
|
MSVCRT__free_locale(global_locale);
|
||||||
|
|
||||||
if (__winitenv && __winitenv != _wenviron)
|
if (__winitenv && __winitenv != _wenviron)
|
||||||
FreeEnvironment((char**)__winitenv);
|
FreeEnvironment((char**)__winitenv);
|
||||||
|
|
|
@ -1042,7 +1042,7 @@
|
||||||
@ cdecl _wcstoi64(wstr ptr long)
|
@ cdecl _wcstoi64(wstr ptr long)
|
||||||
# @ cdecl _wcstoi64_l(wstr ptr long ptr)
|
# @ cdecl _wcstoi64_l(wstr ptr long ptr)
|
||||||
# stub _wcstol_l
|
# stub _wcstol_l
|
||||||
# stub _wcstombs_l
|
@ cdecl _wcstombs_l(ptr ptr long ptr)
|
||||||
# @ cdecl _wcstombs_s_l(ptr ptr long wstr long ptr)
|
# @ cdecl _wcstombs_s_l(ptr ptr long wstr long ptr)
|
||||||
@ cdecl _wcstoui64(wstr ptr long)
|
@ cdecl _wcstoui64(wstr ptr long)
|
||||||
# @ cdecl _wcstoui64_l(wstr ptr long ptr)
|
# @ cdecl _wcstoui64_l(wstr ptr long ptr)
|
||||||
|
|
|
@ -61,6 +61,7 @@ list(APPEND CRT_SOURCE
|
||||||
math/sinf.c
|
math/sinf.c
|
||||||
math/sinh.c
|
math/sinh.c
|
||||||
math/tanh.c
|
math/tanh.c
|
||||||
|
mbstring/_setmbcp.c
|
||||||
mbstring/hanzen.c
|
mbstring/hanzen.c
|
||||||
mbstring/ischira.c
|
mbstring/ischira.c
|
||||||
mbstring/iskana.c
|
mbstring/iskana.c
|
||||||
|
@ -323,7 +324,6 @@ list(APPEND CRT_SOURCE
|
||||||
time/utime64.c
|
time/utime64.c
|
||||||
time/utime.c
|
time/utime.c
|
||||||
time/wasctime.c
|
time/wasctime.c
|
||||||
time/wcsftime.c
|
|
||||||
time/wctime32.c
|
time/wctime32.c
|
||||||
time/wctime64.c
|
time/wctime64.c
|
||||||
time/wctime.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
|
#define MAX_LOCALE_LENGTH 256
|
||||||
extern unsigned char _mbctype[257];
|
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];
|
extern char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH];
|
||||||
|
|
||||||
#if defined (_MSC_VER)
|
#if defined (_MSC_VER)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <internal/wine/eh.h>
|
#include <internal/wine/eh.h>
|
||||||
|
|
||||||
typedef struct MSVCRT_threadlocaleinfostruct {
|
typedef struct MSVCRT_threadlocaleinfostruct {
|
||||||
int refcount;
|
LONG refcount;
|
||||||
unsigned int lc_codepage;
|
unsigned int lc_codepage;
|
||||||
unsigned int lc_collate_cp;
|
unsigned int lc_collate_cp;
|
||||||
unsigned long lc_handle[6];
|
unsigned long lc_handle[6];
|
||||||
|
@ -36,14 +36,14 @@ typedef struct MSVCRT_threadlocaleinfostruct {
|
||||||
struct MSVCRT_lconv *lconv;
|
struct MSVCRT_lconv *lconv;
|
||||||
int *ctype1_refcount;
|
int *ctype1_refcount;
|
||||||
unsigned short *ctype1;
|
unsigned short *ctype1;
|
||||||
unsigned short *pctype;
|
const unsigned short *pctype;
|
||||||
unsigned char *pclmap;
|
unsigned char *pclmap;
|
||||||
unsigned char *pcumap;
|
unsigned char *pcumap;
|
||||||
struct __lc_time_data *lc_time_curr;
|
struct __lc_time_data *lc_time_curr;
|
||||||
} MSVCRT_threadlocinfo;
|
} MSVCRT_threadlocinfo;
|
||||||
|
|
||||||
typedef struct MSVCRT_threadmbcinfostruct {
|
typedef struct MSVCRT_threadmbcinfostruct {
|
||||||
int refcount;
|
LONG refcount;
|
||||||
int mbcodepage;
|
int mbcodepage;
|
||||||
int ismbcodepage;
|
int ismbcodepage;
|
||||||
int mblcid;
|
int mblcid;
|
||||||
|
@ -130,7 +130,16 @@ extern inline void msvcrt_free_tls_mem(void);
|
||||||
#define MSVCRT_ENABLE_PER_THREAD_LOCALE 1
|
#define MSVCRT_ENABLE_PER_THREAD_LOCALE 1
|
||||||
#define MSVCRT_DISABLE_PER_THREAD_LOCALE 2
|
#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);
|
MSVCRT_pthreadlocinfo get_locinfo(void);
|
||||||
void __cdecl MSVCRT__free_locale(MSVCRT__locale_t);
|
void __cdecl MSVCRT__free_locale(MSVCRT__locale_t);
|
||||||
void free_locinfo(MSVCRT_pthreadlocinfo);
|
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 <precomp.h>
|
||||||
#include <mbstring.h>
|
#include <mbstring.h>
|
||||||
|
|
||||||
extern int g_mbcp_is_multibyte;
|
/*********************************************************************
|
||||||
|
* _mbsncpy(MSVCRT.@)
|
||||||
/*
|
* REMARKS
|
||||||
* @implemented
|
* 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;
|
unsigned char* ret = dst;
|
||||||
if(!n)
|
if(!n)
|
||||||
return dst;
|
return dst;
|
||||||
if (g_mbcp_is_multibyte)
|
if (get_mbcinfo()->ismbcodepage)
|
||||||
{
|
{
|
||||||
while (*src && n)
|
while (*src && n)
|
||||||
{
|
{
|
||||||
|
@ -55,48 +56,12 @@ unsigned char* _mbsncpy(unsigned char *dst, const unsigned char *src, size_t n)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
/*
|
* _mbsnbcpy_s(MSVCRT.@)
|
||||||
* The _mbsnbcpy function copies count bytes from src to dest. If src is shorter
|
* REMARKS
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unlike _mbsnbcpy this function does not pad the rest of the dest
|
* Unlike _mbsnbcpy this function does not pad the rest of the dest
|
||||||
* string with 0
|
* string with 0
|
||||||
*/
|
*/
|
||||||
int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src, size_t n)
|
int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src, size_t n)
|
||||||
{
|
{
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
@ -111,7 +76,7 @@ int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src,
|
||||||
if(!n)
|
if(!n)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(g_mbcp_is_multibyte)
|
if(get_mbcinfo()->ismbcodepage)
|
||||||
{
|
{
|
||||||
int is_lead = 0;
|
int is_lead = 0;
|
||||||
while (*src && n)
|
while (*src && n)
|
||||||
|
@ -155,3 +120,40 @@ int CDECL _mbsnbcpy_s(unsigned char* dst, size_t size, const unsigned char* src,
|
||||||
|
|
||||||
return 0;
|
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->tid = GetCurrentThreadId();
|
||||||
ptr->handle = INVALID_HANDLE_VALUE;
|
ptr->handle = INVALID_HANDLE_VALUE;
|
||||||
ptr->random_seed = 1;
|
ptr->random_seed = 1;
|
||||||
//ptr->locinfo = MSVCRT_locale->locinfo;
|
ptr->locinfo = MSVCRT_locale->locinfo;
|
||||||
//ptr->mbcinfo = MSVCRT_locale->mbcinfo;
|
ptr->mbcinfo = MSVCRT_locale->mbcinfo;
|
||||||
}
|
}
|
||||||
SetLastError( err );
|
SetLastError( err );
|
||||||
return ptr;
|
return ptr;
|
||||||
|
|
|
@ -57,6 +57,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||||
#include <internal/atexit.h>
|
#include <internal/atexit.h>
|
||||||
#include <internal/console.h>
|
#include <internal/console.h>
|
||||||
#include <internal/ieee.h>
|
#include <internal/ieee.h>
|
||||||
|
#include <internal/locale.h>
|
||||||
#include <internal/math.h>
|
#include <internal/math.h>
|
||||||
#include <internal/mbstring.h>
|
#include <internal/mbstring.h>
|
||||||
#include <internal/mtdll.h>
|
#include <internal/mtdll.h>
|
||||||
|
|
|
@ -548,24 +548,12 @@ const unsigned short _wctype[] = {
|
||||||
0x0100 | _LOWER, /* 0xfe */
|
0x0100 | _LOWER, /* 0xfe */
|
||||||
0x0100 | _LOWER /* 0xff */
|
0x0100 | _LOWER /* 0xff */
|
||||||
};
|
};
|
||||||
|
|
||||||
const unsigned short *_pctype = _ctype + 1;
|
const unsigned short *_pctype = _ctype + 1;
|
||||||
const unsigned short *_pwctype = _wctype + 1;
|
const unsigned short *_pwctype = _wctype + 1;
|
||||||
|
|
||||||
extern const unsigned short wine_wctype_table[];
|
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
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -238,122 +238,81 @@ wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* wctomb (MSVCRT.@)
|
* wctomb (MSVCRT.@)
|
||||||
*/
|
*/
|
||||||
INT CDECL wctomb(char *mbchar, wchar_t wchar)
|
/*********************************************************************
|
||||||
|
* wctomb (MSVCRT.@)
|
||||||
|
*/
|
||||||
|
INT CDECL wctomb( char *dst, wchar_t ch )
|
||||||
{
|
{
|
||||||
BOOL bUsedDefaultChar;
|
BOOL error;
|
||||||
char chMultiByte[MB_LEN_MAX];
|
INT size;
|
||||||
int nBytes;
|
|
||||||
|
|
||||||
/* At least one parameter needs to be given, the length of a null character cannot be queried (verified by tests under WinXP SP2) */
|
size = WideCharToMultiByte(get_locinfo()->lc_codepage, 0, &ch, 1, dst, dst ? 6 : 0, NULL, &error);
|
||||||
if(!mbchar && !wchar)
|
if(!size || error) {
|
||||||
return 0;
|
*_errno() = EINVAL;
|
||||||
|
return EOF;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
return size;
|
||||||
/* Otherwise return the number of bytes this character occupies. */
|
|
||||||
return nBytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* 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)
|
size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)
|
||||||
{
|
{
|
||||||
BOOL bUsedDefaultChar;
|
return wcsrtombs_l(mbstr, &wcstr, count, NULL);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,320 @@
|
||||||
* PROGRAMER:
|
* PROGRAMER:
|
||||||
*/
|
*/
|
||||||
#include <precomp.h>
|
#include <precomp.h>
|
||||||
#include <tchar.h>
|
|
||||||
|
|
||||||
size_t
|
static inline BOOL strftime_date(char *str, size_t *pos, size_t max,
|
||||||
_tcsftime(_TCHAR *strDest,
|
BOOL alternate, const struct tm *mstm, MSVCRT___lc_time_data *time_data)
|
||||||
size_t maxsize,
|
|
||||||
const _TCHAR *format,
|
|
||||||
const struct tm *timeptr)
|
|
||||||
{
|
{
|
||||||
|
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;
|
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