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.

1373 lines
41 KiB

  1. /*----------------------------------------------------------------------------
  2. %%File: EMTEST.C
  3. %%Unit: Event Monitor (mntr)
  4. %%Contact: daleg
  5. Event Monitor Sample Application, Main Program.
  6. The purpose of this application is to demonstrate how to process events
  7. using the Event Monitor's Rule Compiler and rule engine.
  8. ----------------------------------------------------------------------------*/
  9. //*** genem.c -- 'generic' evtmon client-side stuff
  10. // DESCRIPTION
  11. // the client-side of an evtmon app has two parts:
  12. // - evtmon generic code (client-side)
  13. // - application-specific rules
  14. // this file is reusable (and semi-frozen) generic code. it should be
  15. // #include'ed from the app.
  16. // NOTES
  17. // WARNING: do *not* put app-specific code here. put it in the
  18. // client (emclient/libem.c). in fact in general, think twice before
  19. // modifying this file at all.
  20. //*** YY_* -- generic rules support
  21. //
  22. #define YY_BASE 1 // base features (always needed)
  23. #ifdef YY_BASE
  24. // rulc.exe doesn't create all files if a given feature isn't used,
  25. // so we can't unconditionally include these guys. plus, we don't
  26. // want the helper code if we don't need it.
  27. // turn on these features here if you use them
  28. #ifndef YY_DELAYED
  29. #define YY_DELAYED 0 // delayed actions
  30. #endif
  31. #ifndef YY_CTOR
  32. #define YY_CTOR 0 // action ctors
  33. #endif
  34. #ifndef YY_SEQCHECK
  35. #define YY_SEQCHECK 0 // seq_check
  36. #endif
  37. #define YY_OTHER 0
  38. //#define YY_BRKPT()
  39. #endif
  40. //*** FEATURE_* -- domain-specific rules support
  41. // NOTES
  42. #define FEATURE_DEMO 0 // demo code (e.g. wndproc test app)
  43. #define FEATURE_SAMPLE 0 // sample code (e.g. joe-event firer)
  44. #define FEATURE_OFFICE 0 // base office stuff
  45. #define FEATURE_TEXT 0 // text parser
  46. #define FEATURE_WORD 0 // format parser
  47. #define FEATURE_DEAD 0 // unused/dead code
  48. #define FEATURE_NYI 0
  49. #include "mso.h"
  50. #include "msoem.h"
  51. DEBUGASSERTSZ
  52. #include "msolex.h"
  53. #include "emrule.h"
  54. #include "emkwd.h"
  55. #include "emact.h"
  56. #if FEATURE_DEMO
  57. #include "emtest.h"
  58. #include "emres.h"
  59. #endif
  60. // { Files generated by Rule Compiler
  61. #include "emdef.h" // rules (#defines)
  62. #if YY_CTOR // {
  63. #include "emacts.h" // ctor macro wrappers
  64. #endif // }
  65. #define DEBUG_RULE_POINTERS // Want ptrs to nodes
  66. #include "emruli.h" // rulebase
  67. #if YY_SEQCHECK // seq_check
  68. #include "emsqck.c_" // sequences
  69. #endif
  70. // }
  71. #if FEATURE_TEXT // {
  72. // Constants
  73. #define cbEditText 1024
  74. #ifdef STATIC_INIT
  75. #define grfLexFlagsEm (MsoGrfLexFNoReset \
  76. | MsoGrfLexFLookup \
  77. | MsoGrfLexFLookupIntsAndSyms \
  78. | MsoGrfLexFAllCapsAsFormat)
  79. // EM data structures
  80. MSORULTK rgrultkEmToken[200]; // Text Token cache
  81. MSORULTK rgrultkEmFormat[100]; // Format Token cache
  82. MSOLEXS vlexs =
  83. {
  84. &vkwtbEmTOKEN_KEYTABLE, // pkwtb
  85. {rgrultkEmToken, 200, }, // rultkhToken
  86. {rgrultkEmFormat, 100, }, // rultkhFormat
  87. fTrue, // fInited
  88. isttblDefault, // isttbl
  89. grfLexFlagsEm, // grpfLexFlags
  90. _hObjectNil, // hObjectNil
  91. MsoWchLexGetNextBufferDoc, // pfnlexbuf
  92. FGetNextLexRun, // pfnlexrun
  93. FGetTokenTextObject, // pfnlextxt
  94. NULL, // pfnlexfmt
  95. NULL, // pfnlexrunDiscontig
  96. NULL, // pfnlexrunForceCompl
  97. iNil, // ichRun
  98. -1, // cchLookahead
  99. };
  100. MSOLEXS *vplexs = &vlexs; // Global lexer state
  101. #else /* !STATIC_INIT */
  102. MSOLEXS vlexs; // Global lexer state
  103. MSOLEXS *vplexs; // Global lexer state
  104. #endif /* STATIC_INIT */
  105. #endif // }
  106. #if YY_BASE // {
  107. // Global variables
  108. RULS *vlpruls = &vrulsEm;
  109. #ifndef STATIC_LINK_EM
  110. RULS **_pvlprulsDLL = &vlpruls; // App's Global state
  111. #endif /* !STATIC_LINK_EM */
  112. #endif // }
  113. #if FEATURE_DEMO // {
  114. char vszAppName[20]; // Application name
  115. HWND vhInst; // Instance
  116. HWND vhWndMain; // Main window
  117. HWND vhWndDlg; // Dialog window
  118. char vszEditText[cbEditText]; // Text of edit control
  119. int vcchEditText; // #chs in edit control
  120. static int vcchPrev = 0; // Prev edit box len
  121. static int vcpIpPrev = 0; // Prev edit box ip
  122. int vfSettingDlgItem = fFalse; // Avoid Win recursion
  123. #endif // }
  124. #if YY_BASE // {
  125. #if YY_DELAYED
  126. #include "emactr.h" // data tables
  127. MSOACTTBL vacttbl = {vrgacttrecEm}; // Global action table
  128. MSOACTTBL *_pacttbl = &vacttbl; // Glob action tbl ptr
  129. #endif
  130. #endif // }
  131. #if FEATURE_OFFICE // {
  132. EMS vems; // EM global state
  133. EMS *vpems = &vems; // Ptr to global state
  134. #endif // }
  135. #if YY_BASE // {
  136. #ifdef DEBUG
  137. #ifndef STATIC_LINK_EM
  138. int vwDebugLogFilter = fDebugFilterAll;
  139. int vwDebugLogLvl = -2;
  140. #endif // !STATIC_LINK_EM
  141. // Pointers to global debug logging vars in Mso DLL
  142. int *pvwDebugLogFilter = &vwDebugLogFilter;
  143. int *pvwDebugLogLvl = &vwDebugLogLvl;
  144. #endif /* DEBUG */
  145. #endif // }
  146. #if YY_BASE // {
  147. #ifdef STATIC_INIT // {
  148. /* F I N I T E M */
  149. /*----------------------------------------------------------------------------
  150. %%Function: FInitEm
  151. %%Contact: daleg
  152. Initialize the static (compiled) Event Monitor rules.
  153. ----------------------------------------------------------------------------*/
  154. int FInitEm(void)
  155. {
  156. #ifndef STATIC_LINK_EM
  157. /* Mirror global debug pointers in Mso97.dll */
  158. Debug(pvwDebugLogLvl = MsoPwDebugLogLvl(&pvwDebugLogFilter);)
  159. #endif /* !STATIC_LINK_EM */
  160. Debug(*pvwDebugLogLvl = 7);
  161. #ifndef STATIC_LINK_EM
  162. /* Mirror global pointers (vlpruls, etc) in Mso97.dll */
  163. _pvlprulsDLL = MsoPvlprulsMirror(&vlpruls);
  164. *_pvlprulsDLL = &vrulsEm;
  165. #endif /* !STATIC_LINK_EM */
  166. #ifdef DYN_RULES
  167. /* Load dynamic rules */
  168. FLoadDynEmRules();
  169. #endif /* DYN_RULES */
  170. #if FEATURE_OFFICE
  171. /* For performance reasons, action table is global */
  172. vacttbl.prultkh = &vplexs->rultkhToken;
  173. #endif
  174. #if FEATURE_DEMO
  175. /* Allow Event Drivers to run */
  176. EnableEM();
  177. #endif
  178. /* Propagate the values through the rule network */
  179. MsoScheduleIrul(irul_YYSTD_INIT, fTrue);
  180. #ifdef DYN_RULES
  181. MsoScheduleIrul(irul_YYSTD_LOADING_RULEBASE, fTrue);
  182. #endif /* DYN_RULES */
  183. MsoEvaluateEvents(rulevtEm_YYSTD);
  184. return fTrue;
  185. }
  186. #else /* }{ !STATIC_INIT */
  187. /* F I N I T E M */
  188. /*----------------------------------------------------------------------------
  189. %%Function: FInitEm
  190. %%Contact: daleg
  191. Initialize the static (compiled) Event Monitor rules.
  192. ----------------------------------------------------------------------------*/
  193. int FInitEm(void)
  194. {
  195. #ifndef STATIC_LINK_EM
  196. /* Mirror global debug pointers in Mso97.dll */
  197. Debug(pvwDebugLogLvl = MsoPwDebugLogLvl(&pvwDebugLogFilter);)
  198. #endif /* !STATIC_LINK_EM */
  199. Debug(*pvwDebugLogLvl = 7);
  200. /* Initialize rule base, for performance reasons, rulebase is global */
  201. if (!MsoFInitStaticRuls(&vrulsEm, &vrulsEm))
  202. return fFalse;
  203. #ifndef STATIC_LINK_EM
  204. /* Mirror global pointers (vlpruls, etc) in Mso97.dll */
  205. _pvlprulsDLL = MsoPvlprulsMirror(&vlpruls);
  206. *_pvlprulsDLL = &vrulsEm;
  207. #endif /* !STATIC_LINK_EM */
  208. #ifdef DYN_RULES
  209. /* Load dynamic rules */
  210. FLoadDynEmRules();
  211. #endif /* DYN_RULES */
  212. #if FEATURE_OFFICE
  213. /* Initialize the lexer to scan the doc */
  214. if (!(vplexs = MsoPlexsLexInitDoc
  215. (&vlexs, _hObjectNil, FGetNextLexRun,
  216. FGetTokenTextObject, NULL, NULL, 200, 100)))
  217. return fFalse;
  218. vplexs->pkwtb = &vkwtbEmTOKEN_KEYTABLE;
  219. /* For performance reasons, action table is global */
  220. vacttbl.prultkh = &vplexs->rultkhToken;
  221. #endif
  222. #if FEATURE_DEMO
  223. /* Allow Event Drivers to run */
  224. EnableEM();
  225. #endif
  226. /* Propagate the values through the rule network */
  227. MsoScheduleIrul(irul_YYSTD_INIT, fTrue);
  228. #ifdef DYN_RULES
  229. MsoScheduleIrul(irul_YYSTD_LOADING_RULEBASE, fTrue);
  230. #endif /* DYN_RULES */
  231. MsoEvaluateEvents(rulevtEm_YYSTD);
  232. return fTrue;
  233. }
  234. #endif /* } STATIC_INIT */
  235. #endif // }
  236. #if YY_BASE // {
  237. /* F E V A L E M R U L E */
  238. /*----------------------------------------------------------------------------
  239. %%Function: FEvalEmRule
  240. %%Contact: daleg
  241. Evaluate the rule associated with the given rule ID number.
  242. Return a boolean value for whether its value was TRUE or FALSE.
  243. ----------------------------------------------------------------------------*/
  244. #include "emeval.c"
  245. #endif // }
  246. #if FEATURE_DEMO // {
  247. /* W I N M A I N */
  248. /*----------------------------------------------------------------------------
  249. %%Function: WinMain
  250. %%Contact: daleg
  251. Main routine.
  252. ----------------------------------------------------------------------------*/
  253. int CALLBACK WinMain(
  254. HANDLE hInstance,
  255. HANDLE hPrevInstance,
  256. LPSTR lpszCmdLine,
  257. int nCmdShow
  258. )
  259. {
  260. MSG msg;
  261. int nRc;
  262. char szString[256];
  263. GdiSetBatchLimit(1);
  264. strcpy(vszAppName, "EMTEST");
  265. vhInst = hInstance;
  266. if (!hPrevInstance)
  267. {
  268. /* Register window classes if first instance of application */
  269. if ((nRc = nCwRegisterClasses()) == -1)
  270. {
  271. /* Put up msg if registering one of the windows failed */
  272. LoadString(vhInst, IDS_ERR_REGISTER_CLASS, szString,
  273. sizeof(szString));
  274. MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
  275. return nRc;
  276. }
  277. }
  278. /* Create application's Main window */
  279. vhWndMain = CreateWindow(vszAppName,
  280. NULL,
  281. WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
  282. | WS_MAXIMIZEBOX | WS_THICKFRAME
  283. | WS_CLIPCHILDREN | WS_OVERLAPPED,
  284. 0, 0, 400, 400,
  285. NULL, NULL, vhInst, NULL);
  286. /* If could not create main window, be nice before quitting */
  287. if (vhWndMain == NULL)
  288. {
  289. LoadString(vhInst, IDS_ERR_CREATE_WINDOW, szString, sizeof(szString));
  290. MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
  291. return IDS_ERR_CREATE_WINDOW;
  292. }
  293. /* Initialize the rulebase */
  294. if (!FInitEm())
  295. return 1;
  296. /* Display main window */
  297. ShowWindow(vhWndMain, nCmdShow);
  298. /* Until WM_QUIT message */
  299. while (GetMessage(&msg, NULL, 0, 0))
  300. {
  301. TranslateMessage(&msg);
  302. DispatchMessage(&msg);
  303. }
  304. /* Do clean up before exiting from the application */
  305. CwUnRegisterClasses();
  306. return msg.wParam;
  307. }
  308. /* W N D P R O C */
  309. /*----------------------------------------------------------------------------
  310. %%Function: WndProc
  311. %%Contact: daleg
  312. Windows proc for main window.
  313. ----------------------------------------------------------------------------*/
  314. LONG CALLBACK WndProc(
  315. HWND hWnd,
  316. UINT Message,
  317. WPARAM wParam,
  318. LPARAM lParam
  319. )
  320. {
  321. HMENU hMenu = 0;
  322. int nRc = 0;
  323. switch (Message)
  324. {
  325. case WM_COMMAND:
  326. FEmEvalDialog(wParam);
  327. switch (LOWORD(wParam))
  328. {
  329. case IDM_DIALOG:
  330. /* Respond to the menu item named "Dialog" */
  331. {
  332. FARPROC lpfnDIALOGSMsgProc;
  333. lpfnDIALOGSMsgProc = MakeProcInstance((FARPROC) DIALOGSMsgProc,
  334. vhInst);
  335. nRc = DialogBox(vhInst, MAKEINTRESOURCE(IDM_DIALOG), hWnd,
  336. lpfnDIALOGSMsgProc);
  337. FreeProcInstance(lpfnDIALOGSMsgProc);
  338. }
  339. break;
  340. default:
  341. return DefWindowProc(hWnd, Message, wParam, lParam);
  342. }
  343. break;
  344. case WM_CLOSE:
  345. /* Destroy child windows, modeless dialogs, then, this window */
  346. DestroyWindow(hWnd);
  347. /* Quit the application */
  348. if (hWnd == vhWndMain)
  349. PostQuitMessage(0);
  350. break;
  351. default:
  352. return DefWindowProc(hWnd, Message, wParam, lParam);
  353. }
  354. return 0L;
  355. }
  356. /* D I A L O G S M S G P R O C */
  357. /*----------------------------------------------------------------------------
  358. %%Function: DIALOGSMsgProc
  359. %%Contact: daleg
  360. Dialog proc for inner window.
  361. ----------------------------------------------------------------------------*/
  362. BOOL CALLBACK DIALOGSMsgProc(
  363. HWND hWndDlg,
  364. UINT Message,
  365. WPARAM wParam,
  366. LPARAM lParam
  367. )
  368. {
  369. switch (Message)
  370. {
  371. case WM_INITDIALOG:
  372. cwCenter(hWndDlg, 0);
  373. vcchPrev = 0;
  374. vcpIpPrev = 0;
  375. vhWndDlg = hWndDlg;
  376. break;
  377. case WM_CLOSE:
  378. break;
  379. case WM_COMMAND:
  380. switch (LOWORD(wParam))
  381. {
  382. case IDC_EDIT1:
  383. switch (HIWORD(wParam))
  384. {
  385. case EN_CHANGE:
  386. vcchEditText = GetDlgItemText(hWndDlg, IDC_EDIT1, vszEditText,
  387. cbEditText);
  388. if (!vfSettingDlgItem)
  389. {
  390. MSOCP cpIp;
  391. XCHAR wch;
  392. /* Get IP (Insertion Point) position */
  393. SendDlgItemMessage(hWndDlg, IDC_EDIT1, EM_GETSEL, 0,
  394. (LPARAM)&cpIp);
  395. /* Get character typed */
  396. wch = (vcchEditText > vcchPrev
  397. ? vszEditText[cpIp - 1] // Char typed
  398. : xchBackspace); // Backspace
  399. /* Notify Event Monitor CHAR driver */
  400. FEmEvalChar(wch, cpIp, vszEditText, vcchEditText);
  401. /* Track prev text positions for invalidation detect */
  402. vcchPrev = vcchEditText;
  403. vcpIpPrev = cpIp;
  404. }
  405. break;
  406. }
  407. break;
  408. case IDC_BUTTON1:
  409. case IDC_BUTTON2:
  410. case IDC_START:
  411. case IDC_STOP:
  412. default:
  413. FEmEvalDialog(wParam);
  414. break;
  415. case IDOK:
  416. FEmEvalDialog(wParam);
  417. EndDialog(hWndDlg, FALSE);
  418. break;
  419. }
  420. break;
  421. default:
  422. return FALSE;
  423. }
  424. return TRUE;
  425. }
  426. #endif // }
  427. #if FEATURE_SAMPLE // { joe event firer
  428. /* F E M E V A L D I A L O G */
  429. /*----------------------------------------------------------------------------
  430. %%Function: FEmEvalDialog
  431. %%Contact: daleg
  432. Event Monitor Event Driver for DIALOG events.
  433. ----------------------------------------------------------------------------*/
  434. int FEmEvalDialog(WPARAM wParam)
  435. {
  436. short idc = LOWORD(wParam);
  437. IRUL irul;
  438. #if FEATURE_DEMO
  439. /* Make sure we are enabled (e.g. macros not running) */
  440. if (FEmDisabled())
  441. return fFalse;
  442. #endif
  443. /* Match the (sparse) dialog object to its associated (contig) event, if any */
  444. vlpruls->irulPrimaryEvent = irul
  445. = (IRUL) MsoPkwdlhLookupL(idc, &vkwtbEmIDC_KEYTABLE)->tk;
  446. debugEM1(2, "DIALOG EVENT: %-20.20s\n",
  447. LpchRulName(LprulFromIrul(irul)));
  448. /* Push event into appropriate queue (resets depth) */
  449. MsoScheduleIrul(irul, fTrue);
  450. MsoScheduleIrul(irulIDC_, idc); // non-mapped event (autoclear global)
  451. /* Propagate the values through the rule network */
  452. MsoEvaluateEvents(rulevtEmDIALOG);
  453. // n.b. IDC_ is now autocleared
  454. /* Evaluate any pending actions */
  455. if (_pacttbl->pactPending)
  456. DoPendingActions();
  457. }
  458. /* F E M E V A L C H A R */
  459. /*----------------------------------------------------------------------------
  460. %%Function: FEmEvalChar
  461. %%Contact: daleg
  462. Event Driver for CHAR events in Event Monitor.
  463. Evaluate CHAR (KEYBOARD) events within the Event Monitor rulebase.
  464. Return whether or not it was handled.
  465. ----------------------------------------------------------------------------*/
  466. int FEmEvalChar(
  467. XCHAR wch,
  468. MSOCP cpIp,
  469. XCHAR *wz,
  470. int ichMac
  471. )
  472. {
  473. IRUL irul;
  474. #if FEATURE_DEMO
  475. /* Make sure we are enabled (e.g. macros not running) */
  476. if (FEmDisabled())
  477. return fFalse;
  478. #endif
  479. /* Primitive invalidation */
  480. if (FCheckIfMustReset(wch, ichMac, cpIp))
  481. InvalLex(vplexs);
  482. /* If our running state is still valid, adjust run variables */
  483. if (FInvalLex(vplexs))
  484. FResetEm((vplexs->cpIp = cpIp) - 1, wz, ichMac);
  485. /* Create a "lookahead" token to hold chars not yet scanned by lexer */
  486. vplexs->cchLookahead++;
  487. _CacheTkTextNext(vplexs);
  488. /* Look up character in keyword table */
  489. irul = (IRUL) MsoPkwdLookupName(&wch, 1, &vkwtbEmCHAR_KEYTABLE)->tk;
  490. debugEM3(2, "CHAR EVENT: %-20.20s for '%s' (0x%x)\n",
  491. LpchRulName(LprulFromIrul(irul)),
  492. MsoSzFromRgxchDebug(&wch, 1), wch);
  493. /* Push text token into appropriate queue (resets depth) */
  494. MsoScheduleIrul(irulCH_, wch);
  495. MsoScheduleIrul(vlpruls->irulPrimaryEvent = irul, fTrue);
  496. /* Propagate the values through the rule network */
  497. MsoEvaluateEvents(rulevtEmCHAR);
  498. /* Call TOKEN event driver to process any token events */
  499. FEmEvalToken(cpIp, wz, ichMac);
  500. }
  501. /* E M E V A L T K I R U L */
  502. /*----------------------------------------------------------------------------
  503. %%Function: EmEvalTkIrul
  504. %%Contact: daleg
  505. Evaluate a TOKEN event irul.
  506. ----------------------------------------------------------------------------*/
  507. void EmEvalTkIrul(IRUL irul)
  508. {
  509. MSORULTK *prultk;
  510. debugEM2(2, "TOKEN EVENT: %-20.20s \"%.100s\"\n",
  511. LpchIrulName(irul), MsoSzLexTokenText(vplexs));
  512. /* Push pending token events into appropriate queues */
  513. prultk = PrultkFromTokenIrultk(vplexs, vplexs->rultkhToken.irultkMin);
  514. while (vplexs->rultkhToken.irultkMin != vplexs->rultkhToken.irultkLim)
  515. {
  516. #ifdef DEBUG
  517. if (prultk->tk != irul)
  518. {
  519. debugEM2(4, "EXTRA TOKEN EVENT: %-20.20s %d\n",
  520. LpchIrulName(prultk->tk), prultk->lValue);
  521. debugEM1(8, " at CP %ld\n", prultk->cpFirst);
  522. }
  523. #endif /* DEBUG */
  524. /* Push text token into appropriate queue (resets depth) */
  525. MsoSignalEventIrul(IrulFromTk(prultk->tk), prultk->lValue);
  526. /* Move to next cache record, wrapping around if necessary */
  527. IncrTokenPrultk(vplexs, &prultk, &vplexs->rultkhToken.irultkMin);
  528. }
  529. /* Push any applicable format tokens into appropriate queues */
  530. if (vplexs->rultkhFormat.irultkMin != vplexs->rultkhFormat.irultkLim)
  531. PushIrultkFormatPending();
  532. /* Push text token into appropriate queue (resets depth) */
  533. MsoScheduleIrul(irulTOKEN_, vlpruls->irulPrimaryEvent = irul);
  534. /* Propagate the values through the rule network */
  535. MsoEvaluateEvents(rulevtEmTOKEN);
  536. }
  537. #endif // }
  538. #if FEATURE_SAMPLE // {
  539. /* F E M E V A L T O K E N */
  540. /*----------------------------------------------------------------------------
  541. %%Function: FEmEvalToken
  542. %%Contact: daleg
  543. Event Monitor Event Driver for TOKEN events.
  544. ----------------------------------------------------------------------------*/
  545. int FEmEvalToken(
  546. MSOCP cpIp,
  547. XCHAR *wz,
  548. int ichMac
  549. )
  550. {
  551. IRUL irul;
  552. #if FEATURE_DEMO
  553. /* Make sure we are enabled (e.g. macros not running) */
  554. if (FEmDisabled())
  555. return fFalse;
  556. #endif
  557. /* If our running state is still valid, adjust run variables */
  558. if (!FInvalLex(vplexs))
  559. {
  560. long dwz = wz - vplexs->pxchBuffer;
  561. vplexs->pxchTkStart += dwz;
  562. vplexs->pxchNext += dwz;
  563. vplexs->pxchRun += dwz;
  564. vplexs->pxchBuffer += dwz;
  565. vplexs->cpIp = cpIp;
  566. vplexs->cpLim = ichMac;
  567. vplexs->cchRemain = vplexs->pxchBuffer + vplexs->cpLim
  568. - vplexs->pxchNext;
  569. }
  570. /* Else rescan back up to IP */
  571. else if (!FResetEm((vplexs->cpIp = cpIp) - 1, wz, ichMac))
  572. return fFalse;
  573. /* Inject and eval any complete tokens up to IP */
  574. while (FValidIrul(irul = IrulFromTk(MsoTkLexTextCpLim(vplexs, cpIp))))
  575. EmEvalTkIrul(irul);
  576. /* Evaluate any pending actions */
  577. if (_pacttbl->pactPending)
  578. DoPendingActions();
  579. /* All typed characters must now have been seen by the lexer */
  580. if (vplexs->cchLookahead > 0)
  581. vplexs->cchLookahead = 0;
  582. }
  583. #endif // }
  584. #if FEATURE_TEXT // {
  585. /* P U S H I R U L T K F O R M A T P E N D I N G */
  586. /*----------------------------------------------------------------------------
  587. %%Function: PushIrultkFormatPending
  588. %%Contact: daleg
  589. Push any pending format tokens into appropriate queues.
  590. ----------------------------------------------------------------------------*/
  591. void PushIrultkFormatPending(void)
  592. {
  593. MSORULTK *prultk;
  594. debugEM1(8, "Checking for formatting before CP %ld\n",
  595. CpLexTokenFirst(vplexs));
  596. prultk = PrultkFormatFromIrultk(vplexs, vplexs->rultkhFormat.irultkMin);
  597. while (vplexs->rultkhFormat.irultkMin != vplexs->rultkhFormat.irultkLim
  598. && (prultk->cpFirst
  599. < CpLexTokenFirst(vplexs) + DcpLexToken(vplexs)
  600. || (DcpLexToken(vplexs) == 0
  601. && prultk->cpFirst <= CpLexTokenFirst(vplexs))))
  602. {
  603. debugEM2(2, "FORMAT : %-20.20s %ld\n",
  604. LpchIrulName(prultk->tk), prultk->lValue);
  605. debugEM1(6, " at CP %ld\n", prultk->cpFirst);
  606. /* Push format token into appropriate queue (resets depth) */
  607. MsoSignalEventIrul(IrulFromTk(prultk->tk), prultk->lValue);
  608. /* Move to next cache record, wrapping around if necessary */
  609. IncrFormatPrultk(vplexs, &prultk, &vplexs->rultkhFormat.irultkMin);
  610. }
  611. }
  612. #endif // }
  613. #if FEATURE_TEXT // {
  614. /* F R E S E T E M */
  615. /*----------------------------------------------------------------------------
  616. %%Function: FResetEm
  617. %%Contact: daleg
  618. Reset the Event Monitor rules and lexer due to an IP (cursor) change,
  619. or due to some form of invalidation.
  620. ----------------------------------------------------------------------------*/
  621. int FResetEm(
  622. MSOCP cpIp,
  623. XCHAR *wz,
  624. int ichMac
  625. )
  626. {
  627. MSOCP cpObject = 0;
  628. IRUL irul;
  629. /* Initialize lexer to point to start of buffer */
  630. vplexs->pObjectIp = PObjectCur();
  631. vplexs->pxchBuffer = vplexs->pxchBufferIp = vplexs->pxchRun = wz;
  632. MsoLexSetPos(vplexs, cpObject, 0);
  633. debugEM0(0, "====================================================\n");
  634. debugEM3(0, " FResetEm: RESETTING: pObjectIp %x cpLine %ld cp %ld\n",
  635. vplexs->pObjectIp, cpObject, cpIp);
  636. debugEM0(0, "====================================================\n");
  637. /* Reset rule base TOKEN state variables */
  638. MsoClearEventsForRulevts(rulevtEmTOKEN, drulevtToken,
  639. (vpems->fInternalReset
  640. ? rultPersistentRule | rultAlwaysPersist
  641. : rultAlwaysPersist),
  642. fTrue, fFalse);
  643. vplexs->wInterval = CIntervalsRulevt(rulevtEmTOKEN);
  644. /* Reset lexer base state */
  645. MsoResetLexState(vplexs, fTrue/*fFullReset*/);
  646. vplexs->cpLim = 0;
  647. vplexs->fInvalLexer = fFalse;
  648. /* Mark start of scan */
  649. MsoCacheTkText(vplexs, irulSTART, fTrue);
  650. MsoScheduleIrul(irulSTART, fTrue);
  651. /* Mark start of token cache, but not as events */
  652. MsoCacheTkText(vplexs, irulEND_OBJ, fTrue);
  653. vplexs->rultkhToken.irultkMin = vplexs->rultkhToken.irultkLim;
  654. /* Run only rules not marked as INTERACTIVE_ONLY */
  655. SetCurrRulg(rulgEmALWAYS);
  656. /* Inject and eval any complete tokens up to IP */
  657. while (FValidIrul(irul = IrulFromTk(MsoTkLexTextCpLim(vplexs, cpIp))))
  658. EmEvalTkIrul(irul);
  659. /* Run only rules not marked as INTERACTIVE_ONLY */
  660. SetCurrRulg(rulgEmINTERACTIVE_ONLY);
  661. /* Mark that we are synchronized */
  662. vplexs->cchLookahead = 0;
  663. return fTrue;
  664. }
  665. /* F G E T T O K E N T E X T O B J E C T */
  666. /*----------------------------------------------------------------------------
  667. FGetTokenTextObject
  668. %%Contact: smueller
  669. Determine whether the text of the requested token needs to be fetched
  670. from the document. If so, do so, leaving the results in ppxch and pcch,
  671. and return fTrue. Otherwise, return fFalse.
  672. ----------------------------------------------------------------------------*/
  673. int WIN_CALLBACK FGetTokenTextObject(
  674. MSORULTK *prultk,
  675. const XCHAR **ppxch, // RETURN
  676. int *pcch, // RETURN
  677. struct _MSOLEXS *plexs
  678. )
  679. {
  680. if (plexs->pObject != NULL)
  681. {
  682. // NOT SUPPORTED YET
  683. return fTrue;
  684. }
  685. return fFalse;
  686. }
  687. /* F G E T N E X T L E X R U N */
  688. /*----------------------------------------------------------------------------
  689. %%Function: FGetNextLexRun
  690. %%Contact: daleg
  691. Return next run of text within the current object , and set the lexer
  692. run-state variables.
  693. For this demo, there ain't any, but we will show a commented-out sample.
  694. ----------------------------------------------------------------------------*/
  695. int WIN_CALLBACK FGetNextLexRun(MSOCP cpLim, MSOLEXS *plexs)
  696. {
  697. int fStatus = fTrue;
  698. const XCHAR *pxchPrevEnd = plexs->pxchNext;
  699. /* If prev run at end of current object, move to next object */
  700. if (FLexEndOfScan(vplexs))
  701. {
  702. /* If still have a pending token, complete it first */
  703. if (DcpLexCurr(vplexs) > 0)
  704. return fFalse;
  705. /* Create exactly one inter-object "created" tkEND_OBJ character */
  706. if (plexs->fCreateEndObjCh)
  707. {
  708. /* Make this run "created" text, i.e. no dcp */
  709. fStatus = fFalse;
  710. plexs->cpRun += plexs->ccpRun;
  711. plexs->ichRun += plexs->cchRun;
  712. plexs->cchRun = 1;
  713. plexs->ccpRun = 0;
  714. #ifdef READY
  715. /* Mark run as "created", so dcp calcs will work properly */
  716. plexs->fAdjustTokenCps = fTrue;
  717. plexs->dcpCreated += 1;
  718. if (plexs->cpFirstCreated == 0L)
  719. plexs->cpFirstCreated = plexs->cpRun;
  720. #endif /* READY */
  721. }
  722. /* Else get next object's text */
  723. else
  724. {
  725. if (!FGetNextLexObject(cpLim, plexs))
  726. return fFalse;
  727. /* If in object of IP has passed upper lim of scan, block lexer */
  728. if (plexs->pObject == plexs->pObjectIp && cpLim != msocpMax
  729. && cpLim <= 0 /* plexs->cpRun */)
  730. fStatus = fFalse;
  731. }
  732. }
  733. /* Else move to next run */
  734. else
  735. {
  736. plexs->cpRun += plexs->ccpRun;
  737. plexs->ichRun += plexs->cchRun;
  738. #ifdef PORT_THIS
  739. plexs->cchRun = vcchEditText - plexs->ichRun;
  740. #endif /* PORT_THIS */
  741. plexs->ccpRun = plexs->cchRun;
  742. // Reset buffer pointer if run in a different buffer
  743. #ifdef PORT_THIS
  744. plexs->pxchBuffer = vszEditText;
  745. #endif /* PORT_THIS */
  746. }
  747. /* Set Run length and pointer */
  748. plexs->cchRemain = plexs->cchRun;
  749. plexs->pxchNext = (plexs->pxchRun = plexs->pxchBuffer + plexs->ichRun);
  750. AssertSz0(pxchPrevEnd == plexs->pxchNext
  751. || pxchPrevEnd == plexs->pxchTkStart,
  752. "Discontiguous runs!");
  753. /* If run starts new text (line), reset non-cached tk start pointer */
  754. if (pxchPrevEnd == plexs->pxchTkStart)
  755. plexs->pxchTkStart = plexs->pxchNext;
  756. return fStatus;
  757. }
  758. /* F G E T N E X T L E X O B J E C T */
  759. /*----------------------------------------------------------------------------
  760. %%Function: FGetNextLexObject
  761. %%Contact: daleg
  762. Set the "run" state variables to the first run of a new object, including
  763. the text buffer, and the run lengths.
  764. ----------------------------------------------------------------------------*/
  765. int WIN_CALLBACK FGetNextLexObject(MSOCP cpLim, MSOLEXS *plexs)
  766. {
  767. // If this is the first time thru, do initialization stuff
  768. if (plexs->ichRun == iNil)
  769. {
  770. // YOUR INITS HERE
  771. }
  772. // Fetch new object text
  773. plexs->pObject = PObjectCur();
  774. // Fetch new text (in our case, it is globally static)
  775. plexs->pxchBuffer = vszEditText;
  776. plexs->cchRun = plexs->cpLim = vcchEditText;
  777. plexs->pxchRun = plexs->pxchBuffer;
  778. // Set up other state variables
  779. plexs->ichRun = 0;
  780. plexs->cpRun = 0;
  781. plexs->cpObject = 0;
  782. plexs->ccpRun = plexs->cchRun;
  783. SetCpLexTokenFirst(vplexs, SetCpLexTokenNext(vplexs, 0));
  784. return fTrue;
  785. }
  786. /* F L E X F O R C E C O M P L E T E */
  787. /*----------------------------------------------------------------------------
  788. %%Function: FLexForceComplete
  789. %%Contact: daleg
  790. Force the current token to complete within the lexer. This is a callback
  791. function that gets called when we wish to cause the lexer to finish a
  792. token without peeking at the next character. This is generally when we
  793. are moving the IP out of a cell in a table, and wish to perform automatic
  794. actions anyway.
  795. Once we have completed the token, we clear the callback flag, to resume
  796. normal operation.
  797. ----------------------------------------------------------------------------*/
  798. int WIN_CALLBACK FLexForceComplete(MSOCP cpLim, MSOLEXS *plexs)
  799. {
  800. XCHAR wch;
  801. /* If in the middle of a token complete it if next is EOO or delim */
  802. // REVIEW daleg: This should check for more than just spaces after
  803. if (plexs->iuState > 0
  804. && (cpLim == vplexs->cpLim
  805. || (wch = *vplexs->pxchNext) == xchSpace))
  806. return fTrue;
  807. /* Do not call this routine next time */
  808. plexs->pfnlexrunForceComplete = NULL;
  809. /* Force an END_OBJ token (event) if we are at the cell boundary */
  810. return (cpLim == vplexs->cpLim);
  811. }
  812. #endif // }
  813. #if YY_BASE // {
  814. /* P A C T P C A */
  815. /*----------------------------------------------------------------------------
  816. %%Function: PactPca
  817. %%Contact: daleg
  818. Create a Delayed-Action record, using a MSOCA to define the edit range.
  819. ----------------------------------------------------------------------------*/
  820. MSOACT *PactPca(
  821. MSOACTTBL *pacttbl,
  822. int actt,
  823. MSOCA *pca,
  824. ...
  825. )
  826. {
  827. va_list ap;
  828. MSOACT *pact;
  829. /* Safety first: make sure we have an action structure */
  830. if (!pacttbl)
  831. return NULL;
  832. /* Start varargs */
  833. va_start(ap, pca);
  834. /* Create a new Delayed Action record, and push arg list into it */
  835. pact = MsoPactAp(pacttbl, actt,
  836. (sizeof(MSOCA) + sizeof(long) - 1)/sizeof(long), ap);
  837. /* End varargs */
  838. va_end(ap);
  839. /* Calculate starting CP */
  840. pact->rec1_ca.ca = *pca;
  841. /* Insert the MSOACT record into the edit queue in CP sorted order */
  842. MsoInsertPact(pact, &pacttbl->pactPending);
  843. return pact;
  844. }
  845. #if YY_DELAYED // {
  846. long WIN_CALLBACK DcpDoAct(
  847. MSOACT *pact,
  848. MSOACTTBL *pacttbl,
  849. long *pdcp,
  850. MSOCA *pca,
  851. MSOACT **ppactNext,
  852. int *pfDiscard
  853. );
  854. /* D O P E N D I N G A C T I O N S */
  855. /*----------------------------------------------------------------------------
  856. %%Function: DoPendingActions
  857. %%Contact: daleg
  858. Execute pending actions in delay action queue.
  859. ----------------------------------------------------------------------------*/
  860. void DoPendingActions(void)
  861. {
  862. _pacttbl->cpFirstEditPrev = -1;
  863. _pacttbl->dcpEditPrev = 0;
  864. _pacttbl->cpLimEdit = 0;
  865. MsoReversePact(&_pacttbl->pactPending);
  866. MsoDcpDoActs(&_pacttbl->pactPending, _pacttbl, 0, fTrue, -1, DcpDoAct);
  867. }
  868. /* D C P D O A C T */
  869. /*----------------------------------------------------------------------------
  870. %%Function: DcpDoAct
  871. %%Contact: daleg
  872. Execute the action given by the MSOACT record.
  873. ----------------------------------------------------------------------------*/
  874. long WIN_CALLBACK DcpDoAct(
  875. MSOACT *pact,
  876. MSOACTTBL *pacttbl,
  877. long *pdcp,
  878. MSOCA *pca,
  879. MSOACT **ppactNext,
  880. int *pfDiscard
  881. )
  882. {
  883. switch (pact->rec1.actt)
  884. {
  885. #include "emact.c_"
  886. }
  887. return 0;
  888. }
  889. #endif // }
  890. #endif // }
  891. #if FEATURE_DEMO // {
  892. /* D C P R E P L A C E T E X T */
  893. /*----------------------------------------------------------------------------
  894. %%Function: DcpReplaceText
  895. %%Contact: daleg
  896. Replace the text range given by the range of chars with the new string.
  897. ----------------------------------------------------------------------------*/
  898. int DcpReplaceText(
  899. void *pObject,
  900. int cpFirst,
  901. int cpLim,
  902. char *sz
  903. )
  904. {
  905. int cch = CchSz(sz);
  906. int dcp = cch - (cpLim - cpFirst);
  907. int cchOrig;
  908. char rgch[cbEditText];
  909. MSOCP cpIp;
  910. /* Get current edit control value */
  911. cchOrig = GetDlgItemText(vhWndDlg, IDC_EDIT1, rgch, cbEditText);
  912. /* Do not attempt to expand beyond control's capacity. */
  913. if (cchOrig + dcp >= cbEditText)
  914. return 0;
  915. /* Replace the string */
  916. CopyRgb(rgch + cpLim, rgch + cpLim + dcp, cchOrig - cpLim + 1);
  917. CopyRgbNo(sz, rgch + cpFirst, cch);
  918. /* Set the edit control value with the new string, preserving the IP */
  919. vfSettingDlgItem = fTrue; // Prevent recursion
  920. SendDlgItemMessage(vhWndDlg, IDC_EDIT1, EM_GETSEL, 0, (LPARAM)&cpIp);
  921. SendDlgItemMessage(vhWndDlg, IDC_EDIT1, WM_SETTEXT, 0, (LPARAM)&rgch[0]);
  922. SendDlgItemMessage(vhWndDlg, IDC_EDIT1, EM_SETSEL, cpIp + dcp, cpIp + dcp);
  923. vcchEditText += dcp;
  924. vfSettingDlgItem = fFalse;
  925. debugEM0(2, "Replaced text\n");
  926. return dcp;
  927. }
  928. #endif // }
  929. #if FEATURE_TEXT // {
  930. /* F C H E C K I F M U S T R E S E T */
  931. /*----------------------------------------------------------------------------
  932. %%Function: FCheckIfMustReset
  933. %%Contact: daleg
  934. Do a primitive check to see if we should invalidate our running rulebase
  935. state, and do a full reset scan.
  936. THIS IS NOT A CANONICAL ROUTINE, but there should be something equivalent
  937. in each app.
  938. ----------------------------------------------------------------------------*/
  939. int FCheckIfMustReset(XCHAR wch, int ichMac, MSOCP cpIp)
  940. {
  941. if (wch == xchBackspace)
  942. return fTrue;
  943. /* If user typed a new character, emit character event */
  944. /* REVIEW: pasting will result in multiple new characters, of which we
  945. only notice the last */
  946. if (ichMac > vcchPrev)
  947. {
  948. Assert (cpIp > 0);
  949. /* Without notification of IP moves, there is no way to accurately
  950. identify when lexer needs invalidating; for safety, we could do so
  951. on every character. For demonstrating the lexer, we'll do so only
  952. when the IP didn't move forward by exactly one character, which is
  953. a decent approximation of the right time. */
  954. /* REVIEW: find a more pleasant way to deal with this, like subclassing
  955. the edit control to get precise control over notifications. */
  956. if (cpIp != vcpIpPrev + 1)
  957. return fTrue;
  958. }
  959. return fFalse;
  960. }
  961. #endif // }
  962. #if FEATURE_DEMO // {
  963. /* N C W R E G I S T E R C L A S S E S */
  964. /*----------------------------------------------------------------------------
  965. %%Function: nCwRegisterClasses
  966. %%Contact: daleg
  967. Register window classes
  968. ----------------------------------------------------------------------------*/
  969. int nCwRegisterClasses(void)
  970. {
  971. WNDCLASS wndclass;
  972. memset(&wndclass, 0x00, sizeof(WNDCLASS));
  973. /* load WNDCLASS with window's characteristics */
  974. wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;
  975. wndclass.lpfnWndProc = WndProc;
  976. /* Extra storage for Class and Window objects */
  977. wndclass.cbClsExtra = 0;
  978. wndclass.cbWndExtra = 0;
  979. wndclass.hInstance = vhInst;
  980. wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  981. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  982. /* Create brush for erasing background */
  983. wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  984. wndclass.lpszMenuName = vszAppName; /* Menu Name is App Name */
  985. wndclass.lpszClassName = vszAppName; /* Class Name is App Name */
  986. if (!RegisterClass(&wndclass))
  987. return -1;
  988. return (0);
  989. }
  990. /* C W C E N T E R */
  991. /*----------------------------------------------------------------------------
  992. %%Function: cwCenter
  993. %%Contact: daleg
  994. Center the main window.
  995. ----------------------------------------------------------------------------*/
  996. void cwCenter(hWnd, top)
  997. HWND hWnd;
  998. int top;
  999. {
  1000. POINT pt;
  1001. RECT swp;
  1002. RECT rParent;
  1003. int iwidth;
  1004. int iheight;
  1005. /* get the rectangles for the parent and the child */
  1006. GetWindowRect(hWnd, &swp);
  1007. GetClientRect(vhWndMain, &rParent);
  1008. /* calculate the height and width for MoveWindow */
  1009. iwidth = swp.right - swp.left;
  1010. iheight = swp.bottom - swp.top;
  1011. /* find the center point and convert to screen coordinates */
  1012. pt.x = (rParent.right - rParent.left) / 2;
  1013. pt.y = (rParent.bottom - rParent.top) / 2;
  1014. ClientToScreen(vhWndMain, &pt);
  1015. /* calculate the new x, y starting point */
  1016. pt.x = pt.x - (iwidth / 2);
  1017. pt.y = pt.y - (iheight / 2);
  1018. /* top will adjust the window position, up or down */
  1019. if (top)
  1020. pt.y = pt.y + top;
  1021. /* move the window */
  1022. MoveWindow(hWnd, pt.x, pt.y, iwidth, iheight, FALSE);
  1023. }
  1024. /* C W U N R E G I S T E R C L A S S E S */
  1025. /*----------------------------------------------------------------------------
  1026. %%Function: CwUnRegisterClasses
  1027. %%Contact: daleg
  1028. Un-register the windows classes.
  1029. ----------------------------------------------------------------------------*/
  1030. void CwUnRegisterClasses(void)
  1031. {
  1032. WNDCLASS wndclass;
  1033. memset(&wndclass, 0x00, sizeof(WNDCLASS));
  1034. UnregisterClass(vszAppName, vhInst);
  1035. }
  1036. #endif // }
  1037. #if FEATURE_DEAD // {
  1038. /* A S S E R T L S Z P R O C */
  1039. /*----------------------------------------------------------------------------
  1040. %%Function: AssertLszProc
  1041. %%Contact: daleg
  1042. Print assertion message, and prompt for whether to (f)ail, or (i)gnore.
  1043. ----------------------------------------------------------------------------*/
  1044. int AssertLszProc(
  1045. const char *szExtra,
  1046. const char *szFile,
  1047. int line
  1048. )
  1049. {
  1050. Fail("ASSERTION FAILED: %s IN %s line %d\n", szExtra, szFile, line);
  1051. return 1;
  1052. }
  1053. /* F A I L */
  1054. /*----------------------------------------------------------------------------
  1055. %%Function: Fail
  1056. %%Contact: daleg
  1057. Emit a failure message and exit.
  1058. ----------------------------------------------------------------------------*/
  1059. void __cdecl Fail(const char *sz, ...)
  1060. {
  1061. va_list ap;
  1062. char szBuf[256];
  1063. /* Start variable arglist */
  1064. va_start(ap, sz);
  1065. wvsprintf(szBuf, sz, ap);
  1066. OutputDebugString("FATAL ERROR: ");
  1067. OutputDebugString(szBuf);
  1068. OutputDebugString("\n");
  1069. /* End variable arglist */
  1070. va_end(ap);
  1071. // _asm int 3;
  1072. exit(1);
  1073. }
  1074. #endif // }
  1075. #if FEATURE_DEAD // {
  1076. /* F N E N C L P C H */
  1077. /*----------------------------------------------------------------------------
  1078. %%Function: FNeNcLpch
  1079. %%Contact: daleg
  1080. Compare two strings, case insensitive.
  1081. ----------------------------------------------------------------------------*/
  1082. BOOL FNeNcLpch(
  1083. register const uchar *pch1,
  1084. register const uchar *pch2,
  1085. register int cch
  1086. )
  1087. {
  1088. while (cch-- > 0)
  1089. {
  1090. if (ChUpper(*pch1++) != ChUpper(*pch2++))
  1091. return fTrue;
  1092. }
  1093. return fFalse;
  1094. }
  1095. #endif // }