[ros-diffs] [jmorlan] 35295: - Moved ExpandAlias call from ParseCommandLine to ReadCommand; aliases should only be processed when reading from the console. Removed processing of %variable% substitutions in ExpandAlias - not necessary now that aliases are expanded earlier. - Rewrite %variable% substitution code, should be much more compatible with Windows cmd now.

jmorlan at svn.reactos.org jmorlan at svn.reactos.org
Wed Aug 13 01:46:15 CEST 2008


Author: jmorlan
Date: Tue Aug 12 18:46:15 2008
New Revision: 35295

URL: http://svn.reactos.org/svn/reactos?rev=35295&view=rev
Log:
- Moved ExpandAlias call from ParseCommandLine to ReadCommand; aliases should only be processed when reading from the console. Removed processing of %variable% substitutions in ExpandAlias - not necessary now that aliases are expanded earlier.
- Rewrite %variable% substitution code, should be much more compatible with Windows cmd now.

Modified:
    trunk/reactos/base/shell/cmd/alias.c
    trunk/reactos/base/shell/cmd/cmd.c
    trunk/reactos/base/shell/cmd/cmdinput.c

Modified: trunk/reactos/base/shell/cmd/alias.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/alias.c?rev=35295&r1=35294&r2=35295&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/alias.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/alias.c [iso-8859-1] Tue Aug 12 18:46:15 2008
@@ -89,8 +89,6 @@
 	TCHAR* position;
 	LPTSTR Token;
 	LPTSTR tmp;
-	LPTSTR ip, cp;
-	BOOL   bModeSetA = FALSE;
 
 	tmp = cmd_alloc(maxlen);
 	if (!tmp)
@@ -135,27 +133,6 @@
 	{
 		_tcscpy(cmd, buffer);
 	}
-
-	ip = cp = cmd;
-
-	while (*ip)
-	{
-		if ( (*ip == _T('%')) || (*ip == _T('!')) )
-		{
-			UINT envNameLen;
-			LPCTSTR envVal = GetParsedEnvVar ( ip, &envNameLen, bModeSetA );
-			if ( envVal )
-			{
-				ip += envNameLen;
-				cp = _stpcpy ( cp, envVal );
-			}
-		}
-
-		if (*ip != _T('\0') && (_istcntrl (*ip)))
-			*ip = _T(' ');
-		*cp++ = *ip++;
-	}
-	*cp = _T('\0');
 
 	cmd_free(buffer);
 	cmd_free(tmp);

Modified: trunk/reactos/base/shell/cmd/cmd.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmd.c?rev=35295&r1=35294&r2=35295&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmd.c [iso-8859-1] Tue Aug 12 18:46:15 2008
@@ -712,11 +712,6 @@
 
 	TRACE ("ParseCommandLine: (\'%s\')\n", debugstr_aw(s));
 
-#ifdef FEATURE_ALIASES
-	/* expand all aliases */
-	ExpandAlias (s, CMDLINE_LENGTH);
-#endif /* FEATURE_ALIAS */
-
 #ifdef FEATURE_REDIRECTION
 	/* find the temp path to store temporary files */
 	Length = GetTempPath (MAX_PATH, szTempPath);
@@ -1092,57 +1087,20 @@
 	static LPTSTR ret = NULL;
 	static UINT retlen = 0;
 	UINT size;
-	TCHAR varNameFixed[MAX_PATH];
-	TCHAR ReturnValue[MAX_PATH];
-	LPTSTR position;
-	LPTSTR Token;
-	SIZE_T i = 0;
-	INT StringPart[1] = {0};
-	
-	position = _tcsstr(varName, _T(":~"));
-	if (position)
-		_tcsncpy(varNameFixed, varName, (int) (position - varName));
-	else
-		_tcscpy(varNameFixed, varName);
-
-	size = GetEnvironmentVariable ( varNameFixed, ret, retlen );
+
+	size = GetEnvironmentVariable ( varName, ret, retlen );
 	if ( size > retlen )
 	{
 		if ( !GrowIfNecessary ( size, &ret, &retlen ) )
 			return NULL;
-		size = GetEnvironmentVariable ( varNameFixed, ret, retlen );
+		size = GetEnvironmentVariable ( varName, ret, retlen );
 	}
 	if ( size )
-	{
-		if (position)
-		{
-			position += 2;
-			if (_tcschr(position, _T(',')) != NULL)
-			{
-				Token = _tcstok(position, _T(","));
-				while ((Token != NULL) && (i < 2))
-				{
-					StringPart[i] = _ttoi(Token);
-					i++;
-					Token = _tcstok (NULL, _T(","));
-				}
-				if (i > 0)
-				{
-					if (StringPart[1] < 0)
-						StringPart[1] = _tcslen(ret + StringPart[0]) + StringPart[1];
-					_tcsncpy(ReturnValue, ret + StringPart[0], StringPart[1]);
-					_tcscpy(ret, ReturnValue);
-				}
-			}
-			return ret;
-		}
-		else
-			return ret;
-	}
+		return ret;
 
 	/* env var doesn't exist, look for a "special" one */
 	/* %CD% */
-	if (_tcsicmp(varNameFixed,_T("cd")) ==0)
+	if (_tcsicmp(varName,_T("cd")) ==0)
 	{
 		size = GetCurrentDirectory ( retlen, ret );
 		if ( size > retlen )
@@ -1156,7 +1114,7 @@
 		return ret;
 	}
 	/* %TIME% */
-	else if (_tcsicmp(varNameFixed,_T("time")) ==0)
+	else if (_tcsicmp(varName,_T("time")) ==0)
 	{
 		SYSTEMTIME t;
 		if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
@@ -1168,7 +1126,7 @@
 		return ret;
 	}
 	/* %DATE% */
-	else if (_tcsicmp(varNameFixed,_T("date")) ==0)
+	else if (_tcsicmp(varName,_T("date")) ==0)
 	{
 
 		if ( !GrowIfNecessary ( GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, NULL, 0), &ret, &retlen ) )
@@ -1182,7 +1140,7 @@
 	}
 
 	/* %RANDOM% */
-	else if (_tcsicmp(varNameFixed,_T("random")) ==0)
+	else if (_tcsicmp(varName,_T("random")) ==0)
 	{
 		if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
 			return NULL;
@@ -1192,13 +1150,13 @@
 	}
 
 	/* %CMDCMDLINE% */
-	else if (_tcsicmp(varNameFixed,_T("cmdcmdline")) ==0)
+	else if (_tcsicmp(varName,_T("cmdcmdline")) ==0)
 	{
 		return GetCommandLine();
 	}
 
 	/* %CMDEXTVERSION% */
-	else if (_tcsicmp(varNameFixed,_T("cmdextversion")) ==0)
+	else if (_tcsicmp(varName,_T("cmdextversion")) ==0)
 	{
 		if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
 			return NULL;
@@ -1208,7 +1166,7 @@
 	}
 
 	/* %ERRORLEVEL% */
-	else if (_tcsicmp(varNameFixed,_T("errorlevel")) ==0)
+	else if (_tcsicmp(varName,_T("errorlevel")) ==0)
 	{
 		if ( !GrowIfNecessary ( MAX_PATH, &ret, &retlen ) )
 			return NULL;
@@ -1216,30 +1174,17 @@
 		return ret;
 	}
 
-	GrowIfNecessary(_tcslen(varNameFixed) + 3, &ret, &retlen);
-	_stprintf(ret,_T("%%%s%%"),varNameFixed);
-	return ret; /* not found - return orginal string */
+	return NULL;
 }
 
 LPCTSTR
-GetParsedEnvVar ( LPCTSTR varName, UINT* varNameLen, BOOL ModeSetA )
+GetBatchVar ( LPCTSTR varName, UINT* varNameLen )
 {
 	static LPTSTR ret = NULL;
 	static UINT retlen = 0;
-	LPTSTR p, tmp;
-	UINT size;
-	TCHAR c;
 
 	if ( varNameLen )
-		*varNameLen = 0;
-	SetLastError(0);
-	c = *varName;
-
-	if ( (*varName != '!') && (*varName++ != '%') )
-		return NULL;
-
-	if (c == _T('!'))
-		varName++;
+		*varNameLen = 1;
 
 	switch ( *varName )
 	{
@@ -1248,7 +1193,7 @@
 		if (_tcsncicmp(varName, _T("dp0"), 3) == 0)
 		{
 			if ( varNameLen )
-				*varNameLen = 5;
+				*varNameLen = 4;
 			return bc->BatchFilePath;
 		}
 	case _T('0'):
@@ -1261,60 +1206,16 @@
 	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;
+		return FindArg(*varName - _T('0'));
 
     case _T('*'):
-        if(bc == NULL)
-        {
-            //
-            // No batch file to see here, move along
-            //
-            if ( !GrowIfNecessary ( 3, &ret, &retlen ) )
-                return NULL;
-            ret[0] = _T('%');
-            ret[1] = _T('*');
-            ret[2] = 0;
-            if ( varNameLen )
-                *varNameLen = 2;
-            return ret;
-        }
-
         //
         // Copy over the raw params(not including the batch file name
         //
-        if ( !GrowIfNecessary ( _tcslen(bc->raw_params)+1, &ret, &retlen ) )
-            return NULL;
-        if ( varNameLen )
-            *varNameLen = 2;
-        _tcscpy ( ret, bc->raw_params );
-        return ret;
+        return bc->raw_params;
 
 	case _T('%'):
-		if ( !GrowIfNecessary ( 2, &ret, &retlen ) )
-			return NULL;
-		ret[0] = _T('%');
-		ret[1] = 0;
-		if ( varNameLen )
-			*varNameLen = 2;
-		return ret;
+		return _T("%");
 
 	case _T('?'):
 		/* TODO FIXME 10 is only max size for 32-bit */
@@ -1323,34 +1224,163 @@
 		_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, c );
-	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 );
+	return NULL;
+}
+
+BOOL
+SubstituteVars(TCHAR *Src, TCHAR *Dest, TCHAR Delim, BOOL bIsBatch)
+{
+#define APPEND(From, Length) { \
+	if (Dest + (Length) > DestEnd) \
+		goto too_long; \
+	memcpy(Dest, From, (Length) * sizeof(TCHAR)); \
+	Dest += Length; }
+#define APPEND1(Char) { \
+	if (Dest >= DestEnd) \
+		goto too_long; \
+	*Dest++ = Char; }
+
+	TCHAR *DestEnd = Dest + CMDLINE_LENGTH - 1;
+	const TCHAR *Var;
+	int VarLength;
+	TCHAR *SubstStart;
+	TCHAR EndChr;
+	while (*Src)
+	{
+		if (*Src != Delim)
+		{
+			APPEND1(*Src++)
+			continue;
+		}
+
+		Src++;
+		if (bIsBatch && Delim == _T('%'))
+		{
+			UINT NameLen;
+			Var = GetBatchVar(Src, &NameLen);
+			if (Var != NULL)
+			{
+				VarLength = _tcslen(Var);
+				APPEND(Var, VarLength)
+				Src += NameLen;
+				continue;
+			}
+		}
+
+		/* Find the end of the variable name. A colon (:) will usually
+		 * end the name and begin the optional modifier, but not if it
+		 * is immediately followed by the delimiter (%VAR:%). */
+		SubstStart = Src;
+		while (*Src != Delim && !(*Src == _T(':') && Src[1] != Delim))
+		{
+			if (!*Src)
+				goto bad_subst;
+			Src++;
+		}
+
+		EndChr = *Src;
+		*Src = _T('\0');
+		Var = GetEnvVarOrSpecial(SubstStart);
+		*Src++ = EndChr;
+		if (Var == NULL)
+		{
+			/* In a batch file, %NONEXISTENT% "expands" to an empty string */
+			if (bIsBatch)
+				continue;
+			goto bad_subst;
+		}
+		VarLength = _tcslen(Var);
+
+		if (EndChr == Delim)
+		{
+			/* %VAR% - use as-is */
+			APPEND(Var, VarLength)
+		}
+		else if (*Src == _T('~'))
+		{
+			/* %VAR:~[start][,length]% - substring
+			 * Negative values are offsets from the end */
+			int Start = _tcstol(Src + 1, &Src, 0);
+			int End = VarLength;
+			if (Start < 0)
+				Start += VarLength;
+			Start = max(Start, 0);
+			Start = min(Start, VarLength);
+			if (*Src == _T(','))
+			{
+				End = _tcstol(Src + 1, &Src, 0);
+				End += (End < 0) ? VarLength : Start;
+				End = max(End, Start);
+				End = min(End, VarLength);
+			}
+			if (*Src++ != Delim)
+				goto bad_subst;
+			APPEND(&Var[Start], End - Start);
+		}
+		else
+		{
+			/* %VAR:old=new% - replace all occurrences of old with new
+			 * %VAR:*old=new% - replace first occurrence only,
+			 *                  and remove everything before it */
+			TCHAR *Old, *New;
+			DWORD OldLength, NewLength;
+			BOOL Star = FALSE;
+			int LastMatch = 0, i = 0;
+
+			if (*Src == _T('*'))
+			{
+				Star = TRUE;
+				Src++;
+			}
+
+			/* the string to replace may contain the delimiter */
+			Src = _tcschr(Old = Src, _T('='));
+			if (Src == NULL)
+				goto bad_subst;
+			OldLength = Src++ - Old;
+			if (OldLength == 0)
+				goto bad_subst;
+
+			Src = _tcschr(New = Src, Delim);
+			if (Src == NULL)
+				goto bad_subst;
+			NewLength = Src++ - New;
+
+			while (i < VarLength)
+			{
+				if (_tcsnicmp(&Var[i], Old, OldLength) == 0)
+				{
+					if (!Star)
+						APPEND(&Var[LastMatch], i - LastMatch)
+					APPEND(New, NewLength)
+					i += OldLength;
+					LastMatch = i;
+					if (Star)
+						break;
+					continue;
+				}
+				i++;
+			}
+			APPEND(&Var[LastMatch], VarLength - LastMatch)
+		}
+		continue;
+
+	bad_subst:
+		Src = SubstStart;
+		if (!bIsBatch)
+			APPEND1(Delim)
+	}
+	*Dest = _T('\0');
+	return TRUE;
+too_long:
+	ConOutResPrintf(STRING_ALIAS_ERROR);
+	nErrorLevel = 9023;
+	return FALSE;
+#undef APPEND
+#undef APPEND1
 }
 
 
@@ -1365,10 +1395,7 @@
 	TCHAR commandline[CMDLINE_LENGTH];
 	TCHAR readline[CMDLINE_LENGTH];
 	LPTSTR ip;
-	LPTSTR cp;
-	LPCTSTR tmp;
 	BOOL bEchoThisLine;
-	BOOL bModeSetA;
     BOOL bIsBatch;
 
 	do
@@ -1393,94 +1420,8 @@
 		while ( _istspace(*ip) )
 			++ip;
 
-		cp = commandline;
-		bModeSetA = FALSE;
-		while (*ip)
-		{
-			if ( (*ip == _T('%')) || (*ip == _T('!')) )
-			{
-				UINT envNameLen;
-				LPCTSTR envVal = GetParsedEnvVar ( ip, &envNameLen, bModeSetA );
-				if ( envVal )
-				{
-					ip += envNameLen;
-					cp = _stpcpy ( cp, envVal );
-				}
-			}
-
-			if (*ip != _T('\0') && (_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 (( tmp ) &&
-				( _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"));
-				if ( tmp )
-					tmp += _tcsspn(tmp,_T(" \t"));
-			}
-			/* we should now be pointing to the actual command
-			 * (if there is one yet)*/
-			if ( tmp )
-			{
-				/* 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 )
-				{
-					/* 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('^') )
-						{
-							if ( _tcschr(_T("<>|&"), *++tmp ) && *tmp )
-								++tmp;
-						}
-						else
-						{
-							bModeSetA = FALSE;
-							break;
-						}
-					}
-				}
-			}
-		}
-
-		*cp = _T('\0');
+		if (!SubstituteVars(ip, commandline, _T('%'), bIsBatch))
+			continue;
 
 		/* JPP 19980807 */
 		/* Echo batch file line */
@@ -1489,6 +1430,11 @@
 			PrintPrompt ();
 			ConOutPuts (commandline);
 		}
+
+		/* FIXME: !vars! should be substituted later, after parsing. */
+		if (!SubstituteVars(commandline, readline, _T('!'), bIsBatch))
+			continue;
+		_tcscpy(commandline, readline);
 
 		if (!CheckCtrlBreak(BREAK_INPUT) && *commandline)
 		{

Modified: trunk/reactos/base/shell/cmd/cmdinput.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/cmd/cmdinput.c?rev=35295&r1=35294&r2=35295&view=diff
==============================================================================
--- trunk/reactos/base/shell/cmd/cmdinput.c [iso-8859-1] (original)
+++ trunk/reactos/base/shell/cmd/cmdinput.c [iso-8859-1] Tue Aug 12 18:46:15 2008
@@ -587,4 +587,9 @@
 	while (!bReturn);
 
 	SetCursorType (bInsert, TRUE);
+
+#ifdef FEATURE_ALIASES
+	/* expand all aliases */
+	ExpandAlias (str, maxlen);
+#endif /* FEATURE_ALIAS */
 }



More information about the Ros-diffs mailing list