Changelog: re-did OLE_GetFormatW so that dates are formatted correctly for the XP app i am using caveats: it just does what i needed, i attempted to follow the docs on msdn but i have not tested anything but a few basic dates. also, rather than figure out the old OLE_GetFormatW i just reimplemented it, as i figured it would take less time to do it this way, but i'm sure it would be a better patch if i just fixed what didn't work in OLE_GetFormatW. notes: it seems like, if this ever worked correctly, that OLE_GetFormatA could be implemented by just copying the ascii buffer and sending it along to OLE_GetFormatW?
Index: ole/ole2nls.c =================================================================== RCS file: /home/wine/wine/ole/ole2nls.c,v retrieving revision 1.104 diff -r1.104 ole2nls.c 1573a1574,1583 > * OLE_GetRepW [INTERNAL] > * > * get count of repetitions of c... > */ > static INT OLE_GetRepW(LPCWSTR s, WCHAR c) > { > int i = 0; while (s[i] == c) i++; return i; > } > > /****************************************************************************** 1574a1585,1633 > * > * > * dwFlags[in]: > * LOCALE_NOUSEROVERRIDE : format the struct using system default date format > * LOCALE_USE_CP_ACP : > * DATE_SHORTDATE > * DATE_LONGDATE > * DATE_YEARMONTH > * DATE_USE_ALT_CALENDAR > * DATE_LTRREADING > * DATE_RTLREADING > * > * xtime: pointer to SYSTEMTIME. if null, use current local system date > * > * format: if null, use date format of locale > * d day as digits with no leading zero > * dd day as digits with leading zero > * ddd day as 3 char abbrev. uses LOCALE_SABBREVDAYNAME > * dddd day as full name. uses LOCALE_SDAYNAME > * M month as digits, no leading zero > * MM month as digits, leading zero > * MMM month as 3 char abbrev. uses LOCALE_SABBREVMONTHNAME > * MMMM month as full name. uses LOCALE_SMONTHNAME > * y year as last two digits, no leading zero > * yy year as last two digits, leading zero > * yyyy year as four digits > * gg period, or era string. uses CAL_SERASTRING, not > * used if date does not have an era or period string > * h hours, no leading zero, 12hr clock > * hh hours, leading zero, 12hr clock > * H hours, no leading zero, 24hr clock > * HH hours, leading zero, 24hr clock > * m minutes, no leading zero > * mm minutes, leading zero > * s seconds, no leading zero > * ss seconds, leading zero > * t A or P > * tt AM or PM > * > * output: zero terminated buffer > * > * outlen: specifies len of output. if > * zero, the function returns the number of chars required > * to format the date... > * > * FIXME: > * verify xtime! > * flags: DATE_USE_ALT_CALENDAR, DATE_LTREADING, DATE_RTREADING > * 1577,1579c1636,1638 < const SYSTEMTIME* xtime, < LPCWSTR format, < LPWSTR output, INT outlen) --- > const SYSTEMTIME* xtime, > LPCWSTR format, > LPWSTR output, INT outlen) 1581,1595c1640 < 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 inpos = 0, outpos = 0; 1602,1624c1647,1669 < < 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; --- > > /* outlen must make sense > */ > if (outlen<0) outlen = 0; > if (outlen==0) output=NULL; > > while (format[inpos]) { > WCHAR tmp[256]; > int tl = 0; > char b[256]; > > /* printf("format[%d]: %02x [%c] -> %d\n", inpos, format[inpos], format[inpos], outpos); */ > > if (format[inpos] == (WCHAR) '\'') { > inpos++; > while (format[inpos]) { > if (format[inpos]==(WCHAR)'\'') { > /* ''' -> ' otherwise exit... > */ > if (OLE_GetRepW(format+inpos, (WCHAR) '\'')>=3) { > inpos+=2; > } > else break; 1626,1635c1671,1679 < } 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; --- > if (output!=NULL) { > if (outpos<outlen) { > output[outpos] = format[inpos]; > } > else { > SetLastError(ERROR_INSUFFICIENT_BUFFER); > if (outpos>0) output[outpos-1] = 0; > return 0; > } 1636a1681,1682 > outpos++; > inpos++; 1638,1724c1684,1759 < } 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) < { < case 'd': < if (count == 4) { < GetLocaleInfoW(locale, < LOCALE_SDAYNAME1 + (xtime->wDayOfWeek +6)%7, < buf, sizeof(buf)/sizeof(WCHAR) ); < } else if (count == 3) { < GetLocaleInfoW(locale, < LOCALE_SABBREVDAYNAME1 + < (xtime->wDayOfWeek +6)%7, < buf, sizeof(buf)/sizeof(WCHAR) ); < } else { < sprintf( tmp, "%.*d", count, xtime->wDay ); < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < } < break; < < case 'M': < if (count == 4) { < GetLocaleInfoW(locale, LOCALE_SMONTHNAME1 + < xtime->wMonth -1, buf, < sizeof(buf)/sizeof(WCHAR) ); < } else if (count == 3) { < GetLocaleInfoW(locale, LOCALE_SABBREVMONTHNAME1 + < xtime->wMonth -1, buf, < sizeof(buf)/sizeof(WCHAR) ); < } else { < sprintf( tmp, "%.*d", count, xtime->wMonth ); < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < } < break; < case 'y': < if (count == 4) { < sprintf( tmp, "%d", xtime->wYear ); < } else if (count == 3) { < strcpy( tmp, "yyy" ); < } else { < sprintf( tmp, "%.*d", count, xtime->wYear % 100 ); < } < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < break; < < case 'g': < if (count == 2) { < FIXME("LOCALE_ICALENDARTYPE unimplemented\n"); < strcpy( tmp, "AD" ); < } else { < /* Win API sez we copy it verbatim */ < strcpy( tmp, "g" ); < } < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < break; < < case 'h': < /* hours 1:00-12:00 --- is this right? */ < sprintf( tmp, "%.*d", 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 ); < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < break; < < case 'm': < sprintf( tmp, "%.*d", count, xtime->wMinute ); < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < break; < < case 's': < sprintf( tmp, "%.*d", count, xtime->wSecond ); < MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); < break; < < case 't': < GetLocaleInfoW(locale, (xtime->wHour < 12) ? --- > if (format[inpos]) inpos++; > } > else if (format[inpos] == (WCHAR) 'd') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'd'); > inpos += cnt; > if (cnt==1 || cnt==2) { > sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wDay); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else { > const int dow = (xtime->wDayOfWeek+6)%7; > tl = GetLocaleInfoW(locale, > ((cnt==3) ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1) + dow, > tmp, sizeof(tmp)/sizeof(tmp[0])); > } > } > else if (format[inpos] == (WCHAR) 'M') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'M'); > const int mn = xtime->wMonth; > inpos += cnt; > if (cnt==1 || cnt==2) { > sprintf(b, (cnt==1) ? "%d" : "%02d", mn); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else { > tl = GetLocaleInfoW(locale, > ((cnt==3) ? LOCALE_SABBREVMONTHNAME1 : LOCALE_SMONTHNAME1) + mn, > tmp, sizeof(tmp)/sizeof(tmp[0])); > } > } > else if (format[inpos] == (WCHAR) 'y') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'y'); > const int yr = xtime->wYear; > inpos += cnt; > if (cnt==1 || cnt==2) { > sprintf(b, (cnt==1) ? "%d" : "%02d", yr%100); > } > else sprintf(b, "%d", yr); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else if (format[inpos] == (WCHAR) 'g') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'g'); > inpos += cnt; > /* FIXME: which calendar id? we use 0... > */ > tl = GetCalendarInfoW(locale, 0, CAL_SERASTRING, > tmp, sizeof(tmp)/sizeof(tmp[0]), NULL); > } > else if (format[inpos] == (WCHAR) 'h') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'h'); > inpos += cnt; > sprintf(b, (cnt==1) ? "%d" : "%02d", (xtime->wHour-1)%12+1); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else if (format[inpos] == (WCHAR) 'H') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'H'); > inpos += cnt; > sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wHour); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else if (format[inpos] == (WCHAR) 'm') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 'm'); > inpos += cnt; > sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wMinute); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else if (format[inpos] == (WCHAR) 's') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 's'); > inpos += cnt; > sprintf(b, (cnt==1) ? "%d" : "%02d", xtime->wSecond); > tl = MultiByteToWideChar(CP_ACP, 0, b, -1, tmp, sizeof(tmp)/sizeof(tmp[0])); > } > else if (format[inpos] == (WCHAR) 't') { > const int cnt = OLE_GetRepW(format + inpos, (WCHAR) 't'); > inpos += cnt; > tl = GetLocaleInfoW(locale, (xtime->wHour < 12) ? 1726,1731c1761,1771 < buf, sizeof(buf) ); < if (count == 1) { < buf[1] = 0; < } < break; < } --- > tmp, sizeof(tmp)/sizeof(tmp[0])); > if (cnt==1 && tl>1) { tmp[1] = 0; tl = 2; } > } > /* default case, just copy output char... > */ > else { > tl = 2; > tmp[0] = format[inpos]; > tmp[1] = 0; > inpos++; > } 1733,1745c1773,1787 < /* 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) { < strcpyW( output + outpos, buf ); < outpos += buflen; < } else { < lstrcpynW( output + outpos, buf, outlen - outpos ); < Overflow = 1; < break; /* Abnormal exit */ --- > /* some characters buffered -- put them in output... > */ > if (tl>0) { > if (output!=NULL) { > int j; > for (j=0; j<tl-1; j++) { > if (outpos+j<outlen) { > output[outpos+j] = tmp[j]; > } > else { > if (outpos+j>0 && outlen>0) output[outpos+j-1] = 0; > SetLastError(ERROR_INSUFFICIENT_BUFFER); > return 0; > } > } 1746a1789,1791 > outpos+=tl-1; > } > } 1748,1754c1793,1794 < /* 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 */ --- > if (output!=NULL) { > if (outpos<outlen) { 1756,1778c1796,1799 < 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 { < /* unquoted literals */ < output[outpos++] = format[inpos]; --- > outpos++; > } > else { > output[outpos-1]=0; 1782,1795c1803 < if (Overflow) { < SetLastError(ERROR_INSUFFICIENT_BUFFER); < WARN(" buffer overflow\n"); < }; < < /* final string terminator and sanity check */ < outpos++; < if (outpos > outlen-1) outpos = outlen-1; < output[outpos] = '0'; < < TRACE(" returning %s\n", debugstr_w(output)); < < return (!Overflow) ? outlen : 0; < --- > return outpos; 1798d1805 < 1901c1908,1915 < unsigned short datearr[] = {'1','9','9','4','-','1','-','1',0}; --- > WCHAR format_buf[40]; > LPCWSTR thisformat; > SYSTEMTIME t; > LPSYSTEMTIME thistime; > LCID thislocale; > INT ret; > FILETIME ft; > BOOL res; 1903,1905c1917,1918 < FIXME("STUB (should call OLE_GetFormatW)\n"); < lstrcpynW(date, datearr, datelen); < return ( datelen < 9) ? datelen : 9; --- > TRACE("(0x%04lx,0x%08lx,%p,%p,%p,%d)\n", > locale,flags,xtime,format,date,datelen); 1906a1920,1922 > if (!locale) { > locale = LOCALE_SYSTEM_DEFAULT; > }; 1907a1924,1967 > if (locale == LOCALE_SYSTEM_DEFAULT) { > thislocale = GetSystemDefaultLCID(); > } else if (locale == LOCALE_USER_DEFAULT) { > thislocale = GetUserDefaultLCID(); > } else { > thislocale = locale; > }; > > > if (xtime == NULL) { > GetSystemTime(&t); > } else { > /* Silently correct wDayOfWeek by transforming to FileTime and back again */ > res=SystemTimeToFileTime(xtime,&ft); > /* Check year(?)/month and date for range and set ERROR_INVALID_PARAMETER on error */ > /*FIXME: SystemTimeToFileTime doesn't yet do that check */ > if(!res) > { > SetLastError(ERROR_INVALID_PARAMETER); > return 0; > } > FileTimeToSystemTime(&ft,&t); > > }; > thistime = &t; > > if (format == NULL) { > GetLocaleInfoW(thislocale, ((flags&DATE_LONGDATE) > ? LOCALE_SLONGDATE > : LOCALE_SSHORTDATE), > format_buf, sizeof(format_buf)); > thisformat = format_buf; > } else { > thisformat = format; > }; > > > ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat, > date, datelen); > > TRACE( > "GetDateFormatW() returning %d, with data=%p\n", > ret, date); > return ret;