preferable GetDateFormatW fix
Medland, Bill
Bill.Medland at accpac.com
Wed Oct 23 22:52:27 CDT 2002
Bill Medland (medbi01 at accpac.com)
Fix OLE_GetFormatW so that GetDateFormatW works
Rearranged for simplicity
Index: wine/ole/ole2nls.c
===================================================================
RCS file: /home/wine/wine/ole/ole2nls.c,v
retrieving revision 1.105
diff -u -r1.105 ole2nls.c
--- wine/ole/ole2nls.c 3 Oct 2002 22:57:55 -0000 1.105
+++ wine/ole/ole2nls.c 24 Oct 2002 03:34:12 -0000
@@ -1572,26 +1572,15 @@
/***************************************************************************
***
* 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,
const SYSTEMTIME* xtime,
LPCWSTR format,
- LPWSTR output, INT outlen)
+ LPWSTR output, INT outlen, int dateformat)
{
- INT inpos, 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;
+ INT outpos;
/* 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), "
@@ -1600,55 +1589,50 @@
xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond,
debugstr_w(format), format, output, outlen);
- if(outlen == 0) {
- FIXME("outlen = 0, returning 255\n");
- return 255;
- }
-
/* initialize state variables */
- inpos = outpos = 0;
- count = 0;
- inquote = Overflow = 0;
- /* this is really just a sanity check */
- output[0] = buf[0] = 0;
-
- /* this loop is the core of the function */
- for (inpos = 0; /* we have several break points */ ; inpos++) {
- if (inquote) {
- if (format[inpos] == (WCHAR) '\'') {
- if (format[inpos+1] == '\'') {
- inpos++;
- output[outpos++] = '\'';
- } else {
- inquote = 0;
- continue;
- }
- } else if (format[inpos] == 0) {
- output[outpos++] = 0;
- if (outpos > outlen) Overflow = 1;
- break; /* normal exit (within a quote) */
- } else {
- output[outpos++] = format[inpos]; /* copy input */
- if (outpos > outlen) {
- Overflow = 1;
- output[outpos-1] = 0;
- break;
- }
- }
- } else if ( (count && (format[inpos] != type))
- || ( (count==4 && type =='y') ||
- (count==4 && type =='M') ||
- (count==4 && type =='d') ||
- (count==2 && type =='g') ||
- (count==2 && type =='h') ||
- (count==2 && type =='H') ||
- (count==2 && type =='m') ||
- (count==2 && type =='s') ||
- (count==2 && type =='t') ) ) {
- switch(type)
- {
+ outpos = 0;
+
+ while (*format) {
+ /* Literal string: Maybe terminated early by a \0 */
+ if (*format == (WCHAR) '\'') {
+ format++;
+ while (*format) {
+ if (*format == (WCHAR) '\'') {
+ format++;
+ if (*format != '\'') {
+ break; /* It was a terminating quote */
+ }
+ }
+ if (!outlen)
+ /* We are counting */;
+ else if (outpos >= outlen)
+ goto too_short;
+ else
+ output[outpos] = *format;
+ outpos++;
+ format++;
+ }
+ } else if ( (dateformat && (*format=='d' ||
+ *format=='M' ||
+ *format=='y' ||
+ *format=='g') ) ||
+ (!dateformat && (*format=='H' ||
+ *format=='h' ||
+ *format=='m' ||
+ *format=='s' ||
+ *format=='t') ) ) {
+ int type, count;
+ char tmp[16];
+ WCHAR buf[40];
+ int buflen=0;
+ type = *format;
+ format++;
+ for (count = 1; *format == type; format++)
+ count++;
+ switch(type)
+ {
case 'd':
- if (count == 4) {
+ if (count >= 4) {
GetLocaleInfoW(locale,
LOCALE_SDAYNAME1 + (xtime->wDayOfWeek +6)%7,
buf, sizeof(buf)/sizeof(WCHAR) );
@@ -1664,7 +1648,7 @@
break;
case 'M':
- if (count == 4) {
+ if (count >= 4) {
GetLocaleInfoW(locale, LOCALE_SMONTHNAME1 +
xtime->wMonth -1, buf,
sizeof(buf)/sizeof(WCHAR) );
@@ -1678,12 +1662,10 @@
}
break;
case 'y':
- if (count == 4) {
+ if (count >= 4) {
sprintf( tmp, "%d", xtime->wYear );
- } else if (count == 3) {
- strcpy( tmp, "yyy" );
} 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) );
break;
@@ -1701,22 +1683,22 @@
case 'h':
/* 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) );
break;
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) );
break;
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) );
break;
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) );
break;
@@ -1728,71 +1710,49 @@
buf[1] = 0;
}
break;
- }
-
- /* no matter what happened, we need to check this next
- character the next time we loop through */
- inpos--;
+ }
/* cat buf onto the output */
- outlen = strlenW(buf);
- if (outpos + buflen < outlen) {
+ buflen = strlenW(buf);
+ if (!outlen)
+ /* We are counting */;
+ else if (outpos + buflen < outlen) {
strcpyW( output + outpos, buf );
- outpos += buflen;
} else {
lstrcpynW( output + outpos, buf, outlen - outpos );
- Overflow = 1;
- break; /* Abnormal exit */
+ /* Is this an undocumented feature we are supporting? */
+ goto too_short;
}
-
- /* 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;
+ outpos += buflen;
} else {
- /* unquoted literals */
- output[outpos++] = format[inpos];
+ /* a literal character */
+ 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 */
+ if (!outlen)
+ /* We are counting */;
+ else if (outpos >= outlen)
+ goto too_short;
+ else
+ output[outpos] = '\0';
outpos++;
- if (outpos > outlen-1) outpos = outlen-1;
- output[outpos] = '0';
- TRACE(" returning %s\n", debugstr_w(output));
-
- return (!Overflow) ? outlen : 0;
+ TRACE(" returning %d %s\n", outpos, debugstr_w(output));
+ return outpos;
+too_short:
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ WARN(" buffer overflow\n");
+ return 0;
}
@@ -1910,6 +1870,17 @@
TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",
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) {
locale = LOCALE_SYSTEM_DEFAULT;
};
@@ -1950,7 +1921,7 @@
ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat,
- date, datelen);
+ date, datelen, 1);
TRACE("GetDateFormatW() returning %d, with data=%s\n",
@@ -3067,7 +3038,7 @@
}
ret = OLE_GetFormatW(thislocale, thisflags, flags, thistime,
thisformat,
- timestr, timelen);
+ timestr, timelen, 0);
return ret;
}
Index: wine/dlls/kernel/tests/locale.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/tests/locale.c,v
retrieving revision 1.4
diff -u -r1.4 locale.c
--- wine/dlls/kernel/tests/locale.c 4 Jun 2002 22:12:50 -0000 1.4
+++ wine/dlls/kernel/tests/locale.c 24 Oct 2002 03:34:12 -0000
@@ -30,6 +30,7 @@
#define BUFFER_SIZE 50
/* Buffer used by callback function */
char GlobalBuffer[BUFFER_SIZE];
+#define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
/* TODO :
* Unicode versions
@@ -183,6 +184,58 @@
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()
{
@@ -343,6 +396,7 @@
TestGetLocaleInfoA();
TestGetTimeFormatA();
TestGetDateFormatA();
+ TestGetDateFormatW();
TestGetNumberFormat();
TestGetCurrencyFormat();
TestCompareStringA();
More information about the wine-patches
mailing list