|
|
/*++
Copyright (c) Microsoft Corporation
Module Name:
Timeout.c
Abstract:
This file implements the parsing of the command line for the arguments and also the wait functionality.
Author:
EricB
Revision History:
26-Aug-1991 Created by EricB. 10-Mar-1992 Added the _getch() call to flush the hit key. 17-Apr-1992 Added countdown display. 03-Oct-1992 Ported to NT/Win32 23-May-1995 Added Sleep call 14-Jun-2001 localization added by Wipro Technologies 01-Aug-2001 Added /nobreak option by Wipro Technologies --*/
#include "pch.h"
#include "Timeout.h"
#include "Resource.h"
DWORD _cdecl wmain( IN DWORD argc, IN LPCWSTR argv[] ) /*++
Routine Description: This is main entry point to this utility. Different function calls are made from here to achieve the required functionality.
Arguments: [in] argc : Number of Command line arguments. [in] argv : Pointer to Command line arguments.
Return Value: 0 on success 1 on failure. --*/ { //local variables
CONSOLE_SCREEN_BUFFER_INFO csbi;
time_t tWait = 0L; time_t tLast = 0L; time_t tNow = 0L; time_t tEnd = 0L;
DWORD dwTimeActuals = 0; BOOL bNBActuals = 0; BOOL bUsage = FALSE; BOOL bResult = FALSE; BOOL bStatus = FALSE;
WCHAR wszProgressMsg[ MAX_STRING_LENGTH ] = NULL_U_STRING ; DWORD dwWidth = 0; WCHAR wszBackup[12] = NULL_U_STRING; WCHAR wszTimeout[ MAX_RES_STRING] = NULL_U_STRING; LPWSTR pszStopString = NULL; COORD coord = {0}; HANDLE hOutput = NULL; HANDLE hStdIn = NULL;
DWORD dwMode = 0L; DWORD dwRead = 0L;
INPUT_RECORD InputBuffer[ MAX_NUM_RECS ] = {0}; HRESULT hr = S_OK;
if ( NULL == argv ) { SetLastError (ERROR_INVALID_PARAMETER ); SaveLastError(); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); return EXIT_FAILURE; }
// Parse the command line and get the actual values
bResult = ProcessOptions( argc, argv, &bUsage, &dwTimeActuals, wszTimeout , &bNBActuals ); if( FALSE == bResult ) { // display an error message with respect to the GetReason()
ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); ReleaseGlobals(); return( EXIT_FAILURE ); }
// check for invalid syntax
// 1. check for the case c:\>timeout.exe
// 2. check for the case c:\>timeout.exe /nobreak
// 3. check for the case c:\>timeout.exe /? /?
if ( ( ( 0 == dwTimeActuals ) && ( FALSE == bNBActuals ) && ( FALSE == bUsage ) ) || ( ( 0 == dwTimeActuals ) && ( TRUE == bNBActuals ) ) || ( ( TRUE == bUsage ) && (argc > 2 )) ) { // display an error message as specified syntax is invalid
ShowMessage ( stderr, GetResString (IDS_INVALID_SYNTAX) ); ReleaseGlobals(); return( EXIT_FAILURE ); }
// Check whether the usage(/?) is specified
if( TRUE == bUsage ) { // Display the help/usage for the tool
DisplayUsage(); ReleaseGlobals(); return( EXIT_SUCCESS ); }
// get the value for timeout (/T)
tWait = ( time_t ) wcstol(wszTimeout,&pszStopString,BASE_TEN);
//check whether any non-numeric value specified for timeout value
// if so, display appropriate error message as invalid timeout value specified.
// Also, check for overflow and underflow conds
if( ((NULL != pszStopString) && ( StringLength( pszStopString, 0 ) != 0 )) || (errno == ERANGE) || ( tWait < MIN_TIME_VAL ) || ( tWait >= MAX_TIME_VAL ) ) { ShowMessage ( stderr, GetResString (IDS_ERROR_TIME_VALUE) ); ReleaseGlobals(); return( EXIT_FAILURE ); }
// Get the time elapsed in secs since midnight (00:00:00), January 1, 1970
bResult = GetTimeInSecs( &tNow ); if( FALSE == bResult ) { ReleaseGlobals(); // could not get the time so exit...
return( EXIT_FAILURE ); }
// check for /nobreak option is specified
if ( TRUE == bNBActuals ) { // set console handler to capture the keys like CTRL+BREAK or CRTL+C
bStatus = SetConsoleCtrlHandler( &HandlerRoutine, TRUE ); if ( FALSE == bStatus ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); } }
hStdIn = GetStdHandle( STD_INPUT_HANDLE ); // check for the input redirection on console and telnet session
if( ( hStdIn != (HANDLE)0x0000000F ) && ( hStdIn != (HANDLE)0x00000003 ) && ( hStdIn != INVALID_HANDLE_VALUE ) ) { ShowMessage( stderr, GetResString (IDS_INVALID_INPUT_REDIRECT) ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return EXIT_FAILURE; }
#ifdef WIN32
// Set input mode so that a single key hit can be detected.
if ( GetConsoleMode( hStdIn, &dwMode ) == FALSE ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
// Turn off the following modes:
dwMode &= ~( ENABLE_LINE_INPUT | // Don't wait for CR.
ENABLE_ECHO_INPUT | // Don't echo input.
ENABLE_WINDOW_INPUT | // Don't record window events.
ENABLE_MOUSE_INPUT // Don't record mouse events.
);
// set the input mode of a console's input buffer
if ( SetConsoleMode( hStdIn, dwMode ) == FALSE ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
// retrieve number of unread input records in the console's input buffer.
if( GetNumberOfConsoleInputEvents( hStdIn, &dwRead ) == FALSE ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
// clear the console input buffer
if ( FALSE == FlushConsoleInputBuffer (hStdIn)) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
#endif
// check whether /T value is -1. If so, need to wait indefinitely for a key press..
if( -1 == tWait ) { // check whether /nobreak is specified
if ( FALSE == bNBActuals ) { // Wait until a key hit.
ShowMessage( stdout, GetResString( IDS_WAIT_MSG ) ); } else // /nobreak option is not specified
{ // Wait until a CTRL+C key hit.
ShowMessage( stdout, GetResString( IDS_NO_BREAK_MSG ) ); }
// Ensure infinite do loop.
tEnd = tNow + 1; } else { // Wait with a timeout period.
// Compute end time.
tEnd = tNow + tWait;
// Figure the time display dwWidth.
// Need to decrement the time factor (/T) specified at a specified
// location. To get the position where it needs to be decremented,
// get the width of the /T value
if (tWait < 10) { // if the /T value is less than 10 then set the width as 1
dwWidth = 1; } else { if (tWait < 100) { // if the /T value is less than 100 then set width as 2
dwWidth = 2; } else { if (tWait < 1000) { // if the /T value is less than 1000 then set width as 3
dwWidth = 3; } else { if (tWait < 10000) { // if the /T value is less than 10000 then set width as 4
dwWidth = 4; } else { // if the /T value is less than 100000 then set width as 5
dwWidth = 5; } } } }
if ( FALSE == Replicate ( wszBackup, ONE_BACK_SPACE, dwWidth, SIZE_OF_ARRAY(wszBackup))) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_INTERNAL ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
//
// Initialize the console screen buffer structure to zero's
// and then get the console handle and screen buffer information
//
SecureZeroMemory( wszProgressMsg, sizeof( WCHAR ) * MAX_STRING_LENGTH );
// display the message as ..Waiting for...
//ShowMessage ( stdout, GetResString (IDS_WAIT_MSG_TIME1 ) );
//format the message as .. n seconds...for wait time
//_snwprintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), WAIT_TIME , dwWidth, tWait );
hr = StringCchPrintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), GetResString(IDS_WAIT_MSG_TIME1) , dwWidth, tWait ); if ( FAILED (hr)) { SetLastError (HRESULT_CODE (hr)); SaveLastError(); ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
// print the message.
ShowMessage ( stdout, wszProgressMsg );
//
// Initialize the console screen buffer structure to zero's
// and then get the console handle and screen buffer information
//
SecureZeroMemory( &csbi, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) ); hOutput = GetStdHandle( STD_OUTPUT_HANDLE ); if ( NULL != hOutput ) { // Get the info of screen buffer.
GetConsoleScreenBufferInfo( hOutput, &csbi ); }
// set the cursor position
coord.X = csbi.dwCursorPosition.X; coord.Y = csbi.dwCursorPosition.Y;
// check whether /nobreak is specified or not
if ( FALSE == bNBActuals ) { // display the message as ...press a key to continue ...
ShowMessage ( stdout, GetResString (IDS_WAIT_MSG_TIME2) ); } else { // display the message as ...press CTRL+C to quit...
ShowMessage ( stdout, GetResString (IDS_NB_MSG_TIME) ); }
}
do { // Break out if a key is pressed.
#ifdef WIN32
//reads data from the specified console input buffer without removing it from the buffer.
if( PeekConsoleInput( hStdIn, InputBuffer, MAX_NUM_RECS, &dwRead ) == FALSE ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
if (dwRead > 0) { //reads data from a console input buffer and removes it from the buffer
if( ReadConsoleInput(hStdIn, InputBuffer, MAX_NUM_RECS, &dwRead ) == FALSE ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE ); }
// Filter the input so that ctrl-c can be generated and passed on.
// Also, ignore alt key presses and window focus events.
if( (FOCUS_EVENT != InputBuffer[0].EventType) && (VK_CONTROL != InputBuffer[0].Event.KeyEvent.wVirtualKeyCode) && (VK_CONTROL != InputBuffer[0].Event.KeyEvent.wVirtualScanCode) && (MOUSE_MOVED != InputBuffer[0].Event.MouseEvent.dwEventFlags) && (MOUSE_WHEELED != InputBuffer[0].Event.MouseEvent.dwEventFlags) && (FALSE != InputBuffer[0].Event.KeyEvent.bKeyDown) && (VK_MENU != InputBuffer[0].Event.KeyEvent.wVirtualKeyCode) && ( FALSE == bNBActuals ) ) { // exit from the loop
break; }
} #else
//Checks the console for keyboard input.
if( ( _kbhit() ) && ( FALSE == bNBActuals ) ) { // get characters from the console without echo
_getch();
// exit from the loop
break; } #endif
// check if /T value is other than -1
if( -1 != tWait ) { // Update the time and time value display.
tLast = tNow;
// call the function GetTimeInSecs to get the current time in seconds
bResult = GetTimeInSecs( &tNow ); if( FALSE == bResult ) { // Format an error message accroding to GetLastError() return by API.
ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); // could not get the time so exit...
return( EXIT_FAILURE ); }
// check if tLast value is same as tNow.. if not, display the
// message with tEnd-tNow as a wait value
if (tLast != tNow) {
// Print the message.
SecureZeroMemory( wszProgressMsg, sizeof( WCHAR ) * MAX_STRING_LENGTH );
// fromat the message
//_snwprintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), STRING_FORMAT2 , wszBackup, dwWidth, tEnd - tNow );
hr = StringCchPrintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), STRING_FORMAT2 , wszBackup, dwWidth, tEnd - tNow ); if ( FAILED (hr)) { SetLastError (HRESULT_CODE (hr)); SaveLastError(); ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); ReleaseGlobals(); // to remove the handle
SetConsoleCtrlHandler( NULL, FALSE ); return( EXIT_FAILURE );
}
// set the cursor position
SetConsoleCursorPosition( hOutput, coord );
// display the message as ..tEnd - tNow seconds.. at the current cursor location
ShowMessage ( stdout, wszProgressMsg ); } }
#ifdef WIN32
// Sleep for sometime...
Sleep( 100 ); #endif
}while( tNow < tEnd ); //check till tNow is less than tEnd value
ShowMessage ( stdout, L"\n" ); // release global variables
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
// return 0
return( EXIT_SUCCESS ); }
BOOL GetTimeInSecs( OUT time_t *ptTime ) /*++
Routine Description This function calculates the time elapsed in secs since midnight (00:00:00), January 1, 1970
Arguments: [out] time_t ptTime : variable to hold the time in secs
Return Value TRUE on success FALSE on failure --*/ { #ifdef YANK
//local variables
SYSTEMTIME st = {0}; FILETIME ft = {0};
// check for NULL
if ( NULL == ptTime ) { SetLastError (ERROR_INVALID_PARAMETER ); SaveLastError(); ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); return FALSE; }
// get the system time
GetSystemTime( &st );
// convert system time to file time
if( SystemTimeToFileTime( &st, &ft ) == FALSE ) { // Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM ); return( FALSE ); }
// need to check for LowDateTime rollover...
*ptTime = ft.dwLowDateTime / LOW_DATE_TIME_ROLL_OVER; #else
// This function returns the time elapsed in secs since midnight (00:00:00), January 1, 1970
time( ptTime ); #endif
// return 0
return( TRUE ); }
VOID DisplayUsage( VOID ) /*++
Routine Description This function displays the usage of this utility
Arguments: NONE
Return Value NONE --*/ { // local variable
DWORD dwIndex = 0;
// Displaying main usage
for( dwIndex = IDS_HELP_START; dwIndex <= IDS_HELP_END; dwIndex++ ) { ShowMessage( stdout, GetResString( dwIndex ) ); }
return; }
BOOL ProcessOptions( IN DWORD argc, IN LPCWSTR argv[], OUT BOOL *pbUsage, OUT DWORD *pwTimeActuals, OUT LPWSTR wszTimeout, OUT BOOL *pbNBActuals ) /*++
Routine Description This function processes the command line for the main options
Arguments: [in] argc : Number of Command line arguments. [in] argv : Pointer to Command line arguments. [out] pbUsage : Flag that indicates whether the usage is to be displayed or not. [out] plTimeoutVal : contains the timeout value specified on the command line
Return Value TRUE on success FALSE on failure --*/ {
// sub-local variables
TCMDPARSER2* pcmdParser = NULL; TCMDPARSER2 cmdParserOptions[MAX_COMMANDLINE_OPTIONS]; BOOL bReturn = FALSE;
// command line options
const WCHAR szTimeoutOpt[] = L"t"; const WCHAR szNoBreakOpt[] = L"nobreak"; const WCHAR szHelpOpt[] = L"?";
// -? help/usage
pcmdParser = cmdParserOptions + OI_USAGE;
StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
pcmdParser->dwType = CP_TYPE_BOOLEAN; pcmdParser->pwszOptions = szHelpOpt; pcmdParser->pwszFriendlyName = NULL; pcmdParser->pwszValues = NULL; pcmdParser->dwFlags = CP2_USAGE; pcmdParser->dwCount = 1; pcmdParser->dwActuals = 0; pcmdParser->pValue = pbUsage; pcmdParser->dwLength = MAX_STRING_LENGTH; pcmdParser->pFunction = NULL; pcmdParser->pFunctionData = NULL; pcmdParser->dwReserved = 0; pcmdParser->pReserved1 = NULL; pcmdParser->pReserved2 = NULL; pcmdParser->pReserved3 = NULL;
// -T <timeout>
pcmdParser = cmdParserOptions + OI_TIME_OUT;
StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
pcmdParser->dwType = CP_TYPE_TEXT; pcmdParser->pwszOptions = szTimeoutOpt; pcmdParser->pwszFriendlyName = NULL; pcmdParser->pwszValues = NULL; pcmdParser->dwFlags = CP2_DEFAULT|CP2_VALUE_TRIMINPUT|CP2_VALUE_NONULL; pcmdParser->dwCount = 1; pcmdParser->dwActuals = 0; pcmdParser->pValue = wszTimeout; pcmdParser->dwLength = MAX_STRING_LENGTH; pcmdParser->pFunction = NULL; pcmdParser->pFunctionData = NULL; pcmdParser->dwReserved = 0; pcmdParser->pReserved1 = NULL; pcmdParser->pReserved2 = NULL; pcmdParser->pReserved3 = NULL;
// -NOBREAK
pcmdParser = cmdParserOptions + OI_NB_OUT;
StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
pcmdParser->dwType = CP_TYPE_BOOLEAN; pcmdParser->pwszOptions = szNoBreakOpt; pcmdParser->pwszFriendlyName = NULL; pcmdParser->pwszValues = NULL; pcmdParser->dwFlags = 0; pcmdParser->dwCount = 1; pcmdParser->dwActuals = 0; pcmdParser->pValue = pbNBActuals; pcmdParser->dwLength = MAX_STRING_LENGTH; pcmdParser->pFunction = NULL; pcmdParser->pFunctionData = NULL; pcmdParser->dwReserved = 0; pcmdParser->pReserved1 = NULL; pcmdParser->pReserved2 = NULL; pcmdParser->pReserved3 = NULL;
//
// do the command line parsing and get the appropriate values
//
bReturn = DoParseParam2( argc, argv, -1, SIZE_OF_ARRAY(cmdParserOptions), cmdParserOptions, 0); if( FALSE == bReturn) // Invalid commandline
{ // Reason is already set by DoParseParam2
return FALSE; }
pcmdParser = cmdParserOptions + OI_TIME_OUT; // get the value for /T value
*pwTimeActuals = pcmdParser->dwActuals;
//return 0
return TRUE; }
BOOL WINAPI HandlerRoutine( IN DWORD dwCtrlType // control signal type
) /*++
Routine Description: This function handles the control key CTRL+C.
Arguments: IN dwCtrlType : Error code value
Return Value: TRUE on success and FALSE on failure --*/ { // check for CTRL+C key
if ( dwCtrlType == CTRL_C_EVENT ) { ShowMessage ( stdout, L"\n" ); // release globals
ReleaseGlobals ();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
// exit 0
ExitProcess ( TRUE ); }
// for remaining keys return false
return FALSE; }
|