// // 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; }