- Remove hard-coded reference to cmdstart.bat and load it from registry (Software...
[reactos.git] / reactos / base / shell / cmd / cmd.c
index 526d01b..f2b9243 100644 (file)
  *        Fixed carrage return output to better match MSDOS with echo
  *        on or off. (marked with "JPP 19980708")
  *
- *    07-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    07-Dec-1998 (Eric Kohl)
  *        First ReactOS release.
  *        Extended length of commandline buffers to 512.
  *
- *    13-Dec-1998 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    13-Dec-1998 (Eric Kohl)
  *        Added COMSPEC environment variable.
  *        Added "/t" support (color) on cmd command line.
  *
- *    07-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    07-Jan-1999 (Eric Kohl)
  *        Added help text ("cmd /?").
  *
- *    25-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    25-Jan-1999 (Eric Kohl)
  *        Unicode and redirection safe!
  *        Fixed redirections and piping.
  *        Piping is based on temporary files, but basic support
  *        for anonymous pipes already exists.
  *
- *    27-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    27-Jan-1999 (Eric Kohl)
  *        Replaced spawnl() by CreateProcess().
  *
- *    22-Oct-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    22-Oct-1999 (Eric Kohl)
  *        Added break handler.
  *
- *    15-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    15-Dec-1999 (Eric Kohl)
  *        Fixed current directory
  *
- *    28-Dec-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
+ *    28-Dec-1999 (Eric Kohl)
  *        Restore window title after program/batch execution
  *
- *    03-Feb-2001 (Eric Kohl <ekohl@rz-online.de>)
+ *    03-Feb-2001 (Eric Kohl)
  *        Workaround because argc[0] is NULL under ReactOS
  *
  *    23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
  */
 
 #include <precomp.h>
-#include <malloc.h>
-#include "resource.h"
 
 #ifndef NT_SUCCESS
 #define NT_SUCCESS(StatCode)  ((NTSTATUS)(StatCode) >= 0)
@@ -187,6 +185,9 @@ ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperato
        INT c = 0;
        INT n = 0;
 
+       if (len <= 1)
+               return 0;
+
        if (num.QuadPart == 0)
        {
                des[0] = _T('0');
@@ -203,6 +204,8 @@ ConvertULargeInteger (ULARGE_INTEGER num, LPTSTR des, INT len, BOOL bPutSeperato
                         temp[30 - c++] = (TCHAR)(num.QuadPart % 10) + _T('0');
                        num.QuadPart /= 10;
                }
+        if (c>len)
+                       c=len;
 
                for (n = 0; n <= c; n++)
                        des[n] = temp[31 - c + n];
@@ -346,10 +349,10 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
 #endif
 
        /* we need biger buffer that First, Rest, Full are already
-          need rewrite some code to use realloc when it need instead
+          need rewrite some code to use cmd_realloc when it need instead
           of add 512bytes extra */
 
-       first = malloc ( (_tcslen(First) + 512) * sizeof(TCHAR));
+       first = cmd_alloc ( (_tcslen(First) + 512) * sizeof(TCHAR));
        if (first == NULL)
        {
                error_out_of_memory();
@@ -357,31 +360,31 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
                return ;
        }
 
-       rest = malloc ( (_tcslen(Rest) + 512) * sizeof(TCHAR));
+       rest = cmd_alloc ( (_tcslen(Rest) + 512) * sizeof(TCHAR));
        if (rest == NULL)
        {
-               free (first);
+               cmd_free (first);
                error_out_of_memory();
                 nErrorLevel = 1;
                return ;
        }
 
-       full = malloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
+       full = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
        if (full == NULL)
        {
-               free (first);
-               free (rest);
+               cmd_free (first);
+               cmd_free (rest);
                error_out_of_memory();
                 nErrorLevel = 1;
                return ;
        }
 
-       szFullName = malloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
+       szFullName = cmd_alloc ( (_tcslen(Full) + 512) * sizeof(TCHAR));
        if (full == NULL)
        {
-               free (first);
-               free (rest);
-               free (full);
+               cmd_free (first);
+               cmd_free (rest);
+               cmd_free (full);
                error_out_of_memory();
                 nErrorLevel = 1;
                return ;
@@ -450,10 +453,10 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
 
                if (!working) ConErrResPuts (STRING_FREE_ERROR1);
 
-               free (first);
-               free (rest);
-               free (full);
-               free (szFullName);
+               cmd_free (first);
+               cmd_free (rest);
+               cmd_free (full);
+               cmd_free (szFullName);
                 nErrorLevel = 1;
                return;
        }
@@ -463,10 +466,10 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
        if (!SearchForExecutable (first, szFullName))
        {
                        error_bad_command ();
-                       free (first);
-                       free (rest);
-                       free (full);
-                       free (szFullName);
+                       cmd_free (first);
+                       cmd_free (rest);
+                       cmd_free (full);
+                       cmd_free (szFullName);
                         nErrorLevel = 1;
                        return;
 
@@ -514,7 +517,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
                                   NULL,
                                   &stui,
                                   &prci))
-                                                  
+
                {
                        if (IsConsoleProcess(prci.hProcess))
                        {
@@ -567,10 +570,10 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
        OutputCodePage = GetConsoleOutputCP();
        SetConsoleTitle (szWindowTitle);
 
-       free(first);
-       free(rest);
-       free(full);
-       free (szFullName);
+       cmd_free(first);
+       cmd_free(rest);
+       cmd_free(full);
+       cmd_free (szFullName);
 }
 
 
@@ -583,7 +586,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
  *
  */
 
-static VOID
+VOID
 DoCommand (LPTSTR line)
 {
        TCHAR *com = NULL;  /* the first word in the command */
@@ -597,7 +600,7 @@ DoCommand (LPTSTR line)
        DebugPrintf (_T("DoCommand: (\'%s\')\n"), line);
 #endif /* DEBUG */
 
-       com = malloc( (_tcslen(line) +512)*sizeof(TCHAR) );
+       com = cmd_alloc( (_tcslen(line) +512)*sizeof(TCHAR) );
        if (com == NULL)
        {
                error_out_of_memory();
@@ -641,13 +644,13 @@ DoCommand (LPTSTR line)
                if(_tcslen(com) > MAX_PATH)
                {
                        error_bad_command();
-                       free(com);
+                       cmd_free(com);
                        return;
                }
                */
 
                /* Skip over whitespace to rest of line, exclude 'echo' command */
-               if (_tcsicmp (com, _T("echo"))) 
+               if (_tcsicmp (com, _T("echo")))
                {
                        while (_istspace (*rest))
                        rest++;
@@ -695,7 +698,7 @@ DoCommand (LPTSTR line)
                        }
                }
        }
-       free(com);
+       cmd_free(com);
 }
 
 
@@ -1113,18 +1116,23 @@ VOID ParseCommandLine (LPTSTR cmd)
 }
 
 BOOL
-GrowIfNecessary ( UINT needed, LPTSTR* ret, UINT* retlen )
+GrowIfNecessary_dbg ( UINT needed, LPTSTR* ret, UINT* retlen, const char *file, int line )
 {
        if ( *ret && needed < *retlen )
                return TRUE;
        *retlen = needed;
        if ( *ret )
-               free ( *ret );
-       *ret = (LPTSTR)malloc ( *retlen * sizeof(TCHAR) );
+               cmd_free ( *ret );
+#ifdef _DEBUG_MEM
+       *ret = (LPTSTR)cmd_alloc_dbg ( *retlen * sizeof(TCHAR), file, line );
+#else
+       *ret = (LPTSTR)cmd_alloc ( *retlen * sizeof(TCHAR) );
+#endif
        if ( !*ret )
                SetLastError ( ERROR_OUTOFMEMORY );
        return *ret != NULL;
 }
+#define GrowIfNecessary(x, y, z) GrowIfNecessary_dbg(x, y, z, __FILE__, __LINE__)
 
 LPCTSTR
 GetEnvVarOrSpecial ( LPCTSTR varName )
@@ -1167,24 +1175,18 @@ GetEnvVarOrSpecial ( LPCTSTR varName )
                GetSystemTime(&t);
                _sntprintf ( ret, retlen, _T("%02d%c%02d%c%02d%c%02d"),
                        t.wHour, cTimeSeparator, t.wMinute, cTimeSeparator,
-                       t.wSecond, cDecimalSeparator, t.wMilliseconds );
+                       t.wSecond, cDecimalSeparator, t.wMilliseconds / 10);
                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 )
+               if ( !GrowIfNecessary ( GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0), &ret, &retlen ) )
                        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 */
+
+               size = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, ret, retlen);
+
                if ( !size )
                        return NULL;
                return ret;
@@ -1225,7 +1227,7 @@ GetEnvVarOrSpecial ( LPCTSTR varName )
                return ret;
        }
 
-       GrowIfNecessary(_tcslen(varName) + 2, &ret, &retlen);
+       GrowIfNecessary(_tcslen(varName) + 3, &ret, &retlen);
        _stprintf(ret,_T("%%%s%%"),varName);
        return ret; /* not found - return orginal string */
 }
@@ -1274,7 +1276,7 @@ GetParsedEnvVar ( LPCTSTR varName, UINT* varNameLen, BOOL ModeSetA )
                if ( varNameLen )
                        *varNameLen = 2;
                return ret;
-   
+
     case _T('*'):
         if(bc == NULL)
         {
@@ -1512,21 +1514,21 @@ BOOL WINAPI BreakHandler (DWORD dwCtrlType)
        DWORD                   dwWritten;
        INPUT_RECORD    rec;
        static BOOL SelfGenerated = FALSE;
-    
+
        if ((dwCtrlType != CTRL_C_EVENT) &&
            (dwCtrlType != CTRL_BREAK_EVENT))
        {
                return FALSE;
        }
        else
-       {               
+       {
                if(SelfGenerated)
                {
                        SelfGenerated = FALSE;
                        return TRUE;
                }
        }
-       
+
        if (bChildProcessRunning == TRUE)
        {
                SelfGenerated = TRUE;
@@ -1534,7 +1536,7 @@ BOOL WINAPI BreakHandler (DWORD dwCtrlType)
                return TRUE;
        }
 
-    
+
     rec.EventType = KEY_EVENT;
     rec.Event.KeyEvent.bKeyDown = TRUE;
     rec.Event.KeyEvent.wRepeatCount = 1;
@@ -1542,14 +1544,14 @@ BOOL WINAPI BreakHandler (DWORD dwCtrlType)
     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; 
+    rec.Event.KeyEvent.dwControlKeyState = RIGHT_CTRL_PRESSED;
 
     WriteConsoleInput(
         hIn,
         &rec,
         1,
                &dwWritten);
-        
+
        bCtrlBreak = TRUE;
        /* FIXME: Handle batch files */
 
@@ -1606,6 +1608,33 @@ ShowCommands (VOID)
 }
 #endif
 
+static VOID
+ExecuteAutoRunFile (VOID)
+{
+    TCHAR autorun[MAX_PATH];
+       DWORD len = MAX_PATH;
+       HKEY hkey;
+
+    if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
+                    _T("SOFTWARE\\Microsoft\\Command Processor"),
+                    0, 
+                    KEY_READ, 
+                    &hkey ) == ERROR_SUCCESS)
+    {
+           if(RegQueryValueEx(hkey, 
+                           _T("AutoRun"),
+                           0, 
+                           0, 
+                           (LPBYTE)autorun, 
+                           &len) == ERROR_SUCCESS)
+           {
+                   ParseCommandLine (autorun);
+           }
+    }
+
+       RegCloseKey(hkey);
+}
+
 /*
  * set up global initializations and process parameters
  *
@@ -1614,7 +1643,7 @@ ShowCommands (VOID)
  *
  */
 static VOID
-Initialize (int argc, TCHAR* argv[])
+Initialize (int argc, const TCHAR* argv[])
 {
        TCHAR commandline[CMDLINE_LENGTH];
        TCHAR ModuleName[_MAX_PATH + 1];
@@ -1676,7 +1705,7 @@ Initialize (int argc, TCHAR* argv[])
        if (argc >= 2 && !_tcsncmp (argv[1], _T("/?"), 2))
        {
                ConOutResPaging(TRUE,STRING_CMD_HELP8);
-               ExitProcess(0);
+               cmd_exit(0);
        }
        SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
 
@@ -1723,11 +1752,11 @@ Initialize (int argc, TCHAR* argv[])
                                        }
 
                                        ParseCommandLine(commandline);
-                                       ExitProcess (ProcessInput (TRUE));
+                                       cmd_exit (ProcessInput (TRUE));
                                }
                                else
                                {
-                                       ExitProcess (0);
+                                       cmd_exit (0);
                                }
                        }
                        else if (!_tcsicmp (argv[i], _T("/k")))
@@ -1758,16 +1787,17 @@ Initialize (int argc, TCHAR* argv[])
 #endif
                }
        }
+    else
+    {
+        /* Display a simple version string */
+        ConOutPrintf(_T("ReactOS Operating System [Version %s-%s]\n"), 
+            _T(KERNEL_RELEASE_STR),
+            _T(KERNEL_VERSION_BUILD_STR));
 
-       /* run cmdstart.bat */
-       if (IsExistingFile (_T("cmdstart.bat")))
-       {
-               ParseCommandLine (_T("cmdstart.bat"));
-       }
-       else if (IsExistingFile (_T("\\cmdstart.bat")))
-       {
-               ParseCommandLine (_T("\\cmdstart.bat"));
-       }
+           ConOutPuts (_T("(C) Copyright 1998-2008 ReactOS Team.\n"));
+    }
+
+    ExecuteAutoRunFile ();
 
 #ifdef FEATURE_DIR_STACK
        /* initialize directory stack */
@@ -1792,7 +1822,7 @@ Initialize (int argc, TCHAR* argv[])
 }
 
 
-static VOID Cleanup (int argc, TCHAR *argv[])
+static VOID Cleanup (int argc, const TCHAR *argv[])
 {
        /* run cmdexit.bat */
        if (IsExistingFile (_T("cmdexit.bat")))
@@ -1839,20 +1869,11 @@ static VOID Cleanup (int argc, TCHAR *argv[])
 /*
  * main function
  */
-#ifdef _UNICODE
-int _main(void)
-#else
-int _main (int argc, char *argv[])
-#endif
+int cmd_main (int argc, const TCHAR *argv[])
 {
        TCHAR startPath[MAX_PATH];
        CONSOLE_SCREEN_BUFFER_INFO Info;
        INT nExitCode;
-#ifdef _UNICODE
-       PWCHAR * argv;
-       int argc=0;
-       argv = CommandLineToArgvW(GetCommandLineW(), &argc);
-#endif
 
        GetCurrentDirectory(MAX_PATH,startPath);
        _tchdir(startPath);
@@ -1885,6 +1906,7 @@ int _main (int argc, char *argv[])
        /* do the cleanup */
        Cleanup(argc, argv);
 
+       cmd_exit(nExitCode);
        return(nExitCode);
 }