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=... ============================================================================== --- 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=35... ============================================================================== --- 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?r... ============================================================================== --- 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 */ }