Commit 9134f37e authored by Bill Medland's avatar Bill Medland Committed by Alexandre Julliard

Fix OLE_GetFormatW so that GetDateFormatW works.

Rearranged for simplicity.
parent 97a4384d
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define BUFFER_SIZE 50 #define BUFFER_SIZE 50
/* Buffer used by callback function */ /* Buffer used by callback function */
char GlobalBuffer[BUFFER_SIZE]; char GlobalBuffer[BUFFER_SIZE];
#define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
/* TODO : /* TODO :
* Unicode versions * Unicode versions
...@@ -183,6 +184,58 @@ LCID lcid; ...@@ -183,6 +184,58 @@ LCID lcid;
eq (ret, 0, "GetDateFormat with len=2", "%d"); eq (ret, 0, "GetDateFormat with len=2", "%d");
} }
void TestGetDateFormatW()
{
int ret, error, cmp;
SYSTEMTIME curtime;
WCHAR buffer[BUFFER_SIZE], format[BUFFER_SIZE], Expected[BUFFER_SIZE];
LCID lcid;
lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT );
/* 1. Error cases */
/* 1a If flags is not zero then format must be null. */
ret = GetDateFormatW (LOCALE_SYSTEM_DEFAULT, DATE_LONGDATE, NULL, format, buffer, sizeof(buffer)/sizeof(buffer[0]));
error = ret ? 0 : GetLastError();
ok (ret == 0 && error == ERROR_INVALID_FLAGS, "GetDateFormatW allowed flags and format");
/* 1b The buffer can only be null if the count is zero */
/* For the record other bad pointers result in a page fault (Win98) */
ret = GetDateFormatW (LOCALE_SYSTEM_DEFAULT, 0, NULL, format, NULL, sizeof(buffer)/sizeof(buffer[0]));
error = ret ? 0 : GetLastError();
ok (ret == 0 && error == ERROR_INVALID_PARAMETER, "GetDateFormatW did not detect null buffer pointer.");
ret = GetDateFormatW (LOCALE_SYSTEM_DEFAULT, 0, NULL, format, NULL, 0);
error = ret ? 0 : GetLastError();
ok (ret != 0 && error == 0, "GetDateFormatW did not permit null buffer pointer when counting.");
/* 1c An incorrect day of week is corrected. */
curtime.wYear = 2002;
curtime.wMonth = 10;
curtime.wDay = 23;
curtime.wDayOfWeek = 5; /* should be 3 - Wednesday */
curtime.wHour = 0;
curtime.wMinute = 0;
curtime.wSecond = 0;
curtime.wMilliseconds = 234;
MultiByteToWideChar (CP_ACP, 0, "dddd d MMMM yyyy", -1, format, COUNTOF(format));
ret = GetDateFormatW (lcid, 0, &curtime, format, buffer, COUNTOF(buffer));
error = ret ? 0 : GetLastError();
MultiByteToWideChar (CP_ACP, 0, "Wednesday 23 October 2002", -1, Expected, COUNTOF(Expected));
cmp = ret ? lstrcmpW (buffer, Expected) : 2;
ok (ret == lstrlenW(Expected)+1 && error == 0 && cmp == 0, "Day of week correction failed\n");
/* 1d Invalid year, month or day results in error */
/* 1e Insufficient space results in error */
/* 2. Standard behaviour */
/* 1c is a reasonable test */
/* 3. Replicated undocumented behaviour */
/* e.g. unexepected characters are retained. */
}
void TestGetCurrencyFormat() void TestGetCurrencyFormat()
{ {
...@@ -343,6 +396,7 @@ START_TEST(locale) ...@@ -343,6 +396,7 @@ START_TEST(locale)
TestGetLocaleInfoA(); TestGetLocaleInfoA();
TestGetTimeFormatA(); TestGetTimeFormatA();
TestGetDateFormatA(); TestGetDateFormatA();
TestGetDateFormatW();
TestGetNumberFormat(); TestGetNumberFormat();
TestGetCurrencyFormat(); TestGetCurrencyFormat();
TestCompareStringA(); TestCompareStringA();
......
...@@ -1572,26 +1572,15 @@ static INT OLE_GetFormatA(LCID locale, ...@@ -1572,26 +1572,15 @@ static INT OLE_GetFormatA(LCID locale,
/****************************************************************************** /******************************************************************************
* OLE_GetFormatW [INTERNAL] * OLE_GetFormatW [INTERNAL]
*
* dateformat is set TRUE if being called for a date, false for a time
*/ */
static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
const SYSTEMTIME* xtime, const SYSTEMTIME* xtime,
LPCWSTR format, LPCWSTR format,
LPWSTR output, INT outlen) LPWSTR output, INT outlen, int dateformat)
{ {
INT inpos, outpos; INT outpos;
int count, type=0, inquote;
int Overflow; /* loop check */
char tmp[16];
WCHAR buf[40];
int buflen=0;
WCHAR arg0[] = {0}, arg1[] = {'%','d',0};
WCHAR arg2[] = {'%','0','2','d',0};
WCHAR *argarr[3];
int datevars=0, timevars=0;
argarr[0] = arg0;
argarr[1] = arg1;
argarr[2] = arg2;
/* make a debug report */ /* make a debug report */
TRACE("args: 0x%lx, 0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt:%s (at %p), " TRACE("args: 0x%lx, 0x%lx, 0x%lx, time(d=%d,h=%d,m=%d,s=%d), fmt:%s (at %p), "
...@@ -1600,55 +1589,50 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, ...@@ -1600,55 +1589,50 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond, xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond,
debugstr_w(format), format, output, outlen); debugstr_w(format), format, output, outlen);
if(outlen == 0) {
FIXME("outlen = 0, returning 255\n");
return 255;
}
/* initialize state variables */ /* initialize state variables */
inpos = outpos = 0; outpos = 0;
count = 0;
inquote = Overflow = 0; while (*format) {
/* this is really just a sanity check */ /* Literal string: Maybe terminated early by a \0 */
output[0] = buf[0] = 0; if (*format == (WCHAR) '\'') {
format++;
/* this loop is the core of the function */ while (*format) {
for (inpos = 0; /* we have several break points */ ; inpos++) { if (*format == (WCHAR) '\'') {
if (inquote) { format++;
if (format[inpos] == (WCHAR) '\'') { if (*format != '\'') {
if (format[inpos+1] == '\'') { break; /* It was a terminating quote */
inpos++; }
output[outpos++] = '\''; }
} else { if (!outlen)
inquote = 0; /* We are counting */;
continue; else if (outpos >= outlen)
} goto too_short;
} else if (format[inpos] == 0) { else
output[outpos++] = 0; output[outpos] = *format;
if (outpos > outlen) Overflow = 1; outpos++;
break; /* normal exit (within a quote) */ format++;
} else { }
output[outpos++] = format[inpos]; /* copy input */ } else if ( (dateformat && (*format=='d' ||
if (outpos > outlen) { *format=='M' ||
Overflow = 1; *format=='y' ||
output[outpos-1] = 0; *format=='g') ) ||
break; (!dateformat && (*format=='H' ||
} *format=='h' ||
} *format=='m' ||
} else if ( (count && (format[inpos] != type)) *format=='s' ||
|| ( (count==4 && type =='y') || *format=='t') ) ) {
(count==4 && type =='M') || int type, count;
(count==4 && type =='d') || char tmp[16];
(count==2 && type =='g') || WCHAR buf[40];
(count==2 && type =='h') || int buflen=0;
(count==2 && type =='H') || type = *format;
(count==2 && type =='m') || format++;
(count==2 && type =='s') || for (count = 1; *format == type; format++)
(count==2 && type =='t') ) ) { count++;
switch(type) switch(type)
{ {
case 'd': case 'd':
if (count == 4) { if (count >= 4) {
GetLocaleInfoW(locale, GetLocaleInfoW(locale,
LOCALE_SDAYNAME1 + (xtime->wDayOfWeek +6)%7, LOCALE_SDAYNAME1 + (xtime->wDayOfWeek +6)%7,
buf, sizeof(buf)/sizeof(WCHAR) ); buf, sizeof(buf)/sizeof(WCHAR) );
...@@ -1664,7 +1648,7 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, ...@@ -1664,7 +1648,7 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
break; break;
case 'M': case 'M':
if (count == 4) { if (count >= 4) {
GetLocaleInfoW(locale, LOCALE_SMONTHNAME1 + GetLocaleInfoW(locale, LOCALE_SMONTHNAME1 +
xtime->wMonth -1, buf, xtime->wMonth -1, buf,
sizeof(buf)/sizeof(WCHAR) ); sizeof(buf)/sizeof(WCHAR) );
...@@ -1678,12 +1662,10 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, ...@@ -1678,12 +1662,10 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
} }
break; break;
case 'y': case 'y':
if (count == 4) { if (count >= 4) {
sprintf( tmp, "%d", xtime->wYear ); sprintf( tmp, "%d", xtime->wYear );
} else if (count == 3) {
strcpy( tmp, "yyy" );
} else { } else {
sprintf( tmp, "%.*d", count, xtime->wYear % 100 ); sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wYear % 100 );
} }
MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
break; break;
...@@ -1701,22 +1683,22 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, ...@@ -1701,22 +1683,22 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
case 'h': case 'h':
/* hours 1:00-12:00 --- is this right? */ /* hours 1:00-12:00 --- is this right? */
sprintf( tmp, "%.*d", count, (xtime->wHour-1)%12 +1); sprintf( tmp, "%.*d", count > 2 ? 2 : count, (xtime->wHour-1)%12 +1);
MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
break; break;
case 'H': case 'H':
sprintf( tmp, "%.*d", count, xtime->wHour ); sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wHour );
MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
break; break;
case 'm': case 'm':
sprintf( tmp, "%.*d", count, xtime->wMinute ); sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wMinute );
MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
break; break;
case 's': case 's':
sprintf( tmp, "%.*d", count, xtime->wSecond ); sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wSecond );
MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) );
break; break;
...@@ -1728,71 +1710,49 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, ...@@ -1728,71 +1710,49 @@ static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags,
buf[1] = 0; buf[1] = 0;
} }
break; break;
} }
/* no matter what happened, we need to check this next
character the next time we loop through */
inpos--;
/* cat buf onto the output */ /* cat buf onto the output */
outlen = strlenW(buf); buflen = strlenW(buf);
if (outpos + buflen < outlen) { if (!outlen)
/* We are counting */;
else if (outpos + buflen < outlen) {
strcpyW( output + outpos, buf ); strcpyW( output + outpos, buf );
outpos += buflen;
} else { } else {
lstrcpynW( output + outpos, buf, outlen - outpos ); lstrcpynW( output + outpos, buf, outlen - outpos );
Overflow = 1; /* Is this an undocumented feature we are supporting? */
break; /* Abnormal exit */ goto too_short;
} }
outpos += buflen;
/* reset the variables we used this time */
count = 0;
type = '\0';
} else if (format[inpos] == 0) {
/* we can't check for this at the beginning, because that
would keep us from printing a format spec that ended the
string */
output[outpos] = 0;
break; /* NORMAL EXIT */
} else if (count) {
/* how we keep track of the middle of a format spec */
count++;
continue;
} else if ( (datevars && (format[inpos]=='d' ||
format[inpos]=='M' ||
format[inpos]=='y' ||
format[inpos]=='g') ) ||
(timevars && (format[inpos]=='H' ||
format[inpos]=='h' ||
format[inpos]=='m' ||
format[inpos]=='s' ||
format[inpos]=='t') ) ) {
type = format[inpos];
count = 1;
continue;
} else if (format[inpos] == '\'') {
inquote = 1;
continue;
} else { } else {
/* unquoted literals */ /* a literal character */
output[outpos++] = format[inpos]; if (!outlen)
/* We are counting */;
else if (outpos >= outlen)
goto too_short;
else
output[outpos] = *format;
outpos++;
format++;
} }
} }
if (Overflow) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
WARN(" buffer overflow\n");
};
/* final string terminator and sanity check */ /* final string terminator and sanity check */
if (!outlen)
/* We are counting */;
else if (outpos >= outlen)
goto too_short;
else
output[outpos] = '\0';
outpos++; outpos++;
if (outpos > outlen-1) outpos = outlen-1;
output[outpos] = '0';
TRACE(" returning %s\n", debugstr_w(output)); TRACE(" returning %d %s\n", outpos, debugstr_w(output));
return outpos;
return (!Overflow) ? outlen : 0;
too_short:
SetLastError(ERROR_INSUFFICIENT_BUFFER);
WARN(" buffer overflow\n");
return 0;
} }
...@@ -1910,6 +1870,17 @@ INT WINAPI GetDateFormatW(LCID locale,DWORD flags, ...@@ -1910,6 +1870,17 @@ INT WINAPI GetDateFormatW(LCID locale,DWORD flags,
TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n", TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",
locale,flags,xtime,debugstr_w(format),date,datelen); locale,flags,xtime,debugstr_w(format),date,datelen);
/* Tests (could be left until OLE_GetFormatW) */
if (flags && format)
{
SetLastError (ERROR_INVALID_FLAGS);
return 0;
}
if (datelen && !date)
{
SetLastError (ERROR_INVALID_PARAMETER);
return 0;
}
if (!locale) { if (!locale) {
locale = LOCALE_SYSTEM_DEFAULT; locale = LOCALE_SYSTEM_DEFAULT;
}; };
...@@ -1950,7 +1921,7 @@ INT WINAPI GetDateFormatW(LCID locale,DWORD flags, ...@@ -1950,7 +1921,7 @@ INT WINAPI GetDateFormatW(LCID locale,DWORD flags,
ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat, ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat,
date, datelen); date, datelen, 1);
TRACE("GetDateFormatW() returning %d, with data=%s\n", TRACE("GetDateFormatW() returning %d, with data=%s\n",
...@@ -3067,7 +3038,7 @@ GetTimeFormatW(LCID locale, /* [in] */ ...@@ -3067,7 +3038,7 @@ GetTimeFormatW(LCID locale, /* [in] */
} }
ret = OLE_GetFormatW(thislocale, thisflags, flags, thistime, thisformat, ret = OLE_GetFormatW(thislocale, thisflags, flags, thistime, thisformat,
timestr, timelen); timestr, timelen, 0);
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment