|
|
/*++
Copyright (c) 1991-1996, Microsoft Corporation All rights reserved.
Module Name:
datetime.c
Abstract:
This file contains the API functions that form properly formatted date and time strings for a given locale.
APIs found in this file: GetTimeFormatW GetDateFormatW
Revision History:
05-31-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
//
// Constant Declarations.
//
#define MAX_DATETIME_BUFFER 256 // max size of buffer
//
// Forward Declarations.
//
BOOL IsValidTime( LPSYSTEMTIME lpTime);
BOOL IsValidDate( LPSYSTEMTIME lpDate);
WORD GetCalendarYear( LPWORD *ppRange, CALID CalNum, PCALENDAR_VAR pCalInfo, WORD Year, WORD Month, WORD Day);
int ParseTime( PLOC_HASH pHashN, LPSYSTEMTIME pLocalTime, LPWSTR pFormat, LPWSTR pTimeStr, DWORD dwFlags);
int ParseDate( PLOC_HASH pHashN, LPSYSTEMTIME pLocalDate, LPWSTR pFormat, LPWSTR pDateStr, CALID CalNum, PCALENDAR_VAR pCalInfo);
//-------------------------------------------------------------------------//
// INTERNAL MACROS //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// NLS_COPY_UNICODE_STR
//
// Copies a zero terminated string from pSrc to the pDest buffer. The
// pDest pointer is advanced to the end of the string.
//
// DEFINED AS A MACRO.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define NLS_COPY_UNICODE_STR( pDest, \
pSrc ) \ { \ LPWSTR pTmp; /* temp pointer to source */ \ \ \ pTmp = pSrc; \ while (*pTmp) \ { \ *pDest = *pTmp; \ pDest++; \ pTmp++; \ } \ }
////////////////////////////////////////////////////////////////////////////
//
// NLS_PAD_INT_TO_UNICODE_STR
//
// Converts an integer value to a unicode string and stores it in the
// buffer provided with the appropriate number of leading zeros. The
// pResultBuf pointer is advanced to the end of the string.
//
// DEFINED AS A MACRO.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define MAX_TMP_BUF 20
#define NLS_PAD_INT_TO_UNICODE_STR( Value, \
Base, \ Padding, \ pResultBuf ) \ { \ UNICODE_STRING ObString; /* value string */ \ WCHAR pBuffer[MAX_TMP_BUF]; /* ptr to buffer */ \ UINT LpCtr; /* loop counter */ \ \ \ /* \
* Set up unicode string structure. \ */ \ ObString.Length = MAX_TMP_BUF; \ ObString.MaximumLength = MAX_TMP_BUF; \ ObString.Buffer = pBuffer; \ \ /* \
* Get the value as a string. If there is an error, then do nothing. \ */ \ if (!RtlIntegerToUnicodeString(Value, Base, &ObString)) \ { \ /* \
* Pad the string with the appropriate number of zeros. \ */ \ for (LpCtr = GET_WC_COUNT(ObString.Length); \ LpCtr < Padding; \ LpCtr++, pResultBuf++) \ { \ *pResultBuf = NLS_CHAR_ZERO; \ } \ \ /* \
* Copy the string to the result buffer. \ * The pResultBuf pointer will be advanced in the macro. \ */ \ NLS_COPY_UNICODE_STR(pResultBuf, ObString.Buffer); \ } \ }
////////////////////////////////////////////////////////////////////////////
//
// NLS_STRING_TO_INTEGER
//
// Converts a string to an integer value.
//
// DEFINED AS A MACRO.
//
// 10-19-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
#define NLS_STRING_TO_INTEGER( CalNum, \
pCalId ) \ { \ UNICODE_STRING ObUnicodeStr; /* value string */ \ \ \ /* \
* No need to check return value since the calendar number \ * will be validated after this anyway. \ */ \ RtlInitUnicodeString(&ObUnicodeStr, pCalId); \ RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &CalNum); \ }
//-------------------------------------------------------------------------//
// API ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// GetTimeFormatW
//
// Returns a properly formatted time string for the given locale. It uses
// either the system time or the specified time. This call also indicates
// how much memory is necessary to contain the desired information.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int WINAPI GetTimeFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpTime, LPCWSTR lpFormat, LPWSTR lpTimeStr, int cchTime)
{ PLOC_HASH pHashN; // ptr to LOC hash node
SYSTEMTIME LocalTime; // local time structure
LPWSTR pFormat; // ptr to time format string
int Length = 0; // number of characters written
WCHAR pString[MAX_DATETIME_BUFFER]; // ptr to temporary buffer
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Invalid Parameter Check:
// - validate LCID
// - count is negative
// - NULL data pointer AND count is not zero
//
VALIDATE_LOCALE(Locale, pHashN); if ( (pHashN == NULL) || (cchTime < 0) || ((lpTimeStr == NULL) && (cchTime != 0)) ) { SetLastError(ERROR_INVALID_PARAMETER); return (0); }
//
// Invalid Flags Check:
// - flags other than valid ones
// - lpFormat not NULL AND NoUserOverride flag is set
//
if ( (dwFlags & GTF_INVALID_FLAG) || ((lpFormat != NULL) && (dwFlags & LOCALE_NOUSEROVERRIDE)) ) { SetLastError(ERROR_INVALID_FLAGS); return (0); }
//
// Set pFormat to point at the proper format string.
//
if (lpFormat == NULL) { //
// Get either the user's time format from the registry or
// the default time format from the locale file.
// This string may be a null string.
//
if (!(dwFlags & LOCALE_NOUSEROVERRIDE) && GetUserInfo( Locale, pNlsUserInfo->sTimeFormat, pTemp, FALSE )) { pFormat = pTemp; } else { pFormat = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->STimeFormat; } } else { //
// Use the format string given by the caller.
//
pFormat = (LPWSTR)lpFormat; }
//
// Get the current local system time if one is not given.
//
if (lpTime != NULL) { //
// Time is given by user. Store in local structure and
// validate it.
//
LocalTime.wHour = lpTime->wHour; LocalTime.wMinute = lpTime->wMinute; LocalTime.wSecond = lpTime->wSecond; LocalTime.wMilliseconds = lpTime->wMilliseconds;
if (!IsValidTime(&LocalTime)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); } } else { GetLocalTime(&LocalTime); }
//
// Parse the time format string.
//
Length = ParseTime( pHashN, &LocalTime, pFormat, pString, dwFlags );
//
// Check cchTime for size of given buffer.
//
if (cchTime == 0) { //
// If cchTime is 0, then we can't use lpTimeStr. In this
// case, we simply want to return the length (in characters) of
// the string to be copied.
//
return (Length); } else if (cchTime < Length) { //
// The buffer is too small for the string, so return an error
// and zero bytes written.
//
SetLastError(ERROR_INSUFFICIENT_BUFFER); return (0); }
//
// Copy the time string to lpTimeStr and null terminate it.
// Return the number of characters copied.
//
wcsncpy(lpTimeStr, pString, Length); return (Length); }
////////////////////////////////////////////////////////////////////////////
//
// GetDateFormatW
//
// Returns a properly formatted date string for the given locale. It uses
// either the system date or the specified date. The user may specify
// either the short date format or the long date format. This call also
// indicates how much memory is necessary to contain the desired information.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int WINAPI GetDateFormatW( LCID Locale, DWORD dwFlags, CONST SYSTEMTIME *lpDate, LPCWSTR lpFormat, LPWSTR lpDateStr, int cchDate)
{ PLOC_HASH pHashN; // ptr to LOC hash node
LPWSTR pFormat; // ptr to format string
SYSTEMTIME LocalDate; // local date structure
int Length = 0; // number of characters written
WCHAR pString[MAX_DATETIME_BUFFER]; // ptr to temporary buffer
BOOL fAltCalendar; // if alternate cal flag set
LPWSTR pOptCal; // ptr to optional calendar
PCAL_INFO pCalInfo; // ptr to calendar info
CALID CalNum = 0; // calendar number
ULONG CalDateOffset; // offset to calendar data
ULONG LocDateOffset; // offset to locale data
LPWSTR pRegStr; // ptr to registry string to get
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Invalid Parameter Check:
// - validate LCID
// - count is negative
// - NULL data pointer AND count is not zero
//
VALIDATE_LOCALE(Locale, pHashN); if ( (pHashN == NULL) || (cchDate < 0) || ((lpDateStr == NULL) && (cchDate != 0)) ) { SetLastError(ERROR_INVALID_PARAMETER); return (0); }
//
// Invalid Flags Check:
// - flags other than valid ones
// - lpFormat not NULL AND flags not zero
//
if ( (dwFlags & GDF_INVALID_FLAG) || ((lpFormat != NULL) && (dwFlags & (DATE_SHORTDATE | DATE_LONGDATE | LOCALE_NOUSEROVERRIDE))) ) { SetLastError(ERROR_INVALID_FLAGS); return (0); }
//
// See if the alternate calendar should be used.
//
if (fAltCalendar = (dwFlags & DATE_USE_ALT_CALENDAR)) { //
// Get the default optional calendar.
//
pOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->IOptionalCal;
//
// If there is an optional calendar, store the calendar id.
//
if (((POPT_CAL)pOptCal)->CalId != CAL_NO_OPTIONAL) { CalNum = ((POPT_CAL)pOptCal)->CalId; } }
//
// If there was no alternate calendar, then try (in order):
// - the user's calendar type
// - the system default calendar type
//
if (CalNum == 0) { //
// Get the user's calendar type.
//
if ( !(dwFlags & LOCALE_NOUSEROVERRIDE) && GetUserInfo( Locale, pNlsUserInfo->iCalType, pTemp, TRUE ) && (pOptCal = IsValidCalendarTypeStr( pHashN, pTemp )) ) { CalNum = ((POPT_CAL)pOptCal)->CalId; } else { //
// Get the system default calendar type.
//
NLS_STRING_TO_INTEGER( CalNum, pHashN->pLocaleFixed->szICalendarType ); } }
//
// Get the pointer to the appropriate calendar information.
//
if (GetCalendar(CalNum, &pCalInfo)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); }
//
// Set pFormat to point at the proper format string.
//
if (lpFormat == NULL) { //
// Find out which flag is set and save the appropriate
// information.
//
switch (dwFlags & (DATE_SHORTDATE | DATE_LONGDATE)) { case ( 0 ) : case ( DATE_SHORTDATE ) : { //
// Get the offset values for the shortdate.
//
CalDateOffset = (ULONG)FIELD_OFFSET(CALENDAR_VAR, SShortDate); LocDateOffset = (ULONG)FIELD_OFFSET(LOCALE_VAR, SShortDate); pRegStr = pNlsUserInfo->sShortDate;
break; }
case ( DATE_LONGDATE ) : { //
// Get the offset values for the longdate.
//
CalDateOffset = (ULONG)FIELD_OFFSET(CALENDAR_VAR, SLongDate); LocDateOffset = (ULONG)FIELD_OFFSET(LOCALE_VAR, SLongDate); pRegStr = pNlsUserInfo->sLongDate;
break; }
default : { SetLastError(ERROR_INVALID_FLAGS); return (0); } }
//
// Get the proper format string for the given locale.
// This string may be a null string.
//
pFormat = NULL; if (fAltCalendar && (CalNum != CAL_GREGORIAN)) { pFormat = (LPWORD)pCalInfo + *((LPWORD)((LPBYTE)(pCalInfo) + CalDateOffset));
if (*pFormat == 0) { pFormat = NULL; } }
if (pFormat == NULL) { if (!(dwFlags & LOCALE_NOUSEROVERRIDE) && GetUserInfo( Locale, pRegStr, pTemp, TRUE )) { pFormat = pTemp; } else { pFormat = (LPWORD)pCalInfo + *((LPWORD)((LPBYTE)(pCalInfo) + CalDateOffset));
if (*pFormat == 0) { pFormat = (LPWORD)(pHashN->pLocaleHdr) + *((LPWORD)((LPBYTE)(pHashN->pLocaleHdr) + LocDateOffset)); } } } } else { //
// Use the format string given by the caller.
//
pFormat = (LPWSTR)lpFormat; }
//
// Get the current local system date if one is not given.
//
if (lpDate != NULL) { //
// Date is given by user. Store in local structure and
// validate it.
//
LocalDate.wYear = lpDate->wYear; LocalDate.wMonth = lpDate->wMonth; LocalDate.wDayOfWeek = lpDate->wDayOfWeek; LocalDate.wDay = lpDate->wDay;
if (!IsValidDate(&LocalDate)) { SetLastError(ERROR_INVALID_PARAMETER); return (0); } } else { GetLocalTime(&LocalDate); }
//
// Parse the date format string.
//
Length = ParseDate( pHashN, &LocalDate, pFormat, pString, CalNum, (PCALENDAR_VAR)pCalInfo );
//
// Check cchDate for size of given buffer.
//
if (cchDate == 0) { //
// If cchDate is 0, then we can't use lpDateStr. In this
// case, we simply want to return the length (in characters) of
// the string to be copied.
//
return (Length); } else if (cchDate < Length) { //
// The buffer is too small for the string, so return an error
// and zero bytes written.
//
SetLastError(ERROR_INSUFFICIENT_BUFFER); return (0); }
//
// Copy the date string to lpDateStr and null terminate it.
// Return the number of characters copied.
//
wcsncpy(lpDateStr, pString, Length); return (Length); }
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// IsValidTime
//
// Returns TRUE if the given time is valid. Otherwise, it returns FALSE.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL IsValidTime( LPSYSTEMTIME pTime)
{ //
// Check for invalid time values.
//
if ( (pTime->wHour > 23) || (pTime->wMinute > 59) || (pTime->wSecond > 59) || (pTime->wMilliseconds > 999) ) { return (FALSE); }
//
// Return success.
//
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// IsValidDate
//
// Returns TRUE if the given date is valid. Otherwise, it returns FALSE.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL IsValidDate( LPSYSTEMTIME pDate)
{ LARGE_INTEGER Time; // time as a large integer
TIME_FIELDS TimeFields; // time fields structure
//
// Set up time fields structure with the given date.
// Only want to check the DATE values, so pass in a valid time.
//
TimeFields.Year = pDate->wYear; TimeFields.Month = pDate->wMonth; TimeFields.Day = pDate->wDay; TimeFields.Hour = 0; TimeFields.Minute = 0; TimeFields.Second = 0; TimeFields.Milliseconds = 0;
//
// Check for invalid date values.
//
// NOTE: This routine ignores the Weekday field.
//
if (!RtlTimeFieldsToTime(&TimeFields, &Time)) { return (FALSE); }
//
// Make sure the given day of the week is valid for the given date.
//
RtlTimeToTimeFields(&Time, &TimeFields); pDate->wDayOfWeek = TimeFields.Weekday;
//
// Return success.
//
return (TRUE); }
////////////////////////////////////////////////////////////////////////////
//
// GetCalendarYear
//
// Adjusts the given year to the given calendar's year.
//
// 10-15-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
WORD GetCalendarYear( LPWORD *ppRange, CALID CalNum, PCALENDAR_VAR pCalInfo, WORD Year, WORD Month, WORD Day)
{ LPWORD pRange; // ptr to range position
LPWORD pEndRange; // ptr to the end of the range
//
// Initialize range pointer.
//
*ppRange = NULL;
//
// Adjust the year based on the given calendar
//
switch (CalNum) { case ( 0 ) : case ( CAL_GREGORIAN ) : case ( CAL_GREGORIAN_US ) : default : { //
// Year value is not changed.
//
break; } case ( CAL_JAPAN ) : case ( CAL_TAIWAN ) : { //
// Get pointer to ranges.
//
pRange = ((LPWORD)pCalInfo) + pCalInfo->SEraRanges; pEndRange = ((LPWORD)pCalInfo) + pCalInfo->SShortDate;
//
// Find the appropriate range.
//
while (pRange < pEndRange) { if ((Year > ((PERA_RANGE)pRange)->Year) || ((Year == ((PERA_RANGE)pRange)->Year) && (Month >= ((PERA_RANGE)pRange)->Month) && (Day >= ((PERA_RANGE)pRange)->Day))) { break; }
pRange += ((PERA_RANGE)pRange)->Offset; }
//
// Make sure the year is within the given ranges. If it
// is not, then leave the year in the Gregorian format.
//
if (pRange < pEndRange) { //
// Convert the year to the appropriate Era year.
// Year = Year - EraYear + 1
//
Year = Year - ((PERA_RANGE)pRange)->Year + 1;
//
// Save the pointer to the range.
//
*ppRange = pRange; }
break; } case ( CAL_KOREA ) : case ( CAL_THAI ) : { //
// Get the first range.
//
pRange = ((LPWORD)pCalInfo) + pCalInfo->SEraRanges;
//
// Add the year offset to the given year.
// Year = Year + EraYear
//
Year += ((PERA_RANGE)pRange)->Year;
//
// Save the range.
//
*ppRange = pRange;
break; } }
//
// Return the year.
//
return (Year); }
////////////////////////////////////////////////////////////////////////////
//
// ParseTime
//
// Parses the time format string and puts the properly formatted
// local time into the given string buffer. It returns the number of
// characters written to the string buffer.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int ParseTime( PLOC_HASH pHashN, LPSYSTEMTIME pLocalTime, LPWSTR pFormat, LPWSTR pTimeStr, DWORD dwFlags)
{ LPWSTR pPos; // ptr to pTimeStr current position
LPWSTR pLastPos; // ptr to pTimeStr last valid position
int Repeat; // number of repetitions of same letter
WORD wHour; // hour
WCHAR wchar; // character in format string
LPWSTR pAMPM; // ptr to AM/PM designator
WCHAR pTemp[MAX_REG_VAL_SIZE]; // temp buffer
//
// Initialize position pointer.
//
pPos = pTimeStr; pLastPos = pPos;
//
// Parse through loop and store the appropriate time information
// in the pTimeStr buffer.
//
while (*pFormat) { switch (*pFormat) { case ( L'h' ) : { //
// Check for forced 24 hour time format.
//
wHour = pLocalTime->wHour; if (!(dwFlags & TIME_FORCE24HOURFORMAT)) { //
// Use 12 hour format.
//
if (!(wHour %= 12)) { wHour = 12; } }
//
// Get the number of 'h' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L'h'); Repeat++, pFormat++) ;
switch (Repeat) { case ( 0 ) : { //
// Use NO leading zero for the hour.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( wHour, 10, 1, pPos );
break; }
case ( 1 ) : default : { //
// Use leading zero for the hour.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( wHour, 10, 2, pPos );
break; } }
//
// Save the last position in case one of the NO_xxx
// flags is set.
//
pLastPos = pPos;
break; }
case ( L'H' ) : { //
// Get the number of 'H' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L'H'); Repeat++, pFormat++) ;
switch (Repeat) { case ( 0 ) : { //
// Use NO leading zero for the hour.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalTime->wHour, 10, 1, pPos );
break; }
case ( 1 ) : default : { //
// Use leading zero for the hour.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalTime->wHour, 10, 2, pPos );
break; } }
//
// Save the last position in case one of the NO_xxx
// flags is set.
//
pLastPos = pPos;
break; }
case ( L'm' ) : { //
// Get the number of 'm' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L'm'); Repeat++, pFormat++) ;
//
// If the flag TIME_NOMINUTESORSECONDS is set, then
// skip over the minutes.
//
if (dwFlags & TIME_NOMINUTESORSECONDS) { //
// Reset position pointer to last postion and break
// out of this case statement.
//
// This will remove any separator(s) between the
// hours and minutes.
//
pPos = pLastPos; break; }
switch (Repeat) { case ( 0 ) : { //
// Use NO leading zero for the minute.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalTime->wMinute, 10, 1, pPos );
break; }
case ( 1 ) : default : { //
// Use leading zero for the minute.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalTime->wMinute, 10, 2, pPos );
break; } }
//
// Save the last position in case one of the NO_xxx
// flags is set.
//
pLastPos = pPos;
break; }
case ( L's' ) : { //
// Get the number of 's' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L's'); Repeat++, pFormat++) ;
//
// If the flag TIME_NOMINUTESORSECONDS and/or TIME_NOSECONDS
// is set, then skip over the seconds.
//
if (dwFlags & (TIME_NOMINUTESORSECONDS | TIME_NOSECONDS)) { //
// Reset position pointer to last postion and break
// out of this case statement.
//
// This will remove any separator(s) between the
// minutes and seconds.
//
pPos = pLastPos; break; }
switch (Repeat) { case ( 0 ) : { //
// Use NO leading zero for the second.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalTime->wSecond, 10, 1, pPos );
break; }
case ( 1 ) : default : { //
// Use leading zero for the second.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalTime->wSecond, 10, 2, pPos );
break; } }
//
// Save the last position in case one of the NO_xxx
// flags is set.
//
pLastPos = pPos;
break; }
case ( L't' ) : { //
// Get the number of 't' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L't'); Repeat++, pFormat++) ;
//
// If the flag TIME_NOTIMEMARKER is set, then skip over
// the time marker info.
//
if (dwFlags & TIME_NOTIMEMARKER) { //
// Reset position pointer to last postion.
//
// This will remove any separator(s) between the
// time (hours, minutes, seconds) and the time
// marker.
//
pPos = pLastPos;
//
// Increment the format pointer until it reaches
// an h, H, m, or s. This will remove any
// separator(s) following the time marker.
//
while ( (wchar = *pFormat) && (wchar != L'h') && (wchar != 'H') && (wchar != 'm') && (wchar != 's') ) { pFormat++; }
//
// Break out of this case statement.
//
break; } else { //
// Get AM/PM designator.
// This string may be a null string.
//
if (pLocalTime->wHour < 12) { if (!(dwFlags & LOCALE_NOUSEROVERRIDE) && GetUserInfo( pHashN->Locale, pNlsUserInfo->s1159, pTemp, FALSE )) { pAMPM = pTemp; } else { pAMPM = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->S1159; } } else { if (!(dwFlags & LOCALE_NOUSEROVERRIDE) && GetUserInfo( pHashN->Locale, pNlsUserInfo->s2359, pTemp, FALSE )) { pAMPM = pTemp; } else { pAMPM = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->S2359; } }
if (*pAMPM == 0) { //
// Reset position pointer to last postion and break
// out of this case statement.
//
// This will remove any separator(s) between the
// time (hours, minutes, seconds) and the time
// marker.
//
pPos = pLastPos; break; } }
switch (Repeat) { case ( 0 ) : { //
// One letter of AM/PM designator.
//
*pPos = *pAMPM; pPos++;
break; }
case ( 1 ) : default : { //
// Use entire AM/PM designator string.
// The pPos pointer will be advanced in the macro. \ //
NLS_COPY_UNICODE_STR(pPos, pAMPM);
break; } }
//
// Save the last position in case one of the NO_xxx
// flags is set.
//
pLastPos = pPos;
break; }
case ( NLS_CHAR_QUOTE ) : { //
// Any text enclosed within single quotes should be left
// in the time string in its exact form (without the
// quotes), unless it is an escaped single quote ('').
//
pFormat++; while (*pFormat) { if (*pFormat != NLS_CHAR_QUOTE) { //
// Still within the single quote, so copy
// the character to the buffer.
//
*pPos = *pFormat; pFormat++; pPos++; } else { //
// Found another quote, so skip over it.
//
pFormat++;
//
// Make sure it's not an escaped single quote.
//
if (*pFormat == NLS_CHAR_QUOTE) { //
// Escaped single quote, so just write the
// single quote.
//
*pPos = *pFormat; pFormat++; pPos++; } else { //
// Found the end quote, so break out of loop.
//
break; } } }
break; }
default : { //
// Store the character in the buffer. Should be the
// separator, but copy it even if it isn't.
//
*pPos = *pFormat; pFormat++; pPos++;
break; } } }
//
// Zero terminate the string.
//
*pPos = 0;
//
// Return the number of characters written to the buffer, including
// the null terminator.
//
return ((pPos - pTimeStr) + 1); }
////////////////////////////////////////////////////////////////////////////
//
// ParseDate
//
// Parses the date format string and puts the properly formatted
// local date into the given string buffer. It returns the number of
// characters written to the string buffer.
//
// 04-30-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int ParseDate( PLOC_HASH pHashN, LPSYSTEMTIME pLocalDate, LPWSTR pFormat, LPWSTR pDateStr, CALID CalNum, PCALENDAR_VAR pCalInfo)
{ LPWSTR pPos; // ptr to pDateStr current position
int Repeat; // number of repetitions of same letter
LPWORD pIncr; // ptr to increment amount (day, month)
WORD Incr; // increment amount
BOOL fDayPrecedes = FALSE; // flag for numeric day preceding month
WORD Year; // year value
LPWORD pRange = NULL; // ptr to era ranges
LPWORD pInfo; // ptr to locale or calendar info
LPWORD pInfoC; // ptr to calendar info
//
// Initialize position pointer.
//
pPos = pDateStr;
//
// Parse through loop and store the appropriate date information
// in the pDateStr buffer.
//
while (*pFormat) { switch (*pFormat) { case ( L'd' ) : { //
// Get the number of 'd' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L'd'); Repeat++, pFormat++) ;
switch (Repeat) { case ( 0 ) : { //
// Set flag for day preceding month. The flag
// will be used when the MMMM case follows the
// d or dd case.
//
fDayPrecedes = TRUE;
//
// Use NO leading zero for the day of the month.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalDate->wDay, 10, 1, pPos );
break; }
case ( 1 ) : { //
// Set flag for day preceding month. The flag
// will be used when the MMMM case follows the
// d or dd case.
//
fDayPrecedes = TRUE;
//
// Use leading zero for the day of the month.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalDate->wDay, 10, 2, pPos );
break; }
case ( 2 ) : { //
// Set flag for day preceding month to be FALSE.
//
fDayPrecedes = FALSE;
//
// Get the abbreviated name for the day of the
// week.
// The pPos pointer will be advanced in the macro.
//
// NOTE: LocalTime structure uses:
// 0 = Sun, 1 = Mon, etc.
// Locale file uses:
// SAbbrevDayName1 = Mon, etc.
//
if (pCalInfo->IfNames) { pInfo = (LPWORD)pCalInfo; pIncr = &(pCalInfo->SAbbrevDayName1); } else { pInfo = (LPWORD)(pHashN->pLocaleHdr); pIncr = &(pHashN->pLocaleHdr->SAbbrevDayName1); } pIncr += (((pLocalDate->wDayOfWeek) + 6) % 7);
//
// Copy the abbreviated day name.
//
NLS_COPY_UNICODE_STR( pPos, ((LPWORD)(pInfo) + *pIncr) );
break; }
case ( 3 ) : default : { //
// Set flag for day preceding month to be FALSE.
//
fDayPrecedes = FALSE;
//
// Get the full name for the day of the week.
// The pPos pointer will be advanced in the macro. \ //
// NOTE: LocalTime structure uses:
// 0 = Sunday, 1 = Monday, etc.
// Locale file uses:
// SAbbrevDayName1 = Monday, etc.
//
if (pCalInfo->IfNames) { pInfo = (LPWORD)pCalInfo; pIncr = &(pCalInfo->SDayName1); } else { pInfo = (LPWORD)(pHashN->pLocaleHdr); pIncr = &(pHashN->pLocaleHdr->SDayName1); } pIncr += (((pLocalDate->wDayOfWeek) + 6) % 7);
//
// Copy the abbreviated day name.
//
NLS_COPY_UNICODE_STR( pPos, ((LPWORD)(pInfo) + *pIncr) );
break; } }
break; }
case ( L'M' ) : { //
// Get the number of 'M' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L'M'); Repeat++, pFormat++) ;
switch (Repeat) { case ( 0 ) : { //
// Use NO leading zero for the month.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalDate->wMonth, 10, 1, pPos );
break; }
case ( 1 ) : { //
// Use leading zero for the month.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( pLocalDate->wMonth, 10, 2, pPos );
break; }
case ( 2 ) : case ( 3 ) : default : { //
// Check for abbreviated or full month name.
//
if (Repeat == 2) { pInfoC = &(pCalInfo->SAbbrevMonthName1); pInfo = &(pHashN->pLocaleHdr->SAbbrevMonthName1); } else { pInfoC = &(pCalInfo->SMonthName1); pInfo = &(pHashN->pLocaleHdr->SMonthName1); }
//
// Get the abbreviated name of the month.
// The pPos pointer will be advanced in the macro.
//
if (pCalInfo->IfNames) { pIncr = (pInfoC) + (pLocalDate->wMonth - 1);
//
// Copy the abbreviated month name.
//
NLS_COPY_UNICODE_STR( pPos, ((LPWORD)(pCalInfo) + *pIncr) ); } else { pIncr = (pInfo) + (pLocalDate->wMonth - 1);
//
// Check for numeric day preceding month name.
//
if (fDayPrecedes) { Incr = *pIncr + 1 + NlsStrLenW(((LPWORD)(pHashN->pLocaleHdr) + *pIncr));
if (Incr != *(pIncr + 1)) { //
// Copy the special month name -
// 2nd one in list.
//
NLS_COPY_UNICODE_STR( pPos, ((LPWORD)(pHashN->pLocaleHdr) + Incr) );
break; } }
//
// Just copy the month name.
//
NLS_COPY_UNICODE_STR( pPos, ((LPWORD)(pHashN->pLocaleHdr) + *pIncr) ); }
break; } }
//
// Set flag for day preceding month to be FALSE.
//
fDayPrecedes = FALSE;
break; }
case ( L'y' ) : { //
// Get the number of 'y' repetitions in the format string.
//
pFormat++; for (Repeat = 0; (*pFormat == L'y'); Repeat++, pFormat++) ;
//
// Get proper year for calendar.
//
if (pCalInfo->NumRanges) { if (!pRange) { //
// Adjust the year for the given calendar.
//
Year = GetCalendarYear( &pRange, CalNum, pCalInfo, pLocalDate->wYear, pLocalDate->wMonth, pLocalDate->wDay ); } } else { Year = pLocalDate->wYear; }
//
// Write the year string to the buffer.
//
switch (Repeat) { case ( 0 ) : case ( 1 ) : { //
// Two-digit century with leading zero.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( (Year % 100), 10, (UINT)(Repeat + 1), pPos );
break; }
case ( 2 ) : case ( 3 ) : default : { //
// Full century.
// The pPos pointer will be advanced in the macro.
//
NLS_PAD_INT_TO_UNICODE_STR( Year, 10, 2, pPos );
break; } }
//
// Set flag for day preceding month to be FALSE.
//
fDayPrecedes = FALSE;
break; }
case ( L'g' ) : { //
// Get the number of 'g' repetitions in the format string.
//
// NOTE: It doesn't matter how many g repetitions
// there are. They all mean 'gg'.
//
pFormat++; while (*pFormat == L'g') { pFormat++; }
//
// Copy the era string for the current calendar.
//
if (pCalInfo->NumRanges) { //
// Make sure we have the pointer to the
// appropriate range.
//
if (!pRange) { //
// Get the pointer to the correct range and
// adjust the year for the given calendar.
//
Year = GetCalendarYear( &pRange, CalNum, pCalInfo, pLocalDate->wYear, pLocalDate->wMonth, pLocalDate->wDay ); }
//
// Copy the era string to the buffer, if one exists.
//
if (pRange) { NLS_COPY_UNICODE_STR( pPos, ((PERA_RANGE)pRange)->pYearStr + NlsStrLenW(((PERA_RANGE)pRange)->pYearStr) + 1 ); } }
//
// Set flag for day preceding month to be FALSE.
//
fDayPrecedes = FALSE;
break; }
case ( NLS_CHAR_QUOTE ) : { //
// Any text enclosed within single quotes should be left
// in the date string in its exact form (without the
// quotes), unless it is an escaped single quote ('').
//
pFormat++; while (*pFormat) { if (*pFormat != NLS_CHAR_QUOTE) { //
// Still within the single quote, so copy
// the character to the buffer.
//
*pPos = *pFormat; pFormat++; pPos++; } else { //
// Found another quote, so skip over it.
//
pFormat++;
//
// Make sure it's not an escaped single quote.
//
if (*pFormat == NLS_CHAR_QUOTE) { //
// Escaped single quote, so just write the
// single quote.
//
*pPos = *pFormat; pFormat++; pPos++; } else { //
// Found the end quote, so break out of loop.
//
break; } } }
break; }
default : { //
// Store the character in the buffer. Should be the
// separator, but copy it even if it isn't.
//
*pPos = *pFormat; pFormat++; pPos++;
break; } } }
//
// Zero terminate the string.
//
*pPos = 0;
//
// Return the number of characters written to the buffer, including
// the null terminator.
//
return ((pPos - pDateStr) + 1); }
|