Don't print a CR, if the command line is from a batch file and starts with a '@'.
[reactos.git] / reactos / subsys / system / cmd / cmd.c
index f2238a3..bc7c05e 100644 (file)
  */
 
 #include <precomp.h>
+#include <malloc.h>
 #include "resource.h"
 
 #ifndef NT_SUCCESS
@@ -422,15 +423,12 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
        /* search the PATH environment variable for the binary */
        if (!SearchForExecutable (first, szFullName))
        {
-               if (!SearchForExecutable (full, szFullName))
-               {
                        error_bad_command ();
                        free (first);
                        free (rest);
                        free (full);
                        free (szFullName);
                        return;
-               }
 
        }
 
@@ -1061,6 +1059,213 @@ 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;
+       }
+
+       return _T(""); /* not found - return empty 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
@@ -1072,12 +1277,12 @@ ProcessInput (BOOL bFlag)
 {
        TCHAR commandline[CMDLINE_LENGTH];
        TCHAR readline[CMDLINE_LENGTH];
-       LPTSTR tp = NULL;
        LPTSTR ip;
        LPTSTR cp;
        LPCTSTR tmp;
        BOOL bEchoThisLine;
-       BOOL bSubstitute;
+       BOOL bModeSetA;
+        BOOL bIsBatch;
 
        do
        {
@@ -1090,175 +1295,29 @@ 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;
-               bSubstitute = TRUE;
+               bModeSetA = FALSE;
                while (*ip)
                {
-                       if (bSubstitute && *ip == _T('%'))
+                       if ( *ip == _T('%') )
                        {
-                               switch (*++ip)
-                               {
-                                       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'))))
-                                               {
-                                                       cp = _stpcpy (cp, tp);
-                                                       ip++;
-                                               }
-                                               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 */
-
-                                                       /* %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;
-                               }
+                               UINT envNameLen;
+                               LPCTSTR envVal = GetParsedEnvVar ( ip, &envNameLen, bModeSetA );
+                               if ( !envVal )
+                                       return 1;
+                               ip += envNameLen;
+                               cp = _stpcpy ( cp, envVal );
                                continue;
                        }
 
@@ -1266,7 +1325,7 @@ ProcessInput (BOOL bFlag)
                                *ip = _T(' ');
                        *cp++ = *ip++;
 
-                       /* HACK HACK HACK check whether bSubstitute needs to be toggled */
+                       /* HACK HACK HACK check whether bModeSetA needs to be toggled */
                        *cp = 0;
                        tmp = commandline;
                        tmp += _tcsspn(tmp,_T(" \t"));
@@ -1298,7 +1357,7 @@ ProcessInput (BOOL bFlag)
                                 * 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 ( bSubstitute )
+                               if ( !bModeSetA )
                                {
                                        /* look for set /a */
                                        if ( !_tcsnicmp(tmp,_T("set"),3) )
@@ -1306,7 +1365,7 @@ ProcessInput (BOOL bFlag)
                                                tmp += 3;
                                                tmp += _tcsspn(tmp,_T(" \t"));
                                                if ( !_tcsnicmp(tmp,_T("/a"),2) )
-                                                       bSubstitute = FALSE;
+                                                       bModeSetA = TRUE;
                                        }
                                }
                                /* if we're not currently substituting, it means we're
@@ -1319,12 +1378,12 @@ ProcessInput (BOOL bFlag)
                                        {
                                                if ( *tmp == _T('^') )
                                                {
-                                                       if ( _tcschr(_T("<>|&"), *++tmp ) )
+                                                       if ( _tcschr(_T("<>|&"), *++tmp ) && *tmp )
                                                                ++tmp;
                                                }
                                                else
                                                {
-                                                       bSubstitute = TRUE;
+                                                       bModeSetA = FALSE;
                                                        break;
                                                }
                                        }
@@ -1350,7 +1409,7 @@ ProcessInput (BOOL bFlag)
                if (*commandline)
                {
                        ParseCommandLine (commandline);
-                       if (bEcho && !bIgnoreEcho)
+                       if (bEcho && !bIgnoreEcho && (!bIsBatch || bEchoThisLine))
                                ConOutChar ('\n');
                        bIgnoreEcho = FALSE;
                }
@@ -1496,7 +1555,7 @@ Initialize (int argc, TCHAR* argv[])
           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)
+       if (GetEnvironmentVariable(_T("PROMPT"),lpBuffer, sizeof(lpBuffer) / sizeof(lpBuffer[0])) == 0)
            SetEnvironmentVariable (_T("PROMPT"), _T("$P$G"));
 
 
@@ -1563,13 +1622,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);
                                }
                        }
@@ -1594,24 +1654,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 */
@@ -1638,10 +1680,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")))
        {
@@ -1654,25 +1692,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 ();
@@ -1703,53 +1722,6 @@ static VOID Cleanup (int argc, TCHAR *argv[])
        }
 }
 
-#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
  */
@@ -1765,11 +1737,7 @@ int _main (int argc, char *argv[])
 #ifdef _UNICODE
        PWCHAR * argv;
        int argc=0;
-#ifdef __REACTOS__
-       argv = _CommandLineToArgvW(GetCommandLineW(), &argc);
-#else
        argv = CommandLineToArgvW(GetCommandLineW(), &argc);
-#endif
 #endif
 
        GetCurrentDirectory(MAX_PATH,startPath);