/*++ Copyright (c) Microsoft Corporation Module Name: Choice.c Abstract: Choice is a Win32 console application designed to duplicate the functionality of the choice.com utility found in MSDOS version 6.0. Rather than simply using the C run-time routines, choice utilizes Win32 console routines and the signalling abilities of the file objects. Author: Wipro Technologies 2-July.-2001 (Created it) Revision History: --*/ #include "pch.h" #include "choice.h" DWORD __cdecl wmain( IN DWORD argc, IN LPCWSTR argv[] ) /*++ Routine description : Main function which calls all the other main functions depending on the option specified by the user. Arguments: [in] argc : argument count specified at the command prompt. [in] argv : arguments specified at the command prompt. Return Value : DWORD 0 : If the utility successfully performs the operation. 1 : If the utility is unsuccessful in performing the specified operation. --*/ { TCMDPARSER2 cmdOptions[ MAX_COMMANDLINE_OPTION ]; //command line options WCHAR szChoice[MAX_STRING_LENGTH] ; // to store options for /c WCHAR szMessage[256] ; // Message to be shown for WCHAR szPromptStr[512] ;//Message finaly prompted WCHAR szDefaultChoice[256] ; //default choice string WCHAR wszBuffer[2*MAX_RES_STRING] ; BOOL bShowChoice = FALSE;//choice to be shown or not BOOL bCaseSensitive = FALSE; // choice will be case sensitive or not BOOL bUsage = FALSE; // is help required LONG lTimeoutFactor = 0; //Time out factor BOOL bReturn = FALSE; // Stores the return value DWORD lReturnValue = EXIT__FAILURE; // Return value of application BOOL bErrorOnCarriageReturn = FALSE; HRESULT hr; SecureZeroMemory(szChoice, MAX_STRING_LENGTH * sizeof(WCHAR)); SecureZeroMemory(szMessage, 256 * sizeof(WCHAR)); SecureZeroMemory(szPromptStr, 512 * sizeof(WCHAR)); SecureZeroMemory(szDefaultChoice, 256 * sizeof(WCHAR)); SecureZeroMemory(wszBuffer, (2*MAX_RES_STRING) * sizeof(WCHAR)); bReturn = ProcessCMDLine( argc, argv, &cmdOptions[ 0 ], // Command line struct &bUsage, // Is help szChoice, // Choice &bCaseSensitive, // Casesensitive &bShowChoice, // Show Choice &lTimeoutFactor, // Timeout factor szDefaultChoice, // Timeout choice szMessage // Message ); if( FALSE == bReturn) { // Show Error message on screen depending on Reason Set ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL ); // Release all global memory allocation. This allocation are done // by common functionality. ReleaseGlobals(); return EXIT__FAILURE; } if ( TRUE == bUsage) { ShowUsage(); // Display Usage // Release all global memory allocation. This allocation are done // by common functionality. ReleaseGlobals(); return EXIT_SUCCESS; } // Check if timeout factor is 0 bReturn = BuildPrompt( cmdOptions, bShowChoice, szChoice, szMessage, szPromptStr); // Show message on Prompt. if (FALSE == bReturn) { // Release all global memory allocation. This allocation are done // by common functionality. ReleaseGlobals(); return EXIT__FAILURE; } if((cmdOptions[ ID_TIMEOUT_FACTOR ].dwActuals > 0) && ( 0 == lTimeoutFactor )) { // Release all global memory allocation. This allocation are done // by common functionality. // Safely return from utility SecureZeroMemory(wszBuffer, 2*MAX_STRING_LENGTH); hr = StringCchPrintf(wszBuffer, SIZE_OF_ARRAY(wszBuffer), L"%s%s\n", _X(szPromptStr), _X2(szDefaultChoice)); if(FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); return EXIT__FAILURE; } ShowMessage(stdout,wszBuffer); ReleaseGlobals(); return UniStrChr( szChoice, szDefaultChoice[0] ); } // Now wait for input OR expire of timeout lReturnValue = GetChoice( szPromptStr, lTimeoutFactor, bCaseSensitive, szChoice, szDefaultChoice, &bErrorOnCarriageReturn); if(EXIT__FAILURE == lReturnValue) { if(bErrorOnCarriageReturn == FALSE) { // Show Error message on screen depending on Reason Set StringCopyW( szPromptStr, GetReason(), 2*MAX_STRING_LENGTH ); if(StringLengthW(szPromptStr, 0) == 0) { ShowMessage(stderr, szPromptStr); ShowMessage(stderr, GetResString(IDS_FILE_EMPTY)); } else { hr = StringCchPrintf(szPromptStr, SIZE_OF_ARRAY(szPromptStr), L"\n%s %s", TAG_ERROR, GetReason()); if(FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); return EXIT__FAILURE; } ShowMessage(stderr, szPromptStr); } } else { ShowMessage(stderr, GetReason()); } // Release all global memory allocation. This allocation are done // by common functionality. ReleaseGlobals(); return EXIT__FAILURE; } // Release all global memory allocation. This allocation are done // by common functionality. ReleaseGlobals(); return lReturnValue; } // End of function wmain BOOL ProcessCMDLine( IN DWORD argc, IN LPCWSTR argv[], OUT TCMDPARSER2 *pcmdParcerHead, OUT PBOOL pbUsage, OUT LPWSTR pszChoice, OUT PBOOL pbCaseSensitive, OUT PBOOL pbShowChoice, OUT PLONG plTimeOutFactor, OUT LPWSTR pszDefaultChoice, OUT LPWSTR pszMessage) /*++ Routine Description: This function will prepare column structure for DoParseParam Function. Arguments: IN argc : Command line argument count IN argv : Command line argument OUT pcmdParcerHead : Pointer to Command line parcer structure OUT pbUsage : Stores the status if help required OUT pszChoice : Stores choices given OUT pbCaseSensitive : Stores the status if choices are case-sensitive OUT pbShowChoice : Stores the status if choices to be shown OUT plTimeOutFactor : Stores time out factor OUT pszDefaultChoice : Stores default choices OUT pszMessage : Stores message string Return Value: TRUE : Return successfully FALSE: Return due to error --*/ { BOOL bReturn = FALSE;// strore return value WCHAR szErrorMsg[64] ; WCHAR szCharac[2] ; WCHAR szTemp[128] ; WCHAR szTimeFactor[MAX_STRING_LENGTH] ; TCMDPARSER2* pcmdParcer = NULL; TCMDPARSER2* pcmdTmp = NULL; DWORD dw =0; DWORD dwVal =0; DWORD dwcount = 0; DWORD dwLen = 0; WCHAR* pszStopTimeFactor = NULL; HRESULT hr; const WCHAR* wszOptionHelp = L"?"; //OPTION_HELP const WCHAR* wszOptionChoice = L"C" ; //OPTION_CHOICE const WCHAR* wszOptionPromptChoice = L"N" ; //OPTION_PROMPT_CHOICE const WCHAR* wszOptionCaseSensitive = L"CS" ; //OPTION_CASE_SENSITIVE const WCHAR* wszOptionDefaultChoice = L"D" ; //wszOptionDefaultChoice const WCHAR* wszOptionTimeoutFactor = L"T" ; //OPTION_TIMEOUT_FACTOR const WCHAR* wszOptionDefaultString = L"M" ; //OPTION_DEFAULT_STRING SecureZeroMemory(szErrorMsg, 64 * sizeof(WCHAR)); SecureZeroMemory(szCharac, 2 * sizeof(WCHAR)); SecureZeroMemory(szTemp, 128 * sizeof(WCHAR)); SecureZeroMemory(szTimeFactor, MAX_STRING_LENGTH * sizeof(WCHAR)); // Check validity of Pointer if( (NULL == pcmdParcerHead) || (NULL == pbUsage) || (NULL == pszChoice) || (NULL == pbCaseSensitive) || (NULL == pbShowChoice) || (NULL == plTimeOutFactor) || (NULL == pszDefaultChoice) || (NULL == pszMessage)) { SetLastError( RPC_X_NULL_REF_POINTER ); SaveLastError(); return bReturn; } // Filling m_cmdOptions structure // -? pcmdParcer = pcmdParcerHead + ID_HELP; StringCopyA( pcmdParcer->szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_BOOLEAN; pcmdParcer-> pwszOptions = wszOptionHelp; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = CP2_USAGE; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = pbUsage; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer-> pFunction = NULL; pcmdParcer-> pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; // -c choices pcmdParcer = pcmdParcerHead + ID_CHOICE; StringCopyA( pcmdParcer-> szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_TEXT; pcmdParcer-> pwszOptions = wszOptionChoice; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = 0; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = pszChoice; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer->pFunction = NULL; pcmdParcer->pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; //-n Show choice pcmdParcer = pcmdParcerHead + ID_PROMPT_CHOICE; StringCopyA( pcmdParcer-> szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_BOOLEAN; pcmdParcer-> pwszOptions = wszOptionPromptChoice; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = 0; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = pbShowChoice; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer->pFunction = NULL; pcmdParcer->pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; // -cs case sensitive pcmdParcer = pcmdParcerHead + ID_CASE_SENSITIVE; StringCopyA( pcmdParcer-> szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_BOOLEAN; pcmdParcer-> pwszOptions = wszOptionCaseSensitive; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = 0; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = pbCaseSensitive; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer->pFunction = NULL; pcmdParcer->pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; // -d default choice pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; StringCopyA( pcmdParcer-> szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_TEXT; pcmdParcer-> pwszOptions = wszOptionDefaultChoice; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = CP2_VALUE_TRIMINPUT; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = pszDefaultChoice; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer->pFunction = NULL; pcmdParcer->pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; // -t time-out factor pcmdParcer = pcmdParcerHead + ID_TIMEOUT_FACTOR; StringCopyA( pcmdParcer-> szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_TEXT; pcmdParcer-> pwszOptions = wszOptionTimeoutFactor; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = CP2_VALUE_TRIMINPUT; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = szTimeFactor; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer->pFunction = NULL; pcmdParcer->pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; // -m message text pcmdParcer = pcmdParcerHead + ID_MESSAGE_STRING; StringCopyA( pcmdParcer-> szSignature, "PARSER2\0", 8 ); pcmdParcer-> dwType = CP_TYPE_TEXT; pcmdParcer-> pwszOptions = wszOptionDefaultString; pcmdParcer-> pwszFriendlyName = NULL; pcmdParcer-> pwszValues = NULL; pcmdParcer->dwFlags = CP2_VALUE_TRIMINPUT; pcmdParcer->dwCount = 1; pcmdParcer->dwActuals = 0; pcmdParcer->pValue = pszMessage; pcmdParcer->dwLength = MAX_STRING_LENGTH; pcmdParcer->pFunction = NULL; pcmdParcer->pFunctionData = NULL; pcmdParcer-> dwReserved = 0; pcmdParcer-> pReserved1 = NULL; pcmdParcer-> pReserved2 = NULL; pcmdParcer-> pReserved3 = NULL; // re-assign it to head position pcmdParcer = pcmdParcerHead; bReturn = DoParseParam2( argc, argv, -1, MAX_COMMANDLINE_OPTION, pcmdParcer, 0); if( FALSE == bReturn) // Invalid commandline { // Reason is already set by DoParseParam return FALSE; } if( TRUE == *pbUsage ) { if(2 == argc ) { return( TRUE ); } else { StringCopyW( szErrorMsg, GetResString( IDS_INCORRECT_SYNTAX ), SIZE_OF_ARRAY(szErrorMsg) ); SetReason( szErrorMsg ); return FALSE; } } // /d can be specified only if /t is specified. pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; pcmdTmp = pcmdParcerHead + ID_TIMEOUT_FACTOR; if((pcmdParcer-> dwActuals > 0 ) &&( 0 == pcmdTmp-> dwActuals )) { // Error String will be .. //Invalid syntax. /D can be specified only when /T is //specified. //Type CHOICE /? for usage. StringCopyW( szTemp, GetResString( IDS_D_WITHOUT_T ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } // /f should come if /d is given pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; pcmdTmp = pcmdParcerHead + ID_TIMEOUT_FACTOR; if(( 0 == pcmdParcer-> dwActuals ) &&( pcmdTmp-> dwActuals > 0 ) ) { // Error String will be .. // Invalid syntax. /D missing. // Type CHOICE /? for usage. StringCopyW( szTemp, GetResString( IDS_D_MISSING ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } // Time factor value should be in range TIMEOUT_MIN - TIMEOUT_MAX pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; if(pcmdParcer-> dwActuals > 0 && szTimeFactor != NULL && StringLengthW(szTimeFactor, 0) == 0) { StringCopyW( szTemp, GetResString( IDS_TFACTOR_NULL_STIRNG ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } *plTimeOutFactor = wcstol(szTimeFactor,&pszStopTimeFactor,10); if((errno == ERANGE) || (NULL != pszStopTimeFactor && StringLengthW(pszStopTimeFactor, 0) != 0)) { StringCopyW( szTemp, GetResString( IDS_INVALID_TIMEOUT_FACTOR ), SIZE_OF_ARRAY(szTemp) ); SetReason(szTemp); return FALSE; } if( pcmdParcer-> dwActuals > 0 && (( *plTimeOutFactor < TIMEOUT_MIN)|| ( *plTimeOutFactor > TIMEOUT_MAX ))) { // Error String will be .. // Invalid syntax. Valid range for /t is (0 - 99). // Type CHOICE /? for usage. hr = StringCchPrintf(szTemp, SIZE_OF_ARRAY(szTemp), GetResString(IDS_T_INVALID_VALUE),TIMEOUT_MIN,TIMEOUT_MAX); if(FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); SaveLastError(); return FALSE; } // Set the reason in memory SetReason(szTemp); return FALSE; } // if /c is specified then it cannot be empty pcmdParcer = pcmdParcerHead + ID_CHOICE; if( pcmdParcer-> dwActuals > 0 && (StringLengthW( pszChoice, 0 ) == 0)) { // Error String will be .. // Invalid syntax. Choice cannot be empty. StringCopyW( szTemp, GetResString( IDS_C_EMPTY ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } if( pcmdParcer-> dwActuals > 0) { dwVal = StringLengthW( pszChoice, 0 ); for(dwcount;dwcount < dwVal;dwcount++) { szCharac[0] = pszChoice[dwcount]; szCharac[1] = '\0'; if((dwLen = StringLengthInBytes(szCharac)) > 1) { StringCopyW( szTemp, GetResString( IDS_TWO_BYTES_NOTALLOWED ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } } for(dw;dw < dwVal;dw++) { if( ((DWORD)pszChoice[dw]) <= 47 || (((DWORD)pszChoice[dw]) > 122 &&((DWORD)pszChoice[dw]) < 127)|| (((DWORD)pszChoice[dw]) > 57 &&((DWORD)pszChoice[dw]) < 65 ) || (((DWORD)pszChoice[dw]) > 90 &&((DWORD)pszChoice[dw]) < 97 ) || ((DWORD)pszChoice[dw]) == 160) { StringCopyW( szTemp, GetResString( IDS_CHOICE_INVALID ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } } } // if /c is not specified then make default choice as "YN" pcmdParcer = pcmdParcerHead + ID_CHOICE; if(0 == pcmdParcer-> dwActuals) { StringCopyW( pszChoice, DEFAULT_CHOICE, MAX_STRING_LENGTH); } pcmdParcer = pcmdParcerHead + ID_CHOICE; if((pcmdParcer-> dwActuals > 0 ) && ( FALSE == *pbCaseSensitive )) { dw = 0; for(dw;dw < dwVal;dw++) { if( ((DWORD)pszChoice[dw]) <= 127 ) { if(0 == CharUpperBuff( pszChoice+dw, 1)) { StringCopyW( szTemp, GetResString( IDS_ERR_CHARUPPER ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } } } } //now check for duplicates in choice if(FALSE == CheckforDuplicates( pszChoice ) ) { StringCopyW( szTemp, GetResString( IDS_DUPLICATE_CHOICE ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; if( pcmdParcer-> dwActuals > 0 ) { if(0 == StringLengthW( pszDefaultChoice, 0 )) { StringCopyW( szTemp, GetResString( IDS_DEFAULT_EMPTY ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } if( FALSE == *pbCaseSensitive ) { // Make the string to upper case if( ((DWORD)pszDefaultChoice[0]) <= 127 ) { if( 0 == CharUpperBuff( pszDefaultChoice, StringLengthW( pszDefaultChoice, 0 ))) { StringCopyW( szTemp, GetResString( IDS_ERR_CHARUPPER ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } } } } // length of /d cannot be more than one character pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; if(( pcmdParcer-> dwActuals > 0 ) &&(StringLengthW( pszDefaultChoice, 0 ) > 1 )) { // Error String will be .. // Invalid syntax. /D7/2/2001 accepts only single character. // Type CHOICE /? for usage. StringCopyW( szTemp, GetResString( IDS_D_BIG ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason(szTemp); return FALSE; } // check if timeout choice is given in choice list pcmdParcer = pcmdParcerHead + ID_DEFAULT_CHOICE; if (pcmdParcer-> dwActuals > 0 ) { if(0 == UniStrChr( pszChoice, pszDefaultChoice[ 0 ] )) { // Error String will be .. // Invalid syntax. Time Factor choice not in specified choices. // Type CHOICE /? for usage. StringCopyW( szTemp, GetResString( IDS_D_NOT_MATCHED_TO_C ), SIZE_OF_ARRAY(szTemp) ); // Set the reason in memory SetReason( szTemp ); return FALSE; } } pcmdParcer = pcmdParcerHead + ID_MESSAGE_STRING; if(pcmdParcer-> dwActuals > 0) { if( StringLengthW(pszMessage, 0) > MAX_STRING_LENGTH ) { StringCopyW( szTemp, GetResString( IDS_MESSAGE_OVERFLOW ), SIZE_OF_ARRAY(szTemp) ); SetReason( szTemp ); return FALSE; } } return TRUE; } // End of function ProcessCMDLine void ShowUsage( void ) /*-- Routine Description This function shows help message for CHOICE Arguments: NONE Return Value None --*/ { DWORD dwIndx = 0; // Index Variable for(dwIndx = IDS_HELP1; dwIndx <= IDS_HELP_END; dwIndx++ ) { ShowMessage( stdout, GetResString( dwIndx ) ); } return; } // End of function ShowUsage BOOL BuildPrompt( IN TCMDPARSER2 *pcmdParcer, IN BOOL bShowChoice, IN LPWSTR pszChoice, IN LPWSTR pszMessage, OUT LPWSTR pszPromptStr) /*++ Routine Description: This function will Build command message prompt Arguments: [IN] pcmdParcer : Pointer to Command line parcer structure [IN] bShowChoice : Stores the status, if choice to be shown [IN] pszChoice : Choice string [IN] pszMessage : Message String [OUT] pszPromptStr : Final String to be shown on screen Return Value: TRUE if success FALSE if failure --*/ { WCHAR szChar[32] ; LPWSTR pszTemp = NULL; // Temp. string pointer SecureZeroMemory(szChar, 32 * sizeof(WCHAR)); // Check for validity of pointer variables if (( NULL == pcmdParcer) || ( NULL == pszPromptStr)) { return FALSE; } szChar[1] = NULL_U_CHAR; // make second character as end of line // check if /M is given if given copy it to prompt string pcmdParcer += ID_MESSAGE_STRING; if( pcmdParcer-> dwActuals > 0 ) { StringCopyW( pszPromptStr, pszMessage, 2*MAX_STRING_LENGTH ); StringConcat(pszPromptStr, SPACE, 2*MAX_STRING_LENGTH); } if( TRUE == bShowChoice ) { return TRUE; } // now append '[' to it StringConcat(pszPromptStr, OPEN_BRACKET, 2*MAX_STRING_LENGTH); // now append prompt characters to it pszTemp = pszChoice; do { szChar[ 0 ] = pszTemp[ 0 ]; // always assing first character of //m_pszChoice as first character is // changing in this loop StringConcat(pszPromptStr, szChar, 2*MAX_STRING_LENGTH); // now append a COMMA to this // comma will be appended only if length of m_pszChoise // is grester than 1 if( StringLengthW( pszTemp, 0 ) > 1 ) { StringConcat(pszPromptStr, COMMA, 2*MAX_STRING_LENGTH); } pszTemp = CharNext( pszTemp ); }while( StringLengthW( pszTemp, 0 ) != 0); // now close the bracket StringConcat(pszPromptStr, CLOSED_BRACKET, 2*MAX_STRING_LENGTH); return TRUE; } // End of function BuildPrompt DWORD UniStrChr( IN LPWSTR pszBuf, IN WCHAR szChar ) /*++ Routine Description: This function finds the character in given string Arguments: [IN] pszBuf : Target String in which character is be find [IN] szChar : Character to be found Return Value: returned string pointer after the character found. --*/ { LONG lPos = 0; // find the character in string while( NULL_U_CHAR != *pszBuf ) // Loop till string teminated character found // 0 is always teminated character { lPos++; if ( *(pszBuf++) == szChar ) { return(lPos) ; } } return(0); } // End of function UniStrChr DWORD GetChoice( IN LPCWSTR pszPromptStr, IN LONG lTimeOutFactor, IN BOOL bCaseSensitive, IN LPWSTR pszChoice, IN LPCWSTR pszDefaultChoice, OUT PBOOL pbErrorOnCarriageReturn) /*++ Routine Description: This function get choice from console OR wait for timeout Arguments: IN pszPromptStr : String to be shown as prompt IN lTimeOutFactor : Time out factor IN bCaseSensitive : Stores the state, if choice is case-sensitive IN pszChoice : Choice string IN pszDefaultChoice : Default choice character OUT pbErrorOnCarriageReturn : True, if there is an error on carriage return Return Value: DWORD --*/ { //This function reads the keyboard and handles the I/O HANDLE hInput = 0;// Stores the input handle device HANDLE hOutput = 0;// Stores the output handle device DWORD dwSignal = 0;// Stores return value for WaitForSingleObject DWORD dwBytesRead = 0;// Stores number of byes read from console DWORD dwBytesRead2 = 0;// Stores number of byes read from console DWORD dwMode = 0;// Stores mode for input device DWORD lTimeBefore = 0; DWORD lTimeAfter = 0; DWORD lPosition = 0; DWORD dwRead = 0L; BOOL bSuccess = FALSE; // Stores return value BOOL bStatus = TRUE; BOOL bIndirectionInput = FALSE; BOOL bGetChoice = FALSE; WCHAR szTempChar = NULL_U_CHAR; // Temperory variable WCHAR szTempBuf[ MAX_RES_STRING ] = L"\0"; // Temp. string variable CHAR chTmp = '\0'; WCHAR wchTmp = NULL_U_CHAR; CHAR szAnsiBuf[ 10 ] = "\0"; // buffer of two characters is enough -- but still INPUT_RECORD InputBuffer[ MAX_NUM_RECS ] = {0}; SecureZeroMemory(szTempBuf, MAX_RES_STRING * sizeof(WCHAR)); // Get handle for Input device hInput = GetStdHandle( STD_INPUT_HANDLE ); if( INVALID_HANDLE_VALUE == hInput) { SaveLastError(); return EXIT__FAILURE; } if( ( hInput != (HANDLE)0x0000000F )&&( hInput != (HANDLE)0x00000003 ) && ( hInput != INVALID_HANDLE_VALUE ) ) { bIndirectionInput = TRUE; } // Get handle for Output device hOutput = GetStdHandle( STD_OUTPUT_HANDLE ); if( INVALID_HANDLE_VALUE == hOutput ) { SaveLastError(); return EXIT__FAILURE; } // Get console mode, so we can change the input mode bSuccess = GetConsoleMode( hInput, &dwMode ); if ( TRUE == bSuccess) { // turn off line input and echo dwMode &= ~( ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT ); bSuccess = SetConsoleMode( hInput, dwMode ); if (FALSE == bSuccess) { SaveLastError(); return EXIT__FAILURE; } if ( FlushConsoleInputBuffer( hInput ) == FALSE ) { SaveLastError(); return EXIT__FAILURE; } } // Show prompt message on screen..... ShowMessage( stdout, _X(pszPromptStr) ); bStatus = SetConsoleCtrlHandler( &HandlerRoutine, TRUE ); if ( FALSE == bStatus ) { SaveLastError(); return EXIT__FAILURE; } // init the ANSI buffer with 0's in it ZeroMemory( szAnsiBuf, SIZE_OF_ARRAY( szAnsiBuf ) * sizeof( CHAR ) ); while( FALSE == bGetChoice) { //The WaitForSingleObject function returns when one of the // following occurs: // 1. The specified object is in the signaled state i.e. Key press // from keyboard // 2.The time-out interval elapses. lTimeBefore = GetTickCount(); dwSignal = WaitForSingleObject( hInput, ( lTimeOutFactor ) ? ( lTimeOutFactor * MILI_SEC_TO_SEC_FACTOR) : INFINITE ); lTimeAfter = GetTickCount(); switch(dwSignal) { case WAIT_OBJECT_0: // The input buffer has something { // get first character szTempBuf[ 1 ] = NULL_U_CHAR; // Get character from console if ( bIndirectionInput == FALSE ) { if( PeekConsoleInput(hInput, InputBuffer, MAX_NUM_RECS, &dwRead ) == FALSE ) { SaveLastError(); ReleaseGlobals(); return( EXIT__FAILURE ); } //Ignore all the virtual keys like tab,break,scroll lock etc... if(((InputBuffer[0].Event.KeyEvent.wVirtualKeyCode >= VK_LEFT) && (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode <= VK_DOWN)) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_HOME) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_END) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_INSERT) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_DELETE) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_PRIOR) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_NEXT) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_TAB) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_SPACE)) { if( lTimeOutFactor ) { lTimeOutFactor -= ( DWORD )(( lTimeAfter - lTimeBefore) / MILI_SEC_TO_SEC_FACTOR); } if(0 == Beep( FREQUENCY_IN_HERTZ, DURETION_IN_MILI_SEC )) { if(TRUE == IsConsoleFile(stdout)) { ShowMessage(stdout, L"\a"); } } if ( FlushConsoleInputBuffer( hInput ) == FALSE ) { SaveLastError(); return EXIT__FAILURE; } break; } else if((InputBuffer[0].Event.KeyEvent.wVirtualKeyCode >= VK_F1) && (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode <= VK_F16) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) || ((InputBuffer[0].Event.KeyEvent.wVirtualKeyCode >= VK_LBUTTON) && (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode <= VK_XBUTTON2)) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_PAUSE) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_NUMLOCK) ||(InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_SCROLL) || ((InputBuffer[0].Event.KeyEvent.wVirtualKeyCode >= VK_SELECT) && (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode <= VK_SNAPSHOT)) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_HELP) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_LWIN) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_RWIN) || (InputBuffer[0].Event.KeyEvent.wVirtualKeyCode == VK_APPS) ) { if( lTimeOutFactor ) { lTimeOutFactor -= ( DWORD )(( lTimeAfter - lTimeBefore) / MILI_SEC_TO_SEC_FACTOR); } if ( FlushConsoleInputBuffer( hInput ) == FALSE ) { SaveLastError(); return EXIT__FAILURE; } break; } //Ignore changing the focus,doing alt+tab etc.. if(FOCUS_EVENT == InputBuffer[0].EventType || (VK_MENU == InputBuffer[0].Event.KeyEvent.wVirtualKeyCode ) ||(VK_CONTROL == InputBuffer[0].Event.KeyEvent.wVirtualKeyCode) ||(VK_SHIFT == InputBuffer[0].Event.KeyEvent.wVirtualKeyCode) ||WINDOW_BUFFER_SIZE_EVENT == InputBuffer[0].EventType ||MOUSE_EVENT == InputBuffer[0].EventType ||MENU_EVENT == InputBuffer[0].EventType ||(FALSE == InputBuffer[0].Event.KeyEvent.bKeyDown)) { if( lTimeOutFactor ) { lTimeOutFactor -= ( DWORD )(( lTimeAfter - lTimeBefore) / MILI_SEC_TO_SEC_FACTOR); } if ( FlushConsoleInputBuffer( hInput ) == FALSE ) { SaveLastError(); return EXIT__FAILURE; } break; } StringCopyW( szTempBuf, NULL_U_STRING, MAX_RES_STRING ); bSuccess = ReadConsole(hInput, szTempBuf, MAX_RES_STRING, &dwBytesRead, NULL); if ( FALSE == bSuccess) { SaveLastError(); return EXIT__FAILURE; } } else { //read the contents of file if ( ReadFile(hInput, &chTmp, 1, &dwBytesRead, NULL) == FALSE ) { if(ERROR_BROKEN_PIPE == GetLastError()) { // End of the pipe is reached, so inform the caller *pbErrorOnCarriageReturn = TRUE; StringCopyW( szTempBuf, GetResString(IDS_FILE_EMPTY), MAX_RES_STRING ); SetReason( szTempBuf ); } else { SaveLastError(); } return EXIT__FAILURE; } else { szAnsiBuf[ 0 ] = chTmp; dwBytesRead2 = SIZE_OF_ARRAY( szTempBuf ); GetAsUnicodeString2( szAnsiBuf, szTempBuf, &dwBytesRead2 ); wchTmp = szTempBuf[ 0 ]; } if ( (dwBytesRead == 0)) //|| wchTmp == CARRIAGE_RETURN)) { if((StringLengthW((LPWSTR)pszDefaultChoice, 0)) != 0) { WaitForSingleObject( hInput,( lTimeOutFactor * MILI_SEC_TO_SEC_FACTOR)); ShowMessage( stdout, _X(pszDefaultChoice) ); ShowMessage( stdout, _X(END_OF_LINE) ); return UniStrChr( pszChoice, pszDefaultChoice[0] ); } else { *pbErrorOnCarriageReturn = TRUE; StringCopyW( szTempBuf, GetResString(IDS_FILE_EMPTY), MAX_RES_STRING ); SetReason( szTempBuf ); return EXIT__FAILURE; } } szTempBuf[0] = wchTmp; } //exit if non ascii character is given if( ((DWORD)szTempBuf[0]) <= 47 || (((DWORD)szTempBuf[0])> 122 &&((DWORD)szTempBuf[0])< 127)|| (((DWORD)szTempBuf[0])> 57 &&((DWORD)szTempBuf[0])< 65 ) || (((DWORD)szTempBuf[0])> 90 &&((DWORD)szTempBuf[0])< 97 ) || ((DWORD)szTempBuf[0])== 255) { if(0 == Beep( FREQUENCY_IN_HERTZ, DURETION_IN_MILI_SEC )) { if(TRUE == IsConsoleFile(stdout)) { ShowMessage( stdout, L"\a" ); } } if ( FALSE == bIndirectionInput && FlushConsoleInputBuffer( hInput ) == FALSE ) { SaveLastError(); return EXIT__FAILURE; } if( lTimeOutFactor ) { lTimeOutFactor -= ( DWORD )( lTimeAfter - lTimeBefore) / MILI_SEC_TO_SEC_FACTOR; } break; } if ( FALSE == bCaseSensitive ) { if( ((DWORD)szTempBuf[0]) <= 127 ) { if(0 == CharUpperBuff( szTempBuf, 1 )) { StringCopyW( szTempBuf, GetResString(IDS_ERR_CHARUPPER), MAX_RES_STRING ); // Set the reason in memory SetReason(szTempBuf); return EXIT__FAILURE; } } } szTempChar = szTempBuf[ 0 ]; // Get first character lPosition = UniStrChr( pszChoice, szTempChar ); szTempBuf[ 1 ] = NULL_U_CHAR; // Make second character as NULL if (0 != lPosition) { StringCchPrintfW( szTempBuf,SIZE_OF_ARRAY(szTempBuf), L"%c\n", szTempChar ); // show the input character on output console ShowMessage( stdout, _X(szTempBuf) ); return lPosition; } else // Character enterted not matches with Specified choice { if(0 == Beep( FREQUENCY_IN_HERTZ, DURETION_IN_MILI_SEC )) { if(TRUE == IsConsoleFile(stdout)) { ShowMessage( stdout, L"\a" ); } } if ( FALSE == bIndirectionInput && FlushConsoleInputBuffer( hInput ) == FALSE ) { SaveLastError(); return EXIT__FAILURE; } if( lTimeOutFactor ) { lTimeOutFactor -= ( DWORD )( lTimeAfter - lTimeBefore) / MILI_SEC_TO_SEC_FACTOR; } } } break; case WAIT_TIMEOUT: // The timeout exhausted { // Show timeout message on screen ShowMessage( stdout, _X(pszDefaultChoice) ); ShowMessage( stdout, _X(END_OF_LINE) ); return UniStrChr( pszChoice, pszDefaultChoice[0] ); } break; default: break; } } return EXIT__FAILURE; } // End of function GetChoice BOOL CheckforDuplicates( IN LPWSTR lpszChoice ) /*++ Routine Description: This function checks for the duplicate choices Arguments: IN lpszChoice : The list of choices in which the duplication of choice is to be checked Return Value: TRUE on success and FALSE on failure --*/ { WCHAR wTemp = NULL_U_CHAR; while( lpszChoice[0] ) { wTemp = lpszChoice[0]; lpszChoice++; if( NULL != wcschr( lpszChoice, wTemp ) ) return FALSE; } return TRUE; } //end of checkforDuplicate function BOOL WINAPI HandlerRoutine( DWORD dwCtrlType ) /*++ Routine Description: This function handles the control key CTRL+C and CTRL+BREAK. Arguments: IN dwCtrlType : Error control type Return Value: TRUE on success and FALSE on failure --*/ { // check for CTRL+C key if ( ( dwCtrlType == CTRL_C_EVENT ) ||( dwCtrlType == CTRL_BREAK_EVENT ) ) { exit ( FALSE); } // for remaining keys return false return TRUE; }