WMModuleState.Mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. (** AUTHOR "Michael Szediwy"; PURPOSE "Ports the System.State to an Aos window. There is new an auto-refresh feature."; *)
  2. MODULE WMModuleState;
  3. IMPORT
  4. SYSTEM,
  5. Streams,
  6. Modules,
  7. TextUtilities,
  8. WMComponents,
  9. WMEditors,
  10. WMGraphics,
  11. WMStandardComponents,
  12. WMDialogs,
  13. WMWindowManager,
  14. Commands,
  15. WMRectangles,
  16. Kernel;
  17. CONST
  18. MaxString = 64;
  19. MaxArray = 10;
  20. RefreshOff = "Refresh is off";
  21. RefreshOn = "Refresh is on";
  22. TYPE Bytes = Modules.Bytes;
  23. TYPE StateWindow= OBJECT(WMComponents.FormWindow)
  24. VAR
  25. tw-: TextUtilities.TextWriter;
  26. panel : WMStandardComponents.Panel;
  27. out- : WMEditors.Editor;
  28. open : BOOLEAN;
  29. refresh: WMStandardComponents.Button;
  30. refreshOn: BOOLEAN;
  31. timer : Kernel.Timer;
  32. module: Modules.Module;
  33. interval: LONGINT;
  34. autorefresh: WMStandardComponents.Checkbox;
  35. PROCEDURE &New*(title : ARRAY OF CHAR; interval: LONGINT; name: Modules.Name);
  36. VAR toolbar: WMStandardComponents.Panel;
  37. load, clear : WMStandardComponents.Button;
  38. font: WMGraphics.Font;
  39. dx, dy: LONGINT;
  40. bearing : WMRectangles.Rectangle;
  41. label: WMStandardComponents.Label;
  42. BEGIN
  43. NEW(panel); panel.bounds.SetExtents(640, 420); panel.fillColor.Set(WMGraphics.RGBAToColor(255, 255, 255, 255));
  44. NEW(toolbar);
  45. toolbar.bounds.SetHeight(20);
  46. toolbar.alignment.Set(WMComponents.AlignTop);
  47. panel.AddContent(toolbar);
  48. NEW(clear);
  49. clear.alignment.Set(WMComponents.AlignLeft);
  50. clear.SetCaption("Clear");
  51. clear.onClick.Add(ClearText);
  52. font := clear.GetFont();
  53. font.GetStringSize(" Clear ", dx, dy);
  54. clear.bounds.SetWidth(dx);
  55. toolbar.AddContent(clear);
  56. NEW(load);
  57. load.alignment.Set(WMComponents.AlignLeft);
  58. load.SetCaption("Load module");
  59. load.onClick.Add(Load);
  60. font := load.GetFont();
  61. font.GetStringSize(" Load module ", dx, dy);
  62. load.bounds.SetWidth(dx);
  63. toolbar.AddContent(load);
  64. NEW(refresh);
  65. refresh.alignment.Set(WMComponents.AlignLeft);
  66. refresh.SetCaption("Refresh");
  67. refresh.onClick.Add(Refresh);
  68. font := refresh.GetFont();
  69. font.GetStringSize(" Refresh ", dx, dy);
  70. refresh.bounds.SetWidth(dx);
  71. refreshOn := FALSE;
  72. toolbar.AddContent(refresh);
  73. bearing := WMRectangles.MakeRect(3, 3, 3, 3);
  74. NEW(autorefresh);
  75. autorefresh.onClick.Add(RefreshSwitch);
  76. autorefresh.bearing.Set(bearing);
  77. autorefresh.bounds.SetWidth(14);
  78. autorefresh.alignment.Set(WMComponents.AlignRight);
  79. toolbar.AddContent(autorefresh);
  80. autorefresh.state.Set(0);
  81. NEW(label);
  82. font := label.GetFont();
  83. font.GetStringSize(" auto-refresh ", dx, dy);
  84. label.bounds.SetWidth(dx);
  85. label.SetCaption("auto-refresh");
  86. label.textColor.Set(0000000FFH);
  87. label.alignment.Set(WMComponents.AlignRight);
  88. toolbar.AddContent(label);
  89. NEW(out); out.alignment.Set(WMComponents.AlignClient); out.tv.showBorder.Set(TRUE); panel.AddContent(out);
  90. Init(panel.bounds.GetWidth(), panel.bounds.GetHeight(), FALSE);
  91. SetContent(panel);
  92. manager := WMWindowManager.GetDefaultManager();
  93. SetTitle(WMComponents.NewString(title));
  94. WMWindowManager.DefaultAddWindow(SELF);
  95. NEW(tw, out.text);
  96. open := TRUE;
  97. SELF.interval := interval;
  98. NEW(timer);
  99. IF name # "" THEN
  100. out.text.AcquireWrite();
  101. OutState(name);
  102. out.text.ReleaseWrite();
  103. ELSE
  104. Load(NIL, NIL);
  105. END;
  106. END New;
  107. PROCEDURE Close*;
  108. BEGIN
  109. open := FALSE;
  110. BEGIN{EXCLUSIVE}
  111. refreshOn := FALSE;
  112. END;
  113. Remove(SELF);
  114. Close^
  115. END Close;
  116. PROCEDURE ClearText(sender, data : ANY);
  117. BEGIN
  118. out.text.AcquireWrite();
  119. out.text.Delete(0, out.text.GetLength());
  120. out.tv.firstLine.Set(0); out.tv.cursor.SetPosition(0);
  121. out.text.ReleaseWrite();
  122. END ClearText;
  123. PROCEDURE Load(sender, data : ANY);
  124. VAR
  125. dr: LONGINT;
  126. name: Modules.Name;
  127. temp: BOOLEAN;
  128. BEGIN
  129. temp := refreshOn;
  130. BEGIN {EXCLUSIVE}
  131. refreshOn := FALSE;
  132. END;
  133. dr := WMDialogs.QueryString("Enter module name", name);
  134. IF dr = WMDialogs.ResOk THEN
  135. out.text.AcquireWrite();
  136. OutState(name);
  137. out.text.ReleaseWrite();
  138. END;
  139. BEGIN {EXCLUSIVE}
  140. refreshOn := temp;
  141. END;
  142. END Load;
  143. (* Should be surrounded by out.text.AcquireWrite(); ... out.text.ReleaseWrite();*)
  144. PROCEDURE OutState(name: Modules.Name);
  145. VAR
  146. i, refpos: LONGINT;
  147. mod: Modules.Module;
  148. refs: Bytes;
  149. ch: CHAR;
  150. nameDis: Modules.Name;
  151. BEGIN
  152. out.text.Delete(0, out.text.GetLength());
  153. out.tv.firstLine.Set(0); out.tv.cursor.SetPosition(0);
  154. IF name = "" THEN
  155. IF SELF.module = NIL THEN
  156. RETURN;
  157. ELSE
  158. nameDis := module.name;
  159. mod := module;
  160. tw.SetFontStyle({0});
  161. tw.String(nameDis);
  162. tw.SetFontStyle({});
  163. IF mod # NIL THEN
  164. SELF.module := mod;
  165. tw.String(" SB = ");
  166. tw.Hex(mod.sb, 0); tw.Char("H"); tw.Ln();
  167. refs := SYSTEM.VAL(Bytes, mod.refs);
  168. IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
  169. refpos := FindProc(refs, 0); (* assume module body is at PC = 0 (not true for OMI) *)
  170. IF refpos # -1 THEN
  171. REPEAT ch := refs[refpos]; INC(refpos) UNTIL ch = 0X;
  172. Variables(refs, refpos, mod.sb, tw)
  173. END
  174. END
  175. ELSE
  176. tw.String(" not loaded"); tw.Ln();
  177. END;
  178. tw.Update();
  179. END;
  180. ELSE
  181. (* New module: Have to do some work. *)
  182. i := 0; WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END; name[i] := 0X;
  183. mod := Modules.root;
  184. WHILE (mod # NIL) & (mod.name # name) DO mod := mod.next END;
  185. nameDis := name;
  186. tw.SetFontStyle({0});
  187. tw.String(nameDis);
  188. tw.SetFontStyle({});
  189. IF mod # NIL THEN
  190. SELF.module := mod;
  191. tw.String(" SB =");
  192. tw.Hex(mod.sb, 0); tw.Char("H"); tw.Ln();
  193. refs := SYSTEM.VAL(Bytes, mod.refs);
  194. IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
  195. refpos := FindProc(refs, 0); (* assume module body is at PC = 0 (not true for OMI) *)
  196. IF refpos # -1 THEN
  197. REPEAT ch := refs[refpos]; INC(refpos) UNTIL ch = 0X;
  198. Variables(refs, refpos, mod.sb, tw)
  199. END
  200. END
  201. ELSE
  202. tw.String(" not loaded"); tw.Ln();
  203. END;
  204. tw.Update();
  205. END;
  206. END OutState;
  207. PROCEDURE RefreshSwitch(sender, data : ANY);
  208. BEGIN
  209. BEGIN {EXCLUSIVE} (* Else the waiting process may not be found *)
  210. refreshOn := ~ refreshOn;
  211. END;
  212. IF refreshOn THEN
  213. refresh.onClick.Remove(Refresh);
  214. (*refresh.caption.SetAOC(RefreshOn); *)
  215. ELSE
  216. (* refresh.caption.SetAOC(RefreshOff);*)
  217. refresh.onClick.Add(Refresh);
  218. END;
  219. END RefreshSwitch;
  220. PROCEDURE Refresh(sender, data : ANY);
  221. BEGIN
  222. out.text.AcquireWrite();
  223. OutState("");
  224. out.text.ReleaseWrite();
  225. END Refresh;
  226. PROCEDURE SetInterval*(interval: LONGINT);
  227. BEGIN
  228. SELF.interval := interval;
  229. END SetInterval;
  230. PROCEDURE Variables(refs: Bytes; i: LONGINT; base: ADDRESS; w:Streams.Writer);
  231. VAR
  232. mode, ch: CHAR;
  233. m, type, n, lval, size, tmp1, tdadr: LONGINT;
  234. adr, tmp2: ADDRESS;
  235. etc: BOOLEAN;
  236. sval: SHORTINT;
  237. ival: INTEGER;
  238. tmp: Bytes;
  239. set: SET;
  240. rval: REAL;
  241. lrval: LONGREAL;
  242. BEGIN
  243. m := LEN(refs^); mode := refs[i]; INC(i);
  244. WHILE (i < m) & (mode >= 1X) & (mode <= 3X) DO (* var *)
  245. type := ORD(refs[i]); INC(i); etc := FALSE;
  246. IF type > 80H THEN
  247. IF type = 83H THEN type := 15 ELSE DEC(type, 80H) END;
  248. GetNum(refs, i, n)
  249. ELSIF (type = 16H) OR (type = 1DH) THEN
  250. GetNum(refs, i, tdadr); n := 1
  251. ELSE
  252. IF type = 15 THEN n := MaxString (* best guess *) ELSE n := 1 END
  253. END;
  254. GetNum(refs, i, tmp1); adr := tmp1;
  255. tw.SetFontColor(00BF00FFH);
  256. w.Char(9X); ch := refs[i]; INC(i);
  257. WHILE ch # 0X DO w.Char(ch); ch := refs[i]; INC(i) END;
  258. tw.SetFontColor(WMGraphics.Black);
  259. w.String(" = ");
  260. tw.SetFontColor(WMGraphics.Blue);
  261. INC(adr, base);
  262. IF n = 0 THEN (* open array *)
  263. SYSTEM.GET(adr+4, n) (* real LEN from stack *)
  264. END;
  265. IF type = 15 THEN
  266. IF n > MaxString THEN etc := TRUE; n := MaxString END
  267. ELSE
  268. IF n > MaxArray THEN etc := TRUE; n := MaxArray END
  269. END;
  270. IF mode # 1X THEN SYSTEM.GET(adr, adr) END; (* indirect *)
  271. IF (adr >= -4) & (adr < 4096) THEN
  272. w.String("NIL reference ("); w.Hex( adr,0); w.String("H )")
  273. ELSE
  274. IF type = 15 THEN
  275. w.Char(22X);
  276. LOOP
  277. IF n = 0 THEN EXIT END;
  278. SYSTEM.GET(adr, ch); INC(adr);
  279. IF (ch < " ") OR (ch > "~") THEN EXIT END;
  280. w.Char(ch); DEC(n)
  281. END;
  282. w.Char(22X); etc := (ch # 0X)
  283. ELSE
  284. CASE type OF
  285. 1..4: size := 1
  286. |5: size := 2
  287. |6..7,9,13,14,29: size := 4
  288. |8, 16: size := 8
  289. |22: size := 0; ASSERT(n <= 1)
  290. ELSE
  291. w.String("bad type "); w.Int(type, 1); n := 0
  292. END;
  293. WHILE n > 0 DO
  294. CASE type OF
  295. 1,3: (* BYTE, CHAR *)
  296. SYSTEM.GET(adr, ch);
  297. IF (ch > " ") & (ch <= "~") THEN w.Char(ch)
  298. ELSE w.Hex( ORD(ch), 0); w.Char("X")
  299. END
  300. |2: (* BOOLEAN *)
  301. SYSTEM.GET(adr, ch);
  302. IF ch = 0X THEN w.String("FALSE")
  303. ELSIF ch = 1X THEN w.String("TRUE")
  304. ELSE w.Int(ORD(ch), 1)
  305. END
  306. |4: (* SHORTINT *)
  307. SYSTEM.GET(adr, sval); w.Int( sval, 1)
  308. |5: (* INTEGER *)
  309. SYSTEM.GET(adr, ival); w.Int( ival, 1)
  310. |6: (* LONGINT *)
  311. SYSTEM.GET(adr, lval); w.Int( lval, 1)
  312. |7: (* REAL *)
  313. SYSTEM.GET(adr, rval); w.RawReal(rval)
  314. |8: (* LONGREAL *)
  315. SYSTEM.GET(adr, lrval); w.RawLReal(lrval)
  316. |9: (* SET *)
  317. SYSTEM.GET(adr, set); w.Set(set)
  318. |13, 29: (* POINTER *)
  319. SYSTEM.GET(adr, lval); w.Hex( lval, 0); w.Char("H")
  320. |14: (* PROC *)
  321. SYSTEM.GET(adr, lval);
  322. IF lval = 0 THEN w.String("NIL")
  323. ELSE WriteProc(Modules.ThisModuleByAdr(lval), lval, -1, tmp, tmp1, tmp2, w)
  324. END
  325. |16: (* HUGEINT *)
  326. w.Hex( SYSTEM.GET32(adr+4), 0);
  327. w.Hex( SYSTEM.GET32(adr), 0)
  328. |22: (* RECORD *)
  329. w.Hex( tdadr, 0); w.Char("H")
  330. END;
  331. DEC(n); INC(adr, size);
  332. IF n > 0 THEN w.String(", ") END
  333. END
  334. END
  335. END;
  336. IF etc THEN w.String(" ...") END;
  337. w.Ln();
  338. IF i < m THEN mode := refs[i]; INC(i) END
  339. END;
  340. tw.SetFontColor(WMGraphics.Black);
  341. END Variables;
  342. (* FindProc - Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  343. PROCEDURE FindProc(refs: Bytes; ofs: ADDRESS): LONGINT;
  344. VAR i, m, t, proc: LONGINT; ch: CHAR;
  345. BEGIN
  346. proc := -1; i := 0; m := LEN(refs^);
  347. ch := refs[i]; INC(i);
  348. WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
  349. GetNum(refs, i, t); (* pofs *)
  350. IF t > ofs THEN (* previous procedure was the one *)
  351. ch := 0X (* stop search *)
  352. ELSE (* ~found *)
  353. IF ch = 0F9X THEN
  354. GetNum(refs, i, t); (* nofPars *)
  355. INC(i, 3) (* RetType, procLev, slFlag *)
  356. END;
  357. proc := i; (* remember this position, just before the name *)
  358. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* pname *)
  359. IF i < m THEN
  360. ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
  361. WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  362. ch := refs[i]; INC(i); (* type *)
  363. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  364. GetNum(refs, i, t) (* dim/tdadr *)
  365. END;
  366. GetNum(refs, i, t); (* vofs *)
  367. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
  368. IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
  369. END
  370. END
  371. END
  372. END;
  373. IF (proc = -1) & (i # 0) THEN proc := i END; (* first procedure *)
  374. RETURN proc
  375. END FindProc;
  376. PROCEDURE WriteProc(mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Bytes; VAR refpos: LONGINT; VAR base: ADDRESS; w: Streams.Writer);
  377. VAR ch: CHAR;
  378. BEGIN
  379. refpos := -1;
  380. IF mod = NIL THEN
  381. w.String("Unknown PC ="); w.Hex(pc,0); w.Char("H");
  382. IF fp # -1 THEN
  383. w.String(" EBP ="); w.Hex(fp, 0); w.Char("H")
  384. END
  385. ELSE
  386. w.String(mod.name);
  387. DEC(pc, ADDRESSOF(mod.code[0]));
  388. refs := SYSTEM.VAL(Bytes, mod.refs);
  389. IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
  390. refpos := FindProc(refs, pc);
  391. IF refpos # -1 THEN
  392. w.Char(".");
  393. ch := refs[refpos]; INC(refpos);
  394. IF ch = "$" THEN base := mod.sb ELSE base := fp END; (* for variables *)
  395. WHILE ch # 0X DO w.Char(ch); ch := refs[refpos]; INC(refpos) END
  396. END
  397. END;
  398. w.String(" PC = "); w.Address(pc)
  399. END
  400. END WriteProc;
  401. PROCEDURE GetNum(refs: Bytes; VAR i, num: LONGINT);
  402. VAR n, s: LONGINT; x: CHAR;
  403. BEGIN
  404. s := 0; n := 0; x := refs[i]; INC(i);
  405. WHILE ORD(x) >= 128 DO
  406. INC(n, ASH(ORD(x) - 128, s)); INC(s, 7); x := refs[i]; INC(i)
  407. END;
  408. num := n + ASH(ORD(x) MOD 64 - ORD(x) DIV 64 * 64, s)
  409. END GetNum;
  410. BEGIN {ACTIVE}
  411. LOOP
  412. BEGIN {EXCLUSIVE}
  413. AWAIT(refreshOn);
  414. END;
  415. Refresh(NIL, NIL);
  416. timer.Sleep(interval)
  417. END;
  418. END StateWindow;
  419. TYPE WinCollection = POINTER TO ARRAY OF StateWindow;
  420. VAR
  421. stateWins: WinCollection;
  422. nrWins: LONGINT;
  423. PROCEDURE Remove(stateWin: StateWindow);
  424. VAR
  425. i, j: LONGINT;
  426. wins: WinCollection;
  427. BEGIN {EXCLUSIVE}
  428. i := 0;
  429. WHILE (i < LEN(stateWins)) & (stateWins[i] # stateWin) DO
  430. INC(i)
  431. END;
  432. IF stateWins[i] = stateWin THEN
  433. NEW(wins, LEN(stateWins) - 1);
  434. FOR j := 0 TO i - 1 DO
  435. wins[j] := stateWins[j];
  436. END;
  437. FOR j := i + 1 TO LEN(stateWins) - 1 DO
  438. wins[j-1] := stateWins[j];
  439. END;
  440. DEC(nrWins);
  441. stateWins := wins;
  442. ELSE
  443. (* Not found. *)
  444. END;
  445. END Remove;
  446. (* Usage: WMModuleState.Open modulename [ms] ~ *)
  447. PROCEDURE Open*(context : Commands.Context);
  448. VAR
  449. interval, i: LONGINT;
  450. name: Modules.Name;
  451. wins: WinCollection;
  452. stateWin: StateWindow;
  453. BEGIN
  454. context.arg.SkipWhitespace; context.arg.String(name);
  455. context.arg.SkipWhitespace; context.arg.Int(interval, FALSE);
  456. IF interval < 1 THEN interval := 2000 END; (* default interval *)
  457. NEW(stateWin, "Module State", interval, name);
  458. INC(nrWins);
  459. BEGIN {EXCLUSIVE}
  460. IF stateWins = NIL THEN
  461. NEW(stateWins, 1);
  462. stateWins[0] := stateWin;
  463. ELSE
  464. NEW(wins, LEN(stateWins) + 1);
  465. FOR i := 0 TO LEN(stateWins) - 1 DO
  466. wins[i] := stateWins[i];
  467. END;
  468. wins[LEN(stateWins)] := stateWin;
  469. stateWins := wins;
  470. END;
  471. END;
  472. END Open;
  473. END WMModuleState.
  474. System.Free WMModuleState ~
  475. WMModuleState.Open ~