Restore console title after running a command
[reactos.git] / reactos / subsys / system / cmd / cmd.c
index c735114..d9327a5 100644 (file)
@@ -164,10 +164,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 */
@@ -193,28 +193,6 @@ 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)
        {
@@ -309,23 +287,99 @@ 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 *first = NULL;
+       TCHAR *rest = NULL; 
+       TCHAR *full = 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 (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(":"))))
        {
@@ -354,9 +408,7 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest)
                return;
        }
 
-#ifndef __REACTOS__
        GetConsoleTitle (szWindowTitle, MAX_PATH);
-#endif
 
        /* check if this is a .BAT or .CMD file */
        if (!_tcsicmp (_tcsrchr (szFullName, _T('.')), _T(".bat")) ||
@@ -438,9 +490,11 @@ Execute (LPTSTR full, LPTSTR first, LPTSTR rest)
        /* Get code page if it has been change */
        InputCodePage= GetConsoleCP();
     OutputCodePage = GetConsoleOutputCP();
-#ifndef __REACTOS__
-       SetConsoleTitle (szWindowTitle);
-#endif
+    SetConsoleTitle (szWindowTitle);
+
+ free(first);
+ free(rest);
+ free(full);
 }
 
 
@@ -576,7 +630,7 @@ VOID ParseCommandLine (LPTSTR cmd)
        INT  nRedirFlags = 0;
        INT  Length;
        UINT Attributes;
-
+       BOOL bNewBatch = TRUE;
        HANDLE hOldConIn;
        HANDLE hOldConOut;
        HANDLE hOldConErr;
@@ -629,6 +683,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);
@@ -648,7 +716,7 @@ VOID ParseCommandLine (LPTSTR cmd)
                hFile = CreateFile (in, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING,
                                    FILE_ATTRIBUTE_NORMAL, NULL);
                if (hFile == INVALID_HANDLE_VALUE)
-               {      
+               {
                        LoadString(CMD_ModuleHandle, STRING_CMD_ERROR1, szMsg, RC_STRING_MAX_SIZE);
                        ConErrPrintf(szMsg, in);
                        return;
@@ -739,9 +807,9 @@ VOID ParseCommandLine (LPTSTR cmd)
     /* 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);
+                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
                
     if (hFile == INVALID_HANDLE_VALUE)
                {
@@ -755,9 +823,9 @@ VOID ParseCommandLine (LPTSTR cmd)
       }
       
       out[size]=_T('\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);
+                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
 
      if (hFile == INVALID_HANDLE_VALUE)
      {
@@ -817,10 +885,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)
                        {
@@ -857,12 +925,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);
@@ -964,7 +1037,7 @@ ProcessInput (BOOL bFlag)
        LPTSTR cp;
        BOOL bEchoThisLine;
 
-
        do
        {
                /* if no batch input then... */
@@ -981,7 +1054,7 @@ ProcessInput (BOOL bFlag)
                cp = commandline;
                while (*ip)
                {
-                       if (*ip == _T('%'))
+         if (*ip == _T('%'))
                        {
                                switch (*++ip)
                                {
@@ -1031,12 +1104,14 @@ ProcessInput (BOOL bFlag)
                            GetCurrentDirectory (MAX_PATH, szPath);
                 cp = _stpcpy (cp, szPath);                 
               }
-
               /* %TIME% */
               else if (_tcsicmp(ip,_T("time")) ==0)
               {
-                TCHAR szTime[40];                                                               
-                GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, szTime, sizeof(szTime));              
+                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);                                   
               }
               
@@ -1097,8 +1172,18 @@ ProcessInput (BOOL bFlag)
                 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) );
@@ -1113,6 +1198,7 @@ ProcessInput (BOOL bFlag)
                 {
                                                                 cp = _stpcpy (cp, evar);
                 }
+                                        }
 
                 free(evar);
               }
@@ -1252,9 +1338,35 @@ 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
@@ -1268,16 +1380,19 @@ Initialize (int argc, TCHAR* argv[])
        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))
        {
@@ -1475,6 +1590,11 @@ static VOID Cleanup (int argc, TCHAR *argv[])
        RemoveBreakHandler ();
        SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
                        ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
+
+       if (NtDllModule != NULL)
+       {
+               FreeLibrary(NtDllModule);
+       }
 }
 
 #ifdef __REACTOS__
@@ -1533,6 +1653,7 @@ int _main(void)
 int _main (int argc, char *argv[])
 #endif
 {
+  TCHAR startPath[MAX_PATH];
   CONSOLE_SCREEN_BUFFER_INFO Info;
   INT nExitCode;
 #ifdef _UNICODE
@@ -1544,7 +1665,9 @@ int _main (int argc, char *argv[])
   argv = CommandLineToArgvW(GetCommandLineW(), &argc);
 #endif
 #endif
-     
+      
+  GetCurrentDirectory(MAX_PATH,startPath);
+  _tchdir(startPath);
 
   SetFileApisToOEM();
   InputCodePage= 0;