-/* $Id: cmd.c,v 1.11 2004/04/26 20:26:15 gdalsnes Exp $
- *
+/*
* CMD.C - command-line interface.
*
*
* message!
*
* changed the format to call internal commands (again) so that if
- * they want to split their commands, they can do it themselves
+ * they want to split their commands, they can do it themselves
* (none of the internal functions so far need that much power, anyway)
*
* 27 Aug 1996 (Tim Norman)
*
* 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
* %envvar% replacement conflicted with for.
+ *
+ * 30-Apr-2004 (Filip Navara <xnavara@volny.cz>)
+ * Make MakeSureDirectoryPathExistsEx unicode safe.
+ *
+ * 28-Mai-2004 (Hartmut Birr)
+ * Removed MakeSureDirectoryPathExistsEx.
+ * Use the current directory if GetTempPath fails.
+ *
+ * 12-Jul-2004 (Jens Collin <jens.collin@lakhei.com>)
+ * Added ShellExecute call when all else fails to be able to "launch" any file.
+ *
+ * 02-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
+ * Remove all hardcode string to En.rc
+ *
+ * 06-May-2005 (Klemens Friedl <frik85@gmail.com>)
+ * Add 'help' command (list all commands plus description)
*/
-#include "config.h"
-
-#include <windows.h>
-#include <tchar.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <winnt.h>
-#include <winternl.h>
+#include "precomp.h"
+#include "resource.h"
#ifndef NT_SUCCESS
#define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
#endif
-#include "cmd.h"
-#include "batch.h"
-
typedef NTSTATUS (STDCALL *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS,
PVOID, ULONG, PULONG);
typedef NTSTATUS (STDCALL *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG);
HANDLE hIn;
HANDLE hOut;
HANDLE hConsole;
+HANDLE CMD_ModuleHandle;
static NtQueryInformationProcessProc NtQueryInformationProcessPtr;
static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr;
WORD wDefColor; /* default color */
#endif
-
-
-/***********************************************************************
- * MakeSureDirectoryPathExistsEx
- *
- * If a dir is at the end and the path ends with a backslash, FileAtEnd
- * is ignored. If the path doesn't end with a backslash, FileAtEnd is
- * used to determine if the last part of the path is a file name or a
- * directory.
- *
- * Path may be absolute or relative to current dir.
- *
- * FIXME: maybe put this in a header/library where everyone can use it?????
- */
-BOOL WINAPI MakeSureDirectoryPathExistsEx(LPCSTR DirPath, BOOL FileAtEnd)
-{
- char Path[MAX_PATH];
- char *SlashPos = Path;
- char Slash;
- BOOL bRes;
-
- strcpy(Path, DirPath);
-
- while((SlashPos=strpbrk(SlashPos+1,"\\/")))
- {
- Slash = *SlashPos;
- *SlashPos = 0;
-
- bRes = CreateDirectoryA(Path, NULL);
- if (bRes == FALSE && GetLastError() != ERROR_ALREADY_EXISTS)
- {
- return FALSE;
- }
-
- *SlashPos = Slash;
-
- if (*(SlashPos+1) == 0) return TRUE;
- }
-
- if (!FileAtEnd)
- {
- bRes = CreateDirectoryA(Path, NULL);
- if (bRes == FALSE && GetLastError() != ERROR_ALREADY_EXISTS)
- {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-
-
/*
* is character a delimeter when used on first word?
*
if (NULL == NtQueryInformationProcessPtr || NULL == NtReadVirtualMemoryPtr)
{
- return FALSE;
+ return TRUE;
}
Status = NtQueryInformationProcessPtr(Process, ProcessBasicInformation,
}
+
+#ifdef _UNICODE
+#define SHELLEXECUTETEXT "ShellExecuteW"
+#else
+#define SHELLEXECUTETEXT "ShellExecuteA"
+#endif
+
+typedef HINSTANCE (WINAPI *MYEX)(
+ HWND hwnd,
+ LPCTSTR lpOperation,
+ LPCTSTR lpFile,
+ LPCTSTR lpParameters,
+ LPCTSTR lpDirectory,
+ INT nShowCmd
+);
+
+
+
+static BOOL RunFile(LPTSTR filename)
+{
+ HMODULE hShell32;
+ MYEX hShExt;
+ HINSTANCE ret;
+
+#ifdef _DEBUG
+ DebugPrintf (_T("RunFile(%s)\n"), filename);
+#endif
+ hShell32 = LoadLibrary(_T("SHELL32.DLL"));
+ if (!hShell32)
+ {
+#ifdef _DEBUG
+ DebugPrintf (_T("RunFile: couldn't load SHELL32.DLL!\n"));
+#endif
+ return FALSE;
+ }
+
+ hShExt = (MYEX)(FARPROC)GetProcAddress(hShell32, SHELLEXECUTETEXT);
+ if (!hShExt)
+ {
+#ifdef _DEBUG
+ DebugPrintf (_T("RunFile: couldn't find ShellExecuteA/W in SHELL32.DLL!\n"));
+#endif
+ FreeLibrary(hShell32);
+ return FALSE;
+ }
+
+#ifdef _DEBUG
+ DebugPrintf (_T("RunFile: ShellExecuteA/W is at %x\n"), hShExt);
+#endif
+
+ ret = (hShExt)(NULL, _T("open"), filename, NULL, NULL, SW_SHOWNORMAL);
+
+#ifdef _DEBUG
+ DebugPrintf (_T("RunFile: ShellExecuteA/W returned %d\n"), (DWORD)ret);
+#endif
+
+ FreeLibrary(hShell32);
+ return (((DWORD)ret) > 32);
+}
+
+
+
/*
* This command (in first) was not found in the command table
*
*/
static VOID
-Execute (LPTSTR first, LPTSTR rest)
+Execute (LPTSTR full, LPTSTR first, LPTSTR rest)
{
TCHAR szFullName[MAX_PATH];
#ifndef __REACTOS__
/* check for a drive change */
if ((_istalpha (first[0])) && (!_tcscmp (first + 1, _T(":"))))
- {
+ {
BOOL working = TRUE;
if (!SetCurrentDirectory(first))
/* Guess they changed disc or something, handle that gracefully and get to root */
working = SetCurrentDirectory(str);
}
- if (!working) ConErrPuts (INVALIDDRIVE);
+ if (!working) ConErrResPuts (STRING_FREE_ERROR1);
return;
}
else
{
/* exec the program */
- TCHAR szFullCmdLine [CMDLINE_LENGTH];
PROCESS_INFORMATION prci;
STARTUPINFO stui;
#ifdef _DEBUG
- DebugPrintf (_T("[EXEC: %s %s]\n"), szFullName, rest);
+ DebugPrintf (_T("[EXEC: %s %s]\n"), full, rest);
#endif
/* build command line for CreateProcess() */
- _tcscpy (szFullCmdLine, first);
- _tcscat (szFullCmdLine, _T(" "));
- _tcscat (szFullCmdLine, rest);
/* fill startup info */
memset (&stui, 0, sizeof (STARTUPINFO));
// return console to standard mode
SetConsoleMode (GetStdHandle(STD_INPUT_HANDLE),
ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
-
+
if (CreateProcess (szFullName,
- szFullCmdLine,
+ full,
NULL,
NULL,
- FALSE,
+ TRUE,
CREATE_NEW_PROCESS_GROUP,
NULL,
NULL,
}
else
{
- ErrorMessage (GetLastError (),
- _T("Error executing CreateProcess()!!\n"));
+#ifdef _DEBUG
+ DebugPrintf (_T("[ShellExecute: %s]\n"), full);
+#endif
+ // See if we can run this with ShellExecute() ie myfile.xls
+ if (!RunFile(full))
+ {
+#ifdef _DEBUG
+ DebugPrintf (_T("[ShellExecute failed!: %s]\n"), full);
+#endif
+ error_bad_command ();
+ }
}
// restore console mode
SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
ENABLE_PROCESSED_INPUT );
}
+ /* Get code page if it has been change */
+ InputCodePage= GetConsoleCP();
+ OutputCodePage = GetConsoleOutputCP();
#ifndef __REACTOS__
SetConsoleTitle (szWindowTitle);
#endif
TCHAR com[CMDLINE_LENGTH]; /* the first word in the command */
LPTSTR cp = com;
LPTSTR cstart;
- LPTSTR rest = line; /* pointer to the rest of the command line */
+ LPTSTR rest; /* pointer to the rest of the command line */
INT cl;
LPCOMMAND cmdptr;
#endif /* DEBUG */
/* Skip over initial white space */
- while (_istspace (*rest))
- rest++;
+ while (_istspace (*line))
+ line++;
+ rest = line;
cstart = rest;
while(*rest != _T('\0') && *rest != _T('"'))
*cp++ = _totlower (*rest++);
+ if (*rest == _T('"'))
+ rest++;
}
else
{
/* Terminate first word */
*cp = _T('\0');
-
+
/* commands are limited to MAX_PATH */
if(_tcslen(com) > MAX_PATH)
{
/* If end of table execute ext cmd */
if (cmdptr->name == NULL)
{
- Execute (com, rest);
+ Execute (line, com, rest);
break;
}
VOID ParseCommandLine (LPTSTR cmd)
{
+ TCHAR szMsg[RC_STRING_MAX_SIZE];
TCHAR cmdline[CMDLINE_LENGTH];
LPTSTR s;
#ifdef FEATURE_REDIRECTION
LPTSTR t = NULL;
INT num = 0;
INT nRedirFlags = 0;
+ INT Length;
+ UINT Attributes;
HANDLE hOldConIn;
HANDLE hOldConOut;
#ifdef FEATURE_REDIRECTION
/* find the temp path to store temporary files */
- GetTempPath (MAX_PATH, szTempPath);
- MakeSureDirectoryPathExistsEx(szTempPath, FALSE);
+ Length = GetTempPath (MAX_PATH, szTempPath);
+ if (Length > 0 && Length < MAX_PATH)
+ {
+ Attributes = GetFileAttributes(szTempPath);
+ if (Attributes == 0xffffffff ||
+ !(Attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ Length = 0;
+ }
+ }
+ if (Length == 0 || Length >= MAX_PATH)
+ {
+ _tcscpy(szTempPath, _T(".\\"));
+ }
if (szTempPath[_tcslen (szTempPath) - 1] != _T('\\'))
_tcscat (szTempPath, _T("\\"));
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
- ConErrPrintf (_T("Can't redirect input from file %s\n"), in);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR1, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, in);
return;
}
if (!SetStdHandle (STD_INPUT_HANDLE, hFile))
{
- ConErrPrintf (_T("Can't redirect input from file %s\n"), in);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR1, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, in);
return;
}
#ifdef _DEBUG
/* Create unique temporary file name */
GetTempFileName (szTempPath, _T("CMD"), 0, szFileName[1]);
-
+
/* Set current stdout to temporary file */
hFile[1] = CreateFile (szFileName[1], GENERIC_WRITE, 0, &sa,
TRUNCATE_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
-
- if (hFile[1] == INVALID_HANDLE_VALUE){
- ConErrPrintf (_T("Error creating temporary file for pipe data\n"));
- return;
- }
-
+ if (hFile[1] == INVALID_HANDLE_VALUE)
+ {
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR2, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg);
+ return;
+ }
+
SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
DoCommand (s);
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
- ConErrPrintf (_T("Can't redirect to file %s\n"), out);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, out);
return;
}
if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile))
{
- ConErrPrintf (_T("Can't redirect to file %s\n"), out);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, out);
return;
}
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
- ConErrPrintf (_T("Can't redirect to file %s\n"), err);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, err);
return;
}
}
+
if (!SetStdHandle (STD_ERROR_HANDLE, hFile))
{
- ConErrPrintf (_T("Can't redirect to file %s\n"), err);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, err);
return;
}
/* close old stdin file */
#if 0 /* buggy implementation */
SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
- if ((hFile[0] != INVALID_HANDLE_VALUE) &&
+ if ((hFile[0] != INVALID_HANDLE_VALUE) &&
(hFile[0] != hOldConIn))
{
/* delete old stdin file, if it is a real file */
*
*/
-static INT
+static INT
ProcessInput (BOOL bFlag)
{
TCHAR commandline[CMDLINE_LENGTH];
LPTSTR cp;
BOOL bEchoThisLine;
+
do
{
/* if no batch input then... */
*/
BOOL WINAPI BreakHandler (DWORD dwCtrlType)
{
+
if ((dwCtrlType != CTRL_C_EVENT) &&
(dwCtrlType != CTRL_BREAK_EVENT))
return FALSE;
ShowCommands (VOID)
{
/* print command list */
- ConOutPrintf (_T("\nInternal commands available:\n"));
- PrintCommandList ();
+ ConOutResPuts(STRING_CMD_HELP1);
+ PrintCommandList();
/* print feature list */
- ConOutPuts (_T("\nFeatures available:"));
+ ConOutResPuts(STRING_CMD_HELP2);
+
#ifdef FEATURE_ALIASES
- ConOutPuts (_T(" [aliases]"));
+ ConOutResPuts(STRING_CMD_HELP3);
#endif
#ifdef FEATURE_HISTORY
- ConOutPuts (_T(" [history]"));
+ ConOutResPuts(STRING_CMD_HELP4);
#endif
#ifdef FEATURE_UNIX_FILENAME_COMPLETION
- ConOutPuts (_T(" [unix filename completion]"));
+ ConOutResPuts(STRING_CMD_HELP5);
#endif
#ifdef FEATURE_DIRECTORY_STACK
- ConOutPuts (_T(" [directory stack]"));
+ ConOutResPuts(STRING_CMD_HELP6);
#endif
#ifdef FEATURE_REDIRECTION
- ConOutPuts (_T(" [redirections and piping]"));
+ ConOutResPuts(STRING_CMD_HELP7);
#endif
- ConOutChar (_T('\n'));
+ ConOutChar(_T('\n'));
}
#endif
TCHAR commandline[CMDLINE_LENGTH];
TCHAR ModuleName[_MAX_PATH + 1];
INT i;
+
//INT len;
//TCHAR *ptr, *cmdLine;
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);
+ ConOutResPuts(STRING_CMD_HELP8);
+ ExitProcess(0);
}
SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
{
if (!_tcsicmp (argv[i], _T("/p")))
{
- if (!IsValidFileName (_T("\\autoexec.bat")))
+ if (!IsExistingFile (_T("\\autoexec.bat")))
{
#ifdef INCLUDE_CMD_DATE
cmd_date (_T(""), _T(""));
}
/* run cmdstart.bat */
- if (IsValidFileName (_T("cmdstart.bat")))
+ if (IsExistingFile (_T("cmdstart.bat")))
{
ParseCommandLine (_T("cmdstart.bat"));
}
- else if (IsValidFileName (_T("\\cmdstart.bat")))
+ else if (IsExistingFile (_T("\\cmdstart.bat")))
{
ParseCommandLine (_T("\\cmdstart.bat"));
}
p = _tcsrchr (commandline, _T('\\')) + 1;
_tcscpy (p, _T("cmdstart.bat"));
- if (IsValidFileName (_T("commandline")))
+ if (IsExistingFile (_T("commandline")))
{
- ConErrPrintf (_T("Running %s...\n", commandline));
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR4, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, commandline);
ParseCommandLine (commandline);
}
}
static VOID Cleanup (int argc, TCHAR *argv[])
{
+#ifndef __REACTOS__
+ TCHAR szMsg[RC_STRING_MAX_SIZE];
+#endif
+
/* run cmdexit.bat */
- if (IsValidFileName (_T("cmdexit.bat")))
+ if (IsExistingFile (_T("cmdexit.bat")))
{
- ConErrPrintf (_T("Running cmdexit.bat...\n"));
+ ConErrResPuts(STRING_CMD_ERROR5);
+
ParseCommandLine (_T("cmdexit.bat"));
}
- else if (IsValidFileName (_T("\\cmdexit.bat")))
+ else if (IsExistingFile (_T("\\cmdexit.bat")))
{
- ConErrPrintf (_T("Running \\cmdexit.bat...\n"));
+ ConErrResPuts (STRING_CMD_ERROR5);
ParseCommandLine (_T("\\cmdexit.bat"));
}
#ifndef __REACTOS__
p = _tcsrchr (commandline, _T('\\')) + 1;
_tcscpy (p, _T("cmdexit.bat"));
- if (IsValidFileName (_T("commandline")))
+ if (IsExistingFile (_T("commandline")))
{
- ConErrPrintf (_T("Running %s...\n"), commandline);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR4, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, commandline);
ParseCommandLine (commandline);
}
}
FreeLastPath ();
#endif
-#ifdef FEATURE_HISTORY
+#ifdef FEATURE_HISTORY
CleanHistory();
#endif
#endif
SetFileApisToOEM();
+ InputCodePage= 0;
+ OutputCodePage = 0;
- hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (GetConsoleScreenBufferInfo(hConsole, &Info) == FALSE)
{
- ConErrPrintf (_T("GetConsoleScreenBufferInfo: Error: %ld\n"), GetLastError());
+ ConOutFormatMessage(GetLastError());
return(1);
}
wColor = Info.wAttributes;
wDefColor = wColor;
+ InputCodePage= GetConsoleCP();
+ OutputCodePage = GetConsoleOutputCP();
+ CMD_ModuleHandle = GetModuleHandle(NULL);
+
/* check switches on command-line */
Initialize(argc, argv);