diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in index ba080ed9fc5..59a8d0200d2 100644 --- a/dlls/kernel/Makefile.in +++ b/dlls/kernel/Makefile.in @@ -18,6 +18,7 @@ C_SRCS = \ editline.c \ format_msg.c \ kernel_main.c \ + lcformat.c \ locale.c \ stress.c \ string.c \ diff --git a/dlls/kernel/lcformat.c b/dlls/kernel/lcformat.c new file mode 100644 index 00000000000..bad52ce0183 --- /dev/null +++ b/dlls/kernel/lcformat.c @@ -0,0 +1,1672 @@ +/* + * Locale-dependent format handling + * + * Copyright 1995 Martin von Loewis + * Copyright 1998 David Lee Lambert + * Copyright 2000 Julio César Gázquez + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(nls); + + +/****************************************************************************** + * get_date_time_formatW [Internal] + * + * dateformat is set TRUE if being called for a date, false for a time + * + * This function implements stuff for GetDateFormat() and + * GetTimeFormat(). + * + * d single-digit (no leading zero) day (of month) + * dd two-digit day (of month) + * ddd short day-of-week name + * dddd long day-of-week name + * M single-digit month + * MM two-digit month + * MMM short month name + * MMMM full month name + * y two-digit year, no leading 0 + * yy two-digit year + * yyyy four-digit year + * gg era string + * h hours with no leading zero (12-hour) + * hh hours with full two digits + * H hours with no leading zero (24-hour) + * HH hours with full two digits + * m minutes with no leading zero + * mm minutes with full two digits + * s seconds with no leading zero + * ss seconds with full two digits + * t time marker (A or P) + * tt time marker (AM, PM) + * '' used to quote literal characters + * '' (within a quoted string) indicates a literal ' + * + * If TIME_NOMINUTESORSECONDS or TIME_NOSECONDS is specified, the function + * removes the separator(s) preceding the minutes and/or seconds element(s). + * + * If TIME_NOTIMEMARKER is specified, the function removes the separator(s) + * preceding and following the time marker. + * + * If TIME_FORCE24HOURFORMAT is specified, the function displays any existing + * time marker, unless the TIME_NOTIMEMARKER flag is also set. + * + * These functions REQUIRE valid locale, date, and format. + * + * If the time or date is invalid, return 0 and set ERROR_INVALID_PARAMETER + * + * Return value is the number of characters written, or if outlen is zero + * it is the number of characters required for the output including + * the terminating null. + */ +static INT get_date_time_formatW(LCID locale, DWORD flags, DWORD tflags, + const SYSTEMTIME* xtime, LPCWSTR format, + LPWSTR output, INT outlen, int dateformat) +{ + INT outpos; + INT lastFormatPos; /* the position in the output buffer of */ + /* the end of the output from the last formatting */ + /* character */ + BOOL dropUntilNextFormattingChar = FALSE; /* TIME_NOTIMEMARKER drops + all of the text around the dropped marker, + eg. "h@!t@!m" becomes "hm" */ + + /* 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), " + "%p with max len %d\n", + locale, flags, tflags, + xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond, + debugstr_w(format), format, output, outlen); + + /* initialize state variables */ + outpos = 0; + lastFormatPos = 0; + + while (*format) { + /* Literal string: Maybe terminated early by a \0 */ + if (*format == (WCHAR) '\'') + { + format++; + + /* We loop while we haven't reached the end of the format string */ + /* and until we haven't found another "'" character */ + while (*format) + { + /* we found what might be the close single quote mark */ + /* we need to make sure there isn't another single quote */ + /* after it, if there is we need to skip over this quote mark */ + /* as the user is trying to put a single quote mark in their output */ + if (*format == (WCHAR) '\'') + { + format++; + if (*format != '\'') + { + break; /* It was a terminating quote */ + } + } + + /* if outlen is zero then we are couting the number of */ + /* characters of space we need to output this text, don't */ + /* modify the output buffer */ + if (!outlen) + { + outpos++; /* We are counting */; + } else if (outpos >= outlen) + { + goto too_short; + } else + { + /* even drop literal strings */ + if(!dropUntilNextFormattingChar) + { + 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') ) ) + /* if processing a date and we have a date formatting character, OR */ + /* if we are processing a time and we have a time formatting character */ + { + int type, count; + char tmp[16]; + WCHAR buf[40]; + int buflen=0; + type = *format; + format++; + + /* clear out the drop text flag if we are in here */ + dropUntilNextFormattingChar = FALSE; + + /* count up the number of the same letter values in a row that */ + /* we get, this lets us distinguish between "s" and "ss" and it */ + /* eliminates the duplicate to simplify the below case statement */ + for (count = 1; *format == type; format++) + count++; + + buf[0] = 0; /* always null terminate the buffer */ + + 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 { + sprintf( tmp, "%.*d", count > 2 ? 2 : 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': + /* fallthrough if we are forced to output in 24 hour format */ + if(!(tflags & TIME_FORCE24HOURFORMAT)) + { + /* hours 1:00-12:00 --- is this right? */ + /* NOTE: 0000 hours is also 12 midnight */ + sprintf( tmp, "%.*d", count > 2 ? 2 : count, + xtime->wHour == 0 ? 12 : (xtime->wHour-1)%12 +1); + MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); + break; + } + case 'H': + sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wHour ); + MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); + break; + + case 'm': + /* if TIME_NOMINUTESORSECONDS don't display minutes */ + if(!(tflags & TIME_NOMINUTESORSECONDS)) + { + sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wMinute ); + MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); + } else + { + outpos = lastFormatPos; + } + break; + + case 's': + /* if we have a TIME_NOSECONDS or TIME_NOMINUTESORSECONDS + flag then don't display seconds */ + if(!(tflags & TIME_NOSECONDS) && !(tflags & + TIME_NOMINUTESORSECONDS)) + { + sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wSecond ); + MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); + } else + { + outpos = lastFormatPos; + } + break; + + case 't': + if(!(tflags & TIME_NOTIMEMARKER)) + { + GetLocaleInfoW(locale, (xtime->wHour < 12) ? + LOCALE_S1159 : LOCALE_S2359, + buf, sizeof(buf) ); + if (count == 1) + { + buf[1] = 0; + } + } else + { + outpos = lastFormatPos; /* remove any prior text up until + the output due to formatting characters */ + dropUntilNextFormattingChar = TRUE; /* drop everything + until we hit the next formatting character */ + } + break; + } + + /* cat buf onto the output */ + buflen = strlenW(buf); + + /* we are counting how many characters we need for output */ + /* don't modify the output buffer... */ + if (!outlen) + /* We are counting */; + else if (outpos + buflen < outlen) { + strcpyW( output + outpos, buf ); + } else { + lstrcpynW( output + outpos, buf, outlen - outpos ); + /* Is this an undocumented feature we are supporting? */ + goto too_short; + } + outpos += buflen; + lastFormatPos = outpos; /* record the end of the formatting text we just output */ + } else /* we are processing a NON formatting character */ + { + /* a literal character */ + if (!outlen) + { + outpos++; /* We are counting */; + } + else if (outpos >= outlen) + { + goto too_short; + } + else /* just copy the character into the output buffer */ + { + /* unless we are dropping characters */ + if(!dropUntilNextFormattingChar) + { + output[outpos] = *format; + outpos++; + } + } + format++; + } + } + + /* final string terminator and sanity check */ + if (!outlen) + /* We are counting */; + else if (outpos >= outlen) + goto too_short; + else + output[outpos] = '\0'; + + outpos++; /* add one for the terminating null character */ + + TRACE(" returning %d %s\n", outpos, debugstr_w(output)); + return outpos; + +too_short: + SetLastError(ERROR_INSUFFICIENT_BUFFER); + WARN(" buffer overflow\n"); + return 0; +} + + +/****************************************************************************** + * GetDateFormatA [KERNEL32.@] + * Makes an ASCII string of the date + * + * Acts the same as GetDateFormatW(), except that it's ASCII. + */ +INT WINAPI GetDateFormatA( LCID locale, DWORD flags, const SYSTEMTIME* xtime, + LPCSTR format, LPSTR date, INT datelen ) +{ + INT ret; + LPWSTR wformat = NULL; + LPWSTR wdate = NULL; + + if (format) + { + wformat = HeapAlloc(GetProcessHeap(), 0, + (strlen(format) + 1) * sizeof(wchar_t)); + + MultiByteToWideChar(CP_ACP, 0, format, -1, wformat, strlen(format) + 1); + } + + if (date && datelen) + { + wdate = HeapAlloc(GetProcessHeap(), 0, + (datelen + 1) * sizeof(wchar_t)); + } + + ret = GetDateFormatW(locale, flags, xtime, wformat, wdate, datelen); + + if (wdate) + { + WideCharToMultiByte(CP_ACP, 0, wdate, ret, date, datelen, NULL, NULL); + HeapFree(GetProcessHeap(), 0, wdate); + } + + if (wformat) + { + HeapFree(GetProcessHeap(), 0, wformat); + } + + return ret; +} + + +/****************************************************************************** + * GetDateFormatW [KERNEL32.@] + * Makes a Unicode string of the date + * + * This function uses format to format the date, or, if format + * is NULL, uses the default for the locale. format is a string + * of literal fields and characters as follows: + * + * - d single-digit (no leading zero) day (of month) + * - dd two-digit day (of month) + * - ddd short day-of-week name + * - dddd long day-of-week name + * - M single-digit month + * - MM two-digit month + * - MMM short month name + * - MMMM full month name + * - y two-digit year, no leading 0 + * - yy two-digit year + * - yyyy four-digit year + * - gg era string + * + * Accepts & returns sizes as counts of Unicode characters. + */ +INT WINAPI GetDateFormatW( LCID locale, DWORD flags, const SYSTEMTIME* xtime, + LPCWSTR format, LPWSTR date, INT datelen) +{ + WCHAR format_buf[40]; + LPCWSTR thisformat; + SYSTEMTIME t; + LCID thislocale; + INT ret; + FILETIME ft; + BOOL res; + + TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n", + locale,flags,xtime,debugstr_w(format),date,datelen); + + /* Tests */ + if (flags && format) /* if lpFormat is non-null then flags must be zero */ + { + SetLastError (ERROR_INVALID_FLAGS); + return 0; + } + if (datelen && !date) + { + SetLastError (ERROR_INVALID_PARAMETER); + return 0; + } + if (!locale) + { + locale = LOCALE_SYSTEM_DEFAULT; + } + + if (locale == LOCALE_SYSTEM_DEFAULT) + { + thislocale = GetSystemDefaultLCID(); + } else if (locale == LOCALE_USER_DEFAULT) + { + thislocale = GetUserDefaultLCID(); + } else + { + thislocale = locale; + } + + /* check for invalid flag combinations */ + if((flags & DATE_LTRREADING) && (flags & DATE_RTLREADING)) + { + SetLastError (ERROR_INVALID_FLAGS); + return 0; + } + + /* DATE_SHORTDATE, DATE_LONGDATE and DATE_YEARMONTH are mutually */ + /* exclusive */ + if((flags & (DATE_SHORTDATE|DATE_LONGDATE|DATE_YEARMONTH)) + && !((flags & DATE_SHORTDATE) ^ (flags & + DATE_LONGDATE) ^ (flags & DATE_YEARMONTH))) + { + SetLastError (ERROR_INVALID_FLAGS); + return 0; + } + + /* if the user didn't pass in a pointer to the current time we read it */ + /* here */ + if (xtime == NULL) + { + GetSystemTime(&t); + } else + { + /* NOTE: check here before we perform the SystemTimeToFileTime conversion */ + /* because this conversion will fix invalid time values */ + /* check to see if the time/date is valid */ + /* set ERROR_INVALID_PARAMETER and return 0 if invalid */ + if((xtime->wDay > 31) || (xtime->wMonth > 12)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + /* For all we know the day of week and the time may be absolute + * rubbish. Therefore if we are going to use conversion through + * FileTime we had better use a clean time (and hopefully we won't + * fall over any timezone complications). + * If we go with an alternative method of correcting the day of week + * (e.g. Zeller's congruence) then we won't need to, but we will need + * to check the date. + */ + memset (&t, 0, sizeof(t)); + t.wYear = xtime->wYear; + t.wMonth = xtime->wMonth; + t.wDay = xtime->wDay; + + /* Silently correct wDayOfWeek by transforming to FileTime and back again */ + res=SystemTimeToFileTime(&t,&ft); + + /* Check year(?)/month and date for range and set ERROR_INVALID_PARAMETER on error */ + if(!res) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + FileTimeToSystemTime(&ft,&t); + } + + if (format == NULL) + { + GetLocaleInfoW(thislocale, ((flags&DATE_LONGDATE) + ? LOCALE_SLONGDATE + : LOCALE_SSHORTDATE), + format_buf, sizeof(format_buf)/sizeof(*format_buf)); + thisformat = format_buf; + } else + { + thisformat = format; + } + + ret = get_date_time_formatW(thislocale, flags, 0, &t, thisformat, date, datelen, 1); + + TRACE("GetDateFormatW() returning %d, with data=%s\n", + ret, debugstr_w(date)); + return ret; +} + + +/************************************************************************** + * EnumDateFormatsA (KERNEL32.@) + */ +BOOL WINAPI EnumDateFormatsA( DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags) +{ + LCID Loc = GetUserDefaultLCID(); + if(!lpDateFmtEnumProc) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + switch( Loc ) + { + + case 0x00000407: /* (Loc,"de_DE") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd.MM.yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d.M.yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d.MM.yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d.M.yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dddd,d. MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d. MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d. MMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x0000040c: /* (Loc,"fr_FR") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd.MM.yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd-MM-yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dddd d MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d MMM yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00000c0c: /* (Loc,"fr_CA") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("yy-MM-dd")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd-MM-yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("yy MM dd")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("d MMMM, yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d MMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00000809: /* (Loc,"en_UK") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d.M.yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dd MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00000c09: /* (Loc,"en_AU") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("d/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dddd,d MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00001009: /* (Loc,"en_CA") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("yy-MM-dd")) return TRUE; + if(!(*lpDateFmtEnumProc)("M/dd/yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("d-MMM-yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("MMMM d, yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00001409: /* (Loc,"en_NZ") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("d/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d.MM.yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dddd, d MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00001809: /* (Loc,"en_IE") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d.M.yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dd MMMM yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00001c09: /* (Loc,"en_ZA") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("yy/MM/dd")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dd MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00002009: /* (Loc,"en_JM") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dddd,MMMM dd,yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("MMMM dd,yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dddd,dd MMMM,yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd MMMM,yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + case 0x00002809: /* (Loc,"en_BZ") */ + case 0x00002c09: /* (Loc,"en_TT") */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dddd,dd MMMM yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + default: /* default to US English "en_US" */ + { + switch(dwFlags) + { + case DATE_SHORTDATE: + if(!(*lpDateFmtEnumProc)("M/d/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("M/d/yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("MM/dd/yy")) return TRUE; + if(!(*lpDateFmtEnumProc)("MM/dd/yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("yy/MM/dd")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd-MMM-yy")) return TRUE; + return TRUE; + case DATE_LONGDATE: + if(!(*lpDateFmtEnumProc)("dddd, MMMM dd, yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("MMMM dd, yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dddd, dd MMMM, yyyy")) return TRUE; + if(!(*lpDateFmtEnumProc)("dd MMMM, yyyy")) return TRUE; + return TRUE; + default: + FIXME("Unknown date format (%ld)\n", dwFlags); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + } +} + +/************************************************************************** + * EnumDateFormatsW (KERNEL32.@) + */ +BOOL WINAPI EnumDateFormatsW( DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + FIXME("(%p, %ld, %ld): stub\n", lpDateFmtEnumProc, Locale, dwFlags); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/************************************************************************** + * EnumTimeFormatsA (KERNEL32.@) + */ +BOOL WINAPI EnumTimeFormatsA( TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + LCID Loc = GetUserDefaultLCID(); + if(!lpTimeFmtEnumProc) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if(dwFlags) + { + FIXME("Unknown time format (%ld)\n", dwFlags); + } + + switch( Loc ) + { + case 0x00000407: /* (Loc,"de_DE") */ + { + if(!(*lpTimeFmtEnumProc)("HH.mm")) return TRUE; + if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; + if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; + if(!(*lpTimeFmtEnumProc)("H.mm")) return TRUE; + if(!(*lpTimeFmtEnumProc)("H.mm'Uhr'")) return TRUE; + return TRUE; + } + + case 0x0000040c: /* (Loc,"fr_FR") */ + case 0x00000c0c: /* (Loc,"fr_CA") */ + { + if(!(*lpTimeFmtEnumProc)("H:mm")) return TRUE; + if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; + if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; + if(!(*lpTimeFmtEnumProc)("HH.mm")) return TRUE; + if(!(*lpTimeFmtEnumProc)("HH'h'mm")) return TRUE; + return TRUE; + } + + case 0x00000809: /* (Loc,"en_UK") */ + case 0x00000c09: /* (Loc,"en_AU") */ + case 0x00001409: /* (Loc,"en_NZ") */ + case 0x00001809: /* (Loc,"en_IE") */ + { + if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE; + if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; + if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; + return TRUE; + } + + case 0x00001c09: /* (Loc,"en_ZA") */ + case 0x00002809: /* (Loc,"en_BZ") */ + case 0x00002c09: /* (Loc,"en_TT") */ + { + if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE; + if(!(*lpTimeFmtEnumProc)("hh:mm:ss tt")) return TRUE; + return TRUE; + } + + default: /* default to US style "en_US" */ + { + if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE; + if(!(*lpTimeFmtEnumProc)("hh:mm:ss tt")) return TRUE; + if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; + if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; + return TRUE; + } + } +} + +/************************************************************************** + * EnumTimeFormatsW (KERNEL32.@) + */ +BOOL WINAPI EnumTimeFormatsW( TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags ) +{ + FIXME("(%p,%ld,%ld): stub\n", lpTimeFmtEnumProc, Locale, dwFlags); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/************************************************************************** + * This function is used just locally ! + * Description: Inverts a string. + */ +static void invert_string(char* string) +{ + int i, j; + + for (i = 0, j = strlen(string) - 1; i < j; i++, j--) + { + char ch = string[i]; + string[i] = string[j]; + string[j] = ch; + } +} + +/*************************************************************************************** + * This function is used just locally ! + * Description: Test if the given string (psNumber) is valid or not. + * The valid characters are the following: + * - Characters '0' through '9'. + * - One decimal point (dot) if the number is a floating-point value. + * - A minus sign in the first character position if the number is + * a negative value. + * If the function succeeds, psBefore/psAfter will point to the string + * on the right/left of the decimal symbol. pbNegative indicates if the + * number is negative. + */ +static INT get_number_components(char* pInput, char* psBefore, char* psAfter, BOOL* pbNegative) +{ + char sNumberSet[] = "0123456789"; + BOOL bInDecimal = FALSE; + + /* Test if we do have a minus sign */ + if ( *pInput == '-' ) + { + *pbNegative = TRUE; + pInput++; /* Jump to the next character. */ + } + + while(*pInput != '\0') + { + /* Do we have a valid numeric character */ + if ( strchr(sNumberSet, *pInput) != NULL ) + { + if (bInDecimal == TRUE) + *psAfter++ = *pInput; + else + *psBefore++ = *pInput; + } + else + { + /* Is this a decimal point (dot) */ + if ( *pInput == '.' ) + { + /* Is it the first time we find it */ + if ((bInDecimal == FALSE)) + bInDecimal = TRUE; + else + return -1; /* ERROR: Invalid parameter */ + } + else + { + /* It's neither a numeric character, nor a decimal point. + * Thus, return an error. + */ + return -1; + } + } + pInput++; + } + + /* Add an End of Line character to the output buffers */ + *psBefore = '\0'; + *psAfter = '\0'; + + return 0; +} + +/************************************************************************** + * This function is used just locally ! + * Description: A number could be formatted using different numbers + * of "digits in group" (example: 4;3;2;0). + * The first parameter of this function is an array + * containing the rule to be used. Its format is the following: + * |NDG|DG1|DG2|...|0| + * where NDG is the number of used "digits in group" and DG1, DG2, + * are the corresponding "digits in group". + * Thus, this function returns the grouping value in the array + * pointed by the second parameter. + */ +static INT get_grouping(char* sRule, INT index) +{ + char sData[2], sRuleSize[2]; + INT nData, nRuleSize; + + memcpy(sRuleSize, sRule, 1); + memcpy(sRuleSize+1, "\0", 1); + nRuleSize = atoi(sRuleSize); + + if (index > 0 && index < nRuleSize) + { + memcpy(sData, sRule+index, 1); + memcpy(sData+1, "\0", 1); + nData = atoi(sData); + } + + else + { + memcpy(sData, sRule+nRuleSize-1, 1); + memcpy(sData+1, "\0", 1); + nData = atoi(sData); + } + + return nData; +} + +/************************************************************************** + * GetNumberFormatA (KERNEL32.@) + */ +INT WINAPI GetNumberFormatA(LCID locale, DWORD dwflags, + LPCSTR lpvalue, const NUMBERFMTA * lpFormat, + LPSTR lpNumberStr, int cchNumber) +{ + char sNumberDigits[3], sDecimalSymbol[5], sDigitsInGroup[11], sDigitGroupSymbol[5], sILZero[2]; + INT nNumberDigits, nNumberDecimal, i, j, nCounter, nStep, nRuleIndex, nGrouping, nDigits, retVal, nLZ; + char sNumber[128], sDestination[128], sDigitsAfterDecimal[10], sDigitsBeforeDecimal[128]; + char sRule[10], sSemiColumn[]=";", sBuffer[5], sNegNumber[2]; + char *pStr = NULL, *pTmpStr = NULL; + LCID systemDefaultLCID; + BOOL bNegative = FALSE; + enum Operations + { + USE_PARAMETER, + USE_LOCALEINFO, + USE_SYSTEMDEFAULT, + RETURN_ERROR + } used_operation; + + strncpy(sNumber, lpvalue, 128); + sNumber[127] = '\0'; + + /* Make sure we have a valid input string, get the number + * of digits before and after the decimal symbol, and check + * if this is a negative number. + */ + if (get_number_components(sNumber, sDigitsBeforeDecimal, sDigitsAfterDecimal, &bNegative) != -1) + { + nNumberDecimal = strlen(sDigitsBeforeDecimal); + nDigits = strlen(sDigitsAfterDecimal); + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* Which source will we use to format the string */ + used_operation = RETURN_ERROR; + if (lpFormat != NULL) + { + if (dwflags == 0) + used_operation = USE_PARAMETER; + } + else + { + if (dwflags & LOCALE_NOUSEROVERRIDE) + used_operation = USE_SYSTEMDEFAULT; + else + used_operation = USE_LOCALEINFO; + } + + /* Load the fields we need */ + switch(used_operation) + { + case USE_LOCALEINFO: + GetLocaleInfoA(locale, LOCALE_IDIGITS, sNumberDigits, sizeof(sNumberDigits)); + GetLocaleInfoA(locale, LOCALE_SDECIMAL, sDecimalSymbol, sizeof(sDecimalSymbol)); + GetLocaleInfoA(locale, LOCALE_SGROUPING, sDigitsInGroup, sizeof(sDigitsInGroup)); + GetLocaleInfoA(locale, LOCALE_STHOUSAND, sDigitGroupSymbol, sizeof(sDigitGroupSymbol)); + GetLocaleInfoA(locale, LOCALE_ILZERO, sILZero, sizeof(sILZero)); + GetLocaleInfoA(locale, LOCALE_INEGNUMBER, sNegNumber, sizeof(sNegNumber)); + break; + case USE_PARAMETER: + sprintf(sNumberDigits, "%d",lpFormat->NumDigits); + strcpy(sDecimalSymbol, lpFormat->lpDecimalSep); + sprintf(sDigitsInGroup, "%d;0",lpFormat->Grouping); + /* Win95-WinME only allow 0-9 for grouping, no matter what MSDN says. */ + strcpy(sDigitGroupSymbol, lpFormat->lpThousandSep); + sprintf(sILZero, "%d",lpFormat->LeadingZero); + sprintf(sNegNumber, "%d",lpFormat->NegativeOrder); + break; + case USE_SYSTEMDEFAULT: + systemDefaultLCID = GetSystemDefaultLCID(); + GetLocaleInfoA(systemDefaultLCID, LOCALE_IDIGITS, sNumberDigits, sizeof(sNumberDigits)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_SDECIMAL, sDecimalSymbol, sizeof(sDecimalSymbol)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_SGROUPING, sDigitsInGroup, sizeof(sDigitsInGroup)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_STHOUSAND, sDigitGroupSymbol, sizeof(sDigitGroupSymbol)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_ILZERO, sILZero, sizeof(sILZero)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_INEGNUMBER, sNegNumber, sizeof(sNegNumber)); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + nNumberDigits = atoi(sNumberDigits); + + /* Remove the ";" */ + i=0; + j = 1; + for (nCounter=0; nCounter0) && (atoi(sDigitsBeforeDecimal) != 0)) + { + /* Working on an inverted string is easier ! */ + invert_string(sDigitsBeforeDecimal); + + nStep = nCounter = i = j = 0; + nRuleIndex = 1; + nGrouping = get_grouping(sRule, nRuleIndex); + if (nGrouping == 0) /* If the first grouping is zero */ + nGrouping = nNumberDecimal; /* Don't do grouping */ + + /* Here, we will loop until we reach the end of the string. + * An internal counter (j) is used in order to know when to + * insert the "digit group symbol". + */ + while (nNumberDecimal > 0) + { + i = nCounter + nStep; + memcpy(sDestination + i, sDigitsBeforeDecimal + nCounter, 1); + nCounter++; + j++; + if (j >= nGrouping) + { + j = 0; + if (nRuleIndex < sRule[0]) + nRuleIndex++; + nGrouping = get_grouping(sRule, nRuleIndex); + memcpy(sDestination + i+1, sDigitGroupSymbol, strlen(sDigitGroupSymbol)); + nStep+= strlen(sDigitGroupSymbol); + } + + nNumberDecimal--; + } + + memcpy(sDestination + i+1, "\0", 1); + /* Get the string in the right order ! */ + invert_string(sDestination); + } + else + { + nLZ = atoi(sILZero); + if (nLZ != 0) + { + /* Use 0.xxx instead of .xxx */ + memcpy(sDestination, "0", 1); + memcpy(sDestination+1, "\0", 1); + } + else + memcpy(sDestination, "\0", 1); + + } + + /* Second, format the digits after the decimal. */ + j = 0; + nCounter = nNumberDigits; + if ( (nDigits>0) && (pStr = strstr (sNumber, ".")) ) + { + i = strlen(sNumber) - strlen(pStr) + 1; + strncpy ( sDigitsAfterDecimal, sNumber + i, nNumberDigits); + j = strlen(sDigitsAfterDecimal); + if (j < nNumberDigits) + nCounter = nNumberDigits-j; + } + for (i=0;iNegativeOrder; + nPosOrder = lpFormat->PositiveOrder; + strcpy(sCurrencySymbol, lpFormat->lpCurrencySymbol); + break; + case USE_SYSTEMDEFAULT: + systemDefaultLCID = GetSystemDefaultLCID(); + /* Specific to CURRENCYFMTA */ + GetLocaleInfoA(systemDefaultLCID, LOCALE_INEGCURR, sNegOrder, sizeof(sNegOrder)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_ICURRENCY, sPosOrder, sizeof(sPosOrder)); + GetLocaleInfoA(systemDefaultLCID, LOCALE_SCURRENCY, sCurrencySymbol, sizeof(sCurrencySymbol)); + + nPosOrder = atoi(sPosOrder); + nNegOrder = atoi(sNegOrder); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* Construct a temporary number format structure */ + if (lpFormat != NULL) + { + numberFmt.NumDigits = lpFormat->NumDigits; + numberFmt.LeadingZero = lpFormat->LeadingZero; + numberFmt.Grouping = lpFormat->Grouping; + numberFmt.NegativeOrder = 0; + numberFmt.lpDecimalSep = lpFormat->lpDecimalSep; + numberFmt.lpThousandSep = lpFormat->lpThousandSep; + bValidFormat = TRUE; + } + + /* Make a call to GetNumberFormatA() */ + if (*lpvalue == '-') + { + bIsPositive = FALSE; + retVal = GetNumberFormatA(locale,0,lpvalue+1,(bValidFormat)?&numberFmt:NULL,pNumberFormated,128); + } + else + { + bIsPositive = TRUE; + retVal = GetNumberFormatA(locale,0,lpvalue,(bValidFormat)?&numberFmt:NULL,pNumberFormated,128); + } + + if (retVal == 0) + return 0; + + /* construct the formatted string */ + if (bIsPositive) + { + switch (nPosOrder) + { + case 0: /* Prefix, no separation */ + strcpy (pDestination, sCurrencySymbol); + strcat (pDestination, pNumberFormated); + break; + case 1: /* Suffix, no separation */ + strcpy (pDestination, pNumberFormated); + strcat (pDestination, sCurrencySymbol); + break; + case 2: /* Prefix, 1 char separation */ + strcpy (pDestination, sCurrencySymbol); + strcat (pDestination, " "); + strcat (pDestination, pNumberFormated); + break; + case 3: /* Suffix, 1 char separation */ + strcpy (pDestination, pNumberFormated); + strcat (pDestination, " "); + strcat (pDestination, sCurrencySymbol); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + } + else /* negative number */ + { + switch (nNegOrder) + { + case 0: /* format: ($1.1) */ + strcpy (pDestination, "("); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, pNumberFormated); + strcat (pDestination, ")"); + break; + case 1: /* format: -$1.1 */ + strcpy (pDestination, "-"); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, pNumberFormated); + break; + case 2: /* format: $-1.1 */ + strcpy (pDestination, sCurrencySymbol); + strcat (pDestination, "-"); + strcat (pDestination, pNumberFormated); + break; + case 3: /* format: $1.1- */ + strcpy (pDestination, sCurrencySymbol); + strcat (pDestination, pNumberFormated); + strcat (pDestination, "-"); + break; + case 4: /* format: (1.1$) */ + strcpy (pDestination, "("); + strcat (pDestination, pNumberFormated); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, ")"); + break; + case 5: /* format: -1.1$ */ + strcpy (pDestination, "-"); + strcat (pDestination, pNumberFormated); + strcat (pDestination, sCurrencySymbol); + break; + case 6: /* format: 1.1-$ */ + strcpy (pDestination, pNumberFormated); + strcat (pDestination, "-"); + strcat (pDestination, sCurrencySymbol); + break; + case 7: /* format: 1.1$- */ + strcpy (pDestination, pNumberFormated); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, "-"); + break; + case 8: /* format: -1.1 $ */ + strcpy (pDestination, "-"); + strcat (pDestination, pNumberFormated); + strcat (pDestination, " "); + strcat (pDestination, sCurrencySymbol); + break; + case 9: /* format: -$ 1.1 */ + strcpy (pDestination, "-"); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, " "); + strcat (pDestination, pNumberFormated); + break; + case 10: /* format: 1.1 $- */ + strcpy (pDestination, pNumberFormated); + strcat (pDestination, " "); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, "-"); + break; + case 11: /* format: $ 1.1- */ + strcpy (pDestination, sCurrencySymbol); + strcat (pDestination, " "); + strcat (pDestination, pNumberFormated); + strcat (pDestination, "-"); + break; + case 12: /* format: $ -1.1 */ + strcpy (pDestination, sCurrencySymbol); + strcat (pDestination, " "); + strcat (pDestination, "-"); + strcat (pDestination, pNumberFormated); + break; + case 13: /* format: 1.1- $ */ + strcpy (pDestination, pNumberFormated); + strcat (pDestination, "-"); + strcat (pDestination, " "); + strcat (pDestination, sCurrencySymbol); + break; + case 14: /* format: ($ 1.1) */ + strcpy (pDestination, "("); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, " "); + strcat (pDestination, pNumberFormated); + strcat (pDestination, ")"); + break; + case 15: /* format: (1.1 $) */ + strcpy (pDestination, "("); + strcat (pDestination, pNumberFormated); + strcat (pDestination, " "); + strcat (pDestination, sCurrencySymbol); + strcat (pDestination, ")"); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + } + + retVal = strlen(pDestination) + 1; + + if (cchCurrency) + { + memcpy( lpCurrencyStr, pDestination, min(cchCurrency, retVal) ); + if (cchCurrency < retVal) { + retVal = 0; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } + } + return retVal; +} + +/************************************************************************** + * GetCurrencyFormatW (KERNEL32.@) + */ +INT WINAPI GetCurrencyFormatW(LCID locale, DWORD dwflags, + LPCWSTR lpvalue, const CURRENCYFMTW * lpFormat, + LPWSTR lpCurrencyStr, int cchCurrency) +{ + FIXME("This API function is NOT implemented !\n"); + return 0; +} + + +/****************************************************************************** + * GetTimeFormatA [KERNEL32.@] + * Makes an ASCII string of the time + * + * Formats date according to format, or locale default if format is + * NULL. The format consists of literal characters and fields as follows: + * + * h hours with no leading zero (12-hour) + * hh hours with full two digits + * H hours with no leading zero (24-hour) + * HH hours with full two digits + * m minutes with no leading zero + * mm minutes with full two digits + * s seconds with no leading zero + * ss seconds with full two digits + * t time marker (A or P) + * tt time marker (AM, PM) + * + */ +INT WINAPI +GetTimeFormatA(LCID locale, /* [in] */ + DWORD flags, /* [in] */ + const SYSTEMTIME* xtime, /* [in] */ + LPCSTR format, /* [in] */ + LPSTR timestr, /* [out] */ + INT timelen /* [in] */) +{ + INT ret; + LPWSTR wformat = NULL; + LPWSTR wtime = NULL; + + if (format) + { + wformat = HeapAlloc(GetProcessHeap(), 0, + (strlen(format) + 1) * sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, format, -1, wformat, strlen(format) + 1); + } + + if (timestr && timelen) + { + wtime = HeapAlloc(GetProcessHeap(), 0, + (timelen + 1) * sizeof(wchar_t)); + } + + ret = GetTimeFormatW(locale, flags, xtime, wformat, wtime, timelen); + + if (wtime) + { + WideCharToMultiByte(CP_ACP, 0, wtime, ret, timestr, timelen, NULL, NULL); + HeapFree(GetProcessHeap(), 0, wtime); + } + + if (wformat) + { + HeapFree(GetProcessHeap(), 0, wformat); + } + + return ret; +} + + +/****************************************************************************** + * GetTimeFormatW [KERNEL32.@] + * Makes a Unicode string of the time + * + * NOTE: See get_date_time_formatW() for further documentation + */ +INT WINAPI +GetTimeFormatW(LCID locale, /* [in] */ + DWORD flags, /* [in] */ + const SYSTEMTIME* xtime, /* [in] */ + LPCWSTR format, /* [in] */ + LPWSTR timestr, /* [out] */ + INT timelen /* [in] */) +{ WCHAR format_buf[40]; + LPCWSTR thisformat; + SYSTEMTIME t; + const SYSTEMTIME* thistime; + DWORD thisflags=LOCALE_STIMEFORMAT; /* standard timeformat */ + INT ret; + + TRACE("GetTimeFormat(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",locale,flags, + xtime,debugstr_w(format),timestr,timelen); + + if (!locale) locale = LOCALE_SYSTEM_DEFAULT; + locale = ConvertDefaultLocale( locale ); + + /* if the user didn't specify a format we use the default */ + /* format for this locale */ + if (format == NULL) + { + if (flags & LOCALE_NOUSEROVERRIDE) /* use system default */ + { + locale = GetSystemDefaultLCID(); + } + GetLocaleInfoW(locale, thisflags, format_buf, 40); + thisformat = format_buf; + } + else + { + /* if non-null format and LOCALE_NOUSEROVERRIDE then fail */ + /* NOTE: this could be either invalid flags or invalid parameter */ + /* windows sets it to invalid flags */ + if (flags & LOCALE_NOUSEROVERRIDE) + { + SetLastError(ERROR_INVALID_FLAGS); + return 0; + } + + thisformat = format; + } + + if (xtime == NULL) /* NULL means use the current local time */ + { GetLocalTime(&t); + thistime = &t; + } + else + { + /* check time values */ + if((xtime->wHour > 24) || (xtime->wMinute >= 60) || (xtime->wSecond >= 60)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + thistime = xtime; + } + + ret = get_date_time_formatW(locale, thisflags, flags, thistime, thisformat, + timestr, timelen, 0); + return ret; +} + +/****************************************************************************** + * EnumCalendarInfoA [KERNEL32.@] + */ +BOOL WINAPI EnumCalendarInfoA( CALINFO_ENUMPROCA calinfoproc,LCID locale, + CALID calendar,CALTYPE caltype ) +{ + FIXME("(%p,0x%04lx,0x%08lx,0x%08lx),stub!\n",calinfoproc,locale,calendar,caltype); + return FALSE; +} diff --git a/ole/ole2nls.c b/ole/ole2nls.c index 76f929bc601..a812f0be25a 100644 --- a/ole/ole2nls.c +++ b/ole/ole2nls.c @@ -1216,1672 +1216,3 @@ INT WINAPI lstrcmpiW( LPCWSTR str1, LPCWSTR str2 ) } return strcmpiW( str1, str2 ); } - - -/****************************************************************************** - * OLE_GetFormatW [Internal] - * - * dateformat is set TRUE if being called for a date, false for a time - - This function implements stuff for GetDateFormat() and - GetTimeFormat(). - - d single-digit (no leading zero) day (of month) - dd two-digit day (of month) - ddd short day-of-week name - dddd long day-of-week name - M single-digit month - MM two-digit month - MMM short month name - MMMM full month name - y two-digit year, no leading 0 - yy two-digit year - yyyy four-digit year - gg era string - h hours with no leading zero (12-hour) - hh hours with full two digits - H hours with no leading zero (24-hour) - HH hours with full two digits - m minutes with no leading zero - mm minutes with full two digits - s seconds with no leading zero - ss seconds with full two digits - t time marker (A or P) - tt time marker (AM, PM) - '' used to quote literal characters - '' (within a quoted string) indicates a literal ' - - If TIME_NOMINUTESORSECONDS or TIME_NOSECONDS is specified, the function - removes the separator(s) preceding the minutes and/or seconds element(s). - - If TIME_NOTIMEMARKER is specified, the function removes the separator(s) - preceding and following the time marker. - - If TIME_FORCE24HOURFORMAT is specified, the function displays any existing - time marker, unless the TIME_NOTIMEMARKER flag is also set. - - These functions REQUIRE valid locale, date, and format. - - If the time or date is invalid, return 0 and set ERROR_INVALID_PARAMETER - - Return value is the number of characters written, or if outlen is zero - it is the number of characters required for the output including - the terminating null. - */ -static INT OLE_GetFormatW(LCID locale, DWORD flags, DWORD tflags, - const SYSTEMTIME* xtime, - LPCWSTR format, - LPWSTR output, INT outlen, int dateformat) -{ - INT outpos; - INT lastFormatPos; /* the position in the output buffer of */ - /* the end of the output from the last formatting */ - /* character */ - BOOL dropUntilNextFormattingChar = FALSE; /* TIME_NOTIMEMARKER drops - all of the text around the dropped marker, - eg. "h@!t@!m" becomes "hm" */ - - /* 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), " - "%p with max len %d\n", - locale, flags, tflags, - xtime->wDay, xtime->wHour, xtime->wMinute, xtime->wSecond, - debugstr_w(format), format, output, outlen); - - /* initialize state variables */ - outpos = 0; - lastFormatPos = 0; - - while (*format) { - /* Literal string: Maybe terminated early by a \0 */ - if (*format == (WCHAR) '\'') - { - format++; - - /* We loop while we haven't reached the end of the format string */ - /* and until we haven't found another "'" character */ - while (*format) - { - /* we found what might be the close single quote mark */ - /* we need to make sure there isn't another single quote */ - /* after it, if there is we need to skip over this quote mark */ - /* as the user is trying to put a single quote mark in their output */ - if (*format == (WCHAR) '\'') - { - format++; - if (*format != '\'') - { - break; /* It was a terminating quote */ - } - } - - /* if outlen is zero then we are couting the number of */ - /* characters of space we need to output this text, don't */ - /* modify the output buffer */ - if (!outlen) - { - outpos++; /* We are counting */; - } else if (outpos >= outlen) - { - goto too_short; - } else - { - /* even drop literal strings */ - if(!dropUntilNextFormattingChar) - { - 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') ) ) - /* if processing a date and we have a date formatting character, OR */ - /* if we are processing a time and we have a time formatting character */ - { - int type, count; - char tmp[16]; - WCHAR buf[40]; - int buflen=0; - type = *format; - format++; - - /* clear out the drop text flag if we are in here */ - dropUntilNextFormattingChar = FALSE; - - /* count up the number of the same letter values in a row that */ - /* we get, this lets us distinguish between "s" and "ss" and it */ - /* eliminates the duplicate to simplify the below case statement */ - for (count = 1; *format == type; format++) - count++; - - buf[0] = 0; /* always null terminate the buffer */ - - 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 { - sprintf( tmp, "%.*d", count > 2 ? 2 : 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': - /* fallthrough if we are forced to output in 24 hour format */ - if(!(tflags & TIME_FORCE24HOURFORMAT)) - { - /* hours 1:00-12:00 --- is this right? */ - /* NOTE: 0000 hours is also 12 midnight */ - sprintf( tmp, "%.*d", count > 2 ? 2 : count, - xtime->wHour == 0 ? 12 : (xtime->wHour-1)%12 +1); - MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); - break; - } - case 'H': - sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wHour ); - MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); - break; - - case 'm': - /* if TIME_NOMINUTESORSECONDS don't display minutes */ - if(!(tflags & TIME_NOMINUTESORSECONDS)) - { - sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wMinute ); - MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); - } else - { - outpos = lastFormatPos; - } - break; - - case 's': - /* if we have a TIME_NOSECONDS or TIME_NOMINUTESORSECONDS - flag then don't display seconds */ - if(!(tflags & TIME_NOSECONDS) && !(tflags & - TIME_NOMINUTESORSECONDS)) - { - sprintf( tmp, "%.*d", count > 2 ? 2 : count, xtime->wSecond ); - MultiByteToWideChar( CP_ACP, 0, tmp, -1, buf, sizeof(buf)/sizeof(WCHAR) ); - } else - { - outpos = lastFormatPos; - } - break; - - case 't': - if(!(tflags & TIME_NOTIMEMARKER)) - { - GetLocaleInfoW(locale, (xtime->wHour < 12) ? - LOCALE_S1159 : LOCALE_S2359, - buf, sizeof(buf) ); - if (count == 1) - { - buf[1] = 0; - } - } else - { - outpos = lastFormatPos; /* remove any prior text up until - the output due to formatting characters */ - dropUntilNextFormattingChar = TRUE; /* drop everything - until we hit the next formatting character */ - } - break; - } - - /* cat buf onto the output */ - buflen = strlenW(buf); - - /* we are counting how many characters we need for output */ - /* don't modify the output buffer... */ - if (!outlen) - /* We are counting */; - else if (outpos + buflen < outlen) { - strcpyW( output + outpos, buf ); - } else { - lstrcpynW( output + outpos, buf, outlen - outpos ); - /* Is this an undocumented feature we are supporting? */ - goto too_short; - } - outpos += buflen; - lastFormatPos = outpos; /* record the end of the formatting text we just output */ - } else /* we are processing a NON formatting character */ - { - /* a literal character */ - if (!outlen) - { - outpos++; /* We are counting */; - } - else if (outpos >= outlen) - { - goto too_short; - } - else /* just copy the character into the output buffer */ - { - /* unless we are dropping characters */ - if(!dropUntilNextFormattingChar) - { - output[outpos] = *format; - outpos++; - } - } - format++; - } - } - - /* final string terminator and sanity check */ - if (!outlen) - /* We are counting */; - else if (outpos >= outlen) - goto too_short; - else - output[outpos] = '\0'; - - outpos++; /* add one for the terminating null character */ - - TRACE(" returning %d %s\n", outpos, debugstr_w(output)); - return outpos; - -too_short: - SetLastError(ERROR_INSUFFICIENT_BUFFER); - WARN(" buffer overflow\n"); - return 0; -} - - -/****************************************************************************** - * GetDateFormatA [KERNEL32.@] - * Makes an ASCII string of the date - * - * Acts the same as GetDateFormatW(), except that it's ASCII. - */ -INT WINAPI GetDateFormatA(LCID locale,DWORD flags, - const SYSTEMTIME* xtime, - LPCSTR format, LPSTR date, INT datelen) -{ - INT ret; - LPWSTR wformat = NULL; - LPWSTR wdate = NULL; - - if (format) - { - wformat = HeapAlloc(GetProcessHeap(), 0, - (strlen(format) + 1) * sizeof(wchar_t)); - - MultiByteToWideChar(CP_ACP, 0, format, -1, wformat, strlen(format) + 1); - } - - if (date && datelen) - { - wdate = HeapAlloc(GetProcessHeap(), 0, - (datelen + 1) * sizeof(wchar_t)); - } - - ret = GetDateFormatW(locale, flags, xtime, wformat, wdate, datelen); - - if (wdate) - { - WideCharToMultiByte(CP_ACP, 0, wdate, ret, date, datelen, NULL, NULL); - HeapFree(GetProcessHeap(), 0, wdate); - } - - if (wformat) - { - HeapFree(GetProcessHeap(), 0, wformat); - } - - return ret; -} - -/****************************************************************************** - * GetDateFormatW [KERNEL32.@] - * Makes a Unicode string of the date - * - * This function uses format to format the date, or, if format - * is NULL, uses the default for the locale. format is a string - * of literal fields and characters as follows: - * - * - d single-digit (no leading zero) day (of month) - * - dd two-digit day (of month) - * - ddd short day-of-week name - * - dddd long day-of-week name - * - M single-digit month - * - MM two-digit month - * - MMM short month name - * - MMMM full month name - * - y two-digit year, no leading 0 - * - yy two-digit year - * - yyyy four-digit year - * - gg era string - * - * Accepts & returns sizes as counts of Unicode characters. - */ -INT WINAPI GetDateFormatW(LCID locale,DWORD flags, - const SYSTEMTIME* xtime, - LPCWSTR format, - LPWSTR date, INT datelen) -{ - WCHAR format_buf[40]; - LPCWSTR thisformat; - SYSTEMTIME t; - LPSYSTEMTIME thistime; - LCID thislocale; - INT ret; - FILETIME ft; - BOOL res; - - TRACE("(0x%04lx,0x%08lx,%p,%s,%p,%d)\n", - locale,flags,xtime,debugstr_w(format),date,datelen); - - /* Tests */ - if (flags && format) /* if lpFormat is non-null then flags must be zero */ - { - SetLastError (ERROR_INVALID_FLAGS); - return 0; - } - if (datelen && !date) - { - SetLastError (ERROR_INVALID_PARAMETER); - return 0; - } - if (!locale) - { - locale = LOCALE_SYSTEM_DEFAULT; - }; - - if (locale == LOCALE_SYSTEM_DEFAULT) - { - thislocale = GetSystemDefaultLCID(); - } else if (locale == LOCALE_USER_DEFAULT) - { - thislocale = GetUserDefaultLCID(); - } else - { - thislocale = locale; - }; - - /* check for invalid flag combinations */ - if((flags & DATE_LTRREADING) && (flags & DATE_RTLREADING)) - { - SetLastError (ERROR_INVALID_FLAGS); - return 0; - } - - /* DATE_SHORTDATE, DATE_LONGDATE and DATE_YEARMONTH are mutually */ - /* exclusive */ - if((flags & (DATE_SHORTDATE|DATE_LONGDATE|DATE_YEARMONTH)) - && !((flags & DATE_SHORTDATE) ^ (flags & - DATE_LONGDATE) ^ (flags & DATE_YEARMONTH))) - { - SetLastError (ERROR_INVALID_FLAGS); - return 0; - } - - /* if the user didn't pass in a pointer to the current time we read it */ - /* here */ - if (xtime == NULL) - { - GetSystemTime(&t); - } else - { - /* NOTE: check here before we perform the SystemTimeToFileTime conversion */ - /* because this conversion will fix invalid time values */ - /* check to see if the time/date is valid */ - /* set ERROR_INVALID_PARAMETER and return 0 if invalid */ - if((xtime->wDay > 31) || (xtime->wMonth > 12)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - /* For all we know the day of week and the time may be absolute - * rubbish. Therefore if we are going to use conversion through - * FileTime we had better use a clean time (and hopefully we won't - * fall over any timezone complications). - * If we go with an alternative method of correcting the day of week - * (e.g. Zeller's congruence) then we won't need to, but we will need - * to check the date. - */ - memset (&t, 0, sizeof(t)); - t.wYear = xtime->wYear; - t.wMonth = xtime->wMonth; - t.wDay = xtime->wDay; - - /* Silently correct wDayOfWeek by transforming to FileTime and back again */ - res=SystemTimeToFileTime(&t,&ft); - - /* Check year(?)/month and date for range and set ERROR_INVALID_PARAMETER on error */ - 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)/sizeof(*format_buf)); - thisformat = format_buf; - } else - { - thisformat = format; - }; - - - ret = OLE_GetFormatW(thislocale, flags, 0, thistime, thisformat, - date, datelen, 1); - - - TRACE("GetDateFormatW() returning %d, with data=%s\n", - ret, debugstr_w(date)); - return ret; -} - -/************************************************************************** - * EnumDateFormatsA (KERNEL32.@) - */ -BOOL WINAPI EnumDateFormatsA( - DATEFMT_ENUMPROCA lpDateFmtEnumProc, LCID Locale, DWORD dwFlags) -{ - LCID Loc = GetUserDefaultLCID(); - if(!lpDateFmtEnumProc) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - switch( Loc ) - { - - case 0x00000407: /* (Loc,"de_DE") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd.MM.yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d.M.yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d.MM.yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d.M.yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dddd,d. MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d. MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d. MMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x0000040c: /* (Loc,"fr_FR") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd.MM.yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd-MM-yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dddd d MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d MMM yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00000c0c: /* (Loc,"fr_CA") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("yy-MM-dd")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd-MM-yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("yy MM dd")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("d MMMM, yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d MMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00000809: /* (Loc,"en_UK") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d.M.yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dd MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00000c09: /* (Loc,"en_AU") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("d/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dddd,d MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00001009: /* (Loc,"en_CA") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("yy-MM-dd")) return TRUE; - if(!(*lpDateFmtEnumProc)("M/dd/yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("d-MMM-yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("MMMM d, yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00001409: /* (Loc,"en_NZ") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("d/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d.MM.yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dddd, d MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00001809: /* (Loc,"en_IE") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd/MM/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d/M/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d.M.yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dd MMMM yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("d MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00001c09: /* (Loc,"en_ZA") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("yy/MM/dd")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dd MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00002009: /* (Loc,"en_JM") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dddd,MMMM dd,yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("MMMM dd,yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dddd,dd MMMM,yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd MMMM,yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - case 0x00002809: /* (Loc,"en_BZ") */ - case 0x00002c09: /* (Loc,"en_TT") */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("dd/MM/yyyy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dddd,dd MMMM yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - default: /* default to US English "en_US" */ - { - switch(dwFlags) - { - case DATE_SHORTDATE: - if(!(*lpDateFmtEnumProc)("M/d/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("M/d/yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("MM/dd/yy")) return TRUE; - if(!(*lpDateFmtEnumProc)("MM/dd/yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("yy/MM/dd")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd-MMM-yy")) return TRUE; - return TRUE; - case DATE_LONGDATE: - if(!(*lpDateFmtEnumProc)("dddd, MMMM dd, yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("MMMM dd, yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dddd, dd MMMM, yyyy")) return TRUE; - if(!(*lpDateFmtEnumProc)("dd MMMM, yyyy")) return TRUE; - return TRUE; - default: - FIXME("Unknown date format (%ld)\n", dwFlags); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - } -} - -/************************************************************************** - * EnumDateFormatsW (KERNEL32.@) - */ -BOOL WINAPI EnumDateFormatsW( - DATEFMT_ENUMPROCW lpDateFmtEnumProc, LCID Locale, DWORD dwFlags) -{ - FIXME("(%p, %ld, %ld): stub\n", lpDateFmtEnumProc, Locale, dwFlags); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/************************************************************************** - * EnumTimeFormatsA (KERNEL32.@) - */ -BOOL WINAPI EnumTimeFormatsA( - TIMEFMT_ENUMPROCA lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags) -{ - LCID Loc = GetUserDefaultLCID(); - if(!lpTimeFmtEnumProc) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - if(dwFlags) - { - FIXME("Unknown time format (%ld)\n", dwFlags); - } - - switch( Loc ) - { - case 0x00000407: /* (Loc,"de_DE") */ - { - if(!(*lpTimeFmtEnumProc)("HH.mm")) return TRUE; - if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; - if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; - if(!(*lpTimeFmtEnumProc)("H.mm")) return TRUE; - if(!(*lpTimeFmtEnumProc)("H.mm'Uhr'")) return TRUE; - return TRUE; - } - - case 0x0000040c: /* (Loc,"fr_FR") */ - case 0x00000c0c: /* (Loc,"fr_CA") */ - { - if(!(*lpTimeFmtEnumProc)("H:mm")) return TRUE; - if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; - if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; - if(!(*lpTimeFmtEnumProc)("HH.mm")) return TRUE; - if(!(*lpTimeFmtEnumProc)("HH'h'mm")) return TRUE; - return TRUE; - } - - case 0x00000809: /* (Loc,"en_UK") */ - case 0x00000c09: /* (Loc,"en_AU") */ - case 0x00001409: /* (Loc,"en_NZ") */ - case 0x00001809: /* (Loc,"en_IE") */ - { - if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE; - if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; - if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; - return TRUE; - } - - case 0x00001c09: /* (Loc,"en_ZA") */ - case 0x00002809: /* (Loc,"en_BZ") */ - case 0x00002c09: /* (Loc,"en_TT") */ - { - if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE; - if(!(*lpTimeFmtEnumProc)("hh:mm:ss tt")) return TRUE; - return TRUE; - } - - default: /* default to US style "en_US" */ - { - if(!(*lpTimeFmtEnumProc)("h:mm:ss tt")) return TRUE; - if(!(*lpTimeFmtEnumProc)("hh:mm:ss tt")) return TRUE; - if(!(*lpTimeFmtEnumProc)("H:mm:ss")) return TRUE; - if(!(*lpTimeFmtEnumProc)("HH:mm:ss")) return TRUE; - return TRUE; - } - } -} - -/************************************************************************** - * EnumTimeFormatsW (KERNEL32.@) - */ -BOOL WINAPI EnumTimeFormatsW( - TIMEFMT_ENUMPROCW lpTimeFmtEnumProc, LCID Locale, DWORD dwFlags) -{ - FIXME("(%p,%ld,%ld): stub\n", lpTimeFmtEnumProc, Locale, dwFlags); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/************************************************************************** - * This function is used just locally ! - * Description: Inverts a string. - */ -static void OLE_InvertString(char* string) -{ - char sTmpArray[128]; - INT counter, i = 0; - - for (counter = strlen(string); counter > 0; counter--) - { - memcpy(sTmpArray + i, string + counter-1, 1); - i++; - } - memcpy(sTmpArray + i, "\0", 1); - strcpy(string, sTmpArray); -} - -/*************************************************************************************** - * This function is used just locally ! - * Description: Test if the given string (psNumber) is valid or not. - * The valid characters are the following: - * - Characters '0' through '9'. - * - One decimal point (dot) if the number is a floating-point value. - * - A minus sign in the first character position if the number is - * a negative value. - * If the function succeeds, psBefore/psAfter will point to the string - * on the right/left of the decimal symbol. pbNegative indicates if the - * number is negative. - */ -static INT OLE_GetNumberComponents(char* pInput, char* psBefore, char* psAfter, BOOL* pbNegative) -{ -char sNumberSet[] = "0123456789"; -BOOL bInDecimal = FALSE; - - /* Test if we do have a minus sign */ - if ( *pInput == '-' ) - { - *pbNegative = TRUE; - pInput++; /* Jump to the next character. */ - } - - while(*pInput != '\0') - { - /* Do we have a valid numeric character */ - if ( strchr(sNumberSet, *pInput) != NULL ) - { - if (bInDecimal == TRUE) - *psAfter++ = *pInput; - else - *psBefore++ = *pInput; - } - else - { - /* Is this a decimal point (dot) */ - if ( *pInput == '.' ) - { - /* Is it the first time we find it */ - if ((bInDecimal == FALSE)) - bInDecimal = TRUE; - else - return -1; /* ERROR: Invalid parameter */ - } - else - { - /* It's neither a numeric character, nor a decimal point. - * Thus, return an error. - */ - return -1; - } - } - pInput++; - } - - /* Add an End of Line character to the output buffers */ - *psBefore = '\0'; - *psAfter = '\0'; - - return 0; -} - -/************************************************************************** - * This function is used just locally ! - * Description: A number could be formatted using different numbers - * of "digits in group" (example: 4;3;2;0). - * The first parameter of this function is an array - * containing the rule to be used. Its format is the following: - * |NDG|DG1|DG2|...|0| - * where NDG is the number of used "digits in group" and DG1, DG2, - * are the corresponding "digits in group". - * Thus, this function returns the grouping value in the array - * pointed by the second parameter. - */ -static INT OLE_GetGrouping(char* sRule, INT index) -{ - char sData[2], sRuleSize[2]; - INT nData, nRuleSize; - - memcpy(sRuleSize, sRule, 1); - memcpy(sRuleSize+1, "\0", 1); - nRuleSize = atoi(sRuleSize); - - if (index > 0 && index < nRuleSize) - { - memcpy(sData, sRule+index, 1); - memcpy(sData+1, "\0", 1); - nData = atoi(sData); - } - - else - { - memcpy(sData, sRule+nRuleSize-1, 1); - memcpy(sData+1, "\0", 1); - nData = atoi(sData); - } - - return nData; -} - -/************************************************************************** - * GetNumberFormatA (KERNEL32.@) - */ -INT WINAPI GetNumberFormatA(LCID locale, DWORD dwflags, - LPCSTR lpvalue, const NUMBERFMTA * lpFormat, - LPSTR lpNumberStr, int cchNumber) -{ - char sNumberDigits[3], sDecimalSymbol[5], sDigitsInGroup[11], sDigitGroupSymbol[5], sILZero[2]; - INT nNumberDigits, nNumberDecimal, i, j, nCounter, nStep, nRuleIndex, nGrouping, nDigits, retVal, nLZ; - char sNumber[128], sDestination[128], sDigitsAfterDecimal[10], sDigitsBeforeDecimal[128]; - char sRule[10], sSemiColumn[]=";", sBuffer[5], sNegNumber[2]; - char *pStr = NULL, *pTmpStr = NULL; - LCID systemDefaultLCID; - BOOL bNegative = FALSE; - enum Operations - { - USE_PARAMETER, - USE_LOCALEINFO, - USE_SYSTEMDEFAULT, - RETURN_ERROR - } used_operation; - - strncpy(sNumber, lpvalue, 128); - sNumber[127] = '\0'; - - /* Make sure we have a valid input string, get the number - * of digits before and after the decimal symbol, and check - * if this is a negative number. - */ - if ( OLE_GetNumberComponents(sNumber, sDigitsBeforeDecimal, sDigitsAfterDecimal, &bNegative) != -1) - { - nNumberDecimal = strlen(sDigitsBeforeDecimal); - nDigits = strlen(sDigitsAfterDecimal); - } - else - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - /* Which source will we use to format the string */ - used_operation = RETURN_ERROR; - if (lpFormat != NULL) - { - if (dwflags == 0) - used_operation = USE_PARAMETER; - } - else - { - if (dwflags & LOCALE_NOUSEROVERRIDE) - used_operation = USE_SYSTEMDEFAULT; - else - used_operation = USE_LOCALEINFO; - } - - /* Load the fields we need */ - switch(used_operation) - { - case USE_LOCALEINFO: - GetLocaleInfoA(locale, LOCALE_IDIGITS, sNumberDigits, sizeof(sNumberDigits)); - GetLocaleInfoA(locale, LOCALE_SDECIMAL, sDecimalSymbol, sizeof(sDecimalSymbol)); - GetLocaleInfoA(locale, LOCALE_SGROUPING, sDigitsInGroup, sizeof(sDigitsInGroup)); - GetLocaleInfoA(locale, LOCALE_STHOUSAND, sDigitGroupSymbol, sizeof(sDigitGroupSymbol)); - GetLocaleInfoA(locale, LOCALE_ILZERO, sILZero, sizeof(sILZero)); - GetLocaleInfoA(locale, LOCALE_INEGNUMBER, sNegNumber, sizeof(sNegNumber)); - break; - case USE_PARAMETER: - sprintf(sNumberDigits, "%d",lpFormat->NumDigits); - strcpy(sDecimalSymbol, lpFormat->lpDecimalSep); - sprintf(sDigitsInGroup, "%d;0",lpFormat->Grouping); - /* Win95-WinME only allow 0-9 for grouping, no matter what MSDN says. */ - strcpy(sDigitGroupSymbol, lpFormat->lpThousandSep); - sprintf(sILZero, "%d",lpFormat->LeadingZero); - sprintf(sNegNumber, "%d",lpFormat->NegativeOrder); - break; - case USE_SYSTEMDEFAULT: - systemDefaultLCID = GetSystemDefaultLCID(); - GetLocaleInfoA(systemDefaultLCID, LOCALE_IDIGITS, sNumberDigits, sizeof(sNumberDigits)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_SDECIMAL, sDecimalSymbol, sizeof(sDecimalSymbol)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_SGROUPING, sDigitsInGroup, sizeof(sDigitsInGroup)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_STHOUSAND, sDigitGroupSymbol, sizeof(sDigitGroupSymbol)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_ILZERO, sILZero, sizeof(sILZero)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_INEGNUMBER, sNegNumber, sizeof(sNegNumber)); - break; - default: - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - nNumberDigits = atoi(sNumberDigits); - - /* Remove the ";" */ - i=0; - j = 1; - for (nCounter=0; nCounter0) && (atoi(sDigitsBeforeDecimal) != 0)) - { - /* Working on an inverted string is easier ! */ - OLE_InvertString(sDigitsBeforeDecimal); - - nStep = nCounter = i = j = 0; - nRuleIndex = 1; - nGrouping = OLE_GetGrouping(sRule, nRuleIndex); - if (nGrouping == 0) /* If the first grouping is zero */ - nGrouping = nNumberDecimal; /* Don't do grouping */ - - /* Here, we will loop until we reach the end of the string. - * An internal counter (j) is used in order to know when to - * insert the "digit group symbol". - */ - while (nNumberDecimal > 0) - { - i = nCounter + nStep; - memcpy(sDestination + i, sDigitsBeforeDecimal + nCounter, 1); - nCounter++; - j++; - if (j >= nGrouping) - { - j = 0; - if (nRuleIndex < sRule[0]) - nRuleIndex++; - nGrouping = OLE_GetGrouping(sRule, nRuleIndex); - memcpy(sDestination + i+1, sDigitGroupSymbol, strlen(sDigitGroupSymbol)); - nStep+= strlen(sDigitGroupSymbol); - } - - nNumberDecimal--; - } - - memcpy(sDestination + i+1, "\0", 1); - /* Get the string in the right order ! */ - OLE_InvertString(sDestination); - } - else - { - nLZ = atoi(sILZero); - if (nLZ != 0) - { - /* Use 0.xxx instead of .xxx */ - memcpy(sDestination, "0", 1); - memcpy(sDestination+1, "\0", 1); - } - else - memcpy(sDestination, "\0", 1); - - } - - /* Second, format the digits after the decimal. */ - j = 0; - nCounter = nNumberDigits; - if ( (nDigits>0) && (pStr = strstr (sNumber, ".")) ) - { - i = strlen(sNumber) - strlen(pStr) + 1; - strncpy ( sDigitsAfterDecimal, sNumber + i, nNumberDigits); - j = strlen(sDigitsAfterDecimal); - if (j < nNumberDigits) - nCounter = nNumberDigits-j; - } - for (i=0;iNegativeOrder; - nPosOrder = lpFormat->PositiveOrder; - strcpy(sCurrencySymbol, lpFormat->lpCurrencySymbol); - break; - case USE_SYSTEMDEFAULT: - systemDefaultLCID = GetSystemDefaultLCID(); - /* Specific to CURRENCYFMTA */ - GetLocaleInfoA(systemDefaultLCID, LOCALE_INEGCURR, sNegOrder, sizeof(sNegOrder)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_ICURRENCY, sPosOrder, sizeof(sPosOrder)); - GetLocaleInfoA(systemDefaultLCID, LOCALE_SCURRENCY, sCurrencySymbol, sizeof(sCurrencySymbol)); - - nPosOrder = atoi(sPosOrder); - nNegOrder = atoi(sNegOrder); - break; - default: - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - /* Construct a temporary number format structure */ - if (lpFormat != NULL) - { - numberFmt.NumDigits = lpFormat->NumDigits; - numberFmt.LeadingZero = lpFormat->LeadingZero; - numberFmt.Grouping = lpFormat->Grouping; - numberFmt.NegativeOrder = 0; - numberFmt.lpDecimalSep = lpFormat->lpDecimalSep; - numberFmt.lpThousandSep = lpFormat->lpThousandSep; - bValidFormat = TRUE; - } - - /* Make a call to GetNumberFormatA() */ - if (*lpvalue == '-') - { - bIsPositive = FALSE; - retVal = GetNumberFormatA(locale,0,lpvalue+1,(bValidFormat)?&numberFmt:NULL,pNumberFormated,128); - } - else - { - bIsPositive = TRUE; - retVal = GetNumberFormatA(locale,0,lpvalue,(bValidFormat)?&numberFmt:NULL,pNumberFormated,128); - } - - if (retVal == 0) - return 0; - - /* construct the formatted string */ - if (bIsPositive) - { - switch (nPosOrder) - { - case 0: /* Prefix, no separation */ - strcpy (pDestination, sCurrencySymbol); - strcat (pDestination, pNumberFormated); - break; - case 1: /* Suffix, no separation */ - strcpy (pDestination, pNumberFormated); - strcat (pDestination, sCurrencySymbol); - break; - case 2: /* Prefix, 1 char separation */ - strcpy (pDestination, sCurrencySymbol); - strcat (pDestination, " "); - strcat (pDestination, pNumberFormated); - break; - case 3: /* Suffix, 1 char separation */ - strcpy (pDestination, pNumberFormated); - strcat (pDestination, " "); - strcat (pDestination, sCurrencySymbol); - break; - default: - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - } - else /* negative number */ - { - switch (nNegOrder) - { - case 0: /* format: ($1.1) */ - strcpy (pDestination, "("); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, pNumberFormated); - strcat (pDestination, ")"); - break; - case 1: /* format: -$1.1 */ - strcpy (pDestination, "-"); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, pNumberFormated); - break; - case 2: /* format: $-1.1 */ - strcpy (pDestination, sCurrencySymbol); - strcat (pDestination, "-"); - strcat (pDestination, pNumberFormated); - break; - case 3: /* format: $1.1- */ - strcpy (pDestination, sCurrencySymbol); - strcat (pDestination, pNumberFormated); - strcat (pDestination, "-"); - break; - case 4: /* format: (1.1$) */ - strcpy (pDestination, "("); - strcat (pDestination, pNumberFormated); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, ")"); - break; - case 5: /* format: -1.1$ */ - strcpy (pDestination, "-"); - strcat (pDestination, pNumberFormated); - strcat (pDestination, sCurrencySymbol); - break; - case 6: /* format: 1.1-$ */ - strcpy (pDestination, pNumberFormated); - strcat (pDestination, "-"); - strcat (pDestination, sCurrencySymbol); - break; - case 7: /* format: 1.1$- */ - strcpy (pDestination, pNumberFormated); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, "-"); - break; - case 8: /* format: -1.1 $ */ - strcpy (pDestination, "-"); - strcat (pDestination, pNumberFormated); - strcat (pDestination, " "); - strcat (pDestination, sCurrencySymbol); - break; - case 9: /* format: -$ 1.1 */ - strcpy (pDestination, "-"); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, " "); - strcat (pDestination, pNumberFormated); - break; - case 10: /* format: 1.1 $- */ - strcpy (pDestination, pNumberFormated); - strcat (pDestination, " "); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, "-"); - break; - case 11: /* format: $ 1.1- */ - strcpy (pDestination, sCurrencySymbol); - strcat (pDestination, " "); - strcat (pDestination, pNumberFormated); - strcat (pDestination, "-"); - break; - case 12: /* format: $ -1.1 */ - strcpy (pDestination, sCurrencySymbol); - strcat (pDestination, " "); - strcat (pDestination, "-"); - strcat (pDestination, pNumberFormated); - break; - case 13: /* format: 1.1- $ */ - strcpy (pDestination, pNumberFormated); - strcat (pDestination, "-"); - strcat (pDestination, " "); - strcat (pDestination, sCurrencySymbol); - break; - case 14: /* format: ($ 1.1) */ - strcpy (pDestination, "("); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, " "); - strcat (pDestination, pNumberFormated); - strcat (pDestination, ")"); - break; - case 15: /* format: (1.1 $) */ - strcpy (pDestination, "("); - strcat (pDestination, pNumberFormated); - strcat (pDestination, " "); - strcat (pDestination, sCurrencySymbol); - strcat (pDestination, ")"); - break; - default: - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - } - - retVal = strlen(pDestination) + 1; - - if (cchCurrency) - { - memcpy( lpCurrencyStr, pDestination, min(cchCurrency, retVal) ); - if (cchCurrency < retVal) { - retVal = 0; - SetLastError(ERROR_INSUFFICIENT_BUFFER); - } - } - return retVal; -} - -/************************************************************************** - * GetCurrencyFormatW (KERNEL32.@) - */ -INT WINAPI GetCurrencyFormatW(LCID locale, DWORD dwflags, - LPCWSTR lpvalue, const CURRENCYFMTW * lpFormat, - LPWSTR lpCurrencyStr, int cchCurrency) -{ - FIXME("This API function is NOT implemented !\n"); - return 0; -} - -/****************************************************************************** - * OLE2NLS_CheckLocale [intern] - */ -static LCID OLE2NLS_CheckLocale (LCID locale) -{ - if (!locale) - { locale = LOCALE_SYSTEM_DEFAULT; - } - - if (locale == LOCALE_SYSTEM_DEFAULT) - { return GetSystemDefaultLCID(); - } - else if (locale == LOCALE_USER_DEFAULT) - { return GetUserDefaultLCID(); - } - else - { return locale; - } -} -/****************************************************************************** - * GetTimeFormatA [KERNEL32.@] - * Makes an ASCII string of the time - * - * Formats date according to format, or locale default if format is - * NULL. The format consists of literal characters and fields as follows: - * - * h hours with no leading zero (12-hour) - * hh hours with full two digits - * H hours with no leading zero (24-hour) - * HH hours with full two digits - * m minutes with no leading zero - * mm minutes with full two digits - * s seconds with no leading zero - * ss seconds with full two digits - * t time marker (A or P) - * tt time marker (AM, PM) - * - */ -INT WINAPI -GetTimeFormatA(LCID locale, /* [in] */ - DWORD flags, /* [in] */ - const SYSTEMTIME* xtime, /* [in] */ - LPCSTR format, /* [in] */ - LPSTR timestr, /* [out] */ - INT timelen /* [in] */) -{ - INT ret; - LPWSTR wformat = NULL; - LPWSTR wtime = NULL; - - if (format) - { - wformat = HeapAlloc(GetProcessHeap(), 0, - (strlen(format) + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_ACP, 0, format, -1, wformat, strlen(format) + 1); - } - - if (timestr && timelen) - { - wtime = HeapAlloc(GetProcessHeap(), 0, - (timelen + 1) * sizeof(wchar_t)); - } - - ret = GetTimeFormatW(locale, flags, xtime, wformat, wtime, timelen); - - if (wtime) - { - WideCharToMultiByte(CP_ACP, 0, wtime, ret, timestr, timelen, NULL, NULL); - HeapFree(GetProcessHeap(), 0, wtime); - } - - if (wformat) - { - HeapFree(GetProcessHeap(), 0, wformat); - } - - return ret; -} - - -/****************************************************************************** - * GetTimeFormatW [KERNEL32.@] - * Makes a Unicode string of the time - * - * NOTE: See OLE_GetFormatW() for further documentation - */ -INT WINAPI -GetTimeFormatW(LCID locale, /* [in] */ - DWORD flags, /* [in] */ - const SYSTEMTIME* xtime, /* [in] */ - LPCWSTR format, /* [in] */ - LPWSTR timestr, /* [out] */ - INT timelen /* [in] */) -{ WCHAR format_buf[40]; - LPCWSTR thisformat; - SYSTEMTIME t; - const SYSTEMTIME* thistime; - LCID thislocale=0; - DWORD thisflags=LOCALE_STIMEFORMAT; /* standard timeformat */ - INT ret; - - TRACE("GetTimeFormat(0x%04lx,0x%08lx,%p,%s,%p,%d)\n",locale,flags, - xtime,debugstr_w(format),timestr,timelen); - - thislocale = OLE2NLS_CheckLocale ( locale ); - - /* if the user didn't specify a format we use the default */ - /* format for this locale */ - if (format == NULL) - { - if (flags & LOCALE_NOUSEROVERRIDE) /* use system default */ - { - thislocale = GetSystemDefaultLCID(); - } - GetLocaleInfoW(thislocale, thisflags, format_buf, 40); - thisformat = format_buf; - } - else - { - /* if non-null format and LOCALE_NOUSEROVERRIDE then fail */ - /* NOTE: this could be either invalid flags or invalid parameter */ - /* windows sets it to invalid flags */ - if (flags & LOCALE_NOUSEROVERRIDE) - { - SetLastError(ERROR_INVALID_FLAGS); - return 0; - } - - thisformat = format; - } - - if (xtime == NULL) /* NULL means use the current local time */ - { GetLocalTime(&t); - thistime = &t; - } - else - { - /* check time values */ - if((xtime->wHour > 24) || (xtime->wMinute >= 60) || (xtime->wSecond >= 60)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - thistime = xtime; - } - - ret = OLE_GetFormatW(thislocale, thisflags, flags, thistime, thisformat, - timestr, timelen, 0); - return ret; -} - -/****************************************************************************** - * EnumCalendarInfoA [KERNEL32.@] - */ -BOOL WINAPI EnumCalendarInfoA( - CALINFO_ENUMPROCA calinfoproc,LCID locale,CALID calendar,CALTYPE caltype -) { - FIXME("(%p,0x%04lx,0x%08lx,0x%08lx),stub!\n",calinfoproc,locale,calendar,caltype); - return FALSE; -}