mirror of
https://github.com/reactos/reactos.git
synced 2024-09-28 05:26:58 +00:00
1965b2bf85
Remove extra \r put by hand in some console output functions, so that we use there only \n. But modify the ConWrite function so that, if we redirect output to something else than a console (e.g. redirect to a file or to a serial console via ... > AUX), newline characters \n get converted into \r\n automatically. What you get, for instance, is: https://imageshack.com/a/img853/5834/l34.png svn path=/trunk/; revision=59411
543 lines
11 KiB
C
543 lines
11 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 BOOL
|
|
seta_identval(LPCTSTR ident, INT* result)
|
|
{
|
|
LPCTSTR identVal = GetEnvVarOrSpecial ( ident );
|
|
if ( !identVal )
|
|
{
|
|
/* TODO FIXME - what to do upon failure? */
|
|
*result = 0;
|
|
return FALSE;
|
|
}
|
|
*result = _tcstol ( identVal, NULL, 0 );
|
|
return TRUE;
|
|
}
|
|
|
|
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);
|
|
if ( !seta_identval ( ident, result ) )
|
|
return FALSE;
|
|
}
|
|
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 '<':
|
|
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;
|
|
|
|
if ( !seta_identval ( ident, &identval ) )
|
|
identval = 0;
|
|
switch ( op )
|
|
{
|
|
case '=':
|
|
identval = exprval;
|
|
break;
|
|
case '<':
|
|
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
|