X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fsubsys%2Fsystem%2Fcmd%2Fcmd.c;h=e62a014078a10d4082ccccbbeb19023a0e72055d;hp=dde407d689010e769560a066793dae77411c10d1;hb=593d6d0f28c2aa09f47fe7608beafea1b25da7cc;hpb=d1c9fb08f5c29b7a01dadffe9f37c6debcf14b0e diff --git a/reactos/subsys/system/cmd/cmd.c b/reactos/subsys/system/cmd/cmd.c index dde407d6890..e62a014078a 100644 --- a/reactos/subsys/system/cmd/cmd.c +++ b/reactos/subsys/system/cmd/cmd.c @@ -137,20 +137,21 @@ * * 06-jul-2005 (Magnus Olsen ) * translate '%errorlevel%' to the internal value. - * Add proper memmory alloc ProcessInput, the error + * Add proper memmory alloc ProcessInput, the error * handling for memmory handling need to be improve */ -#include "precomp.h" +#include +#include #include "resource.h" #ifndef NT_SUCCESS #define NT_SUCCESS(StatCode) ((NTSTATUS)(StatCode) >= 0) #endif -typedef NTSTATUS (STDCALL *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS, +typedef NTSTATUS (WINAPI *NtQueryInformationProcessProc)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); -typedef NTSTATUS (STDCALL *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG); +typedef NTSTATUS (WINAPI *NtReadVirtualMemoryProc)(HANDLE, PVOID, PVOID, ULONG, PULONG); BOOL bExit = FALSE; /* indicates EXIT was typed */ BOOL bCanExit = TRUE; /* indicates if this shell is exitable */ @@ -164,10 +165,10 @@ HANDLE hIn; HANDLE hOut; HANDLE hConsole; HANDLE CMD_ModuleHandle; +HMODULE NtDllModule; -static NtQueryInformationProcessProc NtQueryInformationProcessPtr; -static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr; -static BOOL NtDllChecked = FALSE; +static NtQueryInformationProcessProc NtQueryInformationProcessPtr = NULL; +static NtReadVirtualMemoryProc NtReadVirtualMemoryPtr = NULL; #ifdef INCLUDE_CMD_COLOR WORD wColor; /* current color */ @@ -175,10 +176,45 @@ WORD wDefColor; /* default color */ #endif /* - * is character a delimeter when used on first word? + * convert * + * insert commas into a number */ +INT +ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperator) +{ + TCHAR temp[32]; + INT c = 0; + INT n = 0; + + if (num.QuadPart == 0) + { + des[0] = _T('0'); + des[1] = _T('\0'); + n = 1; + } + else + { + temp[31] = 0; + while (num.QuadPart > 0) + { + if ((((c + 1) % (nNumberGroups + 1)) == 0) && (bPutSeperator)) + temp[30 - c++] = cThousandSeparator; + temp[30 - c++] = (TCHAR)(num.QuadPart % 10) + _T('0'); + num.QuadPart /= 10; + } + for (n = 0; n <= c; n++) + des[n] = temp[31 - c + n]; + } + + return n; +} + +/* + * is character a delimeter when used on first word? + * + */ static BOOL IsDelimiter (TCHAR c) { return (c == _T('/') || c == _T('=') || c == _T('\0') || _istspace (c)); @@ -193,36 +229,15 @@ static BOOL IsConsoleProcess(HANDLE Process) PROCESS_BASIC_INFORMATION Info; PEB ProcessPeb; ULONG BytesRead; - HMODULE NtDllModule; - - /* 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 (! NtDllChecked) - { - NtDllChecked = TRUE; - NtDllModule = LoadLibrary(_T("ntdll.dll")); - if (NULL == NtDllModule) - { - /* Probably non-WinNT system. Just wait for the commands - to finish. */ - NtQueryInformationProcessPtr = NULL; - NtReadVirtualMemoryPtr = NULL; - return TRUE; - } - NtQueryInformationProcessPtr = (NtQueryInformationProcessProc) - GetProcAddress(NtDllModule, "NtQueryInformationProcess"); - NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc) - GetProcAddress(NtDllModule, "NtReadVirtualMemory"); - } if (NULL == NtQueryInformationProcessPtr || NULL == NtReadVirtualMemoryPtr) { return TRUE; } - Status = NtQueryInformationProcessPtr(Process, ProcessBasicInformation, - &Info, sizeof(PROCESS_BASIC_INFORMATION), NULL); + Status = NtQueryInformationProcessPtr ( + Process, ProcessBasicInformation, + &Info, sizeof(PROCESS_BASIC_INFORMATION), NULL); if (! NT_SUCCESS(Status)) { #ifdef _DEBUG @@ -230,8 +245,9 @@ static BOOL IsConsoleProcess(HANDLE Process) #endif return TRUE; } - Status = NtReadVirtualMemoryPtr(Process, Info.PebBaseAddress, &ProcessPeb, - sizeof(PEB), &BytesRead); + Status = NtReadVirtualMemoryPtr ( + Process, Info.PebBaseAddress, &ProcessPeb, + sizeof(PEB), &BytesRead); if (! NT_SUCCESS(Status) || sizeof(PEB) != BytesRead) { #ifdef _DEBUG @@ -252,24 +268,24 @@ static BOOL IsConsoleProcess(HANDLE Process) #endif typedef HINSTANCE (WINAPI *MYEX)( - HWND hwnd, - LPCTSTR lpOperation, - LPCTSTR lpFile, - LPCTSTR lpParameters, - LPCTSTR lpDirectory, - INT nShowCmd + HWND hwnd, + LPCTSTR lpOperation, + LPCTSTR lpFile, + LPCTSTR lpParameters, + LPCTSTR lpDirectory, + INT nShowCmd ); static BOOL RunFile(LPTSTR filename) { - HMODULE hShell32; - MYEX hShExt; - HINSTANCE ret; + HMODULE hShell32; + MYEX hShExt; + HINSTANCE ret; #ifdef _DEBUG - DebugPrintf (_T("RunFile(%s)\n"), filename); + DebugPrintf (_T("RunFile(%s)\n"), filename); #endif hShell32 = LoadLibrary(_T("SHELL32.DLL")); if (!hShell32) @@ -309,23 +325,110 @@ static BOOL RunFile(LPTSTR filename) /* * 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 full, LPTSTR first, LPTSTR rest) +Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest) { - TCHAR szFullName[MAX_PATH]; -#ifndef __REACTOS__ + TCHAR *szFullName=NULL; + TCHAR *first = NULL; + TCHAR *rest = NULL; + TCHAR *full = NULL; + TCHAR *dot = NULL; TCHAR szWindowTitle[MAX_PATH]; -#endif DWORD dwExitCode = 0; #ifdef _DEBUG 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 (first); + error_out_of_memory(); + return ; + } + + full = malloc ( (_tcslen(Full) + 512) * sizeof(TCHAR)); + if (full == NULL) + { + free (first); + free (rest); + error_out_of_memory(); + return ; + } + + szFullName = malloc ( (_tcslen(Full) + 512) * sizeof(TCHAR)); + if (full == NULL) + { + free (first); + free (rest); + free (full); + 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 + { + UINT 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(":")))) { @@ -343,6 +446,11 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest) if (!working) ConErrResPuts (STRING_FREE_ERROR1); + free (first); + free (rest); + free (full); + free (szFullName); + return; } @@ -350,17 +458,20 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest) /* search the PATH environment variable for the binary */ if (!SearchForExecutable (first, szFullName)) { - error_bad_command (); - return; + error_bad_command (); + free (first); + free (rest); + free (full); + free (szFullName); + 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"))) + dot = _tcsrchr (szFullName, _T('.')); + if (dot && (!_tcsicmp (dot, _T(".bat")) || !_tcsicmp (dot, _T(".cmd")))) { #ifdef _DEBUG DebugPrintf (_T("[BATCH: %s %s]\n"), szFullName, rest); @@ -393,11 +504,12 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest) NULL, NULL, TRUE, - CREATE_NEW_PROCESS_GROUP, + 0, /* CREATE_NEW_PROCESS_GROUP */ NULL, NULL, &stui, &prci)) + { if (IsConsoleProcess(prci.hProcess)) { @@ -431,16 +543,20 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest) } } // restore console mode - SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ), - ENABLE_PROCESSED_INPUT ); + SetConsoleMode ( + GetStdHandle( STD_INPUT_HANDLE ), + ENABLE_PROCESSED_INPUT ); } /* Get code page if it has been change */ InputCodePage= GetConsoleCP(); - OutputCodePage = GetConsoleOutputCP(); -#ifndef __REACTOS__ + OutputCodePage = GetConsoleOutputCP(); SetConsoleTitle (szWindowTitle); -#endif + + free(first); + free(rest); + free(full); + free (szFullName); } @@ -456,8 +572,8 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest) static VOID DoCommand (LPTSTR line) { - TCHAR com[CMDLINE_LENGTH]; /* the first word in the command */ - LPTSTR cp = com; + TCHAR *com = NULL; /* the first word in the command */ + TCHAR *cp = NULL; LPTSTR cstart; LPTSTR rest; /* pointer to the rest of the command line */ INT cl; @@ -467,6 +583,14 @@ DoCommand (LPTSTR line) DebugPrintf (_T("DoCommand: (\'%s\')\n"), line); #endif /* DEBUG */ + com = malloc( (_tcslen(line) +512)*sizeof(TCHAR) ); + if (com == NULL) + { + error_out_of_memory(); + return; + } + + cp = com; /* Skip over initial white space */ while (_istspace (*line)) line++; @@ -498,16 +622,22 @@ DoCommand (LPTSTR line) /* Terminate first word */ *cp = _T('\0'); - /* commands are limited to MAX_PATH */ + /* Do not limit commands to MAX_PATH */ + /* if(_tcslen(com) > MAX_PATH) { - error_bad_command(); - return; + error_bad_command(); + free(com); + return; } + */ - /* Skip over whitespace to rest of line */ - while (_istspace (*rest)) + /* Skip over whitespace to rest of line, exclude 'echo' command */ + if (_tcsicmp (com, _T("echo"))) + { + while (_istspace (*rest)) rest++; + } /* Scan internal command table */ for (cmdptr = cmds;; cmdptr++) @@ -551,6 +681,9 @@ DoCommand (LPTSTR line) } } } + /* Just in case a CTRL+C slipped through a command */ + bCtrlBreak = FALSE; + free(com); } @@ -576,7 +709,7 @@ VOID ParseCommandLine (LPTSTR cmd) INT nRedirFlags = 0; INT Length; UINT Attributes; - + BOOL bNewBatch = TRUE; HANDLE hOldConIn; HANDLE hOldConOut; HANDLE hOldConErr; @@ -629,6 +762,20 @@ VOID ParseCommandLine (LPTSTR cmd) ; _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); @@ -641,6 +788,10 @@ VOID ParseCommandLine (LPTSTR cmd) 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) @@ -672,9 +823,13 @@ VOID ParseCommandLine (LPTSTR cmd) /* Create unique temporary file name */ GetTempFileName (szTempPath, _T("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); @@ -709,6 +864,9 @@ VOID ParseCommandLine (LPTSTR cmd) _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); @@ -725,14 +883,36 @@ VOID ParseCommandLine (LPTSTR cmd) HANDLE hFile; SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; - hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_READ, &sa, + /* we need make sure the LastError msg is zero before calling CreateFile */ + SetLastError(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, NULL); + 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; + 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)) @@ -784,10 +964,10 @@ VOID ParseCommandLine (LPTSTR cmd) { 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) { @@ -824,12 +1004,17 @@ VOID ParseCommandLine (LPTSTR cmd) 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); @@ -915,6 +1100,215 @@ VOID ParseCommandLine (LPTSTR cmd) #endif /* FEATURE_REDIRECTION */ } +BOOL +GrowIfNecessary ( UINT needed, LPTSTR* ret, UINT* retlen ) +{ + if ( *ret && needed < *retlen ) + return TRUE; + *retlen = needed; + if ( *ret ) + free ( *ret ); + *ret = (LPTSTR)malloc ( *retlen * sizeof(TCHAR) ); + if ( !*ret ) + SetLastError ( ERROR_OUTOFMEMORY ); + return *ret != NULL; +} + +LPCTSTR +GetEnvVarOrSpecial ( LPCTSTR varName ) +{ + static LPTSTR ret = NULL; + static UINT retlen = 0; + UINT size; + + size = GetEnvironmentVariable ( varName, ret, retlen ); + if ( size > retlen ) + { + if ( !GrowIfNecessary ( size, &ret, &retlen ) ) + return NULL; + size = GetEnvironmentVariable ( varName, ret, retlen ); + } + if ( size ) + return ret; + + /* env var doesn't exist, look for a "special" one */ + /* %CD% */ + if (_tcsicmp(varName,_T("cd")) ==0) + { + size = GetCurrentDirectory ( retlen, ret ); + if ( size > retlen ) + { + if ( !GrowIfNecessary ( size, &ret, &retlen ) ) + return NULL; + size = GetCurrentDirectory ( retlen, ret ); + } + if ( !size ) + return NULL; + return ret; + } + /* %TIME% */ + else if (_tcsicmp(varName,_T("time")) ==0) + { + SYSTEMTIME t; + if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) ) + return NULL; + GetSystemTime(&t); + _sntprintf ( ret, retlen, _T("%02d%c%02d%c%02d%c%02d"), + t.wHour, cTimeSeparator, t.wMinute, cTimeSeparator, + t.wSecond, cDecimalSeparator, t.wMilliseconds ); + return ret; + } + /* %DATE% */ + else if (_tcsicmp(varName,_T("date")) ==0) + { + LPTSTR tmp; + + if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) ) + return NULL; + size = GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, _T("ddd"), ret, retlen ); + /* TODO FIXME - test whether GetDateFormat() can return a value indicating the buffer wasn't big enough */ + if ( !size ) + return NULL; + tmp = ret + _tcslen(ret); + *tmp++ = _T(' '); + size = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, tmp, retlen-(tmp-ret)); + /* TODO FIXME - test whether GetDateFormat() can return a value indicating the buffer wasn't big enough */ + if ( !size ) + return NULL; + return ret; + } + + /* %RANDOM% */ + else if (_tcsicmp(varName,_T("random")) ==0) + { + if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) ) + return NULL; + /* Get random number */ + _itot(rand(),ret,10); + return ret; + } + + /* %CMDCMDLINE% */ + else if (_tcsicmp(varName,_T("cmdcmdline")) ==0) + { + return GetCommandLine(); + } + + /* %CMDEXTVERSION% */ + else if (_tcsicmp(varName,_T("cmdextversion")) ==0) + { + if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) ) + return NULL; + /* Set version number to 2 */ + _itot(2,ret,10); + return ret; + } + + /* %ERRORLEVEL% */ + else if (_tcsicmp(varName,_T("errorlevel")) ==0) + { + if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) ) + return NULL; + _itot(nErrorLevel,ret,10); + return ret; + } + + GrowIfNecessary(_tcslen(varName) + 2, &ret, &retlen); + _stprintf(ret,_T("%%%s%%"),varName); + return ret; /* not found - return orginal string */ +} + +LPCTSTR +GetParsedEnvVar ( LPCTSTR varName, UINT* varNameLen, BOOL ModeSetA ) +{ + static LPTSTR ret = NULL; + static UINT retlen = 0; + LPTSTR p, tmp; + UINT size; + + if ( varNameLen ) + *varNameLen = 0; + SetLastError(0); + if ( *varName++ != '%' ) + return NULL; + switch ( *varName ) + { + case _T('0'): + case _T('1'): + case _T('2'): + case _T('3'): + case _T('4'): + case _T('5'): + case _T('6'): + case _T('7'): + case _T('8'): + case _T('9'): + if ((tmp = FindArg (*varName - _T('0')))) + { + if ( varNameLen ) + *varNameLen = 2; + if ( !*tmp ) + return _T(""); + if ( !GrowIfNecessary ( _tcslen(tmp)+1, &ret, &retlen ) ) + return NULL; + _tcscpy ( ret, tmp ); + return ret; + } + if ( !GrowIfNecessary ( 3, &ret, &retlen ) ) + return NULL; + ret[0] = _T('%'); + ret[1] = *varName; + ret[2] = 0; + if ( varNameLen ) + *varNameLen = 2; + return ret; + + case _T('%'): + if ( !GrowIfNecessary ( 2, &ret, &retlen ) ) + return NULL; + ret[0] = _T('%'); + ret[1] = 0; + if ( varNameLen ) + *varNameLen = 2; + return ret; + + case _T('?'): + /* TODO FIXME 10 is only max size for 32-bit */ + if ( !GrowIfNecessary ( 11, &ret, &retlen ) ) + return NULL; + _sntprintf ( ret, retlen, _T("%u"), nErrorLevel); + ret[retlen-1] = 0; + if ( varNameLen ) + *varNameLen = 2; + return ret; + } + if ( ModeSetA ) + { + /* HACK for set/a */ + if ( !GrowIfNecessary ( 2, &ret, &retlen ) ) + return NULL; + ret[0] = _T('%'); + ret[1] = 0; + if ( varNameLen ) + *varNameLen = 1; + return ret; + } + p = _tcschr ( varName, _T('%') ); + if ( !p ) + { + SetLastError ( ERROR_INVALID_PARAMETER ); + return NULL; + } + size = p-varName; + if ( varNameLen ) + *varNameLen = size + 2; + p = alloca ( (size+1) * sizeof(TCHAR) ); + memmove ( p, varName, size * sizeof(TCHAR) ); + p[size] = 0; + varName = p; + return GetEnvVarOrSpecial ( varName ); +} + /* * do the prompt/input/process loop @@ -926,11 +1320,12 @@ ProcessInput (BOOL bFlag) { TCHAR commandline[CMDLINE_LENGTH]; TCHAR readline[CMDLINE_LENGTH]; - LPTSTR tp = NULL; LPTSTR ip; LPTSTR cp; + LPCTSTR tmp; BOOL bEchoThisLine; - + BOOL bModeSetA; + BOOL bIsBatch; do { @@ -943,113 +1338,109 @@ ProcessInput (BOOL bFlag) ReadCommand (readline, CMDLINE_LENGTH); ip = readline; bEchoThisLine = FALSE; + bIsBatch = FALSE; } + else + { + bIsBatch = TRUE; + } + + /* skip leading blanks */ + while ( _istspace(*ip) ) + ++ip; cp = commandline; + bModeSetA = FALSE; while (*ip) { - if (*ip == _T('%')) + if ( *ip == _T('%') ) + { + UINT envNameLen; + LPCTSTR envVal = GetParsedEnvVar ( ip, &envNameLen, bModeSetA ); + if ( envVal ) + { + ip += envNameLen; + cp = _stpcpy ( cp, envVal ); + } + } + + if (_istcntrl (*ip)) + *ip = _T(' '); + *cp++ = *ip++; + + /* HACK HACK HACK check whether bModeSetA needs to be toggled */ + *cp = 0; + tmp = commandline; + tmp += _tcsspn(tmp,_T(" \t")); + /* first we find and skip and pre-redirections... */ + while ( _tcschr(_T("<>"),*tmp) + || !_tcsncmp(tmp,_T("1>"),2) + || !_tcsncmp(tmp,_T("2>"),2) ) + { + if ( _istdigit(*tmp) ) + tmp += 2; + else + tmp++; + tmp += _tcsspn(tmp,_T(" \t")); + if ( *tmp == _T('\"') ) + { + tmp = _tcschr(tmp+1,_T('\"')); + if ( tmp ) + ++tmp; + } + else + tmp = _tcspbrk(tmp,_T(" \t")); + tmp += _tcsspn(tmp,_T(" \t")); + } + /* we should now be pointing to the actual command + * (if there is one yet)*/ + if ( tmp ) { - switch (*++ip) + /* if we're currently substituting ( which is default ) + * check to see if we've parsed out a set/a. if so, we + * need to disable substitution until we come across a + * redirection */ + if ( !bModeSetA ) { - case _T('%'): - *cp++ = *ip++; - break; - - case _T('0'): - case _T('1'): - case _T('2'): - case _T('3'): - case _T('4'): - case _T('5'): - case _T('6'): - case _T('7'): - case _T('8'): - case _T('9'): - if ((tp = FindArg (*ip - _T('0')))) + /* look for set /a */ + if ( !_tcsnicmp(tmp,_T("set"),3) ) + { + tmp += 3; + tmp += _tcsspn(tmp,_T(" \t")); + if ( !_tcsnicmp(tmp,_T("/a"),2) ) + bModeSetA = TRUE; + } + } + /* if we're not currently substituting, it means we're + * already inside a set /a. now we need to look for + * a redirection in order to turn redirection back on */ + else + { + /* look for redirector of some kind after the command */ + while ( (tmp = _tcspbrk ( tmp, _T("^<>|") )) ) + { + if ( *tmp == _T('^') ) { - cp = _stpcpy (cp, tp); - ip++; + if ( _tcschr(_T("<>|&"), *++tmp ) && *tmp ) + ++tmp; } else - *cp++ = _T('%'); - break; - - case _T('?'): - cp += _stprintf (cp, _T("%u"), nErrorLevel); - ip++; - break; - - default: - tp = _tcschr(ip, _T('%')); - if ((tp != NULL) && - (tp <= _tcschr(ip, _T(' ')) - 1)) { - INT size = 512; - TCHAR *evar; - *tp = _T('\0'); - - /* FIXME: Correct error handling when it can not alloc memmory */ - evar = malloc ( size * sizeof(TCHAR)); - if (evar==NULL) - return 1; - - if (_tcsicmp(ip,_T("errorlevel")) ==0) - { - memset(evar,0,512 * sizeof(TCHAR)); - _itot(nErrorLevel,evar,10); - cp = _stpcpy (cp, evar); - } - else - { - size = GetEnvironmentVariable (ip, evar, size); - if (size!=0) - { - evar = realloc(evar,size * sizeof(TCHAR) ); - if (evar!=NULL) - { - size = GetEnvironmentVariable (ip, evar, size); - } - } - - if (size) - { - cp = _stpcpy (cp, evar); - } - } - - if (evar!=NULL) - { - free(evar); - } - ip = tp + 1; - + bModeSetA = FALSE; + break; } - 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) @@ -1058,10 +1449,10 @@ ProcessInput (BOOL bFlag) ConOutPuts (commandline); } - if (*commandline) + if (*commandline && !CheckCtrlBreak(BREAK_INPUT)) { ParseCommandLine (commandline); - if (bEcho && !bIgnoreEcho) + if (bEcho && !bIgnoreEcho && (!bIsBatch || bEchoThisLine)) ConOutChar ('\n'); bIgnoreEcho = FALSE; } @@ -1078,20 +1469,50 @@ ProcessInput (BOOL bFlag) BOOL WINAPI BreakHandler (DWORD dwCtrlType) { + DWORD dwWritten; + INPUT_RECORD rec; + static BOOL SelfGenerated = FALSE; + + rec.EventType = KEY_EVENT; + rec.Event.KeyEvent.bKeyDown = TRUE; + rec.Event.KeyEvent.wRepeatCount = 1; + rec.Event.KeyEvent.wVirtualKeyCode = _T('C'); + rec.Event.KeyEvent.wVirtualScanCode = _T('C') - 35; + rec.Event.KeyEvent.uChar.AsciiChar = _T('C'); + rec.Event.KeyEvent.uChar.UnicodeChar = _T('C'); + rec.Event.KeyEvent.dwControlKeyState = RIGHT_CTRL_PRESSED; + + WriteConsoleInput( + hIn, + &rec, + 1, + &dwWritten); + if ((dwCtrlType != CTRL_C_EVENT) && (dwCtrlType != CTRL_BREAK_EVENT)) + { return FALSE; - + } + else + { + if(SelfGenerated) + { + SelfGenerated = FALSE; + return TRUE; + } + } + if (bChildProcessRunning == TRUE) { - GenerateConsoleCtrlEvent (CTRL_C_EVENT, - dwChildProcessId); + SelfGenerated = TRUE; + GenerateConsoleCtrlEvent (dwCtrlType, 0); return TRUE; } + bCtrlBreak = TRUE; /* FIXME: Handle batch files */ - /* FIXME: Print "^C" */ + //ConOutPrintf(_T("^C")); return TRUE; @@ -1157,32 +1578,59 @@ 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; +#ifdef _DEBUG DebugPrintf (_T("[command args:\n")); - for (x = 0; x < argc; x++) + for (i = 0; i < argc; i++) { - DebugPrintf (_T("%d. %s\n"), x, argv[x]); + DebugPrintf (_T("%d. %s\n"), i, argv[i]); } 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, sizeof(lpBuffer) / sizeof(lpBuffer[0])) == 0) + SetEnvironmentVariable (_T("PROMPT"), _T("$P$G")); + if (argc >= 2 && !_tcsncmp (argv[1], _T("/?"), 2)) { @@ -1247,13 +1695,14 @@ Initialize (int argc, TCHAR* argv[]) ++i; if (i < argc) { - _tcscpy (commandline, argv[i]); + _tcscpy (commandline, _T("\"")); + _tcscat (commandline, argv[i]); + _tcscat (commandline, _T("\"")); while (++i < argc) { _tcscat (commandline, _T(" ")); _tcscat (commandline, argv[i]); } - ParseCommandLine(commandline); } } @@ -1278,24 +1727,6 @@ Initialize (int argc, TCHAR* argv[]) { 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 (IsExistingFile (_T("commandline"))) - { - LoadString(CMD_ModuleHandle, STRING_CMD_ERROR4, szMsg, RC_STRING_MAX_SIZE); - ConErrPrintf(szMsg, commandline); - ParseCommandLine (commandline); - } - } -#endif #ifdef FEATURE_DIR_STACK /* initialize directory stack */ @@ -1322,10 +1753,6 @@ Initialize (int argc, TCHAR* argv[]) static VOID Cleanup (int argc, TCHAR *argv[]) { -#ifndef __REACTOS__ - TCHAR szMsg[RC_STRING_MAX_SIZE]; -#endif - /* run cmdexit.bat */ if (IsExistingFile (_T("cmdexit.bat"))) { @@ -1338,25 +1765,6 @@ static VOID Cleanup (int argc, TCHAR *argv[]) ConErrResPuts (STRING_CMD_ERROR5); 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 (IsExistingFile (_T("commandline"))) - { - LoadString(CMD_ModuleHandle, STRING_CMD_ERROR4, szMsg, RC_STRING_MAX_SIZE); - ConErrPrintf(szMsg, commandline); - ParseCommandLine (commandline); - } - } -#endif #ifdef FEATURE_ALIASES DestroyAlias (); @@ -1380,105 +1788,63 @@ static VOID Cleanup (int argc, TCHAR *argv[]) RemoveBreakHandler (); SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ), ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT ); -} -#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; + if (NtDllModule != NULL) + { + FreeLibrary(NtDllModule); + } } -#endif -#endif /* * main function */ #ifdef _UNICODE -int main(void) +int _main(void) #else -int main (int argc, char *argv[]) +int _main (int argc, char *argv[]) #endif { - CONSOLE_SCREEN_BUFFER_INFO Info; - INT nExitCode; + 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 + PWCHAR * argv; + int argc=0; + argv = CommandLineToArgvW(GetCommandLineW(), &argc); #endif - SetFileApisToOEM(); - InputCodePage= 0; - OutputCodePage = 0; + GetCurrentDirectory(MAX_PATH,startPath); + _tchdir(startPath); - hConsole = CreateFile(_T("CONOUT$"), GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, 0, NULL); - if (GetConsoleScreenBufferInfo(hConsole, &Info) == FALSE) - { - ConOutFormatMessage(GetLastError()); - return(1); - } - wColor = Info.wAttributes; - wDefColor = wColor; + SetFileApisToOEM(); + InputCodePage= 0; + OutputCodePage = 0; - InputCodePage= GetConsoleCP(); - OutputCodePage = GetConsoleOutputCP(); - CMD_ModuleHandle = GetModuleHandle(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) + { + ConErrFormatMessage(GetLastError()); + return(1); + } + wColor = Info.wAttributes; + wDefColor = wColor; + + InputCodePage= GetConsoleCP(); + OutputCodePage = GetConsoleOutputCP(); + CMD_ModuleHandle = GetModuleHandle(NULL); - /* check switches on command-line */ - Initialize(argc, argv); + /* check switches on command-line */ + Initialize(argc, argv); - /* call prompt routine */ - nExitCode = ProcessInput(FALSE); + /* call prompt routine */ + nExitCode = ProcessInput(FALSE); - /* do the cleanup */ - Cleanup(argc, argv); + /* do the cleanup */ + Cleanup(argc, argv); - return(nExitCode); + return(nExitCode); } /* EOF */