-/*
+/* $Id: cmd.c,v 1.24 2001/02/28 22:33:23 ekohl Exp $
+ *
* CMD.C - command-line interface.
*
*
*
* 27-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
* Replaced spawnl() by CreateProcess().
+ *
+ * 22-Oct-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ * Added break handler.
+ *
+ * 15-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ * Fixed current directory
+ *
+ * 28-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ * Restore window title after program/batch execution
+ *
+ * 03-Feb-2001 (Eric Kohl <ekohl@rz-online.de>)
+ * Workaround because argc[0] is NULL under ReactOS
+ *
+ * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
+ * %envvar% replacement conflicted with for.
*/
#include "config.h"
#include "batch.h"
-#define CMDLINE_LENGTH 512
-
-
BOOL bExit = FALSE; /* indicates EXIT was typed */
BOOL bCanExit = TRUE; /* indicates if this shell is exitable */
BOOL bCtrlBreak = FALSE; /* Ctrl-Break or Ctrl-C hit */
BOOL bIgnoreEcho = FALSE; /* Ignore 'newline' before 'cls' */
INT nErrorLevel = 0; /* Errorlevel of last launched external program */
+BOOL bChildProcessRunning = FALSE;
+DWORD dwChildProcessId = 0;
OSVERSIONINFO osvi;
HANDLE hIn;
HANDLE hOut;
#ifdef INCLUDE_CMD_COLOR
-WORD wColor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; /* current color */
-WORD wDefColor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; /* default color */
+WORD wColor; /* current color */
+WORD wDefColor; /* default color */
#endif
-extern COMMAND cmds[]; /* The internal command table */
-
-
/*
* is character a delimeter when used on first word?
*
Execute (LPTSTR first, LPTSTR rest)
{
TCHAR szFullName[MAX_PATH];
+#ifndef __REACTOS__
+ TCHAR szWindowTitle[MAX_PATH];
+#endif
+ DWORD dwExitCode = 0;
+
+#ifdef _DEBUG
+ DebugPrintf ("Execute: \'%s\' \'%s\'\n", first, rest);
+#endif
/* check for a drive change */
- if (!_tcscmp (first + 1, _T(":")) && _istalpha (*first))
+ if ((_istalpha (first[0])) && (!_tcscmp (first + 1, _T(":"))))
{
TCHAR szPath[MAX_PATH];
+ TCHAR szVar[5];
+
+#ifdef _DEBUG
+ DebugPrintf ("Drive change to drive %s\n", first);
+#endif
+ /* save curent directory in environment variable */
+ GetCurrentDirectory (MAX_PATH, szPath);
+
+ _tcscpy (szVar, _T("=A:"));
+ szVar[1] = _totupper (szPath[0]);
- _tcscpy (szPath, _T("A:"));
- szPath[0] = _totupper (*first);
+ SetEnvironmentVariable (szVar, szPath);
+
+
+ /* check for current directory of new drive */
+ _tcscpy (szVar, _T("=A:"));
+ szVar[1] = _totupper (*first);
+
+ if (GetEnvironmentVariable (szVar, szPath, MAX_PATH) == 0)
+ {
+ /* no environment variable found */
+ _tcscpy (szPath, _T("A:\\"));
+ szPath[0] = _totupper (*first);
+ }
+
+#ifdef _DEBUG
+ DebugPrintf ("Drive change to drive %s\n", szPath);
+#endif
+
+ /* set new current directory */
SetCurrentDirectory (szPath);
GetCurrentDirectory (MAX_PATH, szPath);
if (szPath[0] != (TCHAR)_totupper (*first))
return;
}
+#ifndef __REACTOS__
+ GetConsoleTitle (szWindowTitle, MAX_PATH);
+#endif
+
/* check if this is a .BAT or .CMD file */
if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) ||
!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".cmd")))
else
{
/* exec the program */
- TCHAR szFullCmdLine [1024];
+#ifndef __REACTOS__
+ TCHAR szFullCmdLine [CMDLINE_LENGTH];
+#endif
PROCESS_INFORMATION prci;
STARTUPINFO stui;
-// DWORD dwError = 0;
#ifdef _DEBUG
DebugPrintf ("[EXEC: %s %s]\n", szFullName, rest);
#endif
+#ifndef __REACTOS__
/* build command line for CreateProcess() */
_tcscpy (szFullCmdLine, szFullName);
_tcscat (szFullCmdLine, _T(" "));
_tcscat (szFullCmdLine, rest);
+#endif
/* fill startup info */
memset (&stui, 0, sizeof (STARTUPINFO));
stui.cb = sizeof (STARTUPINFO);
stui.dwFlags = STARTF_USESHOWWINDOW;
stui.wShowWindow = SW_SHOWDEFAULT;
-
- if (CreateProcess (NULL, szFullCmdLine, NULL, NULL, FALSE,
- 0, NULL, NULL, &stui, &prci))
+
+#ifndef __REACTOS__
+ if (CreateProcess (NULL,
+ szFullCmdLine,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_PROCESS_GROUP,
+ NULL,
+ NULL,
+ &stui,
+ &prci))
+#else
+ if (CreateProcess (szFullName,
+ rest,
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ NULL,
+ NULL,
+ &stui,
+ &prci))
+#endif
{
- DWORD dwExitCode;
+ /* FIXME: Protect this with critical section */
+ bChildProcessRunning = TRUE;
+ dwChildProcessId = prci.dwProcessId;
+
WaitForSingleObject (prci.hProcess, INFINITE);
+
+ /* FIXME: Protect this with critical section */
+ bChildProcessRunning = TRUE;
+
GetExitCodeProcess (prci.hProcess, &dwExitCode);
nErrorLevel = (INT)dwExitCode;
CloseHandle (prci.hThread);
else
{
ErrorMessage (GetLastError (),
- "Error executing CreateProcess()!!\n");
+ "Error executing CreateProcess()!!\n");
}
}
+
+#ifndef __REACTOS__
+ SetConsoleTitle (szWindowTitle);
+#endif
}
INT cl;
LPCOMMAND cmdptr;
+#ifdef _DEBUG
+ DebugPrintf ("DoCommand: (\'%s\')\n", line);
+#endif /* DEBUG */
+
/* Skip over initial white space */
while (isspace (*rest))
rest++;
* full input/output redirection and piping are supported
*/
-VOID ParseCommandLine (LPTSTR s)
+VOID ParseCommandLine (LPTSTR cmd)
{
+ TCHAR cmdline[CMDLINE_LENGTH];
+ LPTSTR s;
#ifdef FEATURE_REDIRECTION
TCHAR in[CMDLINE_LENGTH] = "";
TCHAR out[CMDLINE_LENGTH] = "";
HANDLE hOldConErr;
#endif /* FEATURE_REDIRECTION */
+ _tcscpy (cmdline, cmd);
+ s = &cmdline[0];
+
#ifdef _DEBUG
- DebugPrintf ("ParseCommandLine: (\'%s\')]\n", s);
-#endif /* _DEBUG */
+ DebugPrintf ("ParseCommandLine: (\'%s\')\n", s);
+#endif /* DEBUG */
#ifdef FEATURE_ALIASES
/* expand all aliases */
HANDLE hFile;
hFile = CreateFile (in, GENERIC_READ, 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
ConErrPrintf ("Can't redirect input from file %s\n", in);
/* Set current stdout to temporary file */
hFile[1] = CreateFile (szFileName[1], GENERIC_WRITE, 0, NULL,
- TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
+ TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
DoCommand (s);
/* open new stdin file */
hFile[0] = CreateFile (szFileName[0], GENERIC_READ, 0, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
+ OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
SetStdHandle (STD_INPUT_HANDLE, hFile[0]);
s = s + _tcslen (s) + 1;
HANDLE hFile;
hFile = CreateFile (out, GENERIC_WRITE, 0, NULL,
- (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
ConErrPrintf ("Can't redirect to file %s\n", out);
#ifdef _DEBUG
DebugPrintf (_T("Stdout and stderr will use the same file!!\n"));
#endif
- DuplicateHandle (GetCurrentProcess (), GetStdHandle (STD_OUTPUT_HANDLE), GetCurrentProcess (),
- &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS);
+ DuplicateHandle (GetCurrentProcess (),
+ GetStdHandle (STD_OUTPUT_HANDLE),
+ GetCurrentProcess (),
+ &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS);
}
else
{
- hFile =
- CreateFile (err, GENERIC_WRITE, 0, NULL,
- (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
+ hFile = CreateFile (err,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
ConErrPrintf ("Can't redirect to file %s\n", err);
#ifdef _DEBUG
DebugPrintf (_T("hFile[0] and hIn dont match!!!\n"));
#endif
-
}
}
}
LPTSTR tp;
LPTSTR ip;
LPTSTR cp;
-
- /* JPP 19980807 - changed name so not to conflict with echo global */
BOOL bEchoThisLine;
do
break;
case _T('?'):
- cp += _stprintf (cp, _T("%u"), nErrorLevel);
+ cp += _stprintf (cp, _T("%u"), nErrorLevel);
ip++;
break;
default:
- if ((tp = _tcschr (ip, _T('%'))))
+ if ((tp = _tcschr (ip, _T('%'))) && (tp<=(unsigned int)strchr(ip,_T(' '))-1))
{
char evar[512];
*tp = _T('\0');
ip = tp + 1;
}
+ else
+ {
+ *cp++ = _T('%');
+ }
break;
}
continue;
*cp = _T('\0');
/* strip trailing spaces */
- while ((--cp >= commandline) && _istspace (*cp))
- ;
+ while ((--cp >= commandline) && _istspace (*cp));
*(cp + 1) = _T('\0');
*/
BOOL BreakHandler (DWORD dwCtrlType)
{
- if ((dwCtrlType == CTRL_C_EVENT) ||
- (dwCtrlType == CTRL_BREAK_EVENT))
+ if ((dwCtrlType != CTRL_C_EVENT) &&
+ (dwCtrlType != CTRL_BREAK_EVENT))
+ return FALSE;
+
+ if (bChildProcessRunning == TRUE)
{
- bCtrlBreak = TRUE; /* indicate the break condition */
+ GenerateConsoleCtrlEvent (CTRL_C_EVENT,
+ dwChildProcessId);
return TRUE;
}
- return FALSE;
+
+ /* FIXME: Handle batch files */
+
+ /* FIXME: Print "^C" */
+
+
+ return TRUE;
+}
+
+
+VOID AddBreakHandler (VOID)
+{
+#ifndef __REACTOS__
+ SetConsoleCtrlHandler ((PHANDLER_ROUTINE)&BreakHandler,
+ TRUE);
+#endif
+}
+
+
+VOID RemoveBreakHandler (VOID)
+{
+#ifndef __REACTOS__
+ SetConsoleCtrlHandler (NULL, FALSE);
+#endif
}
static VOID
ShowCommands (VOID)
{
- LPCOMMAND cmdptr;
- INT y;
-
+ /* print command list */
ConOutPrintf (_T("\nInternal commands available:\n"));
- y = 0;
- cmdptr = cmds;
- while (cmdptr->name)
- {
- if (++y == 8)
- {
- ConOutPuts (cmdptr->name);
- y = 0;
- }
- else
- ConOutPrintf (_T("%-10s"), cmdptr->name);
-
- cmdptr++;
- }
-
- if (y != 0)
- ConOutChar ('\n');
+ PrintCommandList ();
/* print feature list */
ConOutPuts ("\nFeatures available:");
#ifdef FEATURE_REDIRECTION
ConOutPuts (" [redirections and piping]");
#endif
- ConOutChar ('\n');
+ ConOutChar ('\n');
}
* argv - command-line parameters
*
*/
-static VOID Initialize (int argc, char *argv[])
+static VOID
+Initialize (int argc, char *argv[])
{
+ TCHAR commandline[CMDLINE_LENGTH];
INT i;
- /* Added by Rob Lake 06/16/98. This enables the command.com
- * to run the autoexec.bat at startup */
-
#ifdef _DEBUG
INT x;
#endif
/* get version information */
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx (&osvi);
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx (&osvi);
- InitLocale ();
+ InitLocale ();
/* get default input and output console handles */
hOut = GetStdHandle (STD_OUTPUT_HANDLE);
hIn = GetStdHandle (STD_INPUT_HANDLE);
+ SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
+
+ if (argc >= 2 && !_tcsncmp (argv[1], _T("/?"), 2))
+ {
+ ConOutPuts (_T("Starts a new instance of the ReactOS command line interpreter.\n"
+ "\n"
+ "CMD [/[C|K] command][/P][/Q][/T:bf]\n"
+ "\n"
+ " /C command Runs the specified command and terminates.\n"
+ " /K command Runs the specified command and remains.\n"
+ " /P CMD becomes permanent and runs autoexec.bat\n"
+ " (cannot be terminated).\n"
+ " /T:bf Sets the background/foreground color (see COLOR command)."));
+ ExitProcess (0);
+ }
+
#ifdef INCLUDE_CMD_CHDIR
InitLastPath ();
#endif
- if (argc >= 2)
+#ifdef FATURE_ALIASES
+ InitializeAlias ();
+#endif
+
+ if (argc >= 2)
{
- if (!_tcsncmp (argv[1], _T("/?"), 2))
+ for (i = 1; i < argc; i++)
{
- ConOutPuts (_T("Starts a new instance of the ReactOS command line interpreter\n\n"
- "CMD [/P][/C]...\n\n"
- " /P ...\n"
- " /C ..."));
- ExitProcess (0);
- }
- else
- {
- for (i = 1; i < argc; i++)
+ if (!_tcsicmp (argv[i], _T("/p")))
{
- if (!_tcsicmp (argv[i], _T("/p")))
+ if (!IsValidFileName (_T("\\autoexec.bat")))
{
- if (!IsValidFileName (_T("\\autoexec.bat")))
- {
#ifdef INCLUDE_CMD_DATE
- cmd_date ("", "");
+ cmd_date ("", "");
#endif
#ifdef INCLUDE_CMD_TIME
- cmd_time ("", "");
+ cmd_time ("", "");
#endif
- }
- else
- ParseCommandLine ("\\autoexec.bat");
- bCanExit = FALSE;
}
- else if (!_tcsicmp (argv[i], _T("/c")))
+ else
+ {
+ ParseCommandLine (_T("\\autoexec.bat"));
+ }
+ bCanExit = FALSE;
+ }
+ else if (!_tcsicmp (argv[i], _T("/c")))
+ {
+ /* This just runs a program and exits */
+ ++i;
+ if (argv[i])
{
- /* This just runs a program and exits, RL: 06/16,21/98 */
- char commandline[CMDLINE_LENGTH];
- ++i;
- strcpy(commandline, argv[i]);
+ _tcscpy (commandline, argv[i]);
while (argv[++i])
{
- strcat(commandline, " ");
- strcat(commandline, argv[i]);
+ _tcscat (commandline, " ");
+ _tcscat (commandline, argv[i]);
}
ParseCommandLine(commandline);
-
- /* HBP_003 { Fix return value when /C used }*/
ExitProcess (ProcessInput (TRUE));
}
-
-#ifdef INCLUDE_CMD_COLOR
- else if (!_tcsnicmp (argv[i], _T("/t:"), 3))
+ else
{
- /* process /t (color) argument */
- wDefColor = (WORD)strtoul (&argv[i][3], NULL, 16);
- wColor = wDefColor;
+ ExitProcess (0);
}
-#endif
}
+ else if (!_tcsicmp (argv[i], _T("/k")))
+ {
+ /* This just runs a program and remains */
+ ++i;
+ if (argv[i])
+ {
+ _tcscpy (commandline, argv[i]);
+ while (argv[++i])
+ {
+ _tcscat (commandline, " ");
+ _tcscat (commandline, argv[i]);
+ }
+
+ ParseCommandLine(commandline);
+ }
+ }
+#ifdef INCLUDE_CMD_COLOR
+ else if (!_tcsnicmp (argv[i], _T("/t:"), 3))
+ {
+ /* process /t (color) argument */
+ wDefColor = (WORD)strtoul (&argv[i][3], NULL, 16);
+ wColor = wDefColor;
+ SetScreenColor (wColor, TRUE);
+ }
+#endif
}
}
+ ShortVersion ();
+ ShowCommands ();
+
+ /* run cmdstart.bat */
+ if (IsValidFileName (_T("cmdstart.bat")))
+ {
+ ParseCommandLine (_T("cmdstart.bat"));
+ }
+ else if (IsValidFileName (_T("\\cmdstart.bat")))
+ {
+ ParseCommandLine (_T("\\cmdstart.bat"));
+ }
+#ifndef __REACTOS__
+ else
+ {
+ /* try to run cmdstart.bat from install dir */
+ LPTSTR p;
+
+ _tcscpy (commandline, argv[0]);
+ p = _tcsrchr (commandline, _T('\\')) + 1;
+ _tcscpy (p, _T("cmdstart.bat"));
+
+ if (IsValidFileName (_T("commandline")))
+ {
+ ConErrPrintf ("Running %s...\n", commandline);
+ ParseCommandLine (commandline);
+ }
+ }
+#endif
+
#ifdef FEATURE_DIR_STACK
/* initialize directory stack */
InitDirectoryStack ();
#endif
-#ifdef INCLUDE_CMD_COLOR
- /* set default colors */
- SetScreenColor (wColor);
-#endif
- ShortVersion ();
- ShowCommands ();
+#ifdef FEATURE_HISTORY
+ /*initialize history*/
+ InitHistory();
+#endif
/* Set COMSPEC environment variable */
#ifndef __REACTOS__
- if (argv)
- SetEnvironmentVariable (_T("COMSPEC"), argv[0]);
+ if (argv)
+ SetEnvironmentVariable (_T("COMSPEC"), argv[0]);
#endif
- /* add ctrl handler */
-#if 0
- SetConsoleCtrlHandler (NULL, TRUE);
-#endif
+ /* add ctrl break handler */
+ AddBreakHandler ();
}
-static VOID Cleanup (VOID)
+static VOID Cleanup (int argc, char *argv[])
{
+ /* run cmdexit.bat */
+ if (IsValidFileName (_T("cmdexit.bat")))
+ {
+ ConErrPrintf ("Running cmdexit.bat...\n");
+ ParseCommandLine (_T("cmdexit.bat"));
+ }
+ else if (IsValidFileName (_T("\\cmdexit.bat")))
+ {
+ ConErrPrintf ("Running \\cmdexit.bat...\n");
+ ParseCommandLine (_T("\\cmdexit.bat"));
+ }
+#ifndef __REACTOS__
+ else
+ {
+ /* try to run cmdexit.bat from install dir */
+ TCHAR commandline[CMDLINE_LENGTH];
+ LPTSTR p;
+
+ _tcscpy (commandline, argv[0]);
+ p = _tcsrchr (commandline, _T('\\')) + 1;
+ _tcscpy (p, _T("cmdexit.bat"));
+
+ if (IsValidFileName (_T("commandline")))
+ {
+ ConErrPrintf ("Running %s...\n", commandline);
+ ParseCommandLine (commandline);
+ }
+ }
+#endif
+
+#ifdef FEATURE_ALIASES
+ DestroyAlias ();
+#endif
#ifdef FEATURE_DIECTORY_STACK
/* destroy directory stack */
FreeLastPath ();
#endif
- /* remove ctrl handler */
-#if 0
- SetConsoleCtrlHandler ((PHANDLER_ROUTINE)&BreakHandler, FALSE);
+#ifdef FEATURE_HISTORY
+ CleanHistory();
#endif
+
+
+ /* remove ctrl break handler */
+ RemoveBreakHandler ();
}
int main (int argc, char *argv[])
{
INT nExitCode;
+ CONSOLE_SCREEN_BUFFER_INFO Info;
AllocConsole ();
-#ifndef __REACTOS__
- SetFileApisToOEM ();
-#endif
-
-#ifdef __REACTOS__
- SetCurrentDirectory (_T("C:\\"));
-#endif
+ SetFileApisToOEM ();
+ if( GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &Info ) == FALSE )
+ printf( "GetConsoleScreenBufferInfo: Error: %ld\n", GetLastError() );
+ wColor = Info.wAttributes;
+ wDefColor = wColor;
/* check switches on command-line */
Initialize (argc, argv);
/* call prompt routine */
- nExitCode = ProcessInput (FALSE);
+ nExitCode = ProcessInput (FALSE);
/* do the cleanup */
- Cleanup ();
- FreeConsole ();
+ Cleanup (argc, argv);
+ FreeConsole ();
- return nExitCode;
-// return 0;
+ return nExitCode;
}
+
+/* EOF */