/* * 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 ) * added config.h include * * 28-Jul-1998 (John P Price ) * 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 ) * 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