mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
551 lines
12 KiB
C
551 lines
12 KiB
C
/*
|
|
* SET.C - set internal command.
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
* 06/14/97 (Tim Norman)
|
|
* changed static var in set() to a cmd_alloc'd space to pass to putenv.
|
|
* need to find a better way to do this, since it seems it is wasting
|
|
* memory when variables are redefined.
|
|
*
|
|
* 07/08/1998 (John P. Price)
|
|
* removed call to show_environment in set command.
|
|
* moved test for syntax before allocating memory in set command.
|
|
* misc clean up and optimization.
|
|
*
|
|
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
|
* added config.h include
|
|
*
|
|
* 28-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
|
* added set_env function to set env. variable without needing set command
|
|
*
|
|
* 09-Dec-1998 (Eric Kohl)
|
|
* Added help text ("/?").
|
|
*
|
|
* 24-Jan-1999 (Eric Kohl)
|
|
* Fixed Win32 environment handling.
|
|
* Unicode and redirection safe!
|
|
*
|
|
* 25-Feb-1999 (Eric Kohl)
|
|
* Fixed little bug.
|
|
*
|
|
* 30-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
|
|
* Remove all hardcoded strings in En.rc
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#ifdef INCLUDE_CMD_SET
|
|
|
|
|
|
/* initial size of environment variable buffer */
|
|
#define ENV_BUFFER_SIZE 1024
|
|
|
|
static BOOL
|
|
seta_eval ( LPCTSTR expr );
|
|
|
|
static LPCTSTR
|
|
skip_ws ( LPCTSTR p )
|
|
{
|
|
while (*p && *p <= _T(' '))
|
|
p++;
|
|
return p;
|
|
}
|
|
|
|
/* Used to check for and handle:
|
|
* SET "var=value", SET /P "var=prompt", and SET /P var="prompt" */
|
|
static LPTSTR
|
|
GetQuotedString(TCHAR *p)
|
|
{
|
|
TCHAR *end;
|
|
if (*p == _T('"'))
|
|
{
|
|
p = (LPTSTR)skip_ws(p + 1);
|
|
/* If a matching quote is found, truncate the string */
|
|
end = _tcsrchr(p, _T('"'));
|
|
if (end)
|
|
*end = _T('\0');
|
|
}
|
|
return p;
|
|
}
|
|
|
|
INT cmd_set (LPTSTR param)
|
|
{
|
|
LPTSTR p;
|
|
LPTSTR lpEnv;
|
|
LPTSTR lpOutput;
|
|
|
|
if ( !_tcsncmp (param, _T("/?"), 2) )
|
|
{
|
|
ConOutResPaging(TRUE,STRING_SET_HELP);
|
|
return 0;
|
|
}
|
|
|
|
param = (LPTSTR)skip_ws(param);
|
|
|
|
/* if no parameters, show the environment */
|
|
if (param[0] == _T('\0'))
|
|
{
|
|
lpEnv = (LPTSTR)GetEnvironmentStrings ();
|
|
if (lpEnv)
|
|
{
|
|
lpOutput = lpEnv;
|
|
while (*lpOutput)
|
|
{
|
|
if (*lpOutput != _T('='))
|
|
ConOutPuts(lpOutput);
|
|
lpOutput += _tcslen(lpOutput) + 1;
|
|
ConOutChar(_T('\n'));
|
|
}
|
|
FreeEnvironmentStrings (lpEnv);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* the /A does *NOT* have to be followed by a whitespace */
|
|
if ( !_tcsnicmp (param, _T("/A"), 2) )
|
|
{
|
|
BOOL Success;
|
|
StripQuotes(param);
|
|
Success = seta_eval ( skip_ws(param+2) );
|
|
if (!Success)
|
|
{
|
|
/* might seem random but this is what windows xp does */
|
|
nErrorLevel = 9165;
|
|
}
|
|
return !Success;
|
|
}
|
|
|
|
if (!_tcsnicmp(param, _T("/P"), 2))
|
|
{
|
|
TCHAR value[1023];
|
|
param = GetQuotedString((LPTSTR)skip_ws(param + 2));
|
|
p = _tcschr(param, _T('='));
|
|
if (!p)
|
|
{
|
|
ConErrResPuts(STRING_SYNTAX_COMMAND_INCORRECT);
|
|
nErrorLevel = 1;
|
|
return 1;
|
|
}
|
|
|
|
*p++ = _T('\0');
|
|
ConOutPrintf(_T("%s"), GetQuotedString(p));
|
|
ConInString(value, 1023);
|
|
|
|
if (!*value || !SetEnvironmentVariable(param, value))
|
|
{
|
|
nErrorLevel = 1;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
param = GetQuotedString(param);
|
|
|
|
p = _tcschr (param, _T('='));
|
|
if (p)
|
|
{
|
|
/* set or remove environment variable */
|
|
if (p == param)
|
|
{
|
|
/* handle set =val case */
|
|
ConErrResPuts(STRING_SYNTAX_COMMAND_INCORRECT);
|
|
nErrorLevel = 1;
|
|
return 1;
|
|
}
|
|
|
|
*p++ = _T('\0');
|
|
if (!SetEnvironmentVariable(param, *p ? p : NULL))
|
|
{
|
|
nErrorLevel = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* display all environment variable with the given prefix */
|
|
BOOL bFound = FALSE;
|
|
|
|
while (_istspace(*param) || *param == _T(',') || *param == _T(';'))
|
|
param++;
|
|
|
|
p = _tcsrchr(param, _T(' '));
|
|
if (!p)
|
|
p = param + _tcslen(param);
|
|
*p = _T('\0');
|
|
|
|
lpEnv = GetEnvironmentStrings();
|
|
if (lpEnv)
|
|
{
|
|
lpOutput = lpEnv;
|
|
while (*lpOutput)
|
|
{
|
|
if (!_tcsnicmp(lpOutput, param, p - param))
|
|
{
|
|
ConOutPuts(lpOutput);
|
|
ConOutChar(_T('\n'));
|
|
bFound = TRUE;
|
|
}
|
|
lpOutput += _tcslen(lpOutput) + 1;
|
|
}
|
|
FreeEnvironmentStrings(lpEnv);
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
ConErrResPrintf (STRING_PATH_ERROR, param);
|
|
nErrorLevel = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static INT
|
|
ident_len(LPCTSTR p)
|
|
{
|
|
LPCTSTR p2 = p;
|
|
if ( __iscsymf(*p) )
|
|
{
|
|
++p2;
|
|
while ( __iscsym(*p2) )
|
|
++p2;
|
|
}
|
|
return (INT)(p2-p);
|
|
}
|
|
|
|
#define PARSE_IDENT(ident,identlen,p) \
|
|
identlen = ident_len(p); \
|
|
ident = (LPTSTR)alloca ( ( identlen + 1 ) * sizeof(TCHAR) ); \
|
|
memmove ( ident, p, identlen * sizeof(TCHAR) ); \
|
|
ident[identlen] = 0; \
|
|
p += identlen;
|
|
|
|
static INT
|
|
seta_identval(LPCTSTR ident)
|
|
{
|
|
LPCTSTR identVal = GetEnvVarOrSpecial ( ident );
|
|
if ( !identVal )
|
|
return 0;
|
|
else
|
|
return _tcstol ( identVal, NULL, 0 );
|
|
}
|
|
|
|
static BOOL
|
|
calc(INT* lval, TCHAR op, INT rval)
|
|
{
|
|
switch ( op )
|
|
{
|
|
case '*':
|
|
*lval *= rval;
|
|
break;
|
|
case '/':
|
|
*lval /= rval;
|
|
break;
|
|
case '%':
|
|
*lval %= rval;
|
|
break;
|
|
case '+':
|
|
*lval += rval;
|
|
break;
|
|
case '-':
|
|
*lval -= rval;
|
|
break;
|
|
case '&':
|
|
*lval &= rval;
|
|
break;
|
|
case '^':
|
|
*lval ^= rval;
|
|
break;
|
|
case '|':
|
|
*lval |= rval;
|
|
break;
|
|
default:
|
|
ConErrResPuts ( STRING_INVALID_OPERAND );
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_stmt (LPCTSTR* p_, INT* result);
|
|
|
|
static BOOL
|
|
seta_unaryTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
LPCTSTR p = *p_;
|
|
if ( *p == _T('(') )
|
|
{
|
|
INT rval;
|
|
p = skip_ws ( p + 1 );
|
|
if ( !seta_stmt ( &p, &rval ) )
|
|
return FALSE;
|
|
if ( *p++ != _T(')') )
|
|
{
|
|
ConErrResPuts ( STRING_EXPECTED_CLOSE_PAREN );
|
|
return FALSE;
|
|
}
|
|
*result = rval;
|
|
}
|
|
else if ( isdigit(*p) )
|
|
{
|
|
*result = _tcstol ( p, (LPTSTR *)&p, 0 );
|
|
}
|
|
else if ( __iscsymf(*p) )
|
|
{
|
|
LPTSTR ident;
|
|
INT identlen;
|
|
PARSE_IDENT(ident,identlen,p);
|
|
*result = seta_identval ( ident );
|
|
}
|
|
else
|
|
{
|
|
ConErrResPuts ( STRING_EXPECTED_NUMBER_OR_VARIABLE );
|
|
return FALSE;
|
|
}
|
|
*p_ = skip_ws ( p );
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_mulTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
LPCTSTR p = *p_;
|
|
TCHAR op = 0;
|
|
INT rval;
|
|
if ( _tcschr(_T("!~-"),*p) )
|
|
{
|
|
op = *p;
|
|
p = skip_ws ( p + 1 );
|
|
}
|
|
if ( !seta_unaryTerm ( &p, &rval ) )
|
|
return FALSE;
|
|
switch ( op )
|
|
{
|
|
case '!':
|
|
rval = !rval;
|
|
break;
|
|
case '~':
|
|
rval = ~rval;
|
|
break;
|
|
case '-':
|
|
rval = -rval;
|
|
break;
|
|
}
|
|
|
|
*result = rval;
|
|
*p_ = p;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_ltorTerm(LPCTSTR* p_, INT* result, LPCTSTR ops, BOOL (*subTerm)(LPCTSTR*,INT*))
|
|
{
|
|
LPCTSTR p = *p_;
|
|
INT lval;
|
|
if ( !subTerm ( &p, &lval ) )
|
|
return FALSE;
|
|
while ( *p && _tcschr(ops,*p) )
|
|
{
|
|
INT rval;
|
|
TCHAR op = *p;
|
|
|
|
p = skip_ws ( p+1 );
|
|
|
|
if ( !subTerm ( &p, &rval ) )
|
|
return FALSE;
|
|
|
|
if ( !calc ( &lval, op, rval ) )
|
|
return FALSE;
|
|
}
|
|
|
|
*result = lval;
|
|
*p_ = p;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_addTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
return seta_ltorTerm ( p_, result, _T("*/%"), seta_mulTerm );
|
|
}
|
|
|
|
static BOOL
|
|
seta_logShiftTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
return seta_ltorTerm ( p_, result, _T("+-"), seta_addTerm );
|
|
}
|
|
|
|
static BOOL
|
|
seta_bitAndTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
LPCTSTR p = *p_;
|
|
INT lval;
|
|
if ( !seta_logShiftTerm ( &p, &lval ) )
|
|
return FALSE;
|
|
while ( *p && _tcschr(_T("<>"),*p) && p[0] == p[1] )
|
|
{
|
|
INT rval;
|
|
TCHAR op = *p;
|
|
|
|
p = skip_ws ( p+2 );
|
|
|
|
if ( !seta_logShiftTerm ( &p, &rval ) )
|
|
return FALSE;
|
|
|
|
switch ( op )
|
|
{
|
|
case '<':
|
|
{
|
|
/* Shift left has to be a positive number, 0-31 otherwise 0 is returned,
|
|
* which differs from the compiler (for example gcc) so being explicit. */
|
|
if (rval < 0 || rval >= (8 * sizeof(lval)))
|
|
lval = 0;
|
|
else
|
|
lval <<= rval;
|
|
break;
|
|
}
|
|
case '>':
|
|
lval >>= rval;
|
|
break;
|
|
default:
|
|
ConErrResPuts ( STRING_INVALID_OPERAND );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*result = lval;
|
|
*p_ = p;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_bitExclOrTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
return seta_ltorTerm ( p_, result, _T("&"), seta_bitAndTerm );
|
|
}
|
|
|
|
static BOOL
|
|
seta_bitOrTerm(LPCTSTR* p_, INT* result)
|
|
{
|
|
return seta_ltorTerm ( p_, result, _T("^"), seta_bitExclOrTerm );
|
|
}
|
|
|
|
static BOOL
|
|
seta_expr(LPCTSTR* p_, INT* result)
|
|
{
|
|
return seta_ltorTerm ( p_, result, _T("|"), seta_bitOrTerm );
|
|
}
|
|
|
|
static BOOL
|
|
seta_assignment(LPCTSTR* p_, INT* result)
|
|
{
|
|
LPCTSTR p = *p_;
|
|
LPTSTR ident;
|
|
TCHAR op = 0;
|
|
INT identlen, exprval;
|
|
|
|
PARSE_IDENT(ident,identlen,p);
|
|
if ( identlen )
|
|
{
|
|
p = skip_ws(p);
|
|
if ( *p == _T('=') )
|
|
op = *p, p = skip_ws(p+1);
|
|
else if ( _tcschr ( _T("*/%+-&^|"), *p ) && p[1] == _T('=') )
|
|
op = *p, p = skip_ws(p+2);
|
|
else if ( _tcschr ( _T("<>"), *p ) && *p == p[1] && p[2] == _T('=') )
|
|
op = *p, p = skip_ws(p+3);
|
|
}
|
|
|
|
/* allow to chain multiple assignments, such as: a=b=1 */
|
|
if ( ident && op )
|
|
{
|
|
INT identval;
|
|
LPTSTR buf;
|
|
|
|
if ( !seta_assignment ( &p, &exprval ) )
|
|
return FALSE;
|
|
|
|
identval = seta_identval ( ident );
|
|
|
|
switch ( op )
|
|
{
|
|
case '=':
|
|
identval = exprval;
|
|
break;
|
|
case '<':
|
|
{
|
|
/* Shift left has to be a positive number, 0-31 otherwise 0 is returned,
|
|
* which differs from the compiler (for example gcc) so being explicit. */
|
|
if (exprval < 0 || exprval >= (8 * sizeof(identval)))
|
|
identval = 0;
|
|
else
|
|
identval <<= exprval;
|
|
break;
|
|
}
|
|
case '>':
|
|
identval >>= exprval;
|
|
break;
|
|
default:
|
|
if ( !calc ( &identval, op, exprval ) )
|
|
return FALSE;
|
|
}
|
|
buf = (LPTSTR)alloca ( 32 * sizeof(TCHAR) );
|
|
_sntprintf ( buf, 32, _T("%i"), identval );
|
|
SetEnvironmentVariable ( ident, buf ); // TODO FIXME - check return value
|
|
exprval = identval;
|
|
}
|
|
else
|
|
{
|
|
/* restore p in case we found an ident but not an op */
|
|
p = *p_;
|
|
if ( !seta_expr ( &p, &exprval ) )
|
|
return FALSE;
|
|
}
|
|
|
|
*result = exprval;
|
|
*p_ = p;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_stmt(LPCTSTR* p_, INT* result)
|
|
{
|
|
LPCTSTR p = *p_;
|
|
INT rval;
|
|
|
|
if ( !seta_assignment ( &p, &rval ) )
|
|
return FALSE;
|
|
while ( *p == _T(',') )
|
|
{
|
|
p = skip_ws ( p+1 );
|
|
|
|
if ( !seta_assignment ( &p, &rval ) )
|
|
return FALSE;
|
|
}
|
|
|
|
*result = rval;
|
|
*p_ = p;
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
seta_eval(LPCTSTR p)
|
|
{
|
|
INT rval;
|
|
if ( !*p )
|
|
{
|
|
ConErrResPuts ( STRING_SYNTAX_COMMAND_INCORRECT );
|
|
return FALSE;
|
|
}
|
|
if ( !seta_stmt ( &p, &rval ) )
|
|
return FALSE;
|
|
if ( !bc )
|
|
ConOutPrintf ( _T("%i"), rval );
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|