-/* $Id: cmd.c,v 1.1 2003/03/20 19:19:22 rcampbell 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)
+ *
+ * 06-jul-2005 (Magnus Olsen <magnus@greatlord.com>)
+ * translate '%errorlevel%' to the internal value.
+ * Add proper memmory alloc ProcessInput, the error
+ * handling for memmory handling need to be improve
*/
-#include "config.h"
-
-#include <windows.h>
-#include <tchar.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdio.h>
+#include <precomp.h>
+#include "resource.h"
-#include "cmd.h"
-#include "batch.h"
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0)
+#endif
+typedef NTSTATUS (STDCALL *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS,
+ PVOID, ULONG, PULONG);
+typedef NTSTATUS (STDCALL *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG);
BOOL bExit = FALSE; /* indicates EXIT was typed */
BOOL bCanExit = TRUE; /* indicates if this shell is exitable */
OSVERSIONINFO osvi;
HANDLE hIn;
HANDLE hOut;
+HANDLE hConsole;
+HANDLE CMD_ModuleHandle;
+HMODULE NtDllModule;
+
+static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL;
+static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr = NULL;
#ifdef INCLUDE_CMD_COLOR
WORD wColor; /* current color */
WORD wDefColor; /* default color */
#endif
-
/*
* is character a delimeter when used on first word?
*
return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c));
}
+/*
+ * Is a process a console process?
+ */
+static BOOL IsConsoleProcess(HANDLE Process)
+{
+ NTSTATUS Status;
+ PROCESS_BASIC_INFORMATION Info;
+ PEB ProcessPeb;
+ ULONG BytesRead;
+
+ if (NULL == NtQueryInformationProcessPtr || NULL == NtReadVirtualMemoryPtr)
+ {
+ return TRUE;
+ }
+
+ Status = NtQueryInformationProcessPtr(Process, ProcessBasicInformation,
+ &Info, sizeof(PROCESS_BASIC_INFORMATION), NULL);
+ if (! NT_SUCCESS(Status))
+ {
+#ifdef _DEBUG
+ DebugPrintf (_T("NtQueryInformationProcess failed with status %08x\n"), Status);
+#endif
+ return TRUE;
+ }
+ Status = NtReadVirtualMemoryPtr(Process, Info.PebBaseAddress, &ProcessPeb,
+ sizeof(PEB), &BytesRead);
+ if (! NT_SUCCESS(Status) || sizeof(PEB) != BytesRead)
+ {
+#ifdef _DEBUG
+ DebugPrintf (_T("Couldn't read virt mem status %08x bytes read %lu\n"), Status, BytesRead);
+#endif
+ return TRUE;
+ }
+
+ return IMAGE_SUBSYSTEM_WINDOWS_CUI == ProcessPeb.ImageSubSystem;
+}
+
+
+
+#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
*
- * first - first word on command line
- * rest - rest of command line
+ * Full - whole command line
+ * First - first word on command line
+ * Rest - rest of command line
*/
static VOID
-Execute (LPTSTR first, LPTSTR rest)
+Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
{
TCHAR szFullName[MAX_PATH];
-#ifndef __REACTOS__
+ TCHAR *first = NULL;
+ TCHAR *rest = NULL;
+ TCHAR *full = NULL;
TCHAR szWindowTitle[MAX_PATH];
-#endif
DWORD dwExitCode = 0;
#ifdef _DEBUG
- DebugPrintf ("Execute: \'%s\' \'%s\'\n", first, rest);
+ DebugPrintf (_T("Execute: \'%s\' \'%s\'\n"), first, rest);
#endif
+ /* we need biger buffer that First, Rest, Full are already
+ need rewrite some code to use realloc when it need instead
+ of add 512bytes extra */
+
+ first = malloc ( _tcslen(First) + 512 * sizeof(TCHAR));
+ if (first == NULL)
+ {
+ error_out_of_memory();
+ return ;
+ }
+
+ rest = malloc ( _tcslen(Rest) + 512 * sizeof(TCHAR));
+ if (rest == NULL)
+ {
+ free (full);
+ error_out_of_memory();
+ return ;
+ }
+
+ full = malloc ( _tcslen(Full) + 512 * sizeof(TCHAR));
+ if (full == NULL)
+ {
+ free (full);
+ free (rest);
+ error_out_of_memory();
+ return ;
+ }
+
+
+ /* Though it was already parsed once, we have a different set of rules
+ for parsing before we pass to CreateProccess */
+ if(!_tcschr(Full,_T('\"')))
+ {
+ _tcscpy(first,First);
+ _tcscpy(rest,Rest);
+ _tcscpy(full,Full);
+ }
+ else
+ {
+ INT i = 0;
+ BOOL bInside = FALSE;
+ rest[0] = _T('\0');
+ full[0] = _T('\0');
+ first[0] = _T('\0');
+ _tcscpy(first,Full);
+ /* find the end of the command and start of the args */
+ for(i = 0; i < _tcslen(first); i++)
+ {
+ if(!_tcsncmp(&first[i], _T("\""), 1))
+ bInside = !bInside;
+ if(!_tcsncmp(&first[i], _T(" "), 1) && !bInside)
+ {
+ _tcscpy(rest,&first[i]);
+ first[i] = _T('\0');
+ break;
+ }
+
+ }
+ i = 0;
+ /* remove any slashes */
+ while(i < _tcslen(first))
+ {
+ if(first[i] == _T('\"'))
+ memmove(&first[i],&first[i + 1], _tcslen(&first[i]) * sizeof(TCHAR));
+ else
+ i++;
+ }
+ /* Drop quotes around it just in case there is a space */
+ _tcscpy(full,_T("\""));
+ _tcscat(full,first);
+ _tcscat(full,_T("\" "));
+ _tcscat(full,rest);
+ }
+
/* 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 */
{
TCHAR str[4];
str[0]=first[0];
- str[1]=':';
- str[2]='\\';
+ str[1]=_T(':');
+ str[2]=_T('\\');
str[3]=0;
working = SetCurrentDirectory(str);
}
- if (!working) ConErrPuts (INVALIDDRIVE);
+ if (!working) ConErrResPuts (STRING_FREE_ERROR1);
return;
}
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")))
{
#ifdef _DEBUG
- DebugPrintf ("[BATCH: %s %s]\n", szFullName, rest);
+ DebugPrintf (_T("[BATCH: %s %s]\n"), szFullName, rest);
#endif
Batch (szFullName, first, rest);
}
else
{
/* exec the program */
- TCHAR szFullCmdLine [CMDLINE_LENGTH];
PROCESS_INFORMATION prci;
STARTUPINFO stui;
#ifdef _DEBUG
- DebugPrintf ("[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));
stui.wShowWindow = SW_SHOWDEFAULT;
// return console to standard mode
- SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
- ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
-
+ 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,
&stui,
&prci))
{
- /* FIXME: Protect this with critical section */
- bChildProcessRunning = TRUE;
- dwChildProcessId = prci.dwProcessId;
+ if (IsConsoleProcess(prci.hProcess))
+ {
+ /* FIXME: Protect this with critical section */
+ bChildProcessRunning = TRUE;
+ dwChildProcessId = prci.dwProcessId;
- WaitForSingleObject (prci.hProcess, INFINITE);
+ WaitForSingleObject (prci.hProcess, INFINITE);
- /* FIXME: Protect this with critical section */
- bChildProcessRunning = TRUE;
+ /* FIXME: Protect this with critical section */
+ bChildProcessRunning = FALSE;
- GetExitCodeProcess (prci.hProcess, &dwExitCode);
- nErrorLevel = (INT)dwExitCode;
+ GetExitCodeProcess (prci.hProcess, &dwExitCode);
+ nErrorLevel = (INT)dwExitCode;
+ }
CloseHandle (prci.hThread);
CloseHandle (prci.hProcess);
}
else
{
- ErrorMessage (GetLastError (),
- "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 );
}
-#ifndef __REACTOS__
- SetConsoleTitle (szWindowTitle);
-#endif
+ /* Get code page if it has been change */
+ InputCodePage= GetConsoleCP();
+ OutputCodePage = GetConsoleOutputCP();
+ SetConsoleTitle (szWindowTitle);
+
+ free(first);
+ free(rest);
+ free(full);
}
static VOID
DoCommand (LPTSTR line)
{
- TCHAR com[MAX_PATH]; /* the first word in the command */
+ 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;
#ifdef _DEBUG
- DebugPrintf ("DoCommand: (\'%s\')\n", line);
+ DebugPrintf (_T("DoCommand: (\'%s\')\n"), line);
#endif /* DEBUG */
/* Skip over initial white space */
- while (isspace (*rest))
- rest++;
+ while (_istspace (*line))
+ line++;
+ rest = line;
cstart = rest;
/* Anything to do ? */
if (*rest)
{
- /* Copy over 1st word as lower case */
- while (!IsDelimiter (*rest))
- *cp++ = _totlower (*rest++);
+ if (*rest == _T('"'))
+ {
+ /* treat quoted words specially */
+
+ rest++;
+
+ while(*rest != _T('\0') && *rest != _T('"'))
+ *cp++ = _totlower (*rest++);
+ if (*rest == _T('"'))
+ rest++;
+ }
+ else
+ {
+ while (!IsDelimiter (*rest))
+ *cp++ = _totlower (*rest++);
+ }
+
/* Terminate first word */
*cp = _T('\0');
+ /* commands are limited to MAX_PATH */
+ if(_tcslen(com) > MAX_PATH)
+ {
+ error_bad_command();
+ return;
+ }
+
/* Skip over whitespace to rest of line */
while (_istspace (*rest))
rest++;
/* 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
- TCHAR in[CMDLINE_LENGTH] = "";
- TCHAR out[CMDLINE_LENGTH] = "";
- TCHAR err[CMDLINE_LENGTH] = "";
+ TCHAR in[CMDLINE_LENGTH] = _T("");
+ TCHAR out[CMDLINE_LENGTH] = _T("");
+ TCHAR err[CMDLINE_LENGTH] = _T("");
TCHAR szTempPath[MAX_PATH] = _T(".\\");
- TCHAR szFileName[2][MAX_PATH] = {"", ""};
+ TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};
HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
LPTSTR t = NULL;
INT num = 0;
INT nRedirFlags = 0;
-
+ INT Length;
+ UINT Attributes;
+ BOOL bNewBatch = TRUE;
HANDLE hOldConIn;
HANDLE hOldConOut;
HANDLE hOldConErr;
s = &cmdline[0];
#ifdef _DEBUG
- DebugPrintf ("ParseCommandLine: (\'%s\')\n", s);
+ DebugPrintf (_T("ParseCommandLine: (\'%s\')\n"), s);
#endif /* DEBUG */
#ifdef FEATURE_ALIASES
#ifdef FEATURE_REDIRECTION
/* find the temp path to store temporary files */
- GetTempPath (MAX_PATH, szTempPath);
+ 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("\\"));
;
_tcscpy (err, t);
+ if(bc && !_tcslen (in) && _tcslen (bc->In))
+ _tcscpy(in, bc->In);
+ if(bc && !out[0] && _tcslen(bc->Out))
+ {
+ nRedirFlags |= OUTPUT_APPEND;
+ _tcscpy(out, bc->Out);
+ }
+ if(bc && !_tcslen (err) && _tcslen (bc->Err))
+ {
+ nRedirFlags |= ERROR_APPEND;
+ _tcscpy(err, bc->Err);
+ }
+
+
/* Set up the initial conditions ... */
/* preserve STDIN, STDOUT and STDERR handles */
hOldConIn = GetStdHandle (STD_INPUT_HANDLE);
HANDLE hFile;
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
+ /* we need make sure the LastError msg is zero before calling CreateFile */
+ SetLastError(0);
+
+ /* Set up pipe for the standard input handler */
hFile = CreateFile (in, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
- ConErrPrintf ("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 ("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
}
/* Now do all but the last pipe command */
- *szFileName[0] = '\0';
+ *szFileName[0] = _T('\0');
hFile[0] = INVALID_HANDLE_VALUE;
while (num-- > 1)
{
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
+
+ /* Create unique temporary file name */
+ GetTempFileName (szTempPath, _T("CMD"), 0, szFileName[1]);
- /* Create unique temporary file name */
- GetTempFileName (szTempPath, "CMD", 0, szFileName[1]);
+ /* we need make sure the LastError msg is zero before calling CreateFile */
+ SetLastError(0);
/* 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)
+ {
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR2, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg);
+ return;
+ }
+
SetStdHandle (STD_OUTPUT_HANDLE, hFile[1]);
DoCommand (s);
_tcscpy (szFileName[0], szFileName[1]);
*szFileName[1] = _T('\0');
+ /* we need make sure the LastError msg is zero before calling CreateFile */
+ SetLastError(0);
+
/* open new stdin file */
hFile[0] = CreateFile (szFileName[0], GENERIC_READ, 0, &sa,
OPEN_EXISTING, FILE_ATTRIBUTE_TEMPORARY, NULL);
/* Final output to here */
HANDLE hFile;
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
+
+ /* we need make sure the LastError msg is zero before calling CreateFile */
+ SetLastError(0);
- hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_READ, &sa,
+ hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, &sa,
(nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
{
- ConErrPrintf ("Can't redirect to file %s\n", out);
- return;
+ INT size = _tcslen(out)-1;
+
+ if (out[size] != _T(':'))
+ {
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, out);
+ return;
+ }
+
+ out[size]=_T('\0');
+ hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, &sa,
+ (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, out);
+ return;
+ }
+
}
if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile))
{
- ConErrPrintf ("Can't redirect to file %s\n", out);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, out);
return;
}
{
hFile = CreateFile (err,
GENERIC_WRITE,
- 0,
+ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
&sa,
(nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
- ConErrPrintf ("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 ("Can't redirect to file %s\n", err);
+ LoadString(CMD_ModuleHandle, STRING_CMD_ERROR3, szMsg, RC_STRING_MAX_SIZE);
+ ConErrPrintf(szMsg, err);
return;
}
CloseHandle (hErr);
hOldConErr = INVALID_HANDLE_VALUE;
}
+
+ if(bc)
+ bNewBatch = FALSE;
#endif
/* process final command */
DoCommand (s);
#ifdef FEATURE_REDIRECTION
+ if(bNewBatch && bc)
+ AddBatchRedirection(in, out, err);
/* 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... */
cp = commandline;
while (*ip)
{
- if (*ip == _T('%'))
+ if (*ip == _T('%'))
{
switch (*++ip)
{
case _T('9'):
if ((tp = FindArg (*ip - _T('0'))))
{
- cp = stpcpy (cp, tp);
+ cp = _stpcpy (cp, tp);
ip++;
}
else
if ((tp != NULL) &&
(tp <= _tcschr(ip, _T(' ')) - 1))
{
- char evar[512];
+ INT size = 512;
+ TCHAR *evar;
*tp = _T('\0');
- /* FIXME: This is just a quick hack!! */
- /* Do a proper memory allocation!! */
- if (GetEnvironmentVariable (ip, evar, 512))
- cp = stpcpy (cp, evar);
-
+ /* FIXME: Correct error handling when it can not alloc memmory */
+
+ /* %CD% */
+ if (_tcsicmp(ip,_T("cd")) ==0)
+ {
+ TCHAR szPath[MAX_PATH];
+ GetCurrentDirectory (MAX_PATH, szPath);
+ cp = _stpcpy (cp, szPath);
+ }
+ /* %TIME% */
+ else if (_tcsicmp(ip,_T("time")) ==0)
+ {
+ TCHAR szTime[40];
+ SYSTEMTIME t;
+ GetSystemTime(&t);
+
+ _sntprintf(szTime ,40,_T("%02d%c%02d%c%02d%c%02d"), t.wHour, cTimeSeparator,t.wMinute , cTimeSeparator,t.wSecond , cDecimalSeparator, t.wMilliseconds );
+ cp = _stpcpy (cp, szTime);
+ }
+
+ /* %DATE% */
+ else if (_tcsicmp(ip,_T("date")) ==0)
+ {
+ TCHAR szDate[40];
+
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, _T("ddd"), szDate, sizeof (szDate));
+ cp = _stpcpy (cp, szDate);
+ cp = _stpcpy (cp, _T(" "));
+ GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, sizeof (szDate));
+ cp = _stpcpy (cp, szDate);
+ }
+
+ /* %RANDOM% */
+ else if (_tcsicmp(ip,_T("random")) ==0)
+ {
+ TCHAR szRand[40];
+ /* Get random number */
+ _itot(rand(),szRand,10);
+ cp = _stpcpy (cp, szRand);
+ }
+
+ /* %CMDCMDLINE% */
+ else if (_tcsicmp(ip,_T("cmdcmdline")) ==0)
+ {
+ TCHAR *pargv;
+ /* Get random number */
+ pargv = GetCommandLine();
+ cp = _stpcpy (cp, pargv);
+ }
+
+ /* %CMDEXTVERSION% */
+ else if (_tcsicmp(ip,_T("cmdextversion")) ==0)
+ {
+ TCHAR szVER[40];
+ /* Set version number to 2 */
+ _itot(2,szVER,10);
+ cp = _stpcpy (cp, szVER);
+ }
+
+ /* %ERRORLEVEL% */
+ else if (_tcsicmp(ip,_T("errorlevel")) ==0)
+ {
+ evar = malloc ( size * sizeof(TCHAR));
+ if (evar==NULL)
+ return 1;
+
+ memset(evar,0,512 * sizeof(TCHAR));
+ _itot(nErrorLevel,evar,10);
+ cp = _stpcpy (cp, evar);
+
+ free(evar);
+ }
+ else
+ {
+ evar = malloc ( 512 * sizeof(TCHAR));
+ if (evar==NULL)
+ return 1;
+ SetLastError(0);
+ size = GetEnvironmentVariable (ip, evar, 512);
+ if(GetLastError() == ERROR_ENVVAR_NOT_FOUND)
+ {
+ /* if no env var is found you must
+ continue with what was input*/
+ cp = _stpcpy (cp, _T("%"));
+ cp = _stpcpy (cp, ip);
+ cp = _stpcpy (cp, _T("%"));
+ }
+ else
+ {
+ if (size > 512)
+ {
+ evar = realloc(evar,size * sizeof(TCHAR) );
+ if (evar==NULL)
+ {
+ return 1;
+ }
+ size = GetEnvironmentVariable (ip, evar, size);
+ }
+
+ if (size)
+ {
+ cp = _stpcpy (cp, evar);
+ }
+ }
+
+ free(evar);
+ }
+
ip = tp + 1;
+
}
else
{
*cp++ = _T('%');
- }
+ }
+
break;
}
continue;
}
+
+
+
if (_istcntrl (*ip))
*ip = _T(' ');
*cp++ = *ip++;
*cp = _T('\0');
/* strip trailing spaces */
- while ((--cp >= commandline) && _istspace (*cp));
+ while ((--cp >= commandline) && _istspace (*cp));
*(cp + 1) = _T('\0');
-
+
/* JPP 19980807 */
/* Echo batch file line */
if (bEchoThisLine)
/*
* control-break handler.
*/
-BOOL BreakHandler (DWORD dwCtrlType)
+BOOL WINAPI BreakHandler (DWORD dwCtrlType)
{
+
if ((dwCtrlType != CTRL_C_EVENT) &&
(dwCtrlType != CTRL_BREAK_EVENT))
return FALSE;
VOID AddBreakHandler (VOID)
{
-#ifndef __REACTOS__
- SetConsoleCtrlHandler ((PHANDLER_ROUTINE)&BreakHandler,
- TRUE);
-#endif
+ SetConsoleCtrlHandler ((PHANDLER_ROUTINE)BreakHandler, TRUE);
}
VOID RemoveBreakHandler (VOID)
{
-#ifndef __REACTOS__
- SetConsoleCtrlHandler (NULL, FALSE);
-#endif
+ SetConsoleCtrlHandler ((PHANDLER_ROUTINE)BreakHandler, FALSE);
}
* show commands and options that are available.
*
*/
+#if 0
static VOID
ShowCommands (VOID)
{
/* print command list */
- ConOutPrintf (_T("\nInternal commands available:\n"));
- PrintCommandList ();
+ ConOutResPuts(STRING_CMD_HELP1);
+ PrintCommandList();
/* print feature list */
- ConOutPuts ("\nFeatures available:");
+ ConOutResPuts(STRING_CMD_HELP2);
+
#ifdef FEATURE_ALIASES
- ConOutPuts (" [aliases]");
+ ConOutResPuts(STRING_CMD_HELP3);
#endif
#ifdef FEATURE_HISTORY
- ConOutPuts (" [history]");
+ ConOutResPuts(STRING_CMD_HELP4);
#endif
#ifdef FEATURE_UNIX_FILENAME_COMPLETION
- ConOutPuts (" [unix filename completion]");
+ ConOutResPuts(STRING_CMD_HELP5);
#endif
#ifdef FEATURE_DIRECTORY_STACK
- ConOutPuts (" [directory stack]");
+ ConOutResPuts(STRING_CMD_HELP6);
#endif
#ifdef FEATURE_REDIRECTION
- ConOutPuts (" [redirections and piping]");
+ ConOutResPuts(STRING_CMD_HELP7);
#endif
- ConOutChar ('\n');
+ ConOutChar(_T('\n'));
}
-
+#endif
/*
* set up global initializations and process parameters
*
*/
static VOID
-Initialize (int argc, char *argv[])
+Initialize (int argc, TCHAR* argv[])
{
TCHAR commandline[CMDLINE_LENGTH];
TCHAR ModuleName[_MAX_PATH + 1];
INT i;
+ TCHAR lpBuffer[2];
+
+ //INT len;
+ //TCHAR *ptr, *cmdLine;
+
+ /* get version information */
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx (&osvi);
+
+ /* Some people like to run ReactOS cmd.exe on Win98, it helps in the
+ build process. So don't link implicitly against ntdll.dll, load it
+ dynamically instead */
+
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ /* ntdll is always present on NT */
+ NtDllModule = GetModuleHandle(TEXT("ntdll.dll"));
+ }
+ else
+ {
+ /* not all 9x versions have a ntdll.dll, try to load it */
+ NtDllModule = LoadLibrary(TEXT("ntdll.dll"));
+ }
+
+ if (NtDllModule != NULL)
+ {
+ NtQueryInformationProcessPtr = (NtQueryInformationProcessProc)GetProcAddress(NtDllModule, "NtQueryInformationProcess");
+ NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory");
+ }
+
#ifdef _DEBUG
INT x;
- DebugPrintf ("[command args:\n");
+ DebugPrintf (_T("[command args:\n"));
for (x = 0; x < argc; x++)
{
- DebugPrintf ("%d. %s\n", x, argv[x]);
+ DebugPrintf (_T("%d. %s\n"), x, argv[x]);
}
- DebugPrintf ("]\n");
+ DebugPrintf (_T("]\n"));
#endif
- /* get version information */
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- GetVersionEx (&osvi);
-
InitLocale ();
/* get default input and output console handles */
hOut = GetStdHandle (STD_OUTPUT_HANDLE);
hIn = GetStdHandle (STD_INPUT_HANDLE);
+ /* Set EnvironmentVariable PROMPT if it does not exists any env value.
+ for you can change the EnvirommentVariable for prompt before cmd start
+ this patch are not 100% right, if it does not exists a PROMPT value cmd should use
+ $P$G as defualt not set EnvirommentVariable PROMPT to $P$G if it does not exists */
+ if (GetEnvironmentVariable(_T("PROMPT"),lpBuffer, 2 * sizeof(TCHAR)) == 0)
+ SetEnvironmentVariable (_T("PROMPT"), _T("$P$G"));
+
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);
+ ConOutResPaging(TRUE,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 ("", "");
+ cmd_date (_T(""), _T(""));
#endif
#ifdef INCLUDE_CMD_TIME
- cmd_time ("", "");
+ cmd_time (_T(""), _T(""));
#endif
}
else
{
/* This just runs a program and exits */
++i;
- if (argv[i])
+ if (i < argc)
{
_tcscpy (commandline, argv[i]);
- while (argv[++i])
+ while (++i < argc)
{
- _tcscat (commandline, " ");
+ _tcscat (commandline, _T(" "));
_tcscat (commandline, argv[i]);
}
{
/* This just runs a program and remains */
++i;
- if (argv[i])
+ if (i < argc)
{
_tcscpy (commandline, argv[i]);
- while (argv[++i])
+ while (++i < argc)
{
- _tcscat (commandline, " ");
+ _tcscat (commandline, _T(" "));
_tcscat (commandline, argv[i]);
}
else if (!_tcsnicmp (argv[i], _T("/t:"), 3))
{
/* process /t (color) argument */
- wDefColor = (WORD)strtoul (&argv[i][3], NULL, 16);
+ wDefColor = (WORD)_tcstoul (&argv[i][3], NULL, 16);
wColor = wDefColor;
SetScreenColor (wColor, TRUE);
}
}
/* 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 ("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, char *argv[])
+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 ("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 ("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 ("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
RemoveBreakHandler ();
SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
+
+ if (NtDllModule != NULL)
+ {
+ FreeLibrary(NtDllModule);
+ }
}
+#ifdef __REACTOS__
+#ifdef _UNICODE
+PWCHAR * _CommandLineToArgvW(PWCHAR lpCmdLine, int *pNumArgs)
+{
+ PWCHAR * argvw = NULL;
+ PWCHAR ptr = lpCmdLine;
+ PWCHAR str;
+ int len;
+ int NumArgs;
+
+ NumArgs = 0;
+
+ while(lpCmdLine && *lpCmdLine)
+ {
+ while (iswspace(*lpCmdLine)) lpCmdLine++;
+ if (*lpCmdLine)
+ {
+ if ((NumArgs % 10)==0)
+ {
+ PWCHAR * old_argvw = argvw;
+ argvw = malloc((NumArgs + 10) * sizeof(PWCHAR));
+ memcpy(argvw, old_argvw, NumArgs * sizeof(PWCHAR));
+ free(old_argvw);
+ }
+ ptr = wcschr(lpCmdLine, L' ');
+ if (ptr)
+ {
+ len = ptr - lpCmdLine;
+ }
+ else
+ {
+ len = wcslen(lpCmdLine);
+ }
+ str = malloc((len + 1) * sizeof(WCHAR));
+ memcpy(str, lpCmdLine, len * sizeof(WCHAR));
+ str[len] = 0;
+ argvw[NumArgs]=str;
+ NumArgs++;
+ lpCmdLine = ptr;
+ }
+ }
+ *pNumArgs = NumArgs;
+ return argvw;
+}
+#endif
+#endif
/*
* main function
*/
-int main (int argc, char *argv[])
+#ifdef _UNICODE
+int _main(void)
+#else
+int _main (int argc, char *argv[])
+#endif
{
+ TCHAR startPath[MAX_PATH];
CONSOLE_SCREEN_BUFFER_INFO Info;
INT nExitCode;
+#ifdef _UNICODE
+ PWCHAR * argv;
+ int argc=0;
+#ifdef __REACTOS__
+ argv = _CommandLineToArgvW(GetCommandLineW(), &argc);
+#else
+ argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+#endif
+#endif
+
+ GetCurrentDirectory(MAX_PATH,startPath);
+ _tchdir(startPath);
SetFileApisToOEM();
+ InputCodePage= 0;
+ OutputCodePage = 0;
- AllocConsole();
- if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &Info) == FALSE)
+ hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, 0, NULL);
+ if (GetConsoleScreenBufferInfo(hConsole, &Info) == FALSE)
{
- fprintf(stderr, "GetConsoleScreenBufferInfo: Error: %ld\n", GetLastError());
-#ifndef __REACTOS__
- /* On ReactOS GetConsoleScreenBufferInfo returns an error if the stdin
- handle is redirected to a pipe or file. This stops windres from working. */
+ ConErrFormatMessage(GetLastError());
return(1);
-#endif
}
wColor = Info.wAttributes;
wDefColor = wColor;
+ InputCodePage= GetConsoleCP();
+ OutputCodePage = GetConsoleOutputCP();
+ CMD_ModuleHandle = GetModuleHandle(NULL);
+
/* check switches on command-line */
Initialize(argc, argv);
/* call prompt routine */
nExitCode = ProcessInput(FALSE);
+
/* do the cleanup */
Cleanup(argc, argv);
+
return(nExitCode);
}