/* * CHOICE.C - internal command. * * * History: * * 12 Aug 1999 (Eric Kohl) * started. * * 01 Sep 1999 (Eric Kohl) * Fixed help text. * * 26 Sep 1999 (Paolo Pantaleo) * Fixed timeout. */ #include "config.h" #ifdef INCLUDE_CMD_CHOICE #include #include #include #include #include #include "cmd.h" #include "batch.h" #define GC_TIMEOUT -1 #define GC_NOKEY 0 //an event occurred but it wasn't a key pressed #define GC_KEYREAD 1 //a key has been read static INT GetCharacterTimeout (LPTCH ch, DWORD dwMilliseconds) { //-------------------------------------------- // Get a character from standard input but with a timeout. // The function will wait a limited amount // of time, then the function returns GC_TIMEOUT. // // dwMilliseconds is the timeout value, that can // be set to INFINITE, so the function works like // stdio.h's getchar() HANDLE hInput; DWORD dwRead; INPUT_RECORD lpBuffer; hInput = GetStdHandle (STD_INPUT_HANDLE); //if the timeout experied return GC_TIMEOUT if (WaitForSingleObject (hInput, dwMilliseconds) == WAIT_TIMEOUT) return GC_TIMEOUT; //otherwise get the event ReadConsoleInput (hInput, &lpBuffer, 1, &dwRead); //if the event is a key pressed if ((lpBuffer.EventType == KEY_EVENT) && (lpBuffer.Event.KeyEvent.bKeyDown == TRUE)) { //read the key #ifdef _UNICODE *ch = lpBuffer.Event.KeyEvent.uChar.UnicodeChar; #else *ch = lpBuffer.Event.KeyEvent.uChar.AsciiChar; #endif return GC_KEYREAD; } //else return no key return GC_NOKEY; } static INT IsKeyInString (LPTSTR lpString, TCHAR cKey, BOOL bCaseSensitive) { LPTCH p = lpString; INT val = 0; while (*p) { if (bCaseSensitive) { if (*p == cKey) return val; } else { if (_totlower (*p) == _totlower (cKey)) return val; } val++; p++; } return -1; } INT CommandChoice (LPTSTR cmd, LPTSTR param) { LPTSTR lpOptions = "YN"; LPTSTR lpText = NULL; BOOL bNoPrompt = FALSE; BOOL bCaseSensitive = FALSE; BOOL bTimeout = FALSE; INT nTimeout = 0; TCHAR cDefault = _T('\0'); INPUT_RECORD ir; LPTSTR p, np; LPTSTR *arg; INT argc; INT i; INT val; INT GCret; TCHAR Ch; DWORD amount,clk; if (_tcsncmp (param, _T("/?"), 2) == 0) { ConOutPuts (_T("Waits for the user to choose one of a set of choices.\n" "\n" "CHOICE [/C[:]choices][/N][/S][/T[:]c,nn][text]\n" "\n" " /C[:]choices Specifies allowable keys. Default is YN.\n" " /N Do not display choices and ? at the end of the prompt string.\n" " /S Treat choice keys as case sensitive.\n" " /T[:]c,nn Default choice to c after nn seconds.\n" " text Prompt string to display.\n" "\n" "ERRORLEVEL is set to offset of key user presses in choices.")); return 0; } /* retrieve text */ p = param; while (TRUE) { if (*p == _T('\0')) break; if (*p != _T('/')) { lpText = p; break; } np = _tcschr (p, _T(' ')); if (!np) break; p = np + 1; } /* build parameter array */ arg = split (param, &argc, FALSE); /* evaluate arguments */ if (argc > 0) { for (i = 0; i < argc; i++) { if (_tcsnicmp (arg[i], _T("/c"), 2) == 0) { if (arg[i][2] == _T(':')) lpOptions = &arg[i][3]; else lpOptions = &arg[i][2]; if (_tcslen (lpOptions) == 0) { ConErrPuts (_T("Invalid option. Expected format: /C[:]options")); freep (arg); return 1; } } else if (_tcsnicmp (arg[i], _T("/n"), 2) == 0) { bNoPrompt = TRUE; } else if (_tcsnicmp (arg[i], _T("/s"), 2) == 0) { bCaseSensitive = TRUE; } else if (_tcsnicmp (arg[i], _T("/t"), 2) == 0) { LPTSTR s; if (arg[i][2] == _T(':')) { cDefault = arg[i][3]; s = &arg[i][4]; } else { cDefault = arg[i][2]; s = &arg[i][3]; } if (*s != _T(',')) { ConErrPuts (_T("Invalid option. Expected format: /T[:]c,nn")); freep (arg); return 1; } s++; nTimeout = _ttoi(s); bTimeout = TRUE; } else if (arg[i][0] == _T('/')) { ConErrPrintf (_T("Illegal Option: %s"), arg[i]); freep (arg); return 1; } } } /* print text */ if (lpText) ConOutPrintf (_T("%s"), lpText); /* print options */ if (bNoPrompt == FALSE) { ConOutPrintf (_T("[%c"), lpOptions[0]); for (i = 1; (unsigned)i < _tcslen (lpOptions); i++) ConOutPrintf (_T(",%c"), lpOptions[i]); ConOutPrintf (_T("]?")); } ConInFlush (); if(!bTimeout) { while (TRUE) { ConInKey (&ir); val = IsKeyInString (lpOptions, #ifdef _UNICODE ir.Event.KeyEvent.uChar.UnicodeChar, #else ir.Event.KeyEvent.uChar.AsciiChar, #endif /* _UNICODE */ bCaseSensitive); if (val >= 0) { ConOutPrintf (_T("%c\n"), lpOptions[val]); nErrorLevel = val + 1; break; } Beep (440, 50); } freep (arg); return 0; } clk = GetTickCount (); amount = nTimeout*1000; loop: GCret = GetCharacterTimeout (&Ch, amount - (GetTickCount () - clk)); switch (GCret) { case GC_TIMEOUT: #ifdef _DEBUG DebugPrintf (_T("GC_TIMEOUT\n")); DebugPrintf (_T("elapsed %d msecs\n"), GetTickCount () - clk); #endif /* _DEBUG */ break; case GC_NOKEY: #ifdef _DEBUG DebugPrintf(_T("GC_NOKEY\n")); DebugPrintf(_T("elapsed %d msecs\n"), GetTickCount () - clk); #endif /* _DEBUG */ goto loop; case GC_KEYREAD: #ifdef _DEBUG DebugPrintf(_T("GC_KEYREAD\n")); DebugPrintf(_T("elapsed %d msecs\n"), GetTickCount () - clk); DebugPrintf(_T("read %c"), Ch); #endif /* _DEBUG */ if ((val=IsKeyInString(lpOptions,Ch,bCaseSensitive))==-1) { Beep (440, 50); goto loop; } cDefault=Ch; break; } #ifdef _DEBUG DebugPrintf(_T("exiting wait loop after %d msecs\n"), GetTickCount () - clk); #endif /* _DEBUG */ val = IsKeyInString (lpOptions, cDefault, bCaseSensitive); ConOutPrintf (_T("%c\n"), lpOptions[val]); nErrorLevel = val + 1; freep (arg); #ifdef _DEBUG DebugPrintf (_T("ErrorLevel: %d\n"), nErrorLevel); #endif /* _DEBUG */ return 0; } #endif /* INCLUDE_CMD_CHOICE */ /* EOF */