reactos/base/shell/cmd/choice.c
Serge Gautherie 03422451b3 [REACTOS] Add '\n' to debug logs
on TRACE, WARN, FIXME and ERR calls.

Plus a few nit picks.
2022-05-04 03:28:38 +03:00

312 lines
6.8 KiB
C

/*
* 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.
*
* 02 Apr 2005 (Magnus Olsen)
* Remove hardcoded strings so that they can be translated.
*
*/
#include "precomp.h"
#ifdef INCLUDE_CMD_CHOICE
#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 expired 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 != FALSE))
{
//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 param)
{
LPTSTR lpOptions;
TCHAR Options[6];
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;
LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, Options, 4);
lpOptions = Options;
if (_tcsncmp (param, _T("/?"), 2) == 0)
{
ConOutResPaging(TRUE,STRING_CHOICE_HELP);
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, 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)
{
ConErrResPuts(STRING_CHOICE_ERROR);
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(','))
{
ConErrResPuts(STRING_CHOICE_ERROR_TXT);
freep (arg);
return 1;
}
s++;
nTimeout = _ttoi(s);
bTimeout = TRUE;
}
else if (arg[i][0] == _T('/'))
{
ConErrResPrintf(STRING_CHOICE_ERROR_OPTION, 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
bCaseSensitive);
if (val >= 0)
{
ConOutPrintf (_T("%c\n"), lpOptions[val]);
nErrorLevel = val + 1;
break;
}
Beep (440, 50);
}
freep (arg);
TRACE ("ErrorLevel: %d\n", nErrorLevel);
return 0;
}
clk = GetTickCount ();
amount = nTimeout*1000;
loop:
GCret = GetCharacterTimeout (&Ch, amount - (GetTickCount () - clk));
switch (GCret)
{
case GC_TIMEOUT:
TRACE ("GC_TIMEOUT\n");
TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
break;
case GC_NOKEY:
TRACE ("GC_NOKEY\n");
TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
goto loop;
case GC_KEYREAD:
TRACE ("GC_KEYREAD\n");
TRACE ("elapsed %d msecs\n", GetTickCount () - clk);
TRACE ("read %c\n", Ch);
if ((val=IsKeyInString(lpOptions,Ch,bCaseSensitive))==-1)
{
Beep (440, 50);
goto loop;
}
cDefault=Ch;
break;
}
TRACE ("exiting wait loop after %d msecs\n",
GetTickCount () - clk);
val = IsKeyInString (lpOptions, cDefault, bCaseSensitive);
ConOutPrintf(_T("%c\n"), lpOptions[val]);
nErrorLevel = val + 1;
freep (arg);
TRACE ("ErrorLevel: %d\n", nErrorLevel);
return 0;
}
#endif /* INCLUDE_CMD_CHOICE */
/* EOF */