reactos/base/shell/cmd/prompt.c
Hermès Bélusca-Maïto 63316df520
[CMD] Change ERRORLEVEL behaviour for commands ASSOC, PATH, PROMPT and SET.
Commands APPEND/DPATH and FTYPE are also concerned by this; however
we do not implement them in our CMD.EXE yet.

These commands set the ERRORLEVEL differently, whether or not they are
run manually from the command-line/from a .BAT file, or from a .CMD file:

- From command-line/.BAT file, these commands set the ERRORLEVEL only if
  an error occurs. So, if two commands are run consecutively and the first
  one fails, the ERRORLEVEL will remain set even if the second command
  succeeds.

- However, when being run from a .CMD file, these command will always
  set the ERRORLEVEL. In the example case described above, the second
  command that succeeds will reset the ERRORLEVEL to 0.

This behaviour is determined from the top-level batch/script file being
run. This means that, if a .BAT file is first started, then starts a
.CMD file, the commands will still behave the .BAT way; on the opposite,
if a .CMD file is first started, then starts a .BAT file, these commands
will still behave the .CMD way.

To implement this we introduce one global BATCH_TYPE enum variable that
is initialized to the corresponding batch/script file type when the
top-level script is loaded. It is reset to "none" when that script
terminates.

See https://ss64.com/nt/errorlevel.html for more details,
section "Old style .bat Batch files vs .cmd Batch scripts",
and https://groups.google.com/forum/#!msg/microsoft.public.win2000.cmdprompt.admin/XHeUq8oe2wk/LIEViGNmkK0J
(comment by Mark Zbikowski).
2020-09-23 00:22:46 +02:00

285 lines
7.1 KiB
C

/*
* PROMPT.C - prompt handling.
*
*
* History:
*
* 14/01/95 (Tim Normal)
* started.
*
* 08/08/95 (Matt Rains)
* i have cleaned up the source code. changes now bring this source
* into guidelines for recommended programming practice.
*
* 01/06/96 (Tim Norman)
* added day of the week printing (oops, forgot about that!)
*
* 08/07/96 (Steffan Kaiser)
* small changes for speed
*
* 20-Jul-1998 (John P Price <linux-guru@gcfl.net>)
* removed redundant day strings. Use ones defined in date.c.
*
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
* added config.h include
*
* 28-Jul-1998 (John P Price <linux-guru@gcfl.net>)
* moved cmd_prompt from internal.c to here
*
* 09-Dec-1998 (Eric Kohl)
* Added help text ("/?").
*
* 14-Dec-1998 (Eric Kohl)
* Added "$+" option.
*
* 09-Jan-1999 (Eric Kohl)
* Added "$A", "$C" and "$F" option.
* Added locale support.
* Fixed "$V" option.
*
* 20-Jan-1999 (Eric Kohl)
* Unicode and redirection safe!
*
* 24-Jan-1999 (Eric Kohl)
* Fixed Win32 environment handling.
*
* 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
* Remove all hardcoded strings in En.rc
*/
#include "precomp.h"
/* The default prompt */
static TCHAR DefaultPrompt[] = _T("$P$G");
/*
* Initialize prompt support.
*/
VOID InitPrompt(VOID)
{
TCHAR Buffer[2];
/*
* Set the PROMPT environment variable if it doesn't exist already.
* You can change the PROMPT environment variable before cmd starts.
*/
if (GetEnvironmentVariable(_T("PROMPT"), Buffer, _countof(Buffer)) == 0)
SetEnvironmentVariable(_T("PROMPT"), DefaultPrompt);
}
/*
* Print an information line on top of the screen.
*/
VOID PrintInfoLine(VOID)
{
#define FOREGROUND_WHITE (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY)
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
COORD coPos;
DWORD dwWritten;
PTSTR pszInfoLine = NULL;
INT iInfoLineLen;
/* Return directly if the output handle is not a console handle */
if (!GetConsoleScreenBufferInfo(hOutput, &csbi))
return;
iInfoLineLen = LoadString(CMD_ModuleHandle, STRING_CMD_INFOLINE, (PTSTR)&pszInfoLine, 0);
if (!pszInfoLine || iInfoLineLen == 0)
return;
/* Display the localized information line */
coPos.X = 0;
coPos.Y = 0;
FillConsoleOutputAttribute(hOutput, BACKGROUND_BLUE | FOREGROUND_WHITE,
csbi.dwSize.X,
coPos, &dwWritten);
FillConsoleOutputCharacter(hOutput, _T(' '),
csbi.dwSize.X,
coPos, &dwWritten);
WriteConsoleOutputCharacter(hOutput, pszInfoLine, iInfoLineLen,
coPos, &dwWritten);
}
/*
* Print the command-line prompt.
*/
VOID PrintPrompt(VOID)
{
LPTSTR pr, Prompt;
TCHAR szPrompt[256];
TCHAR szPath[MAX_PATH];
if (GetEnvironmentVariable(_T("PROMPT"), szPrompt, _countof(szPrompt)))
Prompt = szPrompt;
else
Prompt = DefaultPrompt;
/*
* Special pre-handling for $I: If the information line is displayed
* on top of the screen, ensure that the prompt won't be hidden below it.
*/
for (pr = Prompt; *pr;)
{
if (*pr++ != _T('$'))
continue;
if (!*pr || _totupper(*pr++) != _T('I'))
continue;
if (GetCursorY() == 0)
ConOutChar(_T('\n'));
break;
}
/* Parse the prompt string */
for (pr = Prompt; *pr; ++pr)
{
if (*pr != _T('$'))
{
ConOutChar(*pr);
}
else
{
++pr;
if (!*pr) break;
switch (_totupper(*pr))
{
case _T('A'):
ConOutChar(_T('&'));
break;
case _T('B'):
ConOutChar(_T('|'));
break;
case _T('C'):
ConOutChar(_T('('));
break;
case _T('D'):
ConOutPrintf(_T("%s"), GetDateString());
break;
case _T('E'):
ConOutChar(_T('\x1B'));
break;
case _T('F'):
ConOutChar(_T(')'));
break;
case _T('G'):
ConOutChar(_T('>'));
break;
case _T('H'):
ConOutPuts(_T("\x08 \x08"));
break;
case _T('I'):
PrintInfoLine();
break;
case _T('L'):
ConOutChar(_T('<'));
break;
case _T('N'):
{
GetCurrentDirectory(_countof(szPath), szPath);
ConOutChar(szPath[0]);
break;
}
case _T('P'):
{
GetCurrentDirectory(_countof(szPath), szPath);
ConOutPrintf(_T("%s"), szPath);
break;
}
case _T('Q'):
ConOutChar(_T('='));
break;
case _T('S'):
ConOutChar(_T(' '));
break;
case _T('T'):
ConOutPrintf(_T("%s"), GetTimeString());
break;
case _T('V'):
PrintOSVersion();
break;
case _T('_'):
ConOutChar(_T('\n'));
break;
case _T('$'):
ConOutChar(_T('$'));
break;
#ifdef FEATURE_DIRECTORY_STACK
case _T('+'):
{
INT i;
for (i = 0; i < GetDirectoryStackDepth(); i++)
ConOutChar(_T('+'));
break;
}
#endif
}
}
}
}
#ifdef INCLUDE_CMD_PROMPT
INT cmd_prompt(LPTSTR param)
{
INT retval = 0;
if (!_tcsncmp(param, _T("/?"), 2))
{
ConOutResPaging(TRUE, STRING_PROMPT_HELP1);
#ifdef FEATURE_DIRECTORY_STACK
ConOutResPaging(FALSE, STRING_PROMPT_HELP2);
#endif
ConOutResPaging(FALSE, STRING_PROMPT_HELP3);
return 0;
}
/*
* Set the PROMPT environment variable. If 'param' is NULL or is
* an empty string (the user entered "prompt" only), then remove
* the environment variable and therefore use the default prompt.
* Otherwise, use the new prompt.
*/
if (!SetEnvironmentVariable(_T("PROMPT"),
(param && param[0] != _T('\0') ? param : NULL)))
{
retval = 1;
}
if (BatType != CMD_TYPE)
{
if (retval != 0)
nErrorLevel = retval;
}
else
{
nErrorLevel = retval;
}
return retval;
}
#endif
/* EOF */