DebugLog.Mod 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. (** AUTHOR "Michael Szediwy"; PURPOSE "Debug Log";
  2. - Shares the interface with KernelLog
  3. -
  4. Todo:
  5. - Mulit-Line support via Enter & Exit
  6. *)
  7. MODULE DebugLog;
  8. IMPORT SYSTEM, Objects, Machine, Streams, Modules, Random, TextUtilities,
  9. Dates, Strings, WMComponents, WMEditors, WMGraphics, WMStandardComponents,
  10. WM := WMWindowManager;
  11. CONST
  12. Title = "Debug Log";
  13. InitListSize = 8;
  14. TYPE
  15. LogWindow = OBJECT(WMComponents.FormWindow)
  16. VAR
  17. tw- : TextUtilities.TextWriter;
  18. panel : WMStandardComponents.Panel;
  19. out- : WMEditors.Editor;
  20. open : BOOLEAN;
  21. PROCEDURE &New*(CONST title : ARRAY OF CHAR);
  22. VAR toolbar : WMStandardComponents.Panel;
  23. clear : WMStandardComponents.Button;
  24. BEGIN
  25. NEW(panel); panel.bounds.SetExtents(640, 420); panel.fillColor.Set(WMGraphics.RGBAToColor(255, 255, 255, 255));
  26. NEW(toolbar);
  27. toolbar.bounds.SetHeight(20);
  28. toolbar.alignment.Set(WMComponents.AlignTop);
  29. panel.AddContent(toolbar);
  30. NEW(clear);
  31. clear.alignment.Set(WMComponents.AlignLeft);
  32. clear.SetCaption("Clear");
  33. clear.onClick.Add(ClearText);
  34. toolbar.AddContent(clear);
  35. NEW(out); out.alignment.Set(WMComponents.AlignClient); out.tv.showBorder.Set(TRUE); panel.AddContent(out);
  36. Init(panel.bounds.GetWidth(), panel.bounds.GetHeight(), FALSE);
  37. SetContent(panel);
  38. manager := WM.GetDefaultManager();
  39. SetTitle(WMComponents.NewString(title));
  40. WM.DefaultAddWindow(SELF);
  41. NEW(tw, out.text);
  42. open := TRUE
  43. END New;
  44. PROCEDURE Close*;
  45. BEGIN
  46. open := FALSE;
  47. Close^
  48. END Close;
  49. PROCEDURE ClearText(sender, data : ANY);
  50. BEGIN
  51. out.text.AcquireWrite();
  52. out.text.Delete(0, out.text.GetLength());
  53. out.tv.firstLine.Set(0); out.tv.cursor.SetPosition(0);
  54. out.text.ReleaseWrite()
  55. END ClearText;
  56. END LogWindow;
  57. TraceSubscriber = OBJECT
  58. VAR
  59. processID : LONGINT;
  60. color : WMGraphics.Color; (* Color property *)
  61. date : BOOLEAN; (* Default setting whether the date is printed or not *)
  62. PROCEDURE &New*(processID : LONGINT; color : WMGraphics.Color; date : BOOLEAN);
  63. BEGIN
  64. SELF.processID := processID;
  65. SELF.color := color;
  66. SELF.date := date
  67. END New;
  68. END TraceSubscriber;
  69. SubscriberList = POINTER TO ARRAY OF TraceSubscriber;
  70. VAR
  71. logwindow : LogWindow;
  72. nrSubscriptions : LONGINT;
  73. subscriptions : SubscriberList;
  74. gen : Random.Sequence;
  75. defaultColor : WMGraphics.Color;
  76. me : Modules.Module;
  77. date : BOOLEAN;
  78. PROCEDURE AlreadySubscribed(processID : LONGINT; VAR sub : TraceSubscriber) : BOOLEAN;
  79. VAR i : LONGINT;
  80. BEGIN
  81. FOR i := 0 TO nrSubscriptions - 1 DO
  82. IF subscriptions[i].processID = processID THEN
  83. IF sub # NIL THEN sub := subscriptions[i] END;
  84. RETURN TRUE
  85. END
  86. END;
  87. sub := NIL;
  88. RETURN FALSE
  89. END AlreadySubscribed;
  90. (* From now on tracing is with or without the date string *)
  91. PROCEDURE SetDate*(new : BOOLEAN);
  92. BEGIN {EXCLUSIVE}
  93. date := new
  94. END SetDate;
  95. (* Get the current date property. *)
  96. PROCEDURE GetDate*() : BOOLEAN;
  97. BEGIN {EXCLUSIVE}
  98. RETURN date
  99. END GetDate;
  100. PROCEDURE GetNextColor() : WMGraphics.Color;
  101. VAR r, g, b : LONGINT;
  102. BEGIN
  103. IF gen = NIL THEN
  104. NEW(gen);
  105. gen.InitSeed(1291)
  106. END;
  107. r := gen.Integer() MOD 100H;
  108. g := gen.Integer() MOD 100H;
  109. b := gen.Integer() MOD 100H;
  110. RETURN WMGraphics.RGBAToColor(r,g,b,0FFH)
  111. END GetNextColor;
  112. PROCEDURE Grow;
  113. VAR tmp : SubscriberList; i : LONGINT;
  114. BEGIN
  115. NEW(tmp, 2 * LEN(subscriptions));
  116. FOR i := 0 TO LEN(subscriptions) - 1 DO
  117. tmp[i] := subscriptions[i]
  118. END;
  119. subscriptions := tmp;
  120. END Grow;
  121. PROCEDURE Subscribe(processID : LONGINT);
  122. VAR sub : TraceSubscriber; color : WMGraphics.Color;
  123. BEGIN
  124. color := GetNextColor(); (* Get a random color *)
  125. NEW(sub, processID, color, date);
  126. IF LEN(subscriptions) = nrSubscriptions THEN Grow END;
  127. subscriptions[nrSubscriptions] := sub;
  128. INC(nrSubscriptions)
  129. END Subscribe;
  130. PROCEDURE GetColor(processID : LONGINT) : WMGraphics.Color;
  131. VAR i : LONGINT;
  132. BEGIN
  133. FOR i := 0 TO LEN(subscriptions) - 1 DO
  134. IF subscriptions[i].processID = processID THEN
  135. RETURN subscriptions[i].color
  136. END
  137. END;
  138. RETURN defaultColor
  139. END GetColor;
  140. PROCEDURE GetSubscription(processID : LONGINT) : TraceSubscriber;
  141. VAR i : LONGINT;
  142. BEGIN
  143. FOR i := 0 TO nrSubscriptions - 1 DO
  144. IF subscriptions[i].processID = processID THEN
  145. RETURN subscriptions[i]
  146. END
  147. END;
  148. RETURN NIL
  149. END GetSubscription;
  150. PROCEDURE TraceIdString;
  151. VAR
  152. bp, pc, nextbp : ADDRESS;
  153. methadr, i : LONGINT;
  154. module : Modules.Module;
  155. process : Objects.Process;
  156. now, name : ARRAY 128 OF CHAR;
  157. ch : CHAR;
  158. out : Streams.Writer;
  159. sub : TraceSubscriber;
  160. BEGIN
  161. IF logwindow = NIL THEN NEW(logwindow, Title) END;
  162. out := logwindow.tw;
  163. process := Objects.CurrentProcess();
  164. IF ~AlreadySubscribed(process.id, sub) THEN
  165. Subscribe(process.id);
  166. END;
  167. sub := GetSubscription(process.id);
  168. (* sub must not be NIL *)
  169. IF sub.date # date THEN
  170. date := sub.date
  171. END;
  172. (* Find the caller outside of this module *)
  173. bp := SYSTEM.GetFramePointer ();
  174. REPEAT
  175. SYSTEM.GET(bp + SIZEOF (ADDRESS), pc);
  176. module := Modules.ThisModuleByAdr(pc);
  177. SYSTEM.GET(bp, bp);
  178. SYSTEM.GET(bp, nextbp)
  179. UNTIL (module # me) OR (nextbp = 0);
  180. (* IF bp = 0 the previous PC is kept. This is the PC of the last PAF. *)
  181. (* Compute module pc *)
  182. DEC(pc, ADDRESSOF(module.code[0]));
  183. methadr := FindProc(module.refs, pc);
  184. IF methadr # -1 THEN
  185. i := 0;
  186. ch := module.refs[methadr]; INC(methadr);
  187. WHILE ch # 0X DO
  188. name[i] := ch;
  189. ch := module.refs[methadr];
  190. INC(methadr);
  191. INC(i)
  192. END
  193. END;
  194. name[i] := 0X;
  195. logwindow.tw.SetFontColor(GetColor(process.id));
  196. IF date THEN
  197. Strings.FormatDateTime("yyyy.mm.dd hh.nn.ss ", Dates.Now(), now);
  198. out.String(now);
  199. out.String(" ")
  200. END;
  201. out.String("P"); out.Int(process.procID, 0);out.String(".");out.Int(process.id, 0);
  202. out.Char(" ");out.String(module.name);out.Char(".");out.String(name);out.String("[");
  203. out.Address(pc); out.String("]> ")
  204. END TraceIdString;
  205. (* Trace a string *)
  206. PROCEDURE String*(CONST str : ARRAY OF CHAR);
  207. VAR out : Streams.Writer;
  208. BEGIN {EXCLUSIVE}
  209. TraceIdString();
  210. out := logwindow.tw;
  211. out.String(str);
  212. out.Ln();
  213. out.Update()
  214. END String;
  215. PROCEDURE TwoStrings*(CONST str1, str2 : ARRAY OF CHAR);
  216. VAR out : Streams.Writer;
  217. BEGIN {EXCLUSIVE}
  218. TraceIdString();
  219. out := logwindow.tw;
  220. out.String(str1);
  221. out.String(str2);
  222. out.Ln();
  223. out.Update()
  224. END TwoStrings;
  225. PROCEDURE Boolean*(x : BOOLEAN);
  226. BEGIN
  227. IF x THEN String("TRUE") ELSE String("FALSE") END
  228. END Boolean;
  229. PROCEDURE TraceDebugBoolean*(CONST name : ARRAY OF CHAR; x : BOOLEAN);
  230. BEGIN
  231. IF x THEN
  232. TraceDebugString(name, "TRUE")
  233. ELSE
  234. TraceDebugString(name, "FALSE")
  235. END
  236. END TraceDebugBoolean;
  237. (** Write a block of memory in hex. *)
  238. PROCEDURE Memory*(adr: ADDRESS; size : SIZE);
  239. VAR i, j : ADDRESS; ch : CHAR; out : Streams.Writer;
  240. BEGIN {EXCLUSIVE}
  241. TraceIdString();
  242. out := logwindow.tw;
  243. out.Ln;
  244. out.Char(0EX); (* "fixed font" *)
  245. size := adr+size-1;
  246. FOR i := adr TO size BY 16 DO
  247. out.Address(i);
  248. FOR j := i TO i+15 DO
  249. IF j <= size THEN
  250. SYSTEM.GET(j, ch);
  251. out.Hex(ORD(ch), -3)
  252. ELSE
  253. out.String(" ")
  254. END
  255. END;
  256. out.String(" ");
  257. FOR j := i TO i+15 DO
  258. IF j <= size THEN
  259. SYSTEM.GET(j, ch);
  260. IF (ch < " ") OR (ch >= CHR(127)) THEN ch := "." END;
  261. out.Char(ch)
  262. END
  263. END;
  264. out.Ln
  265. END;
  266. out.Char(0FX); (* "proportional font" *)
  267. out.Ln(); out.Update()
  268. END Memory;
  269. (** Write a buffer in hex. *)
  270. PROCEDURE Buffer*(VAR buf : ARRAY OF CHAR; ofs, len : LONGINT);
  271. BEGIN
  272. Memory(ADDRESSOF(buf[ofs]), len)
  273. END Buffer;
  274. (** Write "x" as a hexadecimal number. "w" is the field width. Always prints 16 digits. *)
  275. PROCEDURE HIntHex*(x : HUGEINT; w : LONGINT);
  276. VAR
  277. out : Streams.Writer;
  278. BEGIN {EXCLUSIVE}
  279. TraceIdString();
  280. out := logwindow.tw;
  281. out.Hex(SHORT (ASH(x, -32)), w-8);
  282. out.Hex(SHORT (x), 8);
  283. out.Ln(); out.Update();
  284. END HIntHex;
  285. (** Write "x" as a decimal number with a power-of-two multiplier (K, M or G), followed by "suffix". "w" is the field width, excluding "suffix". *)
  286. PROCEDURE IntSuffix*(x, w : LONGINT; CONST suffix : ARRAY OF CHAR);
  287. CONST K = 1024; M = K*K; G = K*M;
  288. VAR mult : CHAR; out : Streams.Writer;
  289. BEGIN {EXCLUSIVE}
  290. TraceIdString();
  291. out := logwindow.tw;
  292. IF x MOD K # 0 THEN
  293. out.Int(x, w)
  294. ELSE
  295. IF x MOD M # 0 THEN mult := "K"; x := x DIV K
  296. ELSIF x MOD G # 0 THEN mult := "M"; x := x DIV M
  297. ELSE mult := "G"; x := x DIV G
  298. END;
  299. out.Int(x, w-1); out.Char(mult)
  300. END;
  301. out.String(suffix);
  302. out.Ln(); out.Update()
  303. END IntSuffix;
  304. PROCEDURE Enter*;
  305. END Enter;
  306. PROCEDURE Exit*;
  307. END Exit;
  308. PROCEDURE GetWriter*() : Streams.Writer;
  309. VAR x : Streams.Writer;
  310. BEGIN
  311. NEW(x, Send, 128);
  312. RETURN x
  313. END GetWriter;
  314. (* UNSAFE *)
  315. (** Send the specified characters to the trace output (cf. Streams.Sender). *)
  316. PROCEDURE Send*(CONST buf : ARRAY OF CHAR; ofs, len : LONGINT; propagate : BOOLEAN; VAR res : WORD);
  317. VAR i : LONGINT; str : POINTER TO ARRAY OF CHAR;
  318. BEGIN
  319. NEW(str, len + 1);
  320. FOR i := 0 TO len - 1 DO
  321. str[i] := buf[ofs + i];
  322. END;
  323. String(str^);
  324. res := Streams.Ok
  325. END Send;
  326. (* Outputs [name] = [value] *)
  327. PROCEDURE TraceDebugString*(CONST name, value : ARRAY OF CHAR);
  328. VAR out : Streams.Writer;
  329. BEGIN {EXCLUSIVE}
  330. TraceIdString();
  331. out := logwindow.tw;
  332. out.String(name);
  333. out.String(" = ");
  334. out.String(value);
  335. out.Ln();
  336. out.Update()
  337. END TraceDebugString;
  338. (* Trace no message only ID *)
  339. PROCEDURE Ln*;
  340. VAR out : Streams.Writer;
  341. BEGIN {EXCLUSIVE}
  342. TraceIdString();
  343. out := logwindow.tw;
  344. out.Ln();
  345. out.Update()
  346. END Ln;
  347. PROCEDURE Int*(x, w : LONGINT);
  348. VAR out : Streams.Writer;
  349. BEGIN {EXCLUSIVE}
  350. TraceIdString();
  351. out := logwindow.tw;
  352. out.Int(x,w);
  353. out.Ln();
  354. out.Update()
  355. END Int;
  356. (* Outputs [name] = [value] *)
  357. PROCEDURE TraceDebugInt*(CONST name : ARRAY OF CHAR; value, w : LONGINT);
  358. VAR
  359. out : Streams.Writer;
  360. BEGIN {EXCLUSIVE}
  361. TraceIdString();
  362. out := logwindow.tw;
  363. out.String(name);
  364. out.String(" = ");
  365. out.Int(value, w);
  366. out.Ln();
  367. out.Update();
  368. END TraceDebugInt;
  369. PROCEDURE Hex*(x, w : LONGINT);
  370. VAR
  371. out : Streams.Writer;
  372. BEGIN {EXCLUSIVE}
  373. TraceIdString();
  374. out := logwindow.tw;
  375. out.Hex(x,w);
  376. out.Ln();
  377. out.Update()
  378. END Hex;
  379. (* Outputs [name] = [value] *)
  380. PROCEDURE TraceDebugHex*(CONST name : ARRAY OF CHAR; value, w : LONGINT);
  381. VAR
  382. out : Streams.Writer;
  383. BEGIN {EXCLUSIVE}
  384. TraceIdString();
  385. out := logwindow.tw;
  386. out.String(name);
  387. out.String(" = ");
  388. out.Hex(value,w);
  389. out.Ln();
  390. out.Update()
  391. END TraceDebugHex;
  392. PROCEDURE Char*(c : CHAR);
  393. VAR
  394. out : Streams.Writer;
  395. BEGIN {EXCLUSIVE}
  396. TraceIdString();
  397. out := logwindow.tw;
  398. out.Char(c);
  399. out.Ln();
  400. out.Update()
  401. END Char;
  402. (* Outputs [name] = [value] *)
  403. PROCEDURE TraceDebugChar*(CONST name : ARRAY OF CHAR; c : CHAR);
  404. VAR
  405. out : Streams.Writer;
  406. BEGIN {EXCLUSIVE}
  407. TraceIdString();
  408. out := logwindow.tw;
  409. out.String(name);
  410. out.String(" = ");
  411. out.Char(c);
  412. out.Ln();
  413. out.Update();
  414. END TraceDebugChar;
  415. PROCEDURE Set*(s : SET);
  416. VAR
  417. out : Streams.Writer;
  418. BEGIN {EXCLUSIVE}
  419. TraceIdString();
  420. out := logwindow.tw;
  421. out.Set(s);
  422. out.Ln();
  423. out.Update()
  424. END Set;
  425. (* Outputs [name] = [value] *)
  426. PROCEDURE TraceDebugSet*(CONST name : ARRAY OF CHAR; s : SET);
  427. VAR
  428. out : Streams.Writer;
  429. BEGIN {EXCLUSIVE}
  430. TraceIdString();
  431. out := logwindow.tw;
  432. out.String(name);
  433. out.String(" = ");
  434. out.Set(s);
  435. out.Ln();
  436. out.Update()
  437. END TraceDebugSet;
  438. (*
  439. These parameter overwrites the the parameter given in a trace procedure.
  440. Parameter:
  441. color: The print color for this process.
  442. date: TRUE, The date will be printed for this process.
  443. FALSE, The date won't be printed for this process.
  444. overwrite: TRUE, If the process is already subscribed this parameter indicates
  445. that the settings are ready to override.
  446. FALSE, The oposite of TRUE ;-)
  447. *)
  448. PROCEDURE SubscribeProcess*(color : WMGraphics.Color; date, overwrite : BOOLEAN);
  449. VAR
  450. sub : TraceSubscriber;
  451. processID : LONGINT;
  452. p : Objects.Process;
  453. BEGIN {EXCLUSIVE}
  454. p := Objects.CurrentProcess();
  455. processID := p.id;
  456. IF (AlreadySubscribed(processID, sub)) & ~(overwrite) THEN
  457. RETURN
  458. ELSIF AlreadySubscribed(processID, sub) THEN
  459. IF ~CheckColor(color) THEN
  460. color := sub.color;
  461. String("Invalid Color! Left old color.")
  462. END;
  463. sub.date := date
  464. ELSE
  465. IF ~CheckColor(color) THEN
  466. color := GetNextColor();
  467. String("Invalid Color! New color choosen.")
  468. END;
  469. NEW(sub, processID, color, date);
  470. IF LEN(subscriptions) = nrSubscriptions THEN
  471. Grow
  472. END;
  473. subscriptions[nrSubscriptions] := sub;
  474. INC(nrSubscriptions)
  475. END
  476. END SubscribeProcess;
  477. PROCEDURE CheckColor(color : WMGraphics.Color) : BOOLEAN;
  478. VAR
  479. r, g, b, a : LONGINT;
  480. BEGIN
  481. WMGraphics.ColorToRGBA(color, r, g, b, a);
  482. RETURN
  483. ( r >= 0 )
  484. & ( g >= 0)
  485. & ( b >= 0)
  486. & ( r <= 255)
  487. & ( g <= 255)
  488. & ( b <= 255)
  489. & ( a = 0FFH);
  490. END CheckColor;
  491. (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  492. PROCEDURE FindProc(refs : Modules.Bytes; modpc : ADDRESS) : LONGINT;
  493. VAR i, m, t, proc : LONGINT; ch : CHAR;
  494. BEGIN
  495. proc := -1; i := 0; m := LEN(refs^);
  496. ch := refs[i]; INC(i);
  497. WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
  498. GetNum(refs, i, t); (* pofs *)
  499. IF t > modpc THEN (* previous procedure was the one *)
  500. ch := 0X (* stop search *)
  501. ELSE (* ~found *)
  502. IF ch = 0F9X THEN
  503. GetNum(refs, i, t); (* nofPars *)
  504. INC(i, 3) (* RetType, procLev, slFlag *)
  505. END;
  506. proc := i; (* remember this position, just before the name *)
  507. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* pname *)
  508. IF i < m THEN
  509. ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
  510. WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  511. ch := refs[i]; INC(i); (* type *)
  512. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  513. GetNum(refs, i, t) (* dim/tdadr *)
  514. END;
  515. GetNum(refs, i, t); (* vofs *)
  516. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
  517. IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
  518. END
  519. END
  520. END
  521. END;
  522. IF (proc = -1) & (i # 0) THEN proc := i END; (* first procedure *)
  523. RETURN proc
  524. END FindProc;
  525. (* Get a compressed refblk number. *)
  526. PROCEDURE GetNum(refs : Modules.Bytes; VAR i, num : LONGINT);
  527. VAR n, s : LONGINT; x : CHAR;
  528. BEGIN
  529. s := 0; n := 0;
  530. x := refs[i]; INC(i);
  531. WHILE ORD(x) >= 128 DO
  532. INC(n, ASH(ORD(x) - 128, s));
  533. INC(s, 7);
  534. x := refs[i]; INC(i)
  535. END;
  536. num := n + ASH(ORD(x) MOD 64 - ORD(x) DIV 64 * 64, s)
  537. END GetNum;
  538. PROCEDURE Open*;
  539. BEGIN
  540. IntOpen();
  541. END Open;
  542. PROCEDURE IntOpen;
  543. BEGIN {EXCLUSIVE}
  544. IF logwindow # NIL THEN
  545. IF ~logwindow.open THEN
  546. WM.DefaultAddWindow(logwindow);
  547. ELSE
  548. WM.DefaultBringToView(logwindow, TRUE)
  549. END
  550. ELSE
  551. NEW(logwindow, Title)
  552. END
  553. END IntOpen;
  554. PROCEDURE Close;
  555. BEGIN {EXCLUSIVE}
  556. IF (logwindow # NIL) & (logwindow.open) THEN
  557. logwindow.Close();
  558. END;
  559. END Close;
  560. BEGIN
  561. date := FALSE;
  562. nrSubscriptions := 0;
  563. NEW(subscriptions, InitListSize);
  564. defaultColor := WMGraphics.RGBAToColor(0,0,0,255);
  565. me := Modules.ThisModuleByAdr(Machine.CurrentPC());
  566. Modules.InstallTermHandler(Close)
  567. END DebugLog.
  568. DebugLog.Open ~
  569. System.Free DebugLog ~