Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1580 lines
36 KiB

//
// Copyright (c) Microsoft Corporation 1995
//
// eval.c
//
// This file contains the evaluation functions for the
// abstract syntax tree.
//
// History:
// 06-15-95 ScottH Created
//
#include "proj.h"
#include "rcids.h"
#include "debug.h"
#define MSECS_FROM_SECS(s) ((s)*1000)
#define RAS_DUMMY_PASSWORD "****************"
//
// Clean expressions
//
/*----------------------------------------------------------
Purpose: Clean expressions.
Returns: --
Cond: --
*/
void PRIVATE Expr_Clean(
PEXPR this)
{
ASSERT(this);
switch (Ast_GetType(this))
{
case AT_INT_EXPR:
case AT_BOOL_EXPR:
case AT_STRING_EXPR:
case AT_VAR_EXPR:
ClearFlag(this->dwFlags, EF_DONE);
break;
case AT_UNOP_EXPR:
ClearFlag(this->dwFlags, EF_DONE);
Expr_Clean(UnOpExpr_GetExpr(this));
break;
case AT_BINOP_EXPR:
ClearFlag(this->dwFlags, EF_DONE);
Expr_Clean(BinOpExpr_GetExpr1(this));
Expr_Clean(BinOpExpr_GetExpr2(this));
break;
default:
ASSERT(0);
break;
}
}
/*----------------------------------------------------------
Purpose: Clean the expressions in the 'waitfor' statement.
Returns: --
Cond: --
*/
void PRIVATE WaitforStmt_Clean(
PSTMT this)
{
PEXPR pexpr;
HSA hsa = WaitforStmt_GetCaseList(this);
DWORD ccase = SAGetCount(hsa);
DWORD i;
pexpr = WaitforStmt_GetUntilExpr(this);
if (pexpr)
Expr_Clean(pexpr);
for (i = 0; i < ccase; i++)
{
PWAITCASE pwc;
SAGetItemPtr(hsa, i, &pwc);
ASSERT(pwc);
Expr_Clean(pwc->pexpr);
}
}
/*----------------------------------------------------------
Purpose: Clean the expressions in the statement
Returns: --
Cond: --
*/
void PRIVATE Stmt_Clean(
PSTMT this)
{
PEXPR pexpr;
ASSERT(this);
switch (Ast_GetType(this))
{
case AT_ENTER_STMT:
case AT_LEAVE_STMT:
case AT_HALT_STMT:
case AT_LABEL_STMT:
case AT_GOTO_STMT:
break;
case AT_WHILE_STMT:
pexpr = WhileStmt_GetExpr(this);
Expr_Clean(pexpr);
break;
case AT_IF_STMT:
pexpr = IfStmt_GetExpr(this);
Expr_Clean(pexpr);
break;
case AT_ASSIGN_STMT:
pexpr = AssignStmt_GetExpr(this);
Expr_Clean(pexpr);
break;
case AT_TRANSMIT_STMT:
pexpr = TransmitStmt_GetExpr(this);
Expr_Clean(pexpr);
break;
case AT_WAITFOR_STMT:
WaitforStmt_Clean(this);
break;
case AT_DELAY_STMT:
pexpr = DelayStmt_GetExpr(this);
Expr_Clean(pexpr);
break;
case AT_SET_STMT:
switch (SetStmt_GetType(this))
{
case ST_IPADDR:
pexpr = SetIPStmt_GetExpr(this);
Expr_Clean(pexpr);
break;
case ST_PORT:
case ST_SCREEN:
break;
default:
ASSERT(0);
break;
}
break;
default:
ASSERT(0);
break;
}
}
//
// Evaluate expressions
//
/*----------------------------------------------------------
Purpose: Evaluates the expression and returns an integer.
Returns: RES_OK
Cond: --
*/
RES PRIVATE IntExpr_Eval(
PEXPR this)
{
ASSERT(this);
ASSERT(AT_INT_EXPR == Ast_GetType(this));
ASSERT(DATA_INT == Expr_GetDataType(this));
Expr_SetRes(this, IntExpr_GetVal(this));
return RES_OK;
}
/*----------------------------------------------------------
Purpose: Evaluates the expression and returns a string.
The returned string should not be freed.
Returns: RES_OK
Cond: --
*/
RES PRIVATE StrExpr_Eval(
PEXPR this)
{
ASSERT(this);
ASSERT(AT_STRING_EXPR == Ast_GetType(this));
ASSERT(DATA_STRING == Expr_GetDataType(this));
Expr_SetRes(this, (ULONG_PTR) StrExpr_GetStr(this));
return RES_OK;
}
/*----------------------------------------------------------
Purpose: Evaluates the expression and returns a boolean
Returns: RES_OK
Cond: --
*/
RES PRIVATE BoolExpr_Eval(
PEXPR this)
{
ASSERT(this);
ASSERT(AT_BOOL_EXPR == Ast_GetType(this));
ASSERT(DATA_BOOL == Expr_GetDataType(this));
Expr_SetRes(this, BoolExpr_GetVal(this));
return RES_OK;
}
/*----------------------------------------------------------
Purpose: Returns the value of the variable.
Returns: RES_OK
Cond: --
*/
RES PRIVATE VarExpr_Eval(
PEXPR this,
PASTEXEC pastexec)
{
RES res;
PSTE pste;
LPSTR pszIdent;
ASSERT(this);
ASSERT(AT_VAR_EXPR == Ast_GetType(this));
pszIdent = VarExpr_GetIdent(this);
if (RES_OK == Symtab_FindEntry(pastexec->pstCur, pszIdent, STFF_DEFAULT, &pste, NULL))
{
EVALRES er;
STE_GetValue(pste, &er);
Expr_SetRes(this, er.dw);
res = RES_OK;
}
else
{
ASSERT(0);
res = RES_E_FAIL;
}
return res;
}
/*----------------------------------------------------------
Purpose: Evaluates the expression..
The returned string should not be freed.
Returns: RES_OK
Cond: --
*/
RES PRIVATE BinOpExpr_Eval(
PEXPR this,
PASTEXEC pastexec)
{
RES res;
PEXPR pexpr1;
PEXPR pexpr2;
ASSERT(this);
ASSERT(AT_BINOP_EXPR == Ast_GetType(this));
pexpr1 = BinOpExpr_GetExpr1(this);
res = Expr_Eval(pexpr1, pastexec);
if (RES_OK == res)
{
pexpr2 = BinOpExpr_GetExpr2(this);
res = Expr_Eval(pexpr2, pastexec);
if (RES_OK == res)
{
PEVALRES per1 = Expr_GetRes(pexpr1);
PEVALRES per2 = Expr_GetRes(pexpr2);
DATATYPE dt = Expr_GetDataType(pexpr1);
// Data types must be the same. This was checked
// during the typechecking phase.
ASSERT(Expr_GetDataType(pexpr1) == Expr_GetDataType(pexpr2));
switch (BinOpExpr_GetType(this))
{
case BOT_OR:
ASSERT(DATA_BOOL == dt);
Expr_SetRes(this, per1->bVal || per2->bVal);
break;
case BOT_AND:
ASSERT(DATA_BOOL == dt);
Expr_SetRes(this, per1->bVal && per2->bVal);
break;
case BOT_LEQ:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, per1->nVal <= per2->nVal);
break;
case BOT_LT:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, per1->nVal < per2->nVal);
break;
case BOT_GEQ:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, per1->nVal >= per2->nVal);
break;
case BOT_GT:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, per1->nVal > per2->nVal);
break;
case BOT_NEQ:
switch (dt)
{
case DATA_INT:
Expr_SetRes(this, per1->nVal != per2->nVal);
break;
case DATA_STRING:
Expr_SetRes(this, !IsSzEqualC(per1->psz, per2->psz));
break;
case DATA_BOOL:
Expr_SetRes(this, per1->bVal != per2->bVal);
break;
default:
ASSERT(0);
break;
}
break;
case BOT_EQ:
switch (dt)
{
case DATA_INT:
Expr_SetRes(this, per1->nVal == per2->nVal);
break;
case DATA_STRING:
Expr_SetRes(this, IsSzEqualC(per1->psz, per2->psz));
break;
case DATA_BOOL:
Expr_SetRes(this, per1->bVal == per2->bVal);
break;
default:
ASSERT(0);
break;
}
break;
case BOT_PLUS:
switch (dt)
{
case DATA_INT:
// Add two integers
Expr_SetRes(this, per1->nVal + per2->nVal);
break;
case DATA_STRING: {
LPSTR psz = NULL;
// Concatenate strings
if ( !GSetString(&psz, per1->psz) ||
!GCatString(&psz, per2->psz))
{
// Free whatever was allocated
GSetString(&psz, NULL);
res = Stxerr_Add(pastexec->hsaStxerr, NULL, Ast_GetLine(this), RES_E_OUTOFMEMORY);
}
Expr_SetRes(this, (ULONG_PTR) psz);
SetFlag(this->dwFlags, EF_ALLOCATED);
}
break;
default:
ASSERT(0);
break;
}
break;
case BOT_MINUS:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, per1->nVal - per2->nVal);
break;
case BOT_MULT:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, per1->nVal * per2->nVal);
break;
case BOT_DIV:
ASSERT(DATA_INT == dt);
if (0 == per2->nVal)
res = Stxerr_Add(pastexec->hsaStxerr, NULL, Ast_GetLine(this), RES_E_DIVBYZERO);
else
Expr_SetRes(this, per1->nVal / per2->nVal);
break;
default:
ASSERT(0);
res = RES_E_INVALIDPARAM;
break;
}
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Evaluate 'getip'.
Returns: RES_OK
RES_FALSE (if the IP address was not read yet)
Cond: --
*/
RES PRIVATE GetIPExpr_Eval(
PEXPR this,
PASTEXEC pastexec,
int nIter)
{
RES res;
DWORD iDummy;
ASSERT(this);
ASSERT(pastexec);
ASSERT(0 < nIter);
TRACE_MSG(TF_ASTEXEC, "Exec: getip %d", nIter);
// Is this function getting re-called due to a pending read?
if ( !Astexec_IsReadPending(pastexec) )
{
// No; prepare to extract the nth IP address
ClearFlag(this->dwFlags, EF_DONE);
ASSERT(NULL == pastexec->hFindFmt);
res = CreateFindFormat(&pastexec->hFindFmt);
if (RSUCCEEDED(res))
{
res = AddFindFormat(pastexec->hFindFmt, "%u.%u.%u.%u", FFF_DEFAULT,
pastexec->szIP, sizeof(pastexec->szIP));
if (RSUCCEEDED(res))
{
// Extract the nth IP address.
pastexec->nIter = nIter;
ASSERT(0 < pastexec->nIter);
}
}
}
if(NULL != pastexec->hFindFmt)
{
res = Astexec_FindFormat(pastexec, &iDummy);
if (RES_OK == res)
{
// Allocate or resize the pointer we already have
LPSTR psz = Expr_GetRes(this)->psz;
if ( !GSetString(&psz, Astexec_GetIPAddr(pastexec)) )
res = Stxerr_Add(pastexec->hsaStxerr, NULL,
Ast_GetLine(this), RES_E_OUTOFMEMORY);
else
{
Expr_SetRes(this, (ULONG_PTR) psz);
SetFlag(this->dwFlags, EF_ALLOCATED);
}
}
}
else
{
res = RES_E_FAIL;
}
return res;
}
/*----------------------------------------------------------
Purpose: Evaluates the expression and returns an integer.
Returns: RES_OK
Cond: --
*/
RES PRIVATE UnOpExpr_Eval(
PEXPR this,
PASTEXEC pastexec)
{
RES res = RES_OK;
PEVALRES per;
PEXPR pexpr;
DATATYPE dt;
ASSERT(this);
ASSERT(AT_UNOP_EXPR == Ast_GetType(this));
pexpr = UnOpExpr_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
per = Expr_GetRes(pexpr);
dt = Expr_GetDataType(pexpr);
switch (UnOpExpr_GetType(this))
{
case UOT_NEG:
ASSERT(DATA_INT == dt);
Expr_SetRes(this, -per->nVal);
break;
case UOT_NOT:
ASSERT(DATA_BOOL == dt);
Expr_SetRes(this, !per->bVal);
break;
case UOT_GETIP:
ASSERT(DATA_INT == dt);
if (0 < per->nVal)
res = GetIPExpr_Eval(this, pastexec, per->nVal);
else
res = Stxerr_Add(pastexec->hsaStxerr, "'getip' parameter", Ast_GetLine(pexpr), RES_E_INVALIDRANGE);
break;
default:
ASSERT(0);
break;
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Evaluates the expression and returns a value.
Returns: RES_OK
Cond: --
*/
RES PUBLIC Expr_Eval(
PEXPR this,
PASTEXEC pastexec)
{
RES res;
ASSERT(this);
ASSERT(pastexec);
// Has this expression already been evaluated?
if (IsFlagSet(this->dwFlags, EF_DONE))
{
// Yes; just return
res = RES_OK;
}
else
{
// No; evaluate it
switch (Ast_GetType(this))
{
case AT_INT_EXPR:
res = IntExpr_Eval(this);
break;
case AT_BOOL_EXPR:
res = BoolExpr_Eval(this);
break;
case AT_STRING_EXPR:
res = StrExpr_Eval(this);
break;
case AT_VAR_EXPR:
res = VarExpr_Eval(this, pastexec);
break;
case AT_UNOP_EXPR:
res = UnOpExpr_Eval(this, pastexec);
break;
case AT_BINOP_EXPR:
res = BinOpExpr_Eval(this, pastexec);
break;
default:
ASSERT(0);
res = RES_E_INVALIDPARAM;
break;
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the prolog
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE EnterStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
ASSERT(this);
ASSERT(pastexec);
TRACE_MSG(TF_ASTEXEC, "Exec: enter");
pastexec->cProcDepth++;
pastexec->pstCur = EnterStmt_GetSymtab(this);
ASSERT(pastexec->pstCur);
return RES_OK;
}
/*----------------------------------------------------------
Purpose: Execute the epilog
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE LeaveStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
ASSERT(this);
ASSERT(pastexec);
TRACE_MSG(TF_ASTEXEC, "Exec: leave");
ASSERT(0 < pastexec->cProcDepth);
pastexec->cProcDepth--;
pastexec->pstCur = Symtab_GetNext(pastexec->pstCur);
ASSERT(pastexec->pstCur);
// Leaving main procedure?
if (0 == pastexec->cProcDepth)
{
// Yes
SetFlag(pastexec->dwFlags, AEF_DONE);
res = RES_HALT;
}
else
res = RES_OK;
return res;
}
/*----------------------------------------------------------
Purpose: Execute the assignment statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE AssignStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
LPSTR pszIdent;
PSTE pste;
ASSERT(this);
ASSERT(pastexec);
pszIdent = AssignStmt_GetIdent(this);
if (RES_OK == Symtab_FindEntry(pastexec->pstCur, pszIdent, STFF_DEFAULT, &pste, NULL))
{
PEXPR pexpr;
pexpr = AssignStmt_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
DEBUG_CODE( DATATYPE dt; )
#ifdef DEBUG
dt = Expr_GetDataType(pexpr);
switch (dt)
{
case DATA_STRING:
TRACE_MSG(TF_ASTEXEC, "Exec: %s = \"%s\"", pszIdent, per->psz);
break;
case DATA_INT:
TRACE_MSG(TF_ASTEXEC, "Exec: %s = %d", pszIdent, per->nVal);
break;
case DATA_BOOL:
TRACE_MSG(TF_ASTEXEC, "Exec: %s = %s", pszIdent, per->bVal ? (LPSTR)"TRUE" : (LPSTR)"FALSE");
break;
default:
ASSERT(0);
break;
}
#endif
pste->er.dw = per->dw;
}
}
else
{
// The identifier should have been in the symbol table!
ASSERT(0);
res = RES_E_FAIL;
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'while' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE WhileStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
PEXPR pexpr;
ASSERT(this);
ASSERT(pastexec);
pexpr = WhileStmt_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
if (!per->bVal)
{
res = Astexec_JumpToLabel(pastexec, WhileStmt_GetEndLabel(this));
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'if' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE IfStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
PEXPR pexpr;
ASSERT(this);
ASSERT(pastexec);
pexpr = IfStmt_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
if (!per->bVal)
{
res = Astexec_JumpToLabel(pastexec, IfStmt_GetElseLabel(this));
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'halt' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE HaltStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
ASSERT(this);
ASSERT(pastexec);
TRACE_MSG(TF_ASTEXEC, "Exec: halt");
SetFlag(pastexec->dwFlags, AEF_HALT);
return RES_HALT;
}
/*----------------------------------------------------------
Purpose: Execute the 'goto' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE GotoStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
LPSTR pszIdent;
ASSERT(this);
ASSERT(pastexec);
pszIdent = GotoStmt_GetIdent(this);
TRACE_MSG(TF_ASTEXEC, "Exec: goto %s", pszIdent);
return Astexec_JumpToLabel(pastexec, pszIdent);
}
/*----------------------------------------------------------
Purpose: Execute the 'transmit' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE TransmitStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
PEXPR pexpr;
ASSERT(this);
ASSERT(pastexec);
pexpr = TransmitStmt_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
DWORD dwFlags = TransmitStmt_GetFlags(this);
CHAR *pszPassword;
TRACE_MSG(TF_ASTEXEC, "Exec: transmit \"%s\"", per->psz);
#ifdef WINNT_RAS
//
// JEFFSI WHISTLER
//
// RASSCRPT_TRACE1("Exec: transmit \"%s\"", per->psz);
if (pszPassword = strstr(per->psz, RAS_DUMMY_PASSWORD))
{
CHAR *psz;
CHAR controlchar = '\0';
#define IS_CARET(ch) ('^' == (ch))
if(per->psz != pszPassword)
{
CHAR *pszT, *pszPrefix = LocalAlloc(LPTR, strlen(per->psz));
if(NULL == pszPrefix)
{
res = E_OUTOFMEMORY;
return res;
}
psz = per->psz;
pszT = pszPrefix;
while(psz != pszPassword)
{
*pszT++ = *psz++;
}
Astexec_SendString(pastexec, pszPrefix,
IsFlagSet(dwFlags, TSF_RAW));
RASSCRPT_TRACE1("Exec: transmi \"%s\"", pszPrefix);
LocalFree(pszPrefix);
}
//
// Check to see if we need to send a control char
// at the end.
//
psz = pszPassword + lstrlen(RAS_DUMMY_PASSWORD);
if(IS_CARET(*psz))
{
psz++;
if(!*psz)
{
;
}
if (InRange(*psz, '@', '_'))
{
controlchar = *psz - '@';
}
else if (InRange(*psz, 'a', 'z'))
{
controlchar = *psz - 'a' + 1;
}
}
(VOID) RxSendCreds(((SCRIPTDATA*)pastexec->hwnd)->hscript,
controlchar);
}
else
{
Astexec_SendString(pastexec, per->psz, IsFlagSet(dwFlags, TSF_RAW));
}
#else
Astexec_SendString(pastexec, per->psz, IsFlagSet(dwFlags, TSF_RAW));
#endif
}
return res;
}
/*----------------------------------------------------------
Purpose: Evaluates each of the wait-case expressions.
Returns: RES_OK
Cond: --
*/
RES PRIVATE WaitforStmt_EvalCaseList(
PSTMT this,
PASTEXEC pastexec)
{
RES res = RES_E_FAIL;
HSA hsa = WaitforStmt_GetCaseList(this);
DWORD i;
DWORD ccase = SAGetCount(hsa);
PWAITCASE pwc;
ASSERT(0 < ccase);
for (i = 0; i < ccase; i++)
{
SAGetItemPtr(hsa, i, &pwc);
ASSERT(pwc);
res = Expr_Eval(pwc->pexpr, pastexec);
if (RES_OK != res)
break;
}
return res;
}
/*----------------------------------------------------------
Purpose: Packages each of the evaluated wait-case expressions
into an array of strings to search for.
Returns: RES_OK
Cond: --
*/
RES PRIVATE WaitforStmt_WrapEmUp(
PSTMT this,
HANDLE hFindFmt)
{
RES res = RES_OK;
HSA hsa = WaitforStmt_GetCaseList(this);
DWORD i;
DWORD ccase = SAGetCount(hsa);
PWAITCASE pwc;
PEVALRES per;
ASSERT(0 < ccase);
for (i = 0; i < ccase; i++)
{
DWORD dwFlags = FFF_DEFAULT;
SAGetItemPtr(hsa, i, &pwc);
ASSERT(pwc);
if (IsFlagSet(pwc->dwFlags, WCF_MATCHCASE))
SetFlag(dwFlags, FFF_MATCHCASE);
per = Expr_GetRes(pwc->pexpr);
res = AddFindFormat(hFindFmt, per->psz, dwFlags, NULL, 0);
if (RFAILED(res))
break;
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the then clause based upon the given case
index.
Returns: RES_OK
Cond: --
*/
RES PRIVATE WaitforStmt_ExecThen(
PSTMT this,
DWORD isa,
PASTEXEC pastexec)
{
RES res = RES_OK;
HSA hsa = WaitforStmt_GetCaseList(this);
PWAITCASE pwc;
if (SAGetItemPtr(hsa, isa, &pwc))
{
ASSERT(pwc);
// If there is a label, jump to it
if (pwc->pszIdent)
res = Astexec_JumpToLabel(pastexec, pwc->pszIdent);
}
else
{
ASSERT(0);
res = RES_E_FAIL;
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'waitfor' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE WaitforStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res = RES_OK;
PEXPR pexpr;
int nTimeoutSecs = -1;
ASSERT(this);
ASSERT(pastexec);
// First evaluate the optional 'until' time
pexpr = WaitforStmt_GetUntilExpr(this);
if (pexpr)
{
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
nTimeoutSecs = per->nVal;
if (0 >= nTimeoutSecs)
res = Stxerr_Add(pastexec->hsaStxerr, "'until' parameter", Ast_GetLine(this), RES_E_INVALIDRANGE);
}
}
if (RES_OK == res)
{
// Evaluate the waitfor string
res = WaitforStmt_EvalCaseList(this, pastexec);
if (RES_OK == res)
{
if (-1 == nTimeoutSecs)
TRACE_MSG(TF_ASTEXEC, "Exec: waitfor ...");
else
TRACE_MSG(TF_ASTEXEC, "Exec: waitfor ... until %d", nTimeoutSecs);
// Is this function getting re-called due to a pending read?
if ( !Astexec_IsReadPending(pastexec) )
{
// No; prepare to wait for the string(s)
ASSERT(NULL == pastexec->hFindFmt);
res = CreateFindFormat(&pastexec->hFindFmt);
if (RSUCCEEDED(res))
{
res = WaitforStmt_WrapEmUp(this, pastexec->hFindFmt);
if (RSUCCEEDED(res))
{
ASSERT(IsFlagClear(pastexec->dwFlags, AEF_WAITUNTIL));
ASSERT(IsFlagClear(pastexec->dwFlags, AEF_STOPWAITING));
ASSERT(IsFlagClear(pastexec->dwFlags, AEF_PAUSED));
pastexec->nIter = 1;
if (-1 != nTimeoutSecs)
{
#ifndef WINNT_RAS
//
// On NT, timeouts are handled by setting dwTimeout in the SCRIPTDATA struct
// for the current script.
//
if (0 != SetTimer(pastexec->hwnd, TIMER_DELAY, MSECS_FROM_SECS(nTimeoutSecs), NULL))
#else // WINNT_RAS
((SCRIPTDATA *)pastexec->hwnd)->dwTimeout = MSECS_FROM_SECS(nTimeoutSecs);
#endif // WINNT_RAS
{
SetFlag(pastexec->dwFlags, AEF_WAITUNTIL);
}
#ifndef WINNT_RAS
else
{
res = Stxerr_Add(pastexec->hsaStxerr, "waitfor", Ast_GetLine(this), RES_E_FAIL);
}
#endif
}
}
}
}
// Have we timed out yet?
if (IsFlagSet(pastexec->dwFlags, AEF_STOPWAITING))
{
// Yes; don't wait for string anymore
ClearFlag(pastexec->dwFlags, AEF_STOPWAITING);
Astexec_SetError(pastexec, FALSE, FALSE);
res = Astexec_DestroyFindFormat(pastexec);
}
else
{
// No; did we find a matching string?
DWORD isa = 0;
res = Astexec_FindFormat(pastexec, &isa);
if (RES_OK == res)
{
// Yes; determine the next action
ClearFlag(pastexec->dwFlags, AEF_WAITUNTIL);
Astexec_SetError(pastexec, TRUE, FALSE);
res = WaitforStmt_ExecThen(this, isa, pastexec);
}
}
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'delay' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE DelayStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
PEXPR pexpr;
ASSERT(this);
ASSERT(pastexec);
pexpr = DelayStmt_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
if (0 >= per->nVal)
res = Stxerr_Add(pastexec->hsaStxerr, "'delay' parameter", Ast_GetLine(this), RES_E_INVALIDRANGE);
else
{
TRACE_MSG(TF_ASTEXEC, "Exec: delay %ld", per->nVal);
#ifndef WINNT_RAS
//
// On NT, timeouts are handled by setting dwTimeout in the SCRIPTDATA struct
// for the current script.
//
if (0 != SetTimer(pastexec->hwnd, TIMER_DELAY, MSECS_FROM_SECS(per->nVal), NULL))
#else // WINNT_RAS
((SCRIPTDATA *)pastexec->hwnd)->dwTimeout = MSECS_FROM_SECS(per->nVal);
#endif // WINNT_RAS
{
// Success
SetFlag(pastexec->dwFlags, AEF_PAUSED);
}
#ifndef WINNT_RAS
else
res = Stxerr_Add(pastexec->hsaStxerr, "delay", Ast_GetLine(this), RES_E_FAIL);
#endif
}
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'set ipaddr' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE IPAddrData_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
PEXPR pexpr;
ASSERT(this);
ASSERT(pastexec);
pexpr = SetIPStmt_GetExpr(this);
res = Expr_Eval(pexpr, pastexec);
if (RES_OK == res)
{
PEVALRES per = Expr_GetRes(pexpr);
ASSERT(per->psz);
TRACE_MSG(TF_ASTEXEC, "Exec: set ipaddr \"%s\"", per->psz);
Astexec_SetIPAddr(pastexec, per->psz);
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'set port' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE PortData_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res = RES_OK;
DCB dcb;
DWORD dwFlags = SetPortStmt_GetFlags(this);
ASSERT(this);
ASSERT(pastexec);
#ifdef DEBUG
if (IsFlagSet(dwFlags, SPF_DATABITS))
TRACE_MSG(TF_ASTEXEC, "Exec: set port databits %u", SetPortStmt_GetDatabits(this));
if (IsFlagSet(dwFlags, SPF_STOPBITS))
TRACE_MSG(TF_ASTEXEC, "Exec: set port stopbits %u", SetPortStmt_GetStopbits(this));
if (IsFlagSet(dwFlags, SPF_PARITY))
TRACE_MSG(TF_ASTEXEC, "Exec: set port parity %u", SetPortStmt_GetParity(this));
#endif
#ifndef WINNT_RAS
//
// On NT, changes to port settings are done through the RasPortSetInfo API.
//
if (GetCommState(pastexec->hport, &dcb))
{
if (IsFlagSet(dwFlags, SPF_DATABITS))
dcb.ByteSize = SetPortStmt_GetDatabits(this);
if (IsFlagSet(dwFlags, SPF_STOPBITS))
dcb.StopBits = SetPortStmt_GetStopbits(this);
if (IsFlagSet(dwFlags, SPF_PARITY))
dcb.Parity = SetPortStmt_GetParity(this);
if (!SetCommState(pastexec->hport, &dcb))
res = Stxerr_Add(pastexec->hsaStxerr, "set port", Ast_GetLine(this), RES_E_FAIL);
}
else
res = Stxerr_Add(pastexec->hsaStxerr, "set port", Ast_GetLine(this), RES_E_FAIL);
#else // WINNT_RAS
res = (RES)RxSetPortData(
((SCRIPTDATA*)pastexec->hwnd)->hscript, this
);
#endif // WINNT_RAS
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'set screen' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE Screen_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
DWORD dwFlags = SetScreenStmt_GetFlags(this);
ASSERT(this);
ASSERT(pastexec);
#ifdef DEBUG
if (IsFlagSet(dwFlags, SPF_KEYBRD))
TRACE_MSG(TF_ASTEXEC, "Exec: set screen keyboard %s", SetScreenStmt_GetKeybrd(this) ? "on" : "off");
#endif
if (IsFlagSet(dwFlags, SPF_KEYBRD))
{
#ifndef WINNT_RAS
//
// On NT, we change the keyboard state by calling RxSetKeyboard
// which will signal an event-code telling whoever started this script
// that the keyboard should be disabled.
//
TerminalSetInput(pastexec->hwnd, SetScreenStmt_GetKeybrd(this));
#else // !WINNT_RAS
RxSetKeyboard(
((SCRIPTDATA*)pastexec->hwnd)->hscript,
SetScreenStmt_GetKeybrd(this)
);
#endif // !WINNT_RAS
res = RES_OK;
}
else
{
ASSERT(0);
res = RES_E_FAIL;
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute the 'set' statement
Returns: RES_OK
or some error result
Cond: --
*/
RES PRIVATE SetStmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
ASSERT(this);
ASSERT(pastexec);
switch (SetStmt_GetType(this))
{
case ST_IPADDR:
res = IPAddrData_Exec(this, pastexec);
break;
case ST_PORT:
res = PortData_Exec(this, pastexec);
break;
case ST_SCREEN:
res = Screen_Exec(this, pastexec);
break;
default:
ASSERT(0);
res = RES_E_INVALIDPARAM;
break;
}
return res;
}
/*----------------------------------------------------------
Purpose: Execute a statement. This function should not be
called to execute a pending statement or expression.
Ast_ExecPending should be used for that purpose.
statements are executed--expressions are evaluated
by the statement execs.
The one exception is when an expression is being
evaluated and it must wait for pending events
(such as more data from the port). In this case it
is put on the pending queue and re-executed here.
Returns: RES_OK
or some error result
Cond: --
*/
RES PUBLIC Stmt_Exec(
PSTMT this,
PASTEXEC pastexec)
{
RES res;
ASSERT(this);
ASSERT(pastexec);
switch (Ast_GetType(this))
{
case AT_ENTER_STMT:
res = EnterStmt_Exec(this, pastexec);
break;
case AT_LEAVE_STMT:
res = LeaveStmt_Exec(this, pastexec);
break;
case AT_WHILE_STMT:
res = WhileStmt_Exec(this, pastexec);
break;
case AT_IF_STMT:
res = IfStmt_Exec(this, pastexec);
break;
case AT_ASSIGN_STMT:
res = AssignStmt_Exec(this, pastexec);
break;
case AT_HALT_STMT:
res = HaltStmt_Exec(this, pastexec);
break;
case AT_TRANSMIT_STMT:
res = TransmitStmt_Exec(this, pastexec);
break;
case AT_WAITFOR_STMT:
res = WaitforStmt_Exec(this, pastexec);
break;
case AT_DELAY_STMT:
res = DelayStmt_Exec(this, pastexec);
break;
case AT_LABEL_STMT:
ASSERT(0); // shouldn't really get here
res = RES_E_FAIL;
break;
case AT_GOTO_STMT:
res = GotoStmt_Exec(this, pastexec);
break;
case AT_SET_STMT:
res = SetStmt_Exec(this, pastexec);
break;
default:
ASSERT(0);
res = RES_E_INVALIDPARAM;
break;
}
// Was the statement completed?
if (RES_OK == res)
{
// Yes; mark all the expressions in the statement as "not done"
// so they will be evaluated from scratch if this statement
// is executed again.
Stmt_Clean(this);
}
return res;
}