|
|
/*++
Copyright (c) 1988-1999 Microsoft Corporation
Module Name:
cclock.c
Abstract:
time/date functions
--*/
#include "cmd.h"
#define MMDDYY 0
#define DDMMYY 1
#define YYMMDD 2
extern TCHAR Fmt04[], Fmt05[], Fmt06[], Fmt10[], Fmt11[]; extern TCHAR Fmt17[], Fmt15[]; extern unsigned DosErr; extern unsigned LastRetCode; // for keeping current console output codepage.
extern UINT CurrentCP;
BOOL TimeAmPm=TRUE; TCHAR TimeSeparator[8]; TCHAR DateSeparator[8]; TCHAR DecimalPlace[8]; int DateFormat; TCHAR *DateFormatString; TCHAR ThousandSeparator[8]; TCHAR ShortMondayName[16]; TCHAR ShortTuesdayName[16]; TCHAR ShortWednesdayName[16]; TCHAR ShortThursdayName[16]; TCHAR ShortFridayName[16]; TCHAR ShortSaturdayName[16]; TCHAR ShortSundayName[16]; TCHAR AMIndicator[8]; TCHAR PMIndicator[8]; ULONG YearWidth;
//
// We snapshot the current LCID at startup and modify it based on the current known
// set of scripts that Console supports.
//
LCID CmdGetUserDefaultLCID( void ) { LCID CmdLcid = GetUserDefaultLCID(); #ifdef LANGPACK
if ( (PRIMARYLANGID(CmdLcid) == LANG_ARABIC) || (PRIMARYLANGID(CmdLcid) == LANG_HEBREW) || (PRIMARYLANGID(CmdLcid) == LANG_THAI) || (PRIMARYLANGID(CmdLcid) == LANG_HINDI) || (PRIMARYLANGID(CmdLcid) == LANG_TAMIL) || (PRIMARYLANGID(CmdLcid) == LANG_FARSI) ) { CmdLcid = MAKELCID (MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT); // 0x409;
} #endif
return CmdLcid; }
VOID InitLocale( VOID ) { TCHAR Buffer[128];
LCID CmdLcid = CmdGetUserDefaultLCID( ); // get the time separator
if (GetLocaleInfo(CmdLcid, LOCALE_STIME, Buffer, sizeof(TimeSeparator))) _tcscpy(TimeSeparator, Buffer); else _tcscpy(TimeSeparator, TEXT(":"));
// determine if we're 0-12 or 0-24
if (GetLocaleInfo(CmdLcid, LOCALE_ITIME, Buffer, 128)) { TimeAmPm = _tcscmp(Buffer,TEXT("1")); }
_tcscpy(AMIndicator, TEXT("a")); _tcscpy(PMIndicator, TEXT("p"));
//
// get the date ordering
//
DateFormat = MMDDYY; if (GetLocaleInfo(CmdLcid, LOCALE_IDATE, Buffer, 128)) { switch (Buffer[0]) { case TEXT('0'): DateFormat = MMDDYY; DateFormatString = TEXT( "MM/dd/yy" ); break; case TEXT('1'): DateFormat = DDMMYY; DateFormatString = TEXT( "dd/MM/yy" ); break; case TEXT('2'): DateFormat = YYMMDD; DateFormatString = TEXT( "yy/MM/dd" ); break; default: break; } }
//
// Get the date width
//
YearWidth = 2; if (GetLocaleInfo( CmdLcid, LOCALE_ICENTURY, Buffer, 128 )) { if (Buffer[0] == TEXT( '1' )) { YearWidth = 4; } }
// get the date separator
if (GetLocaleInfo(CmdLcid, LOCALE_SDATE, Buffer, sizeof(DateSeparator))) _tcscpy(DateSeparator, Buffer); else _tcscpy(DateSeparator, TEXT("/"));
// get the short day names
if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME1, Buffer, sizeof(ShortMondayName))) _tcscpy(ShortMondayName, Buffer); else _tcscpy(ShortMondayName, TEXT("Mon")); if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME2, Buffer, sizeof(ShortTuesdayName))) _tcscpy(ShortTuesdayName, Buffer); else _tcscpy(ShortTuesdayName, TEXT("Tue")); if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME3, Buffer, sizeof(ShortWednesdayName))) _tcscpy(ShortWednesdayName, Buffer); else _tcscpy(ShortWednesdayName, TEXT("Wed")); if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME4, Buffer, sizeof(ShortThursdayName))) _tcscpy(ShortThursdayName, Buffer); else _tcscpy(ShortThursdayName, TEXT("Thu")); if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME5, Buffer, sizeof(ShortFridayName))) _tcscpy(ShortFridayName, Buffer); else _tcscpy(ShortFridayName, TEXT("Fri")); if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME6, Buffer, sizeof(ShortSaturdayName))) _tcscpy(ShortSaturdayName, Buffer); else _tcscpy(ShortSaturdayName, TEXT("Sat")); if (GetLocaleInfo(CmdLcid, LOCALE_SABBREVDAYNAME7, Buffer, sizeof(ShortSundayName))) _tcscpy(ShortSundayName, Buffer); else _tcscpy(ShortSundayName, TEXT("Sun"));
// get decimal and thousand separator strings
if (GetLocaleInfo(CmdLcid, LOCALE_SDECIMAL, Buffer, sizeof(DecimalPlace))) _tcscpy(DecimalPlace, Buffer); else _tcscpy(DecimalPlace, TEXT(".")); if (GetLocaleInfo(CmdLcid, LOCALE_STHOUSAND, Buffer, sizeof(ThousandSeparator))) _tcscpy(ThousandSeparator, Buffer); else _tcscpy(ThousandSeparator, TEXT(","));
//
// Set locale so that we can correctly process extended characters
// Note: The string passed in is expected to be ASCII, not unicode
//
setlocale( LC_ALL, ".OCP" ) ; }
BOOLEAN SetDateTime( IN LPSYSTEMTIME OsDateAndTime ) { //
// We have to do this twice in order to get the leap year set correctly.
//
SetLocalTime( OsDateAndTime ); return(SetLocalTime( OsDateAndTime ) != 0); }
/*** eDate - begin the execution of the Date command
* * Purpose: * To display and/or set the system date. * * Args: * n - the parse tree node containing the date command * * int eDate(struct cmdnode *n) * * Returns: * SUCCESS always. * */
int eDate(n) struct cmdnode *n ; { BOOL bTerse = FALSE; PTCHAR pArgs = n->argptr; DEBUG((CLGRP, DALVL, "eDATE: argptr = `%s'", n->argptr)) ;
//
// If extensions are enabled, allow a /T switch
// to disable inputing a new DATE, just display the
// current date.
//
if (fEnableExtensions) while ( (pArgs = mystrchr( pArgs, TEXT('/') )) != NULL ) { TCHAR c = (TCHAR) _totlower(*(pArgs+1)); if ( c == TEXT('t') ) bTerse = TRUE; pArgs += 2; // just skip it
}
if ( bTerse ) { PrintDate(NULL, PD_PTDATE, (TCHAR *)NULL, 0) ; cmd_printf(CrLf); return(LastRetCode = SUCCESS); }
if ((n->argptr == NULL) || (*(n->argptr = EatWS(n->argptr, NULL)) == NULLC)) { PutStdOut(MSG_CURRENT_DATE, NOARGS) ; PrintDate(NULL, PD_PTDATE, (TCHAR *)NULL, 0) ; cmd_printf(CrLf); };
return(LastRetCode = GetVerSetDateTime(n->argptr, EDATE)) ; }
/*** eTime - begin the execution of the Time command
* * Purpose: * To display and/or set the system date. * * int eTime(struct cmdnode *n) * * Args: * n - the parse tree node containing the time command * * Returns: * SUCCESS always. * */
int eTime(n) struct cmdnode *n ; { BOOL bTerse = FALSE; PTCHAR pArgs = n->argptr; DEBUG((CLGRP, TILVL, "eTIME: argptr = `%s'", n->argptr)) ;
//
// If extensions are enabled, allow a /T switch
// to disable inputing a new TIME, just display the
// current time.
//
if (fEnableExtensions) while ( (pArgs = mystrchr( pArgs, TEXT('/') )) != NULL ) { TCHAR c = (TCHAR) _totlower(*(pArgs+1)); if ( c == TEXT('t') ) bTerse = TRUE; pArgs += 2; // just skip it
}
if ( bTerse ) { PrintTime(NULL, PD_PTDATE, (TCHAR *)NULL, 0) ; cmd_printf(CrLf); return(LastRetCode = SUCCESS); }
if ((n->argptr == NULL) || (*(n->argptr = EatWS(n->argptr, NULL)) == NULLC)) { PutStdOut(MSG_CURRENT_TIME, NOARGS) ; PrintTime(NULL, PT_TIME, (TCHAR *)NULL, 0) ; cmd_printf(CrLf); };
return(LastRetCode = GetVerSetDateTime(n->argptr, ETIME)) ; }
/*** PrintDate - print the date
* * Purpose: * To print the date either in the format used by the Date command or * the format used by the Dir command. The structure Cinfo is checked * for the country date format. * * PrintDate(int flag, TCHAR *buffer) * * Args: * flag - indicates which format to print * *buffer - indicates whether or not to print date message * * Notes: */
int PrintDate(crt_time,flag,buffer,cch) struct tm *crt_time ; int flag ; TCHAR *buffer; int cch; { TCHAR DayOfWeek[10]; TCHAR datebuf [32] ; unsigned i, j, k, m; int ptr = 0; struct tm xcrt_time ; SYSTEMTIME SystemTime; FILETIME FileTime; FILETIME LocalFileTime; int cchUsed; BOOL NeedDayOfWeek = TRUE;
DEBUG((CLGRP, DALVL, "PRINTDATE: flag = %d", flag)) ;
//
// PrintDate is never called with PD_DATE and buffer == NULL
// PrintDate is never called with PD_DIR and buffer == NULL
// PrintDate is never called with PD_PTDATE and buffer != NULL
//
// Another way of saying this is:
// PD_DATE => output to buffer
// PD_DIR => output to buffer
// PD_DIR2000 => output to buffer
// PD_PTDATE => print out
//
// PD_DIR MM/DD/YY
// PD_DIR2000 MM/DD/YYYY
// PD_DATE Japan: MM/DD/YYYY DayOfWeek Rest: DayOfWeek MM/DD/YYYY
// PD_PTDATE Japan: MM/DD/YYYY DayOfWeek Rest: DayOfWeek MM/DD/YYYY
//
//
// If no time was input, then use the current system time. Convert from the
// various formats to something standard.
//
if (!crt_time) { GetSystemTime(&SystemTime); SystemTimeToFileTime(&SystemTime,&FileTime); } else { xcrt_time = *crt_time; ConverttmToFILETIME(&xcrt_time,&FileTime); } FileTimeToLocalFileTime(&FileTime,&LocalFileTime); FileTimeToSystemTime( &LocalFileTime, &SystemTime );
//
// SystemTime now contains the correct local time
// FileTime now contains the correct local time
//
//
// If extensions are enabled, we format things in the culturally
// correct format (from international control panel). if not, then
// we display it as best we can from NT 4.
//
if (fEnableExtensions) {
TCHAR LocaleDateFormat[128]; PTCHAR p; BOOL InQuotes = FALSE;
//
// Map the locale to one that is acceptable to the console subsystem
//
if (!GetLocaleInfo( CmdGetUserDefaultLCID( ), LOCALE_SSHORTDATE, LocaleDateFormat, sizeof( LocaleDateFormat ) / sizeof( LocaleDateFormat[0] ))) { //
// Not enough room for this format, cheat and use the one we
// assumed from the DateFormat
//
_tcscpy( LocaleDateFormat, DateFormatString ); }
//
// The format string may be expanded with widely varying widths. We
// adjust this string to try to make sure that they are all fixed widths.
//
// The picture formats only have varying widths for:
// d (no leading zero date)
// dddd(full date name)
// M (no leading zero month)
// MMMM(full month name)
//
// So, if we see d or M, we change it to dd or MM (leading zero)
// If we see dddd or MMMM we change it to ddd or MMM (three char abbrev)
//
p = LocaleDateFormat; while (*p != TEXT( '\0' )) { TCHAR c = *p;
//
// Text inside single quotes is left alone
//
if (c == TEXT( '\'' )) { InQuotes = !InQuotes; p++; } else if (InQuotes) { p++; } else if (c == TEXT( 'd' ) || c == TEXT( 'M' )) {
//
// Count the number of identical chars
//
int Count = 0;
while (*p == c) { Count++; p++; }
//
// Reset p and shuffle string around based on the repetition count
//
p -= Count;
if (Count == 1) { //
// Move string right by one and copy the first char
//
memmove( (PUCHAR) &p[1], (PUCHAR) &p[0], sizeof( TCHAR ) * (_tcslen( &p[0] ) + 1));
//
// Skip over the format string
//
p += 2;
} else { //
// If the format string is specifying a day of week (d), then we do not
// need to add on the DayOfWeek, below
//
if (c == TEXT( 'd' )) { NeedDayOfWeek = FALSE; }
if (Count > 3) { //
// Move string left from the first different char to just after the 3rd
// repetition
//
memmove( (PUCHAR) &p[3], (PUCHAR) &p[Count], sizeof( TCHAR ) * (_tcslen( &p[Count] ) + 1));
//
// Skip over the format string
//
p += 3;
} else {
//
// Skip over the 2 or 3 count
//
p += Count; } } } else { p++; } }
GetDateFormat( CmdGetUserDefaultLCID( ), 0, &SystemTime, LocaleDateFormat, datebuf, sizeof( datebuf ) / sizeof( datebuf[0] )); } else {
i = SystemTime.wMonth; j = SystemTime.wDay; k = SystemTime.wYear;
//
// only print last two digits for DIR listings
//
if (flag == PD_DIR) { k = k % 100; }
if (DateFormat == YYMMDD ) { m = k ; /* Swap all values */ k = j ; j = i ; i = m ; } else if (DateFormat == DDMMYY) { m = i ; /* Swap mon/day for Europe */ i = j ; j = m ; }
DEBUG((CLGRP, DALVL, "PRINTDATE: i = %d j = %d k = %d", i, j, k)) ;
//
// Format the current date and current day of week
//
_sntprintf(datebuf, 32, Fmt10, i, DateSeparator, j, DateSeparator, k); }
_tcscpy( DayOfWeek, dayptr( SystemTime.wDayOfWeek )) ;
//
// If there is no input buffer, we display the day-of-week and date
// according to language preference. Only in DBCS codepages (aka Japan)
// does the day of week FOLLOW the date
//
if (buffer == NULL) { //
// This can only be PD_PTDATE
//
//
// No day of week means we simply display the date
//
if (!NeedDayOfWeek) { cchUsed = cmd_printf( Fmt11, datebuf ); } else if (IsDBCSCodePage()) { cchUsed = cmd_printf( Fmt15, datebuf, DayOfWeek ); // "%s %s "
} else { cchUsed = cmd_printf( Fmt15, DayOfWeek, datebuf ); // "%s %s "
}
} else { //
// for PD_DATE, we need to output the date in the correct spot
//
if (NeedDayOfWeek && flag == PD_DATE) {
if (IsDBCSCodePage()) { _tcscpy( buffer, datebuf ); _tcscat( buffer, TEXT( " " )); _tcscat( buffer, DayOfWeek ); } else { _tcscpy( buffer, DayOfWeek ); _tcscat( buffer, TEXT( " " )); _tcscat( buffer, datebuf ); } } else { //
// PD_DIR and PD_DIR2000 only get the date
//
_tcscpy( buffer, datebuf ); } cchUsed = _tcslen( buffer ); }
return cchUsed; }
/*** PrintTime - print the time
* * Purpose: * To print the time either in the format used by the Time command or * the format used by the Dir command. The structure Cinfo is checked * for the country time format. * * PrintTime(int flag) * * Args: * flag - indicates which format to print * */
int PrintTime(crt_time, flag, buffer, cch) struct tm *crt_time ; int flag ; TCHAR *buffer; int cch; { TCHAR *ampm ; unsigned hr ; SYSTEMTIME SystemTime; FILETIME FileTime; FILETIME LocalFileTime; int cchUsed;
if (!crt_time) { GetSystemTime(&SystemTime); SystemTimeToFileTime(&SystemTime,&FileTime); } else { ConverttmToFILETIME(crt_time,&FileTime); }
FileTimeToLocalFileTime(&FileTime,&LocalFileTime); FileTimeToSystemTime( &LocalFileTime, &SystemTime );
//
// PT_TIME implies Time Command format. This is nothing more
// than 24 hour clock with tenths
//
if (flag == PT_TIME) { /* Print time in Time command format */ if (!buffer) { cchUsed = cmd_printf(Fmt06, SystemTime.wHour, TimeSeparator, SystemTime.wMinute, TimeSeparator, SystemTime.wSecond, DecimalPlace, SystemTime.wMilliseconds/10 ) ; } else { cchUsed = _sntprintf(buffer, cch, Fmt06, SystemTime.wHour, TimeSeparator, SystemTime.wMinute, TimeSeparator, SystemTime.wSecond, DecimalPlace, SystemTime.wMilliseconds/10 ) ; }
} else {
TCHAR TimeBuffer[32];
//
// Print time in Dir command format. If extensions are enabled
// then we have the culturally correct time, otherwise we use
// the NT 4 format.
//
if (fEnableExtensions) { TCHAR LocaleTimeFormat[128]; PTCHAR p; BOOL InQuotes = FALSE;
if (!GetLocaleInfo( CmdGetUserDefaultLCID( ), LOCALE_STIMEFORMAT, LocaleTimeFormat, sizeof( LocaleTimeFormat ) / sizeof( LocaleTimeFormat[0] ))) { //
// Not enough room for this format, cheat and use the one we
// assumed from the DateFormat
//
_tcscpy( LocaleTimeFormat, TEXT( "HH:mm:ss t" )); }
//
// Scan the string looking for "h", "H", or "m" and make sure there are two of them.
// If there is a single one, replicate it. We do this to ensure leading zeros
// which we need to make this a fixed-width string
//
p = LocaleTimeFormat; while (*p != TEXT( '\0' )) { TCHAR c = *p;
//
// Text inside single quotes is left alone
//
if (c == TEXT( '\'' )) { InQuotes = !InQuotes; p++; } else if (InQuotes) { p++; } else if (c == TEXT( 'h' ) || c == TEXT( 'H' ) || c == TEXT( 'm' )) {
//
// Count the number of identical chars
//
int Count = 0;
while (*p == c) { Count++; p++; }
//
// Reset p and shuffle string around based on the repetition count
//
p -= Count;
if (Count == 1) { memmove( (PUCHAR) &p[1], (PUCHAR) &p[0], sizeof( TCHAR ) * (_tcslen( &p[0] ) + 1)); *p = c; }
p++;
}
p++; }
cchUsed = GetTimeFormat( CmdGetUserDefaultLCID( ), TIME_NOSECONDS, &SystemTime, LocaleTimeFormat, TimeBuffer, sizeof( TimeBuffer ) / sizeof( TimeBuffer[0] ));
if (cchUsed == 0) { TimeBuffer[0] = TEXT( '\0' ); }
} else { ampm = AMIndicator ; hr = SystemTime.wHour; if ( TimeAmPm ) { /* 12 hour am/pm format */ if ( hr >= 12) { if (hr > 12) { hr -= 12 ; } ampm = PMIndicator ; } else if (hr == 0) { hr = 12 ; } } else { /* 24 hour format */ ampm = TEXT( " " ); }
_sntprintf( TimeBuffer, sizeof( TimeBuffer ) / sizeof( TimeBuffer[0] ), Fmt04, hr, TimeSeparator, SystemTime.wMinute, ampm ); }
if (!buffer) { cchUsed = CmdPutString( TimeBuffer ); } else { _tcsncpy( buffer, TimeBuffer, cch ); buffer[cch] = TEXT( '\0' ); cchUsed = _tcslen( buffer ); }
}
return cchUsed; }
/*** GetVerSetDateTime - controls the changing of the date/time
* * Purpose: * To prompt the user for a date or time, verify it, and set it. * On entry, if *dtstr is not '\0', it already points to a date or time * string. * * If null input is given to one of the prompts, the command execution * ends; neither the date or the time is changed. * * Once valid input has been received the date/time is updated. * * int GetVerSetDateTime(TCHAR *dtstr, int call) * * Args: * dtstr - ptr to command line date/time string and is used to hold a ptr * to the tokenized date/time string * call - indicates whether to prompt for date or time * */
int GetVerSetDateTime(dtstr, call) TCHAR *dtstr ; int call ; { TCHAR dtseps[16] ; /* Date/Time separators passed to TokStr() */ TCHAR *scan; TCHAR separators[16]; TCHAR LocalBuf[MAX_PATH];
unsigned int dformat ; SYSTEMTIME OsDateAndTime; LONG cbRead; int ret;
if (call == EDATE) { /* Initialize date/time separator list */ dtseps[0] = TEXT('/') ; dtseps[1] = TEXT('-') ; dtseps[2] = TEXT('.') ; _tcscpy(&dtseps[3], DateSeparator) ; } else { dtseps[0] = TEXT(':'); dtseps[1] = TEXT('.'); dtseps[2] = TimeSeparator[0] ; _tcscpy(&dtseps[3], DecimalPlace) ; /* decimal separator should */ /* always be last */ }
DEBUG((CLGRP, DALVL|TILVL, "GVSDT: dtseps = `%s'", dtseps)) ;
for ( ; ; ) { /* Date/time get-verify-set loop */ if ((dtstr) && (*dtstr != NULLC)) { /* If a date/time was passed copy it into input buffer */ _tcscpy(LocalBuf, dtstr) ; *dtstr = NULLC ; } else { /* Otherwise, prompt for new date/time */ switch (DateFormat) { /* M012 */ /* case USA: */ case MMDDYY: /* @@ */ dformat = MSG_ENTER_NEW_DATE ; break ;
/* case JAPAN:
case CHINA: case SWEDEN: case FCANADA: @@ */ case YYMMDD: dformat = MSG_ENTER_JAPAN_DATE ; break ;
default: dformat = MSG_ENTER_DEF_DATE ; } ;
if ( call == EDATE ) PutStdOut(dformat, ONEARG, DateSeparator ); else PutStdOut(MSG_ENTER_NEW_TIME, NOARGS);
scan = LocalBuf; ret = ReadBufFromInput(CRTTONT(STDIN),LocalBuf,MAX_PATH,&cbRead); if (ret && cbRead != 0) {
*(scan + cbRead) = NULLC ;
} else {
//
// attempt to read past eof or error in pipe
// etc.
//
return( FAILURE );
} for (scan = LocalBuf; *scan; scan++) if ( (*scan == '\n') || (*scan == '\r' )) { *scan = '\0'; break; } if (!FileIsDevice(STDIN)) cmd_printf(Fmt17, LocalBuf) ; DEBUG((CLGRP, DALVL|TILVL, "GVSDT: LocalBuf = `%s'", LocalBuf)) ; }
_tcscpy( separators, dtseps); _tcscat( separators, TEXT(";") ); if (*(dtstr = TokStr(LocalBuf,separators, TS_SDTOKENS )) == NULLC) return( SUCCESS ) ; /* If empty input, return */
/* - Fill date/time buffer with correct date time and overlay that
* of the user */ GetLocalTime( &OsDateAndTime );
if (((call == EDATE) ? VerifyDateString(&OsDateAndTime,dtstr,dtseps) : VerifyTimeString(&OsDateAndTime,dtstr,dtseps))) {
if (SetDateTime( &OsDateAndTime )) { return( SUCCESS ) ; } else { if (GetLastError() == ERROR_PRIVILEGE_NOT_HELD) { PutStdErr(GetLastError(),NOARGS); return( FAILURE ); } } }
DEBUG((CLGRP, DALVL|TILVL, "GVSDT: Bad date/time entered.")) ;
PutStdOut(((call == EDATE) ? MSG_INVALID_DATE : MSG_REN_INVALID_TIME), NOARGS); *dtstr = NULLC ; } return( SUCCESS ); }
/*** VerifyDateString - verifies a date string
* * Purpose: * To verify a date string and load it into OsDateAndTime. * * VerifyDateString(TCHAR *dtoks, TCHAR *dseps) * * Args: * OsDateAndTime - where to store output numbers. * dtoks - tokenized date string * dseps - valid date separator characters * * Returns: * TRUE if the date string is valid. * FALSE if the date string is invalid. * */
VerifyDateString(OsDateAndTime, dtoks, dseps) LPSYSTEMTIME OsDateAndTime ; TCHAR *dtoks ; TCHAR *dseps ; { int indexes[3] ; /* Storage for date elements */ int i ; /* Work variable */ int y, d, m ; /* Array indexes */
switch (DateFormat) { /* Set array according to date format */ case MMDDYY: m = 0 ; d = 1 ; y = 2 ; break ;
case YYMMDD: y = 0 ; m = 1 ; d = 2 ; break ;
default: d = 0 ; m = 1 ; y = 2 ; }
DEBUG((CLGRP, DALVL, "VDATES: m = %d, d = %d, y = %d", m, d, y)) ;
/* Loop through the tokens in dtoks, and load them into the array. Note
* that the separators are also tokens in the string requiring the token * pointer to be advanced twice for each element. */ for (i = 0 ; i < 3 ; i++, dtoks += _tcslen(dtoks)+1) { TCHAR *j; int Length;
DEBUG((CLGRP, DALVL, "VDATES: i = %d dtoks = `%ws'", i, dtoks)) ;
//
// The atoi() return code will not suffice to reject date field strings with
// non-digit characters. It is zero, both for error and for the valid integer
// zero. Also, a string like "8$" will return 8. For that reason, each
// character must be tested.
//
j = dtoks; while (*j != TEXT( '\0' )) { if (!_istdigit( *j )) { return FALSE; } j++; }
//
// Verify lengths:
// years can be 2 or 4 chars in length
// Days can be 1 or 2 chars in length
// Months can be 1 or 2 chars in length
//
indexes[i] = _tcstol(dtoks, NULL, 10) ;
Length = (int)(j - dtoks); if (i == y) { if (Length != 2 && Length != 4) { return FALSE; } else if (Length == 4 && indexes[i] < 1600) { return FALSE; } } else if (Length != 1 && Length != 2) { return FALSE; }
dtoks = j + 1; DEBUG((CLGRP, DALVL, "VDATES: *dtoks = %02x", *dtoks)) ;
if (i < 2 && (!*dtoks || !_tcschr(dseps, *dtoks))) return(FALSE) ; }
//
// FIX,FIX - need to calculate OsDateAndTime->wDayOfWeek
//
OsDateAndTime->wDay = (WORD)indexes[d] ; OsDateAndTime->wMonth = (WORD)indexes[m] ;
//
// Take two-digit years and convert them appropriately:
// 80...99 => 1980...1999
// 00...79 => 2000...2079
//
// Four-digit years are taken at face value
//
if (indexes[y] < 0) { return FALSE; } else if (00 <= indexes[y] && indexes[y] <= 79) { indexes[y] += 2000; } else if (80 <= indexes[y] && indexes[y] <= 99) { indexes[y] += 1900; } else if (100 <= indexes[y] && indexes[y] <= 1979) { return FALSE; }
OsDateAndTime->wYear = (WORD)indexes[y] ; return(TRUE) ; }
/*** VerifyTimeString - verifies a time string
* * Purpose: * To verify a date string and load it into OsDateAndTime. * * VerifyTimeString(TCHAR *ttoks) * * Args: / * OsDateAndTime - where to store output numbers. * ttoks - Tokenized time string. NOTE: Each time field and each * separator field is an individual token in the time string. * Thus the token advancing formula "str += mystrlen(str)+1", * must be used twice to go from one time field to the next. * * Returns: * TRUE if the time string is valid. * FALSE if the time string is invalid. * */
VerifyTimeString(OsDateAndTime, ttoks, tseps) LPSYSTEMTIME OsDateAndTime ; TCHAR *ttoks ; TCHAR *tseps ; { int i ; /* Work variables */ int j ; TCHAR *p1, *p2; WORD *pp; TCHAR tsuffixes[] = TEXT("aApP");
p2 = &tseps[ 1 ];
pp = &OsDateAndTime->wHour;
for (i = 0 ; i < 4 ; i++, ttoks += mystrlen(ttoks)+1) {
DEBUG((CLGRP,TILVL, "VTIMES: ttoks = `%ws' i = %d", ttoks, i)) ;
/* First insure that field is <= 2 bytes and they are digits. Note this
* also verifies that field is present. */
if ((j = mystrlen(ttoks)) > 2 || !_istdigit(*ttoks) || (*(ttoks+1) && !_istdigit(*(ttoks+1)))) break;
*pp++ = (TCHAR)_tcstol(ttoks, NULL, 10) ; /* Field OK, store int */ ttoks += j+1 ; /* Adv to separator tok */
DEBUG((CLGRP, TILVL, "VTIMES: separator = `%ws'", ttoks)) ;
if (!*ttoks) /* No separator field? */ break ; /* If so, exit loop */
/* handle AM or PM
*/ if (mystrchr(tsuffixes, *ttoks)) { goto HandleAMPM; } /* M000 - Fixed ability to use '.' as separator for time strings
*/ if ( i < 2 ) { if ( ! (p1 = mystrchr(tseps, *ttoks) ) ) return(FALSE) ;
} else { if (*ttoks != *p2) /* Is decimal seperator */ return(FALSE) ; /* valid. */ } } ;
//
// see if there's an a or p specified. if there's a P, adjust
// for PM time
//
if (*ttoks) { BOOL pm; if (!mystrchr(tsuffixes, *ttoks)) { return FALSE; } HandleAMPM: pm = (*ttoks == TEXT('p') || *ttoks == TEXT('P'));
// if we're here, we've encountered an 'a' or 'p'. make
// sure that it's the last character or that the only
// character left is an 'm'. remember that since
// 'a' and 'p' are separators, they get separated from the 'm'.
ttoks += 2; // go past 'a' or 'p' plus null.
if (*ttoks != NULLC && *ttoks != TEXT('m') && *ttoks != TEXT('M')) { return FALSE; } if (pm) { if (OsDateAndTime->wHour != 12) { OsDateAndTime->wHour += 12; } } else { if (OsDateAndTime->wHour == 12) { OsDateAndTime->wHour -= 12; } } }
/* M002 - If we got at least one field, fill the rest with 00's
*/ while (++i < 4) *pp++ = 0 ;
return(TRUE) ; }
VOID ConverttmToFILETIME ( struct tm *Time, LPFILETIME FileTime )
/*++
Routine Description:
This routine converts an NtTime value to its corresponding Fat time value.
Arguments:
Time - Supplies the C Runtime Time value to convert from
FileTime - Receives the equivalent File date and time
Return Value:
BOOLEAN - TRUE if the Nt time value is within the range of Fat's time range, and FALSE otherwise
--*/
{ SYSTEMTIME SystemTime;
if (!Time) { GetSystemTime(&SystemTime); } else {
//
// Pack the input time/date into a system time record
//
SystemTime.wYear = (WORD)Time->tm_year; SystemTime.wMonth = (WORD)(Time->tm_mon+1); // C is [0..11]
// NT is [1..12]
SystemTime.wDay = (WORD)Time->tm_mday; SystemTime.wHour = (WORD)Time->tm_hour; SystemTime.wMinute = (WORD)Time->tm_min; SystemTime.wSecond = (WORD)Time->tm_sec; SystemTime.wDayOfWeek = (WORD)Time->tm_wday; SystemTime.wMilliseconds = 0; } SystemTimeToFileTime( &SystemTime, FileTime );
}
VOID ConvertFILETIMETotm ( LPFILETIME FileTime, struct tm *Time )
/*++
Routine Description:
This routine converts a file time to its corresponding C Runtime time value.
Arguments:
FileTime - Supplies the File date and time to convert from
Time - Receives the equivalent C Runtime Time value
Return Value:
--*/
{ SYSTEMTIME SystemTime;
// why skip printing the date if it's invalid?
//if (FileTime->dwLowDateTime == 0 && FileTime->dwHighDateTime == 0) {
// return( FALSE );
// }
FileTimeToSystemTime( FileTime, &SystemTime );
//
// Pack the input time/date into a time field record
//
Time->tm_year = SystemTime.wYear; Time->tm_mon = SystemTime.wMonth-1; // NT is [1..12]
// C is [0..11]
Time->tm_mday = SystemTime.wDay; Time->tm_hour = SystemTime.wHour; Time->tm_min = SystemTime.wMinute; Time->tm_sec = SystemTime.wSecond; Time->tm_wday = SystemTime.wDayOfWeek; Time->tm_yday = 0; Time->tm_isdst = 0; }
|