Source code of Windows XP (NT5)
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
35 KiB

  1. //
  2. // Copyright (c) Microsoft Corporation 1995
  3. //
  4. // eval.c
  5. //
  6. // This file contains the evaluation functions for the
  7. // abstract syntax tree.
  8. //
  9. // History:
  10. // 06-15-95 ScottH Created
  11. //
  12. #include "proj.h"
  13. #include "rcids.h"
  14. #include "debug.h"
  15. #define MSECS_FROM_SECS(s) ((s)*1000)
  16. #define RAS_DUMMY_PASSWORD "****************"
  17. //
  18. // Clean expressions
  19. //
  20. /*----------------------------------------------------------
  21. Purpose: Clean expressions.
  22. Returns: --
  23. Cond: --
  24. */
  25. void PRIVATE Expr_Clean(
  26. PEXPR this)
  27. {
  28. ASSERT(this);
  29. switch (Ast_GetType(this))
  30. {
  31. case AT_INT_EXPR:
  32. case AT_BOOL_EXPR:
  33. case AT_STRING_EXPR:
  34. case AT_VAR_EXPR:
  35. ClearFlag(this->dwFlags, EF_DONE);
  36. break;
  37. case AT_UNOP_EXPR:
  38. ClearFlag(this->dwFlags, EF_DONE);
  39. Expr_Clean(UnOpExpr_GetExpr(this));
  40. break;
  41. case AT_BINOP_EXPR:
  42. ClearFlag(this->dwFlags, EF_DONE);
  43. Expr_Clean(BinOpExpr_GetExpr1(this));
  44. Expr_Clean(BinOpExpr_GetExpr2(this));
  45. break;
  46. default:
  47. ASSERT(0);
  48. break;
  49. }
  50. }
  51. /*----------------------------------------------------------
  52. Purpose: Clean the expressions in the 'waitfor' statement.
  53. Returns: --
  54. Cond: --
  55. */
  56. void PRIVATE WaitforStmt_Clean(
  57. PSTMT this)
  58. {
  59. PEXPR pexpr;
  60. HSA hsa = WaitforStmt_GetCaseList(this);
  61. DWORD ccase = SAGetCount(hsa);
  62. DWORD i;
  63. pexpr = WaitforStmt_GetUntilExpr(this);
  64. if (pexpr)
  65. Expr_Clean(pexpr);
  66. for (i = 0; i < ccase; i++)
  67. {
  68. PWAITCASE pwc;
  69. SAGetItemPtr(hsa, i, &pwc);
  70. ASSERT(pwc);
  71. Expr_Clean(pwc->pexpr);
  72. }
  73. }
  74. /*----------------------------------------------------------
  75. Purpose: Clean the expressions in the statement
  76. Returns: --
  77. Cond: --
  78. */
  79. void PRIVATE Stmt_Clean(
  80. PSTMT this)
  81. {
  82. PEXPR pexpr;
  83. ASSERT(this);
  84. switch (Ast_GetType(this))
  85. {
  86. case AT_ENTER_STMT:
  87. case AT_LEAVE_STMT:
  88. case AT_HALT_STMT:
  89. case AT_LABEL_STMT:
  90. case AT_GOTO_STMT:
  91. break;
  92. case AT_WHILE_STMT:
  93. pexpr = WhileStmt_GetExpr(this);
  94. Expr_Clean(pexpr);
  95. break;
  96. case AT_IF_STMT:
  97. pexpr = IfStmt_GetExpr(this);
  98. Expr_Clean(pexpr);
  99. break;
  100. case AT_ASSIGN_STMT:
  101. pexpr = AssignStmt_GetExpr(this);
  102. Expr_Clean(pexpr);
  103. break;
  104. case AT_TRANSMIT_STMT:
  105. pexpr = TransmitStmt_GetExpr(this);
  106. Expr_Clean(pexpr);
  107. break;
  108. case AT_WAITFOR_STMT:
  109. WaitforStmt_Clean(this);
  110. break;
  111. case AT_DELAY_STMT:
  112. pexpr = DelayStmt_GetExpr(this);
  113. Expr_Clean(pexpr);
  114. break;
  115. case AT_SET_STMT:
  116. switch (SetStmt_GetType(this))
  117. {
  118. case ST_IPADDR:
  119. pexpr = SetIPStmt_GetExpr(this);
  120. Expr_Clean(pexpr);
  121. break;
  122. case ST_PORT:
  123. case ST_SCREEN:
  124. break;
  125. default:
  126. ASSERT(0);
  127. break;
  128. }
  129. break;
  130. default:
  131. ASSERT(0);
  132. break;
  133. }
  134. }
  135. //
  136. // Evaluate expressions
  137. //
  138. /*----------------------------------------------------------
  139. Purpose: Evaluates the expression and returns an integer.
  140. Returns: RES_OK
  141. Cond: --
  142. */
  143. RES PRIVATE IntExpr_Eval(
  144. PEXPR this)
  145. {
  146. ASSERT(this);
  147. ASSERT(AT_INT_EXPR == Ast_GetType(this));
  148. ASSERT(DATA_INT == Expr_GetDataType(this));
  149. Expr_SetRes(this, IntExpr_GetVal(this));
  150. return RES_OK;
  151. }
  152. /*----------------------------------------------------------
  153. Purpose: Evaluates the expression and returns a string.
  154. The returned string should not be freed.
  155. Returns: RES_OK
  156. Cond: --
  157. */
  158. RES PRIVATE StrExpr_Eval(
  159. PEXPR this)
  160. {
  161. ASSERT(this);
  162. ASSERT(AT_STRING_EXPR == Ast_GetType(this));
  163. ASSERT(DATA_STRING == Expr_GetDataType(this));
  164. Expr_SetRes(this, (ULONG_PTR) StrExpr_GetStr(this));
  165. return RES_OK;
  166. }
  167. /*----------------------------------------------------------
  168. Purpose: Evaluates the expression and returns a boolean
  169. Returns: RES_OK
  170. Cond: --
  171. */
  172. RES PRIVATE BoolExpr_Eval(
  173. PEXPR this)
  174. {
  175. ASSERT(this);
  176. ASSERT(AT_BOOL_EXPR == Ast_GetType(this));
  177. ASSERT(DATA_BOOL == Expr_GetDataType(this));
  178. Expr_SetRes(this, BoolExpr_GetVal(this));
  179. return RES_OK;
  180. }
  181. /*----------------------------------------------------------
  182. Purpose: Returns the value of the variable.
  183. Returns: RES_OK
  184. Cond: --
  185. */
  186. RES PRIVATE VarExpr_Eval(
  187. PEXPR this,
  188. PASTEXEC pastexec)
  189. {
  190. RES res;
  191. PSTE pste;
  192. LPSTR pszIdent;
  193. ASSERT(this);
  194. ASSERT(AT_VAR_EXPR == Ast_GetType(this));
  195. pszIdent = VarExpr_GetIdent(this);
  196. if (RES_OK == Symtab_FindEntry(pastexec->pstCur, pszIdent, STFF_DEFAULT, &pste, NULL))
  197. {
  198. EVALRES er;
  199. STE_GetValue(pste, &er);
  200. Expr_SetRes(this, er.dw);
  201. res = RES_OK;
  202. }
  203. else
  204. {
  205. ASSERT(0);
  206. res = RES_E_FAIL;
  207. }
  208. return res;
  209. }
  210. /*----------------------------------------------------------
  211. Purpose: Evaluates the expression..
  212. The returned string should not be freed.
  213. Returns: RES_OK
  214. Cond: --
  215. */
  216. RES PRIVATE BinOpExpr_Eval(
  217. PEXPR this,
  218. PASTEXEC pastexec)
  219. {
  220. RES res;
  221. PEXPR pexpr1;
  222. PEXPR pexpr2;
  223. ASSERT(this);
  224. ASSERT(AT_BINOP_EXPR == Ast_GetType(this));
  225. pexpr1 = BinOpExpr_GetExpr1(this);
  226. res = Expr_Eval(pexpr1, pastexec);
  227. if (RES_OK == res)
  228. {
  229. pexpr2 = BinOpExpr_GetExpr2(this);
  230. res = Expr_Eval(pexpr2, pastexec);
  231. if (RES_OK == res)
  232. {
  233. PEVALRES per1 = Expr_GetRes(pexpr1);
  234. PEVALRES per2 = Expr_GetRes(pexpr2);
  235. DATATYPE dt = Expr_GetDataType(pexpr1);
  236. // Data types must be the same. This was checked
  237. // during the typechecking phase.
  238. ASSERT(Expr_GetDataType(pexpr1) == Expr_GetDataType(pexpr2));
  239. switch (BinOpExpr_GetType(this))
  240. {
  241. case BOT_OR:
  242. ASSERT(DATA_BOOL == dt);
  243. Expr_SetRes(this, per1->bVal || per2->bVal);
  244. break;
  245. case BOT_AND:
  246. ASSERT(DATA_BOOL == dt);
  247. Expr_SetRes(this, per1->bVal && per2->bVal);
  248. break;
  249. case BOT_LEQ:
  250. ASSERT(DATA_INT == dt);
  251. Expr_SetRes(this, per1->nVal <= per2->nVal);
  252. break;
  253. case BOT_LT:
  254. ASSERT(DATA_INT == dt);
  255. Expr_SetRes(this, per1->nVal < per2->nVal);
  256. break;
  257. case BOT_GEQ:
  258. ASSERT(DATA_INT == dt);
  259. Expr_SetRes(this, per1->nVal >= per2->nVal);
  260. break;
  261. case BOT_GT:
  262. ASSERT(DATA_INT == dt);
  263. Expr_SetRes(this, per1->nVal > per2->nVal);
  264. break;
  265. case BOT_NEQ:
  266. switch (dt)
  267. {
  268. case DATA_INT:
  269. Expr_SetRes(this, per1->nVal != per2->nVal);
  270. break;
  271. case DATA_STRING:
  272. Expr_SetRes(this, !IsSzEqualC(per1->psz, per2->psz));
  273. break;
  274. case DATA_BOOL:
  275. Expr_SetRes(this, per1->bVal != per2->bVal);
  276. break;
  277. default:
  278. ASSERT(0);
  279. break;
  280. }
  281. break;
  282. case BOT_EQ:
  283. switch (dt)
  284. {
  285. case DATA_INT:
  286. Expr_SetRes(this, per1->nVal == per2->nVal);
  287. break;
  288. case DATA_STRING:
  289. Expr_SetRes(this, IsSzEqualC(per1->psz, per2->psz));
  290. break;
  291. case DATA_BOOL:
  292. Expr_SetRes(this, per1->bVal == per2->bVal);
  293. break;
  294. default:
  295. ASSERT(0);
  296. break;
  297. }
  298. break;
  299. case BOT_PLUS:
  300. switch (dt)
  301. {
  302. case DATA_INT:
  303. // Add two integers
  304. Expr_SetRes(this, per1->nVal + per2->nVal);
  305. break;
  306. case DATA_STRING: {
  307. LPSTR psz = NULL;
  308. // Concatenate strings
  309. if ( !GSetString(&psz, per1->psz) ||
  310. !GCatString(&psz, per2->psz))
  311. {
  312. // Free whatever was allocated
  313. GSetString(&psz, NULL);
  314. res = Stxerr_Add(pastexec->hsaStxerr, NULL, Ast_GetLine(this), RES_E_OUTOFMEMORY);
  315. }
  316. Expr_SetRes(this, (ULONG_PTR) psz);
  317. SetFlag(this->dwFlags, EF_ALLOCATED);
  318. }
  319. break;
  320. default:
  321. ASSERT(0);
  322. break;
  323. }
  324. break;
  325. case BOT_MINUS:
  326. ASSERT(DATA_INT == dt);
  327. Expr_SetRes(this, per1->nVal - per2->nVal);
  328. break;
  329. case BOT_MULT:
  330. ASSERT(DATA_INT == dt);
  331. Expr_SetRes(this, per1->nVal * per2->nVal);
  332. break;
  333. case BOT_DIV:
  334. ASSERT(DATA_INT == dt);
  335. if (0 == per2->nVal)
  336. res = Stxerr_Add(pastexec->hsaStxerr, NULL, Ast_GetLine(this), RES_E_DIVBYZERO);
  337. else
  338. Expr_SetRes(this, per1->nVal / per2->nVal);
  339. break;
  340. default:
  341. ASSERT(0);
  342. res = RES_E_INVALIDPARAM;
  343. break;
  344. }
  345. }
  346. }
  347. return res;
  348. }
  349. /*----------------------------------------------------------
  350. Purpose: Evaluate 'getip'.
  351. Returns: RES_OK
  352. RES_FALSE (if the IP address was not read yet)
  353. Cond: --
  354. */
  355. RES PRIVATE GetIPExpr_Eval(
  356. PEXPR this,
  357. PASTEXEC pastexec,
  358. int nIter)
  359. {
  360. RES res;
  361. DWORD iDummy;
  362. ASSERT(this);
  363. ASSERT(pastexec);
  364. ASSERT(0 < nIter);
  365. TRACE_MSG(TF_ASTEXEC, "Exec: getip %d", nIter);
  366. // Is this function getting re-called due to a pending read?
  367. if ( !Astexec_IsReadPending(pastexec) )
  368. {
  369. // No; prepare to extract the nth IP address
  370. ClearFlag(this->dwFlags, EF_DONE);
  371. ASSERT(NULL == pastexec->hFindFmt);
  372. res = CreateFindFormat(&pastexec->hFindFmt);
  373. if (RSUCCEEDED(res))
  374. {
  375. res = AddFindFormat(pastexec->hFindFmt, "%u.%u.%u.%u", FFF_DEFAULT,
  376. pastexec->szIP, sizeof(pastexec->szIP));
  377. if (RSUCCEEDED(res))
  378. {
  379. // Extract the nth IP address.
  380. pastexec->nIter = nIter;
  381. ASSERT(0 < pastexec->nIter);
  382. }
  383. }
  384. }
  385. if(NULL != pastexec->hFindFmt)
  386. {
  387. res = Astexec_FindFormat(pastexec, &iDummy);
  388. if (RES_OK == res)
  389. {
  390. // Allocate or resize the pointer we already have
  391. LPSTR psz = Expr_GetRes(this)->psz;
  392. if ( !GSetString(&psz, Astexec_GetIPAddr(pastexec)) )
  393. res = Stxerr_Add(pastexec->hsaStxerr, NULL,
  394. Ast_GetLine(this), RES_E_OUTOFMEMORY);
  395. else
  396. {
  397. Expr_SetRes(this, (ULONG_PTR) psz);
  398. SetFlag(this->dwFlags, EF_ALLOCATED);
  399. }
  400. }
  401. }
  402. else
  403. {
  404. res = RES_E_FAIL;
  405. }
  406. return res;
  407. }
  408. /*----------------------------------------------------------
  409. Purpose: Evaluates the expression and returns an integer.
  410. Returns: RES_OK
  411. Cond: --
  412. */
  413. RES PRIVATE UnOpExpr_Eval(
  414. PEXPR this,
  415. PASTEXEC pastexec)
  416. {
  417. RES res = RES_OK;
  418. PEVALRES per;
  419. PEXPR pexpr;
  420. DATATYPE dt;
  421. ASSERT(this);
  422. ASSERT(AT_UNOP_EXPR == Ast_GetType(this));
  423. pexpr = UnOpExpr_GetExpr(this);
  424. res = Expr_Eval(pexpr, pastexec);
  425. if (RES_OK == res)
  426. {
  427. per = Expr_GetRes(pexpr);
  428. dt = Expr_GetDataType(pexpr);
  429. switch (UnOpExpr_GetType(this))
  430. {
  431. case UOT_NEG:
  432. ASSERT(DATA_INT == dt);
  433. Expr_SetRes(this, -per->nVal);
  434. break;
  435. case UOT_NOT:
  436. ASSERT(DATA_BOOL == dt);
  437. Expr_SetRes(this, !per->bVal);
  438. break;
  439. case UOT_GETIP:
  440. ASSERT(DATA_INT == dt);
  441. if (0 < per->nVal)
  442. res = GetIPExpr_Eval(this, pastexec, per->nVal);
  443. else
  444. res = Stxerr_Add(pastexec->hsaStxerr, "'getip' parameter", Ast_GetLine(pexpr), RES_E_INVALIDRANGE);
  445. break;
  446. default:
  447. ASSERT(0);
  448. break;
  449. }
  450. }
  451. return res;
  452. }
  453. /*----------------------------------------------------------
  454. Purpose: Evaluates the expression and returns a value.
  455. Returns: RES_OK
  456. Cond: --
  457. */
  458. RES PUBLIC Expr_Eval(
  459. PEXPR this,
  460. PASTEXEC pastexec)
  461. {
  462. RES res;
  463. ASSERT(this);
  464. ASSERT(pastexec);
  465. // Has this expression already been evaluated?
  466. if (IsFlagSet(this->dwFlags, EF_DONE))
  467. {
  468. // Yes; just return
  469. res = RES_OK;
  470. }
  471. else
  472. {
  473. // No; evaluate it
  474. switch (Ast_GetType(this))
  475. {
  476. case AT_INT_EXPR:
  477. res = IntExpr_Eval(this);
  478. break;
  479. case AT_BOOL_EXPR:
  480. res = BoolExpr_Eval(this);
  481. break;
  482. case AT_STRING_EXPR:
  483. res = StrExpr_Eval(this);
  484. break;
  485. case AT_VAR_EXPR:
  486. res = VarExpr_Eval(this, pastexec);
  487. break;
  488. case AT_UNOP_EXPR:
  489. res = UnOpExpr_Eval(this, pastexec);
  490. break;
  491. case AT_BINOP_EXPR:
  492. res = BinOpExpr_Eval(this, pastexec);
  493. break;
  494. default:
  495. ASSERT(0);
  496. res = RES_E_INVALIDPARAM;
  497. break;
  498. }
  499. }
  500. return res;
  501. }
  502. /*----------------------------------------------------------
  503. Purpose: Execute the prolog
  504. Returns: RES_OK
  505. or some error result
  506. Cond: --
  507. */
  508. RES PRIVATE EnterStmt_Exec(
  509. PSTMT this,
  510. PASTEXEC pastexec)
  511. {
  512. ASSERT(this);
  513. ASSERT(pastexec);
  514. TRACE_MSG(TF_ASTEXEC, "Exec: enter");
  515. pastexec->cProcDepth++;
  516. pastexec->pstCur = EnterStmt_GetSymtab(this);
  517. ASSERT(pastexec->pstCur);
  518. return RES_OK;
  519. }
  520. /*----------------------------------------------------------
  521. Purpose: Execute the epilog
  522. Returns: RES_OK
  523. or some error result
  524. Cond: --
  525. */
  526. RES PRIVATE LeaveStmt_Exec(
  527. PSTMT this,
  528. PASTEXEC pastexec)
  529. {
  530. RES res;
  531. ASSERT(this);
  532. ASSERT(pastexec);
  533. TRACE_MSG(TF_ASTEXEC, "Exec: leave");
  534. ASSERT(0 < pastexec->cProcDepth);
  535. pastexec->cProcDepth--;
  536. pastexec->pstCur = Symtab_GetNext(pastexec->pstCur);
  537. ASSERT(pastexec->pstCur);
  538. // Leaving main procedure?
  539. if (0 == pastexec->cProcDepth)
  540. {
  541. // Yes
  542. SetFlag(pastexec->dwFlags, AEF_DONE);
  543. res = RES_HALT;
  544. }
  545. else
  546. res = RES_OK;
  547. return res;
  548. }
  549. /*----------------------------------------------------------
  550. Purpose: Execute the assignment statement
  551. Returns: RES_OK
  552. or some error result
  553. Cond: --
  554. */
  555. RES PRIVATE AssignStmt_Exec(
  556. PSTMT this,
  557. PASTEXEC pastexec)
  558. {
  559. RES res;
  560. LPSTR pszIdent;
  561. PSTE pste;
  562. ASSERT(this);
  563. ASSERT(pastexec);
  564. pszIdent = AssignStmt_GetIdent(this);
  565. if (RES_OK == Symtab_FindEntry(pastexec->pstCur, pszIdent, STFF_DEFAULT, &pste, NULL))
  566. {
  567. PEXPR pexpr;
  568. pexpr = AssignStmt_GetExpr(this);
  569. res = Expr_Eval(pexpr, pastexec);
  570. if (RES_OK == res)
  571. {
  572. PEVALRES per = Expr_GetRes(pexpr);
  573. DEBUG_CODE( DATATYPE dt; )
  574. #ifdef DEBUG
  575. dt = Expr_GetDataType(pexpr);
  576. switch (dt)
  577. {
  578. case DATA_STRING:
  579. TRACE_MSG(TF_ASTEXEC, "Exec: %s = \"%s\"", pszIdent, per->psz);
  580. break;
  581. case DATA_INT:
  582. TRACE_MSG(TF_ASTEXEC, "Exec: %s = %d", pszIdent, per->nVal);
  583. break;
  584. case DATA_BOOL:
  585. TRACE_MSG(TF_ASTEXEC, "Exec: %s = %s", pszIdent, per->bVal ? (LPSTR)"TRUE" : (LPSTR)"FALSE");
  586. break;
  587. default:
  588. ASSERT(0);
  589. break;
  590. }
  591. #endif
  592. pste->er.dw = per->dw;
  593. }
  594. }
  595. else
  596. {
  597. // The identifier should have been in the symbol table!
  598. ASSERT(0);
  599. res = RES_E_FAIL;
  600. }
  601. return res;
  602. }
  603. /*----------------------------------------------------------
  604. Purpose: Execute the 'while' statement
  605. Returns: RES_OK
  606. or some error result
  607. Cond: --
  608. */
  609. RES PRIVATE WhileStmt_Exec(
  610. PSTMT this,
  611. PASTEXEC pastexec)
  612. {
  613. RES res;
  614. PEXPR pexpr;
  615. ASSERT(this);
  616. ASSERT(pastexec);
  617. pexpr = WhileStmt_GetExpr(this);
  618. res = Expr_Eval(pexpr, pastexec);
  619. if (RES_OK == res)
  620. {
  621. PEVALRES per = Expr_GetRes(pexpr);
  622. if (!per->bVal)
  623. {
  624. res = Astexec_JumpToLabel(pastexec, WhileStmt_GetEndLabel(this));
  625. }
  626. }
  627. return res;
  628. }
  629. /*----------------------------------------------------------
  630. Purpose: Execute the 'if' statement
  631. Returns: RES_OK
  632. or some error result
  633. Cond: --
  634. */
  635. RES PRIVATE IfStmt_Exec(
  636. PSTMT this,
  637. PASTEXEC pastexec)
  638. {
  639. RES res;
  640. PEXPR pexpr;
  641. ASSERT(this);
  642. ASSERT(pastexec);
  643. pexpr = IfStmt_GetExpr(this);
  644. res = Expr_Eval(pexpr, pastexec);
  645. if (RES_OK == res)
  646. {
  647. PEVALRES per = Expr_GetRes(pexpr);
  648. if (!per->bVal)
  649. {
  650. res = Astexec_JumpToLabel(pastexec, IfStmt_GetElseLabel(this));
  651. }
  652. }
  653. return res;
  654. }
  655. /*----------------------------------------------------------
  656. Purpose: Execute the 'halt' statement
  657. Returns: RES_OK
  658. or some error result
  659. Cond: --
  660. */
  661. RES PRIVATE HaltStmt_Exec(
  662. PSTMT this,
  663. PASTEXEC pastexec)
  664. {
  665. ASSERT(this);
  666. ASSERT(pastexec);
  667. TRACE_MSG(TF_ASTEXEC, "Exec: halt");
  668. SetFlag(pastexec->dwFlags, AEF_HALT);
  669. return RES_HALT;
  670. }
  671. /*----------------------------------------------------------
  672. Purpose: Execute the 'goto' statement
  673. Returns: RES_OK
  674. or some error result
  675. Cond: --
  676. */
  677. RES PRIVATE GotoStmt_Exec(
  678. PSTMT this,
  679. PASTEXEC pastexec)
  680. {
  681. LPSTR pszIdent;
  682. ASSERT(this);
  683. ASSERT(pastexec);
  684. pszIdent = GotoStmt_GetIdent(this);
  685. TRACE_MSG(TF_ASTEXEC, "Exec: goto %s", pszIdent);
  686. return Astexec_JumpToLabel(pastexec, pszIdent);
  687. }
  688. /*----------------------------------------------------------
  689. Purpose: Execute the 'transmit' statement
  690. Returns: RES_OK
  691. or some error result
  692. Cond: --
  693. */
  694. RES PRIVATE TransmitStmt_Exec(
  695. PSTMT this,
  696. PASTEXEC pastexec)
  697. {
  698. RES res;
  699. PEXPR pexpr;
  700. ASSERT(this);
  701. ASSERT(pastexec);
  702. pexpr = TransmitStmt_GetExpr(this);
  703. res = Expr_Eval(pexpr, pastexec);
  704. if (RES_OK == res)
  705. {
  706. PEVALRES per = Expr_GetRes(pexpr);
  707. DWORD dwFlags = TransmitStmt_GetFlags(this);
  708. CHAR *pszPassword;
  709. TRACE_MSG(TF_ASTEXEC, "Exec: transmit \"%s\"", per->psz);
  710. #ifdef WINNT_RAS
  711. //
  712. // JEFFSI WHISTLER
  713. //
  714. // RASSCRPT_TRACE1("Exec: transmit \"%s\"", per->psz);
  715. if (pszPassword = strstr(per->psz, RAS_DUMMY_PASSWORD))
  716. {
  717. CHAR *psz;
  718. CHAR controlchar = '\0';
  719. #define IS_CARET(ch) ('^' == (ch))
  720. if(per->psz != pszPassword)
  721. {
  722. CHAR *pszT, *pszPrefix = LocalAlloc(LPTR, strlen(per->psz));
  723. if(NULL == pszPrefix)
  724. {
  725. res = E_OUTOFMEMORY;
  726. return res;
  727. }
  728. psz = per->psz;
  729. pszT = pszPrefix;
  730. while(psz != pszPassword)
  731. {
  732. *pszT++ = *psz++;
  733. }
  734. Astexec_SendString(pastexec, pszPrefix,
  735. IsFlagSet(dwFlags, TSF_RAW));
  736. RASSCRPT_TRACE1("Exec: transmi \"%s\"", pszPrefix);
  737. LocalFree(pszPrefix);
  738. }
  739. //
  740. // Check to see if we need to send a control char
  741. // at the end.
  742. //
  743. psz = pszPassword + lstrlen(RAS_DUMMY_PASSWORD);
  744. if(IS_CARET(*psz))
  745. {
  746. psz++;
  747. if(!*psz)
  748. {
  749. ;
  750. }
  751. if (InRange(*psz, '@', '_'))
  752. {
  753. controlchar = *psz - '@';
  754. }
  755. else if (InRange(*psz, 'a', 'z'))
  756. {
  757. controlchar = *psz - 'a' + 1;
  758. }
  759. }
  760. (VOID) RxSendCreds(((SCRIPTDATA*)pastexec->hwnd)->hscript,
  761. controlchar);
  762. }
  763. else
  764. {
  765. Astexec_SendString(pastexec, per->psz, IsFlagSet(dwFlags, TSF_RAW));
  766. }
  767. #else
  768. Astexec_SendString(pastexec, per->psz, IsFlagSet(dwFlags, TSF_RAW));
  769. #endif
  770. }
  771. return res;
  772. }
  773. /*----------------------------------------------------------
  774. Purpose: Evaluates each of the wait-case expressions.
  775. Returns: RES_OK
  776. Cond: --
  777. */
  778. RES PRIVATE WaitforStmt_EvalCaseList(
  779. PSTMT this,
  780. PASTEXEC pastexec)
  781. {
  782. RES res = RES_E_FAIL;
  783. HSA hsa = WaitforStmt_GetCaseList(this);
  784. DWORD i;
  785. DWORD ccase = SAGetCount(hsa);
  786. PWAITCASE pwc;
  787. ASSERT(0 < ccase);
  788. for (i = 0; i < ccase; i++)
  789. {
  790. SAGetItemPtr(hsa, i, &pwc);
  791. ASSERT(pwc);
  792. res = Expr_Eval(pwc->pexpr, pastexec);
  793. if (RES_OK != res)
  794. break;
  795. }
  796. return res;
  797. }
  798. /*----------------------------------------------------------
  799. Purpose: Packages each of the evaluated wait-case expressions
  800. into an array of strings to search for.
  801. Returns: RES_OK
  802. Cond: --
  803. */
  804. RES PRIVATE WaitforStmt_WrapEmUp(
  805. PSTMT this,
  806. HANDLE hFindFmt)
  807. {
  808. RES res = RES_OK;
  809. HSA hsa = WaitforStmt_GetCaseList(this);
  810. DWORD i;
  811. DWORD ccase = SAGetCount(hsa);
  812. PWAITCASE pwc;
  813. PEVALRES per;
  814. ASSERT(0 < ccase);
  815. for (i = 0; i < ccase; i++)
  816. {
  817. DWORD dwFlags = FFF_DEFAULT;
  818. SAGetItemPtr(hsa, i, &pwc);
  819. ASSERT(pwc);
  820. if (IsFlagSet(pwc->dwFlags, WCF_MATCHCASE))
  821. SetFlag(dwFlags, FFF_MATCHCASE);
  822. per = Expr_GetRes(pwc->pexpr);
  823. res = AddFindFormat(hFindFmt, per->psz, dwFlags, NULL, 0);
  824. if (RFAILED(res))
  825. break;
  826. }
  827. return res;
  828. }
  829. /*----------------------------------------------------------
  830. Purpose: Execute the then clause based upon the given case
  831. index.
  832. Returns: RES_OK
  833. Cond: --
  834. */
  835. RES PRIVATE WaitforStmt_ExecThen(
  836. PSTMT this,
  837. DWORD isa,
  838. PASTEXEC pastexec)
  839. {
  840. RES res = RES_OK;
  841. HSA hsa = WaitforStmt_GetCaseList(this);
  842. PWAITCASE pwc;
  843. if (SAGetItemPtr(hsa, isa, &pwc))
  844. {
  845. ASSERT(pwc);
  846. // If there is a label, jump to it
  847. if (pwc->pszIdent)
  848. res = Astexec_JumpToLabel(pastexec, pwc->pszIdent);
  849. }
  850. else
  851. {
  852. ASSERT(0);
  853. res = RES_E_FAIL;
  854. }
  855. return res;
  856. }
  857. /*----------------------------------------------------------
  858. Purpose: Execute the 'waitfor' statement
  859. Returns: RES_OK
  860. or some error result
  861. Cond: --
  862. */
  863. RES PRIVATE WaitforStmt_Exec(
  864. PSTMT this,
  865. PASTEXEC pastexec)
  866. {
  867. RES res = RES_OK;
  868. PEXPR pexpr;
  869. int nTimeoutSecs = -1;
  870. ASSERT(this);
  871. ASSERT(pastexec);
  872. // First evaluate the optional 'until' time
  873. pexpr = WaitforStmt_GetUntilExpr(this);
  874. if (pexpr)
  875. {
  876. res = Expr_Eval(pexpr, pastexec);
  877. if (RES_OK == res)
  878. {
  879. PEVALRES per = Expr_GetRes(pexpr);
  880. nTimeoutSecs = per->nVal;
  881. if (0 >= nTimeoutSecs)
  882. res = Stxerr_Add(pastexec->hsaStxerr, "'until' parameter", Ast_GetLine(this), RES_E_INVALIDRANGE);
  883. }
  884. }
  885. if (RES_OK == res)
  886. {
  887. // Evaluate the waitfor string
  888. res = WaitforStmt_EvalCaseList(this, pastexec);
  889. if (RES_OK == res)
  890. {
  891. if (-1 == nTimeoutSecs)
  892. TRACE_MSG(TF_ASTEXEC, "Exec: waitfor ...");
  893. else
  894. TRACE_MSG(TF_ASTEXEC, "Exec: waitfor ... until %d", nTimeoutSecs);
  895. // Is this function getting re-called due to a pending read?
  896. if ( !Astexec_IsReadPending(pastexec) )
  897. {
  898. // No; prepare to wait for the string(s)
  899. ASSERT(NULL == pastexec->hFindFmt);
  900. res = CreateFindFormat(&pastexec->hFindFmt);
  901. if (RSUCCEEDED(res))
  902. {
  903. res = WaitforStmt_WrapEmUp(this, pastexec->hFindFmt);
  904. if (RSUCCEEDED(res))
  905. {
  906. ASSERT(IsFlagClear(pastexec->dwFlags, AEF_WAITUNTIL));
  907. ASSERT(IsFlagClear(pastexec->dwFlags, AEF_STOPWAITING));
  908. ASSERT(IsFlagClear(pastexec->dwFlags, AEF_PAUSED));
  909. pastexec->nIter = 1;
  910. if (-1 != nTimeoutSecs)
  911. {
  912. #ifndef WINNT_RAS
  913. //
  914. // On NT, timeouts are handled by setting dwTimeout in the SCRIPTDATA struct
  915. // for the current script.
  916. //
  917. if (0 != SetTimer(pastexec->hwnd, TIMER_DELAY, MSECS_FROM_SECS(nTimeoutSecs), NULL))
  918. #else // WINNT_RAS
  919. ((SCRIPTDATA *)pastexec->hwnd)->dwTimeout = MSECS_FROM_SECS(nTimeoutSecs);
  920. #endif // WINNT_RAS
  921. {
  922. SetFlag(pastexec->dwFlags, AEF_WAITUNTIL);
  923. }
  924. #ifndef WINNT_RAS
  925. else
  926. {
  927. res = Stxerr_Add(pastexec->hsaStxerr, "waitfor", Ast_GetLine(this), RES_E_FAIL);
  928. }
  929. #endif
  930. }
  931. }
  932. }
  933. }
  934. // Have we timed out yet?
  935. if (IsFlagSet(pastexec->dwFlags, AEF_STOPWAITING))
  936. {
  937. // Yes; don't wait for string anymore
  938. ClearFlag(pastexec->dwFlags, AEF_STOPWAITING);
  939. Astexec_SetError(pastexec, FALSE, FALSE);
  940. res = Astexec_DestroyFindFormat(pastexec);
  941. }
  942. else
  943. {
  944. // No; did we find a matching string?
  945. DWORD isa = 0;
  946. res = Astexec_FindFormat(pastexec, &isa);
  947. if (RES_OK == res)
  948. {
  949. // Yes; determine the next action
  950. ClearFlag(pastexec->dwFlags, AEF_WAITUNTIL);
  951. Astexec_SetError(pastexec, TRUE, FALSE);
  952. res = WaitforStmt_ExecThen(this, isa, pastexec);
  953. }
  954. }
  955. }
  956. }
  957. return res;
  958. }
  959. /*----------------------------------------------------------
  960. Purpose: Execute the 'delay' statement
  961. Returns: RES_OK
  962. or some error result
  963. Cond: --
  964. */
  965. RES PRIVATE DelayStmt_Exec(
  966. PSTMT this,
  967. PASTEXEC pastexec)
  968. {
  969. RES res;
  970. PEXPR pexpr;
  971. ASSERT(this);
  972. ASSERT(pastexec);
  973. pexpr = DelayStmt_GetExpr(this);
  974. res = Expr_Eval(pexpr, pastexec);
  975. if (RES_OK == res)
  976. {
  977. PEVALRES per = Expr_GetRes(pexpr);
  978. if (0 >= per->nVal)
  979. res = Stxerr_Add(pastexec->hsaStxerr, "'delay' parameter", Ast_GetLine(this), RES_E_INVALIDRANGE);
  980. else
  981. {
  982. TRACE_MSG(TF_ASTEXEC, "Exec: delay %ld", per->nVal);
  983. #ifndef WINNT_RAS
  984. //
  985. // On NT, timeouts are handled by setting dwTimeout in the SCRIPTDATA struct
  986. // for the current script.
  987. //
  988. if (0 != SetTimer(pastexec->hwnd, TIMER_DELAY, MSECS_FROM_SECS(per->nVal), NULL))
  989. #else // WINNT_RAS
  990. ((SCRIPTDATA *)pastexec->hwnd)->dwTimeout = MSECS_FROM_SECS(per->nVal);
  991. #endif // WINNT_RAS
  992. {
  993. // Success
  994. SetFlag(pastexec->dwFlags, AEF_PAUSED);
  995. }
  996. #ifndef WINNT_RAS
  997. else
  998. res = Stxerr_Add(pastexec->hsaStxerr, "delay", Ast_GetLine(this), RES_E_FAIL);
  999. #endif
  1000. }
  1001. }
  1002. return res;
  1003. }
  1004. /*----------------------------------------------------------
  1005. Purpose: Execute the 'set ipaddr' statement
  1006. Returns: RES_OK
  1007. or some error result
  1008. Cond: --
  1009. */
  1010. RES PRIVATE IPAddrData_Exec(
  1011. PSTMT this,
  1012. PASTEXEC pastexec)
  1013. {
  1014. RES res;
  1015. PEXPR pexpr;
  1016. ASSERT(this);
  1017. ASSERT(pastexec);
  1018. pexpr = SetIPStmt_GetExpr(this);
  1019. res = Expr_Eval(pexpr, pastexec);
  1020. if (RES_OK == res)
  1021. {
  1022. PEVALRES per = Expr_GetRes(pexpr);
  1023. ASSERT(per->psz);
  1024. TRACE_MSG(TF_ASTEXEC, "Exec: set ipaddr \"%s\"", per->psz);
  1025. Astexec_SetIPAddr(pastexec, per->psz);
  1026. }
  1027. return res;
  1028. }
  1029. /*----------------------------------------------------------
  1030. Purpose: Execute the 'set port' statement
  1031. Returns: RES_OK
  1032. or some error result
  1033. Cond: --
  1034. */
  1035. RES PRIVATE PortData_Exec(
  1036. PSTMT this,
  1037. PASTEXEC pastexec)
  1038. {
  1039. RES res = RES_OK;
  1040. DCB dcb;
  1041. DWORD dwFlags = SetPortStmt_GetFlags(this);
  1042. ASSERT(this);
  1043. ASSERT(pastexec);
  1044. #ifdef DEBUG
  1045. if (IsFlagSet(dwFlags, SPF_DATABITS))
  1046. TRACE_MSG(TF_ASTEXEC, "Exec: set port databits %u", SetPortStmt_GetDatabits(this));
  1047. if (IsFlagSet(dwFlags, SPF_STOPBITS))
  1048. TRACE_MSG(TF_ASTEXEC, "Exec: set port stopbits %u", SetPortStmt_GetStopbits(this));
  1049. if (IsFlagSet(dwFlags, SPF_PARITY))
  1050. TRACE_MSG(TF_ASTEXEC, "Exec: set port parity %u", SetPortStmt_GetParity(this));
  1051. #endif
  1052. #ifndef WINNT_RAS
  1053. //
  1054. // On NT, changes to port settings are done through the RasPortSetInfo API.
  1055. //
  1056. if (GetCommState(pastexec->hport, &dcb))
  1057. {
  1058. if (IsFlagSet(dwFlags, SPF_DATABITS))
  1059. dcb.ByteSize = SetPortStmt_GetDatabits(this);
  1060. if (IsFlagSet(dwFlags, SPF_STOPBITS))
  1061. dcb.StopBits = SetPortStmt_GetStopbits(this);
  1062. if (IsFlagSet(dwFlags, SPF_PARITY))
  1063. dcb.Parity = SetPortStmt_GetParity(this);
  1064. if (!SetCommState(pastexec->hport, &dcb))
  1065. res = Stxerr_Add(pastexec->hsaStxerr, "set port", Ast_GetLine(this), RES_E_FAIL);
  1066. }
  1067. else
  1068. res = Stxerr_Add(pastexec->hsaStxerr, "set port", Ast_GetLine(this), RES_E_FAIL);
  1069. #else // WINNT_RAS
  1070. res = (RES)RxSetPortData(
  1071. ((SCRIPTDATA*)pastexec->hwnd)->hscript, this
  1072. );
  1073. #endif // WINNT_RAS
  1074. return res;
  1075. }
  1076. /*----------------------------------------------------------
  1077. Purpose: Execute the 'set screen' statement
  1078. Returns: RES_OK
  1079. or some error result
  1080. Cond: --
  1081. */
  1082. RES PRIVATE Screen_Exec(
  1083. PSTMT this,
  1084. PASTEXEC pastexec)
  1085. {
  1086. RES res;
  1087. DWORD dwFlags = SetScreenStmt_GetFlags(this);
  1088. ASSERT(this);
  1089. ASSERT(pastexec);
  1090. #ifdef DEBUG
  1091. if (IsFlagSet(dwFlags, SPF_KEYBRD))
  1092. TRACE_MSG(TF_ASTEXEC, "Exec: set screen keyboard %s", SetScreenStmt_GetKeybrd(this) ? "on" : "off");
  1093. #endif
  1094. if (IsFlagSet(dwFlags, SPF_KEYBRD))
  1095. {
  1096. #ifndef WINNT_RAS
  1097. //
  1098. // On NT, we change the keyboard state by calling RxSetKeyboard
  1099. // which will signal an event-code telling whoever started this script
  1100. // that the keyboard should be disabled.
  1101. //
  1102. TerminalSetInput(pastexec->hwnd, SetScreenStmt_GetKeybrd(this));
  1103. #else // !WINNT_RAS
  1104. RxSetKeyboard(
  1105. ((SCRIPTDATA*)pastexec->hwnd)->hscript,
  1106. SetScreenStmt_GetKeybrd(this)
  1107. );
  1108. #endif // !WINNT_RAS
  1109. res = RES_OK;
  1110. }
  1111. else
  1112. {
  1113. ASSERT(0);
  1114. res = RES_E_FAIL;
  1115. }
  1116. return res;
  1117. }
  1118. /*----------------------------------------------------------
  1119. Purpose: Execute the 'set' statement
  1120. Returns: RES_OK
  1121. or some error result
  1122. Cond: --
  1123. */
  1124. RES PRIVATE SetStmt_Exec(
  1125. PSTMT this,
  1126. PASTEXEC pastexec)
  1127. {
  1128. RES res;
  1129. ASSERT(this);
  1130. ASSERT(pastexec);
  1131. switch (SetStmt_GetType(this))
  1132. {
  1133. case ST_IPADDR:
  1134. res = IPAddrData_Exec(this, pastexec);
  1135. break;
  1136. case ST_PORT:
  1137. res = PortData_Exec(this, pastexec);
  1138. break;
  1139. case ST_SCREEN:
  1140. res = Screen_Exec(this, pastexec);
  1141. break;
  1142. default:
  1143. ASSERT(0);
  1144. res = RES_E_INVALIDPARAM;
  1145. break;
  1146. }
  1147. return res;
  1148. }
  1149. /*----------------------------------------------------------
  1150. Purpose: Execute a statement. This function should not be
  1151. called to execute a pending statement or expression.
  1152. Ast_ExecPending should be used for that purpose.
  1153. statements are executed--expressions are evaluated
  1154. by the statement execs.
  1155. The one exception is when an expression is being
  1156. evaluated and it must wait for pending events
  1157. (such as more data from the port). In this case it
  1158. is put on the pending queue and re-executed here.
  1159. Returns: RES_OK
  1160. or some error result
  1161. Cond: --
  1162. */
  1163. RES PUBLIC Stmt_Exec(
  1164. PSTMT this,
  1165. PASTEXEC pastexec)
  1166. {
  1167. RES res;
  1168. ASSERT(this);
  1169. ASSERT(pastexec);
  1170. switch (Ast_GetType(this))
  1171. {
  1172. case AT_ENTER_STMT:
  1173. res = EnterStmt_Exec(this, pastexec);
  1174. break;
  1175. case AT_LEAVE_STMT:
  1176. res = LeaveStmt_Exec(this, pastexec);
  1177. break;
  1178. case AT_WHILE_STMT:
  1179. res = WhileStmt_Exec(this, pastexec);
  1180. break;
  1181. case AT_IF_STMT:
  1182. res = IfStmt_Exec(this, pastexec);
  1183. break;
  1184. case AT_ASSIGN_STMT:
  1185. res = AssignStmt_Exec(this, pastexec);
  1186. break;
  1187. case AT_HALT_STMT:
  1188. res = HaltStmt_Exec(this, pastexec);
  1189. break;
  1190. case AT_TRANSMIT_STMT:
  1191. res = TransmitStmt_Exec(this, pastexec);
  1192. break;
  1193. case AT_WAITFOR_STMT:
  1194. res = WaitforStmt_Exec(this, pastexec);
  1195. break;
  1196. case AT_DELAY_STMT:
  1197. res = DelayStmt_Exec(this, pastexec);
  1198. break;
  1199. case AT_LABEL_STMT:
  1200. ASSERT(0); // shouldn't really get here
  1201. res = RES_E_FAIL;
  1202. break;
  1203. case AT_GOTO_STMT:
  1204. res = GotoStmt_Exec(this, pastexec);
  1205. break;
  1206. case AT_SET_STMT:
  1207. res = SetStmt_Exec(this, pastexec);
  1208. break;
  1209. default:
  1210. ASSERT(0);
  1211. res = RES_E_INVALIDPARAM;
  1212. break;
  1213. }
  1214. // Was the statement completed?
  1215. if (RES_OK == res)
  1216. {
  1217. // Yes; mark all the expressions in the statement as "not done"
  1218. // so they will be evaluated from scratch if this statement
  1219. // is executed again.
  1220. Stmt_Clean(this);
  1221. }
  1222. return res;
  1223. }