Oberon.System.Mod 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE System IN Oberon; (** portable, except where noted *) (* pjm *)
  3. (**
  4. * Based on System.Mod by jg, nw, ard, nm, jm, ejz et al.
  5. * Aos Native Oberon
  6. *
  7. * History:
  8. *
  9. * 16.03.2007 Activate SystemTools.FreeDownTo instead of AosTools.FreeDownTo in procedure FreeOberon (staubesv)
  10. *)
  11. IMPORT SYSTEM, Kernel, AosFS := Files IN A2, Files, Modules, Objects, Display, Input, Fonts, Viewers, Texts, Oberon, TextFrames,
  12. KernelLog IN A2, Streams IN A2, Machine IN A2, Heaps IN A2, AosModules := Modules IN A2, AosActive := Objects IN A2,
  13. ProcessInfo IN A2, Commands IN A2;
  14. CONST
  15. OberonBaseModule = "Oberon-Kernel";
  16. WMWindowManager = "WMWindowManager";
  17. LogWindow = "LogWindow"; (* must have a Close command *)
  18. MaxString = 64;
  19. MaxArray = 10;
  20. LogTime = Input.TimeUnit DIV 2;
  21. BufSize = 8192;
  22. TYPE
  23. Bytes = AosModules.Bytes;
  24. OberonRunner = OBJECT
  25. VAR exception : BOOLEAN;
  26. BEGIN {ACTIVE, SAFE, PRIORITY(AosActive.Normal)}
  27. IF ~exception THEN
  28. exception := TRUE;
  29. KernelLog.Enter; KernelLog.String("Oberon started"); KernelLog.Exit;
  30. Oberon.Loop;
  31. ELSE
  32. KernelLog.Enter; KernelLog.String("Oberon restarted due to an exception"); KernelLog.Exit;
  33. Oberon.Loop;
  34. END;
  35. KernelLog.Enter; KernelLog.String("Oberon stopped"); KernelLog.Exit;
  36. END OberonRunner;
  37. VAR
  38. W, LogW: Texts.Writer;
  39. init: BOOLEAN;
  40. count: LONGINT;
  41. task: Oberon.Task;
  42. fixed: Fonts.Font;
  43. buf: POINTER TO ARRAY OF CHAR;
  44. log: Texts.Text;
  45. oberonRunner : OberonRunner;
  46. time0, date0: LONGINT;
  47. PROCEDURE OpenText(title: ARRAY OF CHAR; T: Texts.Text; system: BOOLEAN);
  48. VAR W: INTEGER;
  49. BEGIN
  50. IF system THEN W := Display.Width DIV 8*3 ELSE W := 400 END;
  51. Oberon.OpenText(title, T, W, 240)
  52. END OpenText;
  53. (* --- Toolbox for system control *)
  54. PROCEDURE SetFont*;
  55. VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner; f: Fonts.Font;
  56. BEGIN
  57. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  58. IF (S.class = Texts.Char) & (S.c = "^") THEN
  59. Oberon.GetSelection(T, beg, end, time);
  60. IF time # -1 THEN
  61. Texts.OpenScanner(S, T, beg); Texts.Scan(S);
  62. IF S.class = Texts.Name THEN
  63. f := Fonts.This(S.s);
  64. IF f # NIL THEN Oberon.SetFont(f) END
  65. END
  66. END
  67. ELSIF S.class = Texts.Name THEN
  68. f := Fonts.This(S.s);
  69. IF f # NIL THEN Oberon.SetFont(f) END
  70. END
  71. END SetFont;
  72. PROCEDURE SetColor*;
  73. VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner; ch: CHAR;
  74. BEGIN
  75. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  76. IF (S.class = Texts.Char) & (S.c = "^") THEN
  77. Oberon.GetSelection(T, beg, end, time);
  78. IF time # -1 THEN
  79. Texts.OpenReader(S, T, beg); Texts.Read(S, ch); Oberon.SetColor(S.col)
  80. END
  81. ELSIF S.class = Texts.Int THEN Oberon.SetColor(SHORT(SHORT(S.i)))
  82. END
  83. END SetColor;
  84. PROCEDURE SetOffset*;
  85. VAR beg, end, time: LONGINT; T: Texts.Text;S: Texts.Scanner; ch: CHAR;
  86. BEGIN
  87. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  88. IF (S.class = Texts.Char) & (S.c = "^") THEN
  89. Oberon.GetSelection(T, beg, end, time);
  90. IF time # -1 THEN
  91. Texts.OpenReader(S, T, beg); Texts.Read(S, ch); Oberon.SetOffset(S.voff)
  92. END
  93. ELSIF S.class = Texts.Int THEN Oberon.SetOffset(SHORT(SHORT(S.i)))
  94. END
  95. END SetOffset;
  96. PROCEDURE Time*;
  97. VAR par: Oberon.ParList; S: Texts.Scanner; t, d, hr, min, sec, yr, mo, day: LONGINT;
  98. PROCEDURE WritePair(ch: CHAR; x: LONGINT);
  99. BEGIN Texts.Write(W, ch);
  100. Texts.Write(W, CHR(x DIV 10 + 30H)); Texts.Write(W, CHR(x MOD 10 + 30H))
  101. END WritePair;
  102. BEGIN
  103. par := Oberon.Par;
  104. Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
  105. IF S.class = Texts.Int THEN (*set date*)
  106. day := S.i; Texts.Scan(S); mo := S.i; Texts.Scan(S); yr := S.i; Texts.Scan(S);
  107. hr := S.i; Texts.Scan(S); min := S.i; Texts.Scan(S); sec := S.i;
  108. IF yr > 1900 THEN DEC(yr, 1900) END; (* compatible with old two-digit format *)
  109. t := (hr*64 + min)*64 + sec; d := (yr*16 + mo)*32 + day;
  110. Oberon.SetClock(t, d)
  111. ELSE (*read date*)
  112. Texts.WriteString(W, "System.Time");
  113. Oberon.GetClock(t, d); Texts.WriteDate(W, t, d);
  114. IF (S.class = Texts.Name) & (S.s = "start") THEN
  115. Texts.WriteString(W, ", started");
  116. time0 := t; date0 := d
  117. ELSIF (S.class = Texts.Name) & (S.s = "lap") THEN
  118. hr := t DIV 4096 MOD 32; min := t DIV 64 MOD 64; sec := t MOD 64;
  119. DEC(sec, time0 MOD 64);
  120. IF sec < 0 THEN INC(sec, 60); DEC(min) END;
  121. DEC(min, time0 DIV 64 MOD 64);
  122. IF min < 0 THEN INC(min, 60); DEC(hr) END;
  123. DEC(hr, time0 DIV 4096 MOD 32);
  124. IF hr < 0 THEN INC(hr, 24) END; (* assume one day passed *)
  125. Texts.WriteString(W, ", "); WritePair(" ", hr);
  126. WritePair(":", min); WritePair(":", sec);
  127. Texts.WriteString(W, " elapsed");
  128. IF d # date0 THEN
  129. Texts.WriteString(W, " (may be incorrect due to date change)")
  130. END
  131. END;
  132. Texts.WriteLn(W);
  133. Texts.Append(Oberon.Log, W.buf)
  134. END
  135. END Time;
  136. (* Perform an immediate garbage collection. *)
  137. PROCEDURE Collect*;
  138. BEGIN
  139. Heaps.GC; (* force garbage collection *)
  140. Kernel.GC (* call Oberon finalizers *)
  141. END Collect;
  142. (* --- Toolbox for standard display *)
  143. PROCEDURE Open*;
  144. VAR par: Oberon.ParList; T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
  145. BEGIN
  146. par := Oberon.Par;
  147. Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
  148. IF (S.class = Texts.Char) & (S.c = "^") OR (S.line # 0) THEN
  149. Oberon.GetSelection(T, beg, end, time);
  150. IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END
  151. END;
  152. IF S.class IN {Texts.Name, Texts.String} THEN
  153. OpenText(S.s, TextFrames.Text(S.s), TRUE)
  154. END
  155. END Open;
  156. PROCEDURE OpenLog*;
  157. BEGIN
  158. OpenText("System.Log", Oberon.Log, TRUE);
  159. END OpenLog;
  160. PROCEDURE Clear*;
  161. VAR S: Texts.Scanner; par: Oberon.ParList; F: Display.Frame; L: Objects.LinkMsg; A: Objects.AttrMsg;
  162. BEGIN
  163. par := Oberon.Par; F := NIL;
  164. L.id := Objects.get; L.name := "Model"; L.obj := NIL;
  165. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  166. IF (S.class = Texts.Char) & (S.c = "*") THEN
  167. F := Oberon.MarkedFrame()
  168. ELSIF (par.vwr # NIL) & (par.vwr.dsc # NIL) THEN
  169. F := par.vwr.dsc.next;
  170. F.handle(F, L);
  171. IF (L.obj # NIL) & (L.obj IS Display.Frame) THEN
  172. A.id := Objects.get; A.name := "Gen"; L.obj.handle(L.obj, A);
  173. IF A.s = "PanelDocs.NewDoc" THEN (* Desktop *)
  174. F := Oberon.Par.obj(Display.Frame);
  175. F := F.dlink(Display.Frame);
  176. F := F.next.dsc
  177. ELSE
  178. F := L.obj(Display.Frame)
  179. END
  180. END
  181. END;
  182. IF F # NIL THEN
  183. F.handle(F, L);
  184. IF (L.obj # NIL) & (L.obj IS Texts.Text) THEN
  185. Texts.Delete(L.obj(Texts.Text), 0, L.obj(Texts.Text).len)
  186. END
  187. END
  188. END Clear;
  189. PROCEDURE Close*;
  190. VAR par: Oberon.ParList; V: Viewers.Viewer;
  191. BEGIN
  192. par := Oberon.Par;
  193. IF par.frame = par.vwr.dsc THEN V := par.vwr
  194. ELSE V := Oberon.MarkedViewer()
  195. END;
  196. Viewers.Close(V)
  197. END Close;
  198. PROCEDURE CloseTrack*;
  199. VAR V: Viewers.Viewer;
  200. BEGIN
  201. V := Oberon.MarkedViewer(); Viewers.CloseTrack(V.X)
  202. END CloseTrack;
  203. PROCEDURE Recall*;
  204. VAR V: Viewers.Viewer; M: Display.ControlMsg;
  205. BEGIN
  206. Viewers.Recall(V);
  207. IF (V # NIL) & (V.state = 0) THEN
  208. Viewers.Open(V, V.X, V.Y + V.H); M.F := NIL; M.id := Display.restore; V.handle(V, M)
  209. END
  210. END Recall;
  211. PROCEDURE Copy*;
  212. VAR V, V1: Viewers.Viewer; M: Objects.CopyMsg; N: Display.ControlMsg;
  213. BEGIN
  214. M.id := Objects.shallow;
  215. V := Oberon.Par.vwr; V.handle(V, M); V1 := M.obj(Viewers.Viewer);
  216. Viewers.Open(V1, V.X, V.Y + V.H DIV 2);
  217. N.F := NIL; N.id := Display.restore; V1.handle(V1, N)
  218. END Copy;
  219. PROCEDURE Grow*;
  220. VAR par: Oberon.ParList; V, V1: Viewers.Viewer; M: Objects.CopyMsg; N: Display.ControlMsg; DW, DH: INTEGER;
  221. BEGIN
  222. par := Oberon.Par;
  223. IF par.frame = par.vwr.dsc THEN V := par.vwr
  224. ELSE V := Oberon.MarkedViewer()
  225. END;
  226. DW := Oberon.DisplayWidth(V.X); DH := Oberon.DisplayHeight(V.X);
  227. IF V.H < DH - Viewers.minH THEN Oberon.OpenTrack(V.X, V.W)
  228. ELSIF V.W < DW THEN Oberon.OpenTrack(Oberon.UserTrack(V.X), DW)
  229. END;
  230. IF (V.H < DH - Viewers.minH) OR (V.W < DW) THEN
  231. M.id := Objects.shallow;
  232. V.handle(V, M); V1 := M.obj(Viewers.Viewer);
  233. Viewers.Open(V1, V.X, DH);
  234. N.F := NIL; N.id := Display.restore; V1.handle(V1, N)
  235. END
  236. END Grow;
  237. (* --- Toolbox for module management *)
  238. PROCEDURE Free*;
  239. VAR par: Oberon.ParList; S: Texts.Scanner; F: TextFrames.Frame; time, beg, end, pos: LONGINT; T: Texts.Text;
  240. PROCEDURE FreeFile;
  241. (*VAR i: LONGINT;*)
  242. BEGIN
  243. (*IF S.nextCh # "*" THEN Modules.Free(S.s, FALSE)
  244. ELSE Modules.Free(S.s, TRUE); Texts.Scan(S)
  245. END*)
  246. (*i := 0; WHILE (S.s[i] # 0X) & (S.s[i] # ".") DO INC(i) END;
  247. S.s[i] := 0X;*)
  248. Modules.Free(S.s, FALSE);
  249. IF Modules.res = 0 THEN
  250. Texts.WriteString(W, S.s); Texts.WriteString(W, " unloaded")
  251. ELSE
  252. Texts.WriteString(W, Modules.resMsg)
  253. END;
  254. Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  255. END FreeFile;
  256. BEGIN
  257. par := Oberon.Par;
  258. Oberon.GetSelection(T, beg, end, time);
  259. Texts.WriteString(W, "System.Free"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
  260. IF (par.vwr.dsc = NIL) OR (par.vwr.dsc # par.frame) OR ~(par.vwr.dsc.next IS TextFrames.Frame) THEN
  261. Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
  262. IF (S.class = Texts.Char) & (S.c = "^") OR (S.class = Texts.Inval) THEN
  263. IF time # -1 THEN
  264. Texts.OpenScanner(S, T, beg); pos := Texts.Pos(S)-1; Texts.Scan(S);
  265. WHILE ~S.eot & (S.class = Texts.Name) & (pos < end) DO
  266. FreeFile; pos := Texts.Pos(S); Texts.Scan(S);
  267. WHILE ~S.eot & (S.class = Texts.Int) DO pos := Texts.Pos(S); Texts.Scan(S) END
  268. END
  269. END
  270. ELSE
  271. WHILE S.class = Texts.Name DO FreeFile; Texts.Scan(S) END
  272. END
  273. ELSE
  274. F := par.vwr.dsc.next(TextFrames.Frame);
  275. IF F.sel > 0 THEN
  276. Texts.OpenScanner(S, F.text, F.selbeg.pos);
  277. WHILE ~S.eot & (Texts.Pos(S) < F.selend.pos) DO
  278. Texts.Scan(S);
  279. IF S.class = Texts.Name THEN FreeFile;
  280. IF Modules.res = 0 THEN
  281. Texts.OpenReader(S, F.text, F.selbeg.pos);
  282. REPEAT Texts.Read(S, S.nextCh) UNTIL S.eot OR (S.nextCh = 0DX);
  283. Texts.Delete(F.text, F.selbeg.pos, Texts.Pos(S));
  284. DEC(F.selend.pos, Texts.Pos(S) - F.selbeg.pos);
  285. Texts.OpenScanner(S, F.text, F.selbeg.pos);
  286. END
  287. ELSE F.selbeg.pos := Texts.Pos(S)
  288. END
  289. END
  290. END
  291. END
  292. END Free;
  293. PROCEDURE WriteK(VAR W: Texts.Writer; k: LONGINT);
  294. VAR suffix: CHAR;
  295. BEGIN
  296. IF k < 100*1024 THEN suffix := "K"
  297. ELSIF k < 100*1024*1024 THEN suffix := "M"; k := k DIV 1024
  298. ELSE suffix := "G"; k := k DIV (1024*1024)
  299. END;
  300. Texts.WriteInt(W, k, 1); Texts.Write(W, suffix); Texts.Write(W, "B")
  301. END WriteK;
  302. PROCEDURE ShowModules*;
  303. VAR T: Texts.Text; M: Modules.Module; n, t: LONGINT; size: SIZE; tag: ADDRESS;
  304. BEGIN
  305. T := TextFrames.Text("");
  306. M := AosModules.root; n := 0; t := 0;
  307. WHILE M # NIL DO
  308. SYSTEM.GET(SYSTEM.VAL(ADDRESS, M.code)- SIZEOF (ADDRESS), tag); (* indirect tag *)
  309. SYSTEM.GET(tag, size);
  310. Texts.WriteString(W, M.name); Texts.WriteInt(W, LONGINT (size), 8);
  311. Texts.WriteInt(W, M.refcnt, 4);
  312. Texts.WriteLn(W); M := M.next;
  313. INC(n); INC(t, LONGINT (size))
  314. END;
  315. IF n > 1 THEN
  316. Texts.WriteLn(W); Texts.WriteInt(W, n, 1); Texts.WriteString(W, " modules use ");
  317. WriteK(W, (t+512) DIV 1024)
  318. END;
  319. M := AosModules.freeRoot;
  320. IF M # NIL THEN
  321. Texts.WriteLn(W); Texts.WriteLn(W);
  322. WHILE M # NIL DO
  323. Texts.WriteString(W, M.name); Texts.WriteLn(W); M := M.next
  324. END
  325. END;
  326. Texts.WriteLn(W); Texts.Append(T, W.buf);
  327. OpenText("Modules|System.Close System.Free Edit.Search Edit.Store", T, TRUE)
  328. END ShowModules;
  329. (* --- Toolbox for library management *)
  330. PROCEDURE ListLibrary (L: Objects.Library);
  331. BEGIN
  332. Texts.WriteString(W, L.name); Texts.WriteLn(W); INC(count)
  333. END ListLibrary;
  334. PROCEDURE ShowLibraries*;
  335. VAR t: Texts.Text;
  336. BEGIN
  337. t := TextFrames.Text(""); count := 0;
  338. Objects.Enumerate(ListLibrary);
  339. IF count > 1 THEN
  340. Texts.WriteLn(W); Texts.WriteInt(W, count, 1); Texts.WriteString(W, " public libraries")
  341. END;
  342. Texts.WriteLn(W); Texts.Append(t, W.buf);
  343. OpenText("Libraries", t, TRUE)
  344. END ShowLibraries;
  345. PROCEDURE FreeLibraries*;
  346. VAR par: Oberon.ParList; T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
  347. BEGIN
  348. par := Oberon.Par;
  349. Texts.WriteString(W, "System.FreeLibraries "); Texts.WriteLn(W);
  350. Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
  351. IF (S.class = Texts.Char) & (S.c = "^") THEN
  352. Oberon.GetSelection(T, beg, end, time);
  353. IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S)
  354. ELSE S.class := Texts.Inval
  355. END
  356. ELSE end := MAX(LONGINT)
  357. END;
  358. WHILE (S.class = Texts.Name) & (Texts.Pos(S) <= end) DO
  359. Objects.FreeLibrary(S.s); Texts.WriteString(W,S.s); Texts.WriteLn(W);
  360. Texts.Scan(S)
  361. END;
  362. Texts.Append(Oberon.Log, W.buf)
  363. END FreeLibraries;
  364. (* --- Toolbox of file system *)
  365. PROCEDURE Directory*;
  366. VAR
  367. beg, end, time, date, size, count, total: LONGINT; enum: AosFS.Enumerator;
  368. par: Oberon.ParList; R: Texts.Reader; T, t: Texts.Text; flags, fileflags: SET;
  369. diroption, ch: CHAR; pat: ARRAY 32 OF CHAR;
  370. name: AosFS.FileName;
  371. PROCEDURE ReadString(VAR s: ARRAY OF CHAR);
  372. VAR i, m: LONGINT;
  373. BEGIN
  374. Texts.Read(R, ch);
  375. WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch <= " ") & (ch # 0DX) DO Texts.Read(R, ch) END;
  376. i := 0; m := LEN(s)-1;
  377. IF ch = 22X THEN
  378. Texts.Read(R, ch);
  379. WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch # 22X) & (ch # 0DX) & (i # m) DO
  380. s[i] := ch; INC(i); Texts.Read(R, ch)
  381. END;
  382. IF ~R.eot & (ch = 22X) THEN Texts.Read(R, ch) END
  383. ELSE
  384. WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch > " ") & (ch # Oberon.OptionChar) & (i # m) DO
  385. s[i] := ch; INC(i); Texts.Read(R, ch)
  386. END
  387. END;
  388. s[i] := 0X
  389. END ReadString;
  390. BEGIN
  391. par := Oberon.Par;
  392. Texts.OpenReader(R, par.text, par.pos); ReadString(pat);
  393. IF (pat[0] = "^") OR (pat[0] = 0X) THEN
  394. Oberon.GetSelection(T, beg, end, time);
  395. IF time # -1 THEN
  396. Texts.OpenReader(R, T, beg); ReadString(pat)
  397. END
  398. END;
  399. IF ch = Oberon.OptionChar THEN Texts.Read(R, diroption) ELSE diroption := 0X END;
  400. IF diroption = "d" THEN flags := {AosFS.EnumSize, AosFS.EnumTime} ELSE flags := {} END;
  401. NEW(enum);
  402. enum.Open(pat, flags);
  403. count := 0; total := 0;
  404. WHILE enum.GetEntry(name, fileflags, time, date, size) DO
  405. INC(count);
  406. Texts.WriteString(W, name);
  407. IF AosFS.EnumTime IN flags THEN
  408. Texts.Write(W, 9X); Texts.WriteDate(W, time, date)
  409. END;
  410. IF AosFS.EnumSize IN flags THEN
  411. Texts.Write(W, 9X); Texts.WriteInt(W, size, 1);
  412. INC(total, size)
  413. END;
  414. Texts.WriteLn(W)
  415. END;
  416. enum.Close;
  417. NEW(t); Texts.Open(t, "");
  418. IF count > 1 THEN
  419. Texts.WriteLn(W); Texts.WriteInt(W, count, 1); Texts.WriteString(W, " files");
  420. IF AosFS.EnumSize IN flags THEN
  421. Texts.WriteString(W, " use "); WriteK(W, (total+1023) DIV 1024)
  422. END
  423. END;
  424. Texts.Append(t, W.buf);
  425. OpenText("Directory", t, TRUE)
  426. END Directory;
  427. PROCEDURE CopyFile(name: ARRAY OF CHAR; VAR S: Texts.Scanner);
  428. CONST BufLen = 8192;
  429. VAR f, g: Files.File; Rf, Rg: Files.Rider; buf : ARRAY BufLen OF CHAR; i: LONGINT;
  430. BEGIN
  431. Texts.Scan(S);
  432. IF (S.class = Texts.Char) & (S.c = "=") THEN
  433. Texts.Scan(S);
  434. IF (S.class = Texts.Char) & (S.c = ">") THEN
  435. Texts.Scan(S);
  436. IF S.class IN {Texts.Name, Texts.String} THEN
  437. Texts.WriteString(W, name); Texts.WriteString(W, " => "); Texts.WriteString(W, S.s);
  438. Texts.WriteString(W, " copying"); Texts.Append(Oberon.Log, W.buf);
  439. f := Files.Old(name);
  440. IF f # NIL THEN g := Files.New(S.s) END;
  441. IF (f # NIL) & (g # NIL) THEN
  442. Files.Set(Rf, f, 0); Files.Set(Rg, g, 0);
  443. i := 0;
  444. WHILE i < Files.Length(f) DIV BufLen DO
  445. Files.ReadBytes(Rf,buf,BufLen); Files.WriteBytes(Rg,buf,BufLen); INC(i)
  446. END;
  447. Files.ReadBytes(Rf, buf, Files.Length(f) MOD BufLen);
  448. Files.WriteBytes(Rg, buf, Files.Length(f) MOD BufLen);
  449. Files.Register(g)
  450. ELSE
  451. Texts.WriteString(W, " failed"); S.eot := TRUE
  452. END;
  453. Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  454. END
  455. END
  456. END
  457. END CopyFile;
  458. PROCEDURE CopyFiles*;
  459. VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner;
  460. BEGIN
  461. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  462. Texts.WriteString(W, "System.CopyFiles"); Texts.WriteLn(W);
  463. Texts.Append(Oberon.Log, W.buf);
  464. IF (S.class = Texts.Char) & (S.c = "^") THEN
  465. Oberon.GetSelection(T, beg, end, time);
  466. IF time # -1 THEN
  467. Texts.OpenScanner(S, T, beg); Texts.Scan(S);
  468. IF S.class IN {Texts.Name, Texts.String} THEN CopyFile(S.s, S) END
  469. END
  470. ELSE
  471. WHILE ~S.eot & (S.class IN {Texts.Name, Texts.String}) DO
  472. CopyFile(S.s, S); IF ~S.eot THEN Texts.Scan(S) END
  473. END
  474. END
  475. END CopyFiles;
  476. PROCEDURE RenameFile (name: ARRAY OF CHAR; VAR S: Texts.Scanner);
  477. VAR res: INTEGER;
  478. BEGIN
  479. Texts.Scan(S);
  480. IF (S.class = Texts.Char) & (S.c = "=") THEN
  481. Texts.Scan(S);
  482. IF (S.class = Texts.Char) & (S.c = ">") THEN
  483. Texts.Scan(S);
  484. IF S.class IN {Texts.Name, Texts.String} THEN
  485. Texts.WriteString(W, name); Texts.WriteString(W, " => "); Texts.WriteString(W, S.s);
  486. Texts.WriteString(W, " renaming"); Texts.Append(Oberon.Log, W.buf);
  487. Files.Rename(name, S.s, res);
  488. IF (res < 0) OR (res > 1) THEN Texts.WriteString(W, " failed"); S.eot := TRUE END;
  489. Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  490. END
  491. END
  492. END
  493. END RenameFile;
  494. PROCEDURE RenameFiles*;
  495. VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner;
  496. BEGIN
  497. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  498. Texts.WriteString(W, "System.RenameFiles"); Texts.WriteLn(W);
  499. Texts.Append(Oberon.Log, W.buf);
  500. IF (S.class = Texts.Char) & (S.c = "^") THEN
  501. Oberon.GetSelection(T, beg, end, time);
  502. IF time # -1 THEN
  503. Texts.OpenScanner(S, T, beg); Texts.Scan(S);
  504. IF S.class IN {Texts.Name, Texts.String} THEN RenameFile(S.s, S) END
  505. END
  506. ELSE
  507. WHILE ~S.eot & (S.class IN {Texts.Name, Texts.String}) DO
  508. RenameFile(S.s, S); IF ~S.eot THEN Texts.Scan(S) END
  509. END
  510. END
  511. END RenameFiles;
  512. PROCEDURE DeleteFile(VAR name: ARRAY OF CHAR; VAR S: Texts.Scanner);
  513. VAR res: INTEGER;
  514. BEGIN
  515. Texts.WriteString(W, name); Texts.WriteString(W, " deleting");
  516. Texts.Append(Oberon.Log, W.buf); Files.Delete(name, res);
  517. IF res # 0 THEN Texts.WriteString(W, " failed"); S.eot := TRUE END;
  518. Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  519. END DeleteFile;
  520. PROCEDURE DeleteFiles*;
  521. VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner;
  522. BEGIN
  523. Oberon.GetSelection(T, beg, end, time);
  524. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  525. Texts.WriteString(W, "System.DeleteFiles"); Texts.WriteLn(W);
  526. Texts.Append(Oberon.Log, W.buf);
  527. IF (S.class = Texts.Char) & (S.c = "^") THEN
  528. IF time # -1 THEN
  529. Texts.OpenScanner(S, T, beg); Texts.Scan(S);
  530. IF S.class IN {Texts.Name, Texts.String} THEN DeleteFile(S.s, S) END
  531. END
  532. ELSE
  533. WHILE ~S.eot & (S.class IN {Texts.Name, Texts.String}) DO
  534. DeleteFile(S.s, S); IF ~S.eot THEN Texts.Scan(S) END
  535. END
  536. END
  537. END DeleteFiles;
  538. (* --- Toolbox for system inspection *)
  539. PROCEDURE Watch*;
  540. VAR free, total, largest, low, high, i: SIZE; list: AosFS.FileSystemTable; fs: AosFS.FileSystem;
  541. BEGIN
  542. Texts.WriteString(W, "System.Watch"); Texts.WriteLn(W);
  543. AosFS.GetList(list);
  544. IF list # NIL THEN
  545. FOR i := 0 TO LEN(list)-1 DO
  546. fs := list[i];
  547. Texts.Write(W, 9X); Texts.WriteString(W, fs.prefix); Texts.WriteString(W, ": ");
  548. IF fs.vol # NIL THEN
  549. free := ENTIER(fs.vol.Available()/1024.0D0 * fs.vol.blockSize);
  550. total := ENTIER(fs.vol.size/1024.0D0 * fs.vol.blockSize);
  551. WriteK(W, LONGINT(free)); Texts.WriteString(W, " of ");
  552. WriteK(W, LONGINT(total)); Texts.WriteString(W, " free")
  553. ELSE
  554. Texts.WriteString(W, fs.desc)
  555. END;
  556. Texts.WriteLn(W)
  557. END
  558. END;
  559. (* heap info *)
  560. Heaps.GetHeapInfo(total, free, largest);
  561. (*total := (total+512) DIV 1024;*)
  562. free := (free+512) DIV 1024;
  563. largest := (largest+512) DIV 1024;
  564. Machine.GetFreeK(total, low, high);
  565. INC(free, low+high);
  566. IF high > largest THEN largest := high END;
  567. IF low > largest THEN largest := low END;
  568. Texts.Write(W, 9X); Texts.WriteString(W, "Heap has ");
  569. WriteK(W, LONGINT(free)); Texts.WriteString(W, " of ");
  570. WriteK(W, LONGINT(total)); Texts.WriteString(W, " free (");
  571. WriteK(W, LONGINT(largest)); Texts.WriteString(W, " contiguous)"); Texts.WriteLn(W);
  572. Texts.Append(Oberon.Log, W.buf)
  573. END Watch;
  574. PROCEDURE GetNum(refs: Bytes; VAR i, num: LONGINT);
  575. VAR n, s: LONGINT; x: CHAR;
  576. BEGIN
  577. s := 0; n := 0; x := refs[i]; INC(i);
  578. WHILE ORD(x) >= 128 DO
  579. INC(n, ASH(ORD(x) - 128, s)); INC(s, 7); x := refs[i]; INC(i)
  580. END;
  581. num := n + ASH(ORD(x) MOD 64 - ORD(x) DIV 64 * 64, s)
  582. END GetNum;
  583. (*
  584. Reference = {OldRef | ProcRef} .
  585. OldRef = 0F8X offset/n name/s {Variable} .
  586. ProcRef = 0F9X offset/n nofPars/n RetType procLev/1 slFlag/1 name/s {Variable} .
  587. RetType = 0X | Var | ArrayType | Record .
  588. ArrayType = 12X | 14X | 15X . (* static array, dynamic array, open array *)
  589. Record = 16X .
  590. Variable = VarMode (Var | ArrayVar | RecordVar ) offset/n name/s .
  591. VarMode = 1X | 3X . (* direct, indirect *)
  592. Var = 1X .. 0FX . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc, string *)
  593. ArrayVar = (81X .. 8EX) dim/n . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc *)
  594. RecordVar = (16X | 1DX) tdadr/n . (* record, recordpointer *)
  595. *)
  596. (* FindProc - Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  597. PROCEDURE FindProc(refs: Bytes; ofs: LONGINT): LONGINT;
  598. VAR i, m, t, proc: LONGINT; ch: CHAR;
  599. BEGIN
  600. proc := -1; i := 0; m := LEN(refs^);
  601. ch := refs[i]; INC(i);
  602. WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
  603. GetNum(refs, i, t); (* pofs *)
  604. IF t > ofs THEN (* previous procedure was the one *)
  605. ch := 0X (* stop search *)
  606. ELSE (* ~found *)
  607. IF ch = 0F9X THEN
  608. GetNum(refs, i, t); (* nofPars *)
  609. INC(i, 3) (* RetType, procLev, slFlag *)
  610. END;
  611. proc := i; (* remember this position, just before the name *)
  612. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* pname *)
  613. IF i < m THEN
  614. ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
  615. WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  616. ch := refs[i]; INC(i); (* type *)
  617. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  618. GetNum(refs, i, t) (* dim/tdadr *)
  619. END;
  620. GetNum(refs, i, t); (* vofs *)
  621. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
  622. IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
  623. END
  624. END
  625. END
  626. END;
  627. IF (proc = -1) & (i # 0) THEN proc := i END; (* first procedure *)
  628. RETURN proc
  629. END FindProc;
  630. PROCEDURE WriteProc(mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Bytes; VAR refpos, base: LONGINT);
  631. VAR ch: CHAR;
  632. BEGIN
  633. refpos := -1;
  634. IF mod = NIL THEN
  635. Texts.WriteString(W, "Unknown EIP ="); Texts.WriteHex(W, LONGINT(pc)); Texts.Write(W, "H");
  636. IF fp # -1 THEN
  637. Texts.WriteString(W, " EBP ="); Texts.WriteHex(W, LONGINT(fp)); Texts.Write(W, "H")
  638. END
  639. ELSE
  640. Texts.WriteString(W, mod.name);
  641. DEC(pc, LONGINT(ADDRESSOF(mod.code[0])));
  642. refs := SYSTEM.VAL(Bytes, mod.refs);
  643. IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
  644. refpos := FindProc(refs, LONGINT(pc));
  645. IF refpos # -1 THEN
  646. Texts.Write(W, ".");
  647. ch := refs[refpos]; INC(refpos);
  648. IF ch = "$" THEN base := LONGINT(mod.sb) ELSE base := LONGINT(fp) END; (* for variables *)
  649. WHILE ch # 0X DO Texts.Write(W, ch); ch := refs[refpos]; INC(refpos) END
  650. END
  651. END;
  652. Texts.WriteString(W, " PC = "); Texts.WriteInt(W, LONGINT(pc), 1)
  653. END
  654. END WriteProc;
  655. PROCEDURE Variables(refs: Bytes; i, base: LONGINT);
  656. VAR
  657. mode, ch: CHAR; m, adr, type, n, lval, size, tmp1, tmp2, tdadr: LONGINT; etc: BOOLEAN;
  658. sval: SHORTINT; ival: INTEGER; tmp: Bytes; set: SET;
  659. rval: REAL; lrval: LONGREAL;
  660. BEGIN
  661. m := LEN(refs^); mode := refs[i]; INC(i);
  662. WHILE (i < m) & (mode >= 1X) & (mode <= 3X) DO (* var *)
  663. type := ORD(refs[i]); INC(i); etc := FALSE;
  664. IF type > 80H THEN
  665. IF type = 83H THEN type := 15 ELSE DEC(type, 80H) END;
  666. GetNum(refs, i, n)
  667. ELSIF (type = 16H) OR (type = 1DH) THEN
  668. GetNum(refs, i, tdadr); n := 1
  669. ELSE
  670. IF type = 15 THEN n := MaxString (* best guess *) ELSE n := 1 END
  671. END;
  672. GetNum(refs, i, adr);
  673. Texts.Write(W, 9X); ch := refs[i]; INC(i);
  674. WHILE ch # 0X DO Texts.Write(W, ch); ch := refs[i]; INC(i) END;
  675. Texts.WriteString(W, " = ");
  676. INC(adr, base);
  677. IF n = 0 THEN (* open array *)
  678. SYSTEM.GET(adr+4, n) (* real LEN from stack *)
  679. END;
  680. IF type = 15 THEN
  681. IF n > MaxString THEN etc := TRUE; n := MaxString END
  682. ELSE
  683. IF n > MaxArray THEN etc := TRUE; n := MaxArray END
  684. END;
  685. IF mode # 1X THEN SYSTEM.GET(adr, adr) END; (* indirect *)
  686. IF (adr >= -4) & (adr < 4096) THEN
  687. Texts.WriteString(W, "NIL reference ("); Texts.WriteHex(W, adr); Texts.WriteString(W, "H )")
  688. ELSE
  689. IF type = 15 THEN
  690. Texts.Write(W, 22X);
  691. LOOP
  692. IF n = 0 THEN EXIT END;
  693. SYSTEM.GET(adr, ch); INC(adr);
  694. IF (ch < " ") OR (ch > "~") THEN EXIT END;
  695. Texts.Write(W, ch); DEC(n)
  696. END;
  697. Texts.Write(W, 22X); etc := (ch # 0X)
  698. ELSE
  699. CASE type OF
  700. 1..4: size := 1
  701. |5: size := 2
  702. |6..7,9,13,14,29: size := 4
  703. |8, 16: size := 8
  704. |22: size := 0; ASSERT(n <= 1)
  705. ELSE
  706. Texts.WriteString(W, "bad type "); Texts.WriteInt(W, type, 1); n := 0
  707. END;
  708. WHILE n > 0 DO
  709. CASE type OF
  710. 1,3: (* BYTE, CHAR *)
  711. SYSTEM.GET(adr, ch);
  712. IF (ch > " ") & (ch <= "~") THEN Texts.Write(W, ch)
  713. ELSE Texts.WriteHex(W, ORD(ch)); Texts.Write(W, "X")
  714. END
  715. |2: (* BOOLEAN *)
  716. SYSTEM.GET(adr, ch);
  717. IF ch = 0X THEN Texts.WriteString(W, "FALSE")
  718. ELSIF ch = 1X THEN Texts.WriteString(W, "TRUE")
  719. ELSE Texts.WriteInt(W, ORD(ch), 1)
  720. END
  721. |4: (* SHORTINT *)
  722. SYSTEM.GET(adr, sval); Texts.WriteInt(W, sval, 1)
  723. |5: (* INTEGER *)
  724. SYSTEM.GET(adr, ival); Texts.WriteInt(W, ival, 1)
  725. |6: (* LONGINT *)
  726. SYSTEM.GET(adr, lval); Texts.WriteInt(W, lval, 1)
  727. |7: (* REAL *)
  728. SYSTEM.GET(adr, rval); Texts.WriteReal(W, rval, 15)
  729. |8: (* LONGREAL *)
  730. SYSTEM.GET(adr, lrval); Texts.WriteLongReal(W, lrval, 24)
  731. |9: (* SET *)
  732. SYSTEM.GET(adr, set); Texts.WriteSet(W, set)
  733. |13, 29: (* POINTER *)
  734. SYSTEM.GET(adr, lval); Texts.WriteHex(W, lval); Texts.Write(W, "H")
  735. |14: (* PROC *)
  736. SYSTEM.GET(adr, lval);
  737. IF lval = 0 THEN Texts.WriteString(W, "NIL")
  738. ELSE WriteProc(AosModules.ThisModuleByAdr(lval), lval, -1, tmp, tmp1, tmp2)
  739. END
  740. |16: (* HUGEINT *)
  741. Texts.WriteHex(W, SYSTEM.GET32(adr+4));
  742. Texts.WriteHex(W, SYSTEM.GET32(adr))
  743. |22: (* RECORD *)
  744. Texts.WriteHex(W, tdadr); Texts.Write(W, "H")
  745. END;
  746. DEC(n); INC(adr, size);
  747. IF n > 0 THEN Texts.WriteString(W, ", ") END
  748. END
  749. END
  750. END;
  751. IF etc THEN Texts.WriteString(W, " ...") END;
  752. Texts.WriteLn(W);
  753. IF i < m THEN mode := refs[i]; INC(i) END
  754. END
  755. END Variables;
  756. PROCEDURE OutState (VAR name: ARRAY OF CHAR; t: Texts.Text);
  757. VAR mod: Modules.Module; refpos, i: LONGINT; refs: Bytes; ch: CHAR;
  758. BEGIN
  759. i := 0; WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
  760. name[i] := 0X;
  761. Texts.WriteString(W, name); mod := AosModules.root;
  762. WHILE (mod # NIL) & (mod.name # name) DO mod := mod.next END;
  763. IF mod # NIL THEN
  764. Texts.WriteString(W, " SB ="); Texts.WriteHex(W, LONGINT(mod.sb)); Texts.Write(W, "H"); Texts.WriteLn(W);
  765. refs := SYSTEM.VAL(Bytes, mod.refs);
  766. IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
  767. refpos := FindProc(refs, 0); (* assume module body is at PC = 0 (not true for OMI) *)
  768. IF refpos # -1 THEN
  769. REPEAT ch := refs[refpos]; INC(refpos) UNTIL ch = 0X;
  770. Variables(refs, refpos, LONGINT(mod.sb))
  771. END
  772. END
  773. ELSE
  774. Texts.WriteString(W, " not loaded"); Texts.WriteLn(W)
  775. END;
  776. Texts.Append(t, W.buf)
  777. END OutState;
  778. PROCEDURE State*;
  779. VAR T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
  780. BEGIN
  781. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  782. IF (S.class = Texts.Char) & (S.c = "^") THEN
  783. Oberon.GetSelection(T, beg, end, time);
  784. IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END
  785. END;
  786. IF S.class = Texts.Name THEN
  787. T := TextFrames.Text(""); OutState(S.s, T);
  788. OpenText("State", T, TRUE)
  789. END
  790. END State;
  791. PROCEDURE ShowCommands*;
  792. VAR M: Modules.Module; beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner; i: INTEGER;
  793. BEGIN
  794. Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  795. IF (S.class = Texts.Char) & (S.c = "^") THEN
  796. Oberon.GetSelection(T, beg, end, time);
  797. IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END
  798. END;
  799. IF S.class = Texts.Name THEN
  800. i := 0; WHILE (S.s[i] # 0X) & (S.s[i] # ".") DO INC(i) END; S.s[i] := 0X;
  801. M := Modules.ThisMod(S.s);
  802. IF M # NIL THEN
  803. T := TextFrames.Text("");
  804. i := 0;
  805. WHILE i < LEN(M.command) DO
  806. IF M.command[i].entryAdr # Heaps.NilVal THEN (* only show Oberon commands *)
  807. Texts.WriteString(W, S.s); Texts.Write(W, ".");
  808. Texts.WriteString(W, M.command[i].name);
  809. Texts.WriteLn(W)
  810. END;
  811. INC(i)
  812. END;
  813. Texts.Append(T, W.buf);
  814. OpenText("Commands", T, TRUE)
  815. ELSE
  816. Texts.WriteString(W, Modules.resMsg); Texts.WriteLn(W);
  817. Texts.Append(Oberon.Log, W.buf)
  818. END
  819. END
  820. END ShowCommands;
  821. PROCEDURE ShowTasks*;
  822. VAR T: Texts.Text; n: Oberon.Task; ofs: ADDRESS; t: LONGINT; m: Modules.Module;
  823. BEGIN
  824. n := Oberon.NextTask; t := Input.Time();
  825. REPEAT
  826. ofs := SYSTEM.VAL(ADDRESS, n.handle); m := AosModules.ThisModuleByAdr(ofs);
  827. Texts.WriteString(W, m.name); Texts.WriteString(W, " PC = ");
  828. Texts.WriteInt(W, LONGINT(ofs-ADDRESSOF(m.code[0])), 1);
  829. IF n.safe THEN Texts.WriteString(W, " safe ")
  830. ELSE Texts.WriteString(W, " unsafe ")
  831. END;
  832. Texts.WriteInt(W, n.time, 1);
  833. IF n.time - t <= 0 THEN
  834. Texts.WriteString(W, " ready")
  835. ELSE
  836. Texts.WriteString(W, " waiting "); Texts.WriteInt(W, (n.time-t)*1000 DIV Input.TimeUnit, 1);
  837. Texts.WriteString(W, "ms")
  838. END;
  839. Texts.WriteLn(W);
  840. n := n.next
  841. UNTIL n = Oberon.NextTask;
  842. T := TextFrames.Text("");
  843. Texts.Append(T, W.buf);
  844. OpenText("Tasks", T, TRUE)
  845. END ShowTasks;
  846. (*
  847. PROCEDURE WriteTrap(VAR W: Texts.Writer; error, page: LONGINT);
  848. BEGIN
  849. Texts.WriteString(W, "TRAP "); Texts.WriteInt(W, error, 1);
  850. Texts.WriteString(W, " ");
  851. IF error > 0 THEN
  852. CASE error OF
  853. 1: Texts.WriteString(W, "WITH guard failed")
  854. |2: Texts.WriteString(W, "CASE invalid")
  855. |3: Texts.WriteString(W, "RETURN missing")
  856. |5: Texts.WriteString(W, "Implicit type guard failed")
  857. |6: Texts.WriteString(W, "Type guard failed")
  858. |7: Texts.WriteString(W, "Index out of range")
  859. |8: Texts.WriteString(W, "ASSERT failed")
  860. |9: Texts.WriteString(W, "Array dimension error")
  861. |13: Texts.WriteString(W, "Keyboard interrupt")
  862. |14: Texts.WriteString(W, "Out of memory")
  863. |15: Texts.WriteString(W, "Bad sector number")
  864. |16: Texts.WriteString(W, "Disk full")
  865. |17: Texts.WriteString(W, "Disk error")
  866. |18: Texts.WriteString(W, "File too large")
  867. |19: Texts.WriteString(W, "Buffer overflow")
  868. (* for NCFS/OFS *)
  869. |20: Texts.WriteString(W, "Volume full")
  870. |21: Texts.WriteString(W, "Volume write-protected")
  871. |22: Texts.WriteString(W, "Volume not found")
  872. |23: Texts.WriteString(W, "Illegal Access")
  873. |24: Texts.WriteString(W, "Volume in use")
  874. |25: Texts.WriteString(W, "Volume modified")
  875. |26: Texts.WriteString(W, "Not a valid volume")
  876. |27: Texts.WriteString(W, "Cannot contact server ")
  877. ELSE
  878. IF error = MAX(INTEGER) THEN Texts.WriteString(W, "Trace "); Texts.WriteInt(W, trap, 1); INC(trap)
  879. ELSE Texts.WriteString(W, "HALT statement")
  880. END
  881. END
  882. ELSE
  883. error := -error;
  884. IF (error >= 32) & (error <= 39) THEN Texts.WriteString(W, "Floating-point ") END;
  885. CASE error OF
  886. 0,32: Texts.WriteString(W, "Division by zero")
  887. |4,33: Texts.WriteString(W, "Overflow")
  888. |6: Texts.WriteString(W, "Invalid instruction")
  889. |12: Texts.WriteString(W, "Stack overflow")
  890. |13: Texts.WriteString(W, "General protection fault")
  891. |14: (* page fault *)
  892. IF (page >= -4) & (page < 4096) THEN Texts.WriteString(W, "NIL reference (")
  893. (*ELSIF (page >= 100000H) & (page < Kernel.StackOrg) THEN Texts.WriteString(W, "Stack overflow (")*)
  894. ELSE Texts.WriteString(W, "Page fault (")
  895. END;
  896. Texts.WriteHex(W, page); Texts.WriteString(W, "H )")
  897. |34: Texts.WriteString(W, "operation invalid")
  898. |35: Texts.WriteString(W, "stack fault")
  899. ELSE Texts.WriteString(W, "CPU exception")
  900. END
  901. END
  902. END WriteTrap;
  903. PROCEDURE Trap*(error, fp, pc, page: LONGINT); (** non-portable *) (* exported for Debug debugger *)
  904. VAR
  905. T: Texts.Text; refpos: LONGINT;
  906. mod: Modules.Module; lastfp, base: LONGINT; refs: Bytes;
  907. BEGIN
  908. IF trapped = 0 THEN
  909. trapped := 1;
  910. Display.ResetClip;
  911. IF Kernel.copro THEN Reals.SetFCR(Reals.DefaultFCR) ELSE resetfp() END;
  912. IF error # MAX(INTEGER) THEN Viewers.Close(NIL) END; (* close offending viewer, if any *)
  913. T := TextFrames.Text("");
  914. mod := AosModules.ThisModuleByAdr(pc);
  915. WriteTrap(W, error, page); Texts.WriteLn(W);
  916. LOOP
  917. WriteProc(mod, pc, fp, refs, refpos, base); Texts.WriteLn(W);
  918. IF refpos # -1 THEN Variables(refs, refpos, base) END;
  919. lastfp := fp;
  920. SYSTEM.GET(fp+4, pc); SYSTEM.GET(fp, fp); (* return addr from stack *)
  921. (*IF (fp < lastfp) OR (fp >= Kernel.StackOrg) THEN EXIT END; (* not called from stack *)*)
  922. IF fp = 0 THEN EXIT END;
  923. mod := AosModules.ThisModuleByAdr(pc)
  924. END;
  925. Texts.Append(T, W.buf);
  926. OpenText("Trap", T, TRUE)
  927. ELSIF trapped = 1 THEN
  928. trapped := 2;
  929. T := TextFrames.Text(""); Texts.WriteLn(W);
  930. Texts.WriteString(W, "TRAP "); Texts.WriteInt(W, error, 3); Texts.WriteString(W, " (recursive)");
  931. Texts.WriteLn(W); Texts.Append(T, W.buf);
  932. OpenText("Trap", T, TRUE)
  933. ELSIF trapped = 2 THEN
  934. trapped := 3;
  935. Texts.WriteLn(W); Texts.WriteString(W, "TRAP "); Texts.WriteInt(W, error, 3);
  936. Texts.WriteString(W, " (recursive)"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  937. ELSE (* skip *)
  938. END;
  939. trapped := 0
  940. END Trap;
  941. *)
  942. (* Returns TRUE iff Oberon is running in "stand-alone" mode. *)
  943. PROCEDURE Standalone(): BOOLEAN;
  944. BEGIN
  945. RETURN AosModules.ModuleByName(WMWindowManager) = NIL
  946. END Standalone;
  947. PROCEDURE FreeOberon;
  948. VAR context : Commands.Context; arg : Streams.StringReader; res: LONGINT; msg: ARRAY 128 OF CHAR;
  949. BEGIN
  950. Oberon.OpenTrack(0, Display.Width); (* inhibit display updates *)
  951. COPY(OberonBaseModule, msg);
  952. NEW(arg, LEN(msg)); arg.SetRaw(msg, 0, LEN(msg));
  953. NEW(context, NIL, arg, NIL, NIL, NIL);
  954. Commands.Activate("SystemTools.FreeDownTo", context, {}, res, msg);
  955. Kernel.UnlockOberon;
  956. AosActive.Terminate (* kill Oberon process in an unclean way (race with above! workaround in SystemTools.Mod) *)
  957. END FreeOberon;
  958. PROCEDURE Quit*;
  959. BEGIN
  960. IF Standalone() THEN
  961. AosModules.Shutdown(AosModules.PowerDown)
  962. ELSE
  963. FreeOberon
  964. END
  965. END Quit;
  966. PROCEDURE Reboot*; (** non-portable *)
  967. BEGIN
  968. IF Standalone() THEN
  969. AosModules.Shutdown(AosModules.Reboot)
  970. ELSE
  971. FreeOberon
  972. END
  973. END Reboot;
  974. PROCEDURE LogHandler(me: Oberon.Task);
  975. VAR i: LONGINT; t: Texts.Text; ch: CHAR; s: ARRAY 512 OF CHAR;
  976. BEGIN
  977. t := log;
  978. REPEAT
  979. KernelLog.GetBuffer(s);
  980. i := 0;
  981. LOOP
  982. ch := s[i];
  983. IF ch = 0X THEN EXIT END;
  984. IF (ch < 20X) & (ORD(ch) IN {01H, 02H, 03H, 0DH, 0AH, 0EH, 0FH}) THEN
  985. IF ch = 01X THEN (* start trap *)
  986. IF t = log THEN (* flush buffer to kernel log text *)
  987. Texts.Append(t, LogW.buf);
  988. t := TextFrames.Text("");
  989. OpenText("Trap", t, TRUE)
  990. END
  991. ELSIF ch = 02X THEN (* stop trap *)
  992. IF t # log THEN (* flush buffer to trap text *)
  993. Texts.Append(t, LogW.buf); t := log
  994. END
  995. ELSIF ch = 03X THEN
  996. Texts.WriteString(LogW, " **overflow**"); Texts.WriteLn(LogW)
  997. ELSIF ch = 0DX THEN Texts.WriteLn(LogW)
  998. ELSIF ch = 0EX THEN Texts.SetFont(LogW, fixed)
  999. ELSIF ch = 0FX THEN Texts.SetFont(LogW, Fonts.Default)
  1000. ELSE (* skip *)
  1001. END
  1002. ELSE
  1003. Texts.Write(LogW, ch)
  1004. END;
  1005. INC(i)
  1006. END
  1007. UNTIL i = 0;
  1008. IF LogW.buf.len # 0 THEN (* flush buffer to kernel log or trap text *)
  1009. Texts.Append(t, LogW.buf)
  1010. END;
  1011. me.time := Input.Time() + LogTime
  1012. END LogHandler;
  1013. PROCEDURE OpenKernelLog*; (** non-portable *)
  1014. BEGIN
  1015. IF log = NIL THEN NEW(log); Texts.Open(log, "") END;
  1016. IF task = NIL THEN
  1017. Texts.WriteString(W, "Execute System.StartLog to enable logging"); Texts.WriteLn(W);
  1018. Texts.Append(log, W.buf)
  1019. END;
  1020. OpenText("Kernel.Log|System.Close System.Copy Edit.Search System.Clear", log, TRUE)
  1021. END OpenKernelLog;
  1022. PROCEDURE Init*; (** non-portable, for internal use *)
  1023. VAR S: Texts.Scanner; Wt: Texts.Writer; T: Texts.Text; F: TextFrames.Frame; ok: BOOLEAN;
  1024. BEGIN
  1025. IF ~Machine.AtomicTestSet(init) THEN (* avoid user call and ignore restart due to exception *)
  1026. Texts.OpenWriter(Wt);
  1027. Oberon.OpenScanner(S, "System.InitCommands");
  1028. IF S.class = Texts.Inval THEN
  1029. OpenLog;
  1030. OpenText("System.Tool", TextFrames.Text("System.Tool"), TRUE);
  1031. StartLog
  1032. ELSE
  1033. WHILE ~S.eot & (S.class = Texts.Char) & (S.c = "{") DO
  1034. ok := FALSE; Texts.Scan(S);
  1035. IF S.class = Texts.Name THEN
  1036. ok := TRUE; Texts.WriteString(Wt, S.s)
  1037. END;
  1038. IF ~((S.class = Texts.Char) & (S.c = "}")) THEN
  1039. WHILE ~S.eot & (S.nextCh # "}") DO
  1040. IF ok THEN Texts.Write(Wt, S.nextCh) END;
  1041. Texts.Read(S, S.nextCh)
  1042. END
  1043. END;
  1044. IF ok THEN
  1045. Texts.WriteLn(Wt); T := TextFrames.Text(""); Texts.Append(T, Wt.buf);
  1046. F := TextFrames.NewText(T, 0); TextFrames.Call(F, 0, FALSE)
  1047. END;
  1048. Texts.Scan(S); Texts.Scan(S)
  1049. END
  1050. END;
  1051. NEW(oberonRunner);
  1052. ELSE
  1053. KernelLog.Enter; KernelLog.String("Only one instance of Oberon can be started"); KernelLog.Exit
  1054. END;
  1055. END Init;
  1056. PROCEDURE Greetings;
  1057. BEGIN
  1058. Oberon.GetClock(time0, date0); Texts.WriteString(W, "System.Time");
  1059. Texts.WriteDate(W, time0, date0); Texts.WriteLn(W);
  1060. Texts.WriteString(W, "ETH Oberon / ");
  1061. Texts.WriteString(W, Kernel.version); Texts.WriteLn(W);
  1062. Texts.Append(Oberon.Log, W.buf)
  1063. END Greetings;
  1064. PROCEDURE WriteType(VAR W: Texts.Writer; adr: LONGINT);
  1065. VAR m: AosModules.Module; t: AosModules.TypeDesc;
  1066. BEGIN
  1067. AosModules.ThisTypeByAdr(adr, m, t);
  1068. IF m # NIL THEN
  1069. Texts.WriteString(W, m.name); Texts.Write(W, ".");
  1070. IF t.name = "" THEN Texts.WriteString(W, "TYPE") ELSE Texts.WriteString(W, t.name) END
  1071. ELSE
  1072. Texts.WriteString(W, "NIL")
  1073. END
  1074. END WriteType;
  1075. (** Display the approximate state of all threads in the system. *)
  1076. PROCEDURE ShowActive*; (** non-portable *)
  1077. VAR
  1078. processes : ARRAY ProcessInfo.MaxNofProcesses OF AosActive.Process; nofProcesses : LONGINT;
  1079. t: AosActive.Process; i, mode, adr: LONGINT; T: Texts.Text;
  1080. pc, tmp1, tmp2: LONGINT; refs: Bytes;
  1081. BEGIN
  1082. ProcessInfo.GetProcesses(processes, nofProcesses);
  1083. ProcessInfo.Sort(processes, nofProcesses, ProcessInfo.SortByID);
  1084. (* display the threads *)
  1085. Texts.SetFont(W, fixed);
  1086. FOR i := 0 TO nofProcesses - 1 DO
  1087. t := processes[i];
  1088. Texts.WriteInt(W, t.id, 4); Texts.Write(W, " ");
  1089. mode := t.mode;
  1090. CASE mode OF
  1091. AosActive.Ready: Texts.WriteString(W, "rdy")
  1092. |AosActive.Running: Texts.WriteString(W, "run")
  1093. |AosActive.AwaitingLock: Texts.WriteString(W, "awl")
  1094. |AosActive.AwaitingCond: Texts.WriteString(W, "awc")
  1095. |AosActive.AwaitingEvent: Texts.WriteString(W, "awe")
  1096. |AosActive.Terminated: Texts.WriteString(W, "rip")
  1097. ELSE Texts.WriteInt(W, mode, 3)
  1098. END;
  1099. Texts.WriteInt(W, t.procID, 2); Texts.WriteInt(W, t.priority, 2);
  1100. (*Texts.WriteHex(W, SYSTEM.VAL(LONGINT, t)); Texts.Write(W, "H");*)
  1101. adr := SYSTEM.VAL(LONGINT, t.obj);
  1102. IF adr # 0 THEN
  1103. Texts.WriteHex(W, adr); Texts.Write(W, "H");
  1104. SYSTEM.GET(adr-4, adr); Texts.Write(W, ":"); WriteType(W, adr)
  1105. ELSE
  1106. Texts.WriteString(W, " SYSTEM")
  1107. END;
  1108. (*Texts.WriteHex(W, t.state.EIP); Texts.Write(W, "H");*)
  1109. IF mode = AosActive.AwaitingLock THEN
  1110. adr := SYSTEM.VAL(LONGINT, t.waitingOn);
  1111. Texts.WriteHex(W, adr); Texts.Write(W, "H");
  1112. IF adr # 0 THEN
  1113. SYSTEM.GET(adr-4, adr); Texts.Write(W, ":"); WriteType(W, adr)
  1114. END
  1115. ELSIF mode = AosActive.AwaitingCond THEN
  1116. Texts.Write(W, " ");
  1117. pc := SYSTEM.VAL(LONGINT, t.condition);
  1118. WriteProc(AosModules.ThisModuleByAdr(pc), pc, t.condFP, refs, tmp1, tmp2);
  1119. (*Texts.WriteHex(W, SYSTEM.VAL(LONGINT, t.condition)); Texts.Write(W, "H");*)
  1120. (*Texts.WriteHex(W, t.condFP); Texts.Write(W, "H")*)
  1121. END;
  1122. IF AosActive.Restart IN t.flags THEN Texts.WriteString(W, " rst") END;
  1123. IF AosActive.PleaseHalt IN t.flags THEN Texts.WriteString(W, " hlt") END;
  1124. IF AosActive.Unbreakable IN t.flags THEN Texts.WriteString(W, " unb"); END;
  1125. IF AosActive.SelfTermination IN t.flags THEN Texts.WriteString(W, " slf"); END;
  1126. IF AosActive.Preempted IN t.flags THEN Texts.WriteString(W, " pre"); END;
  1127. IF AosActive.Resistant IN t.flags THEN Texts.WriteString(W, " res") END;
  1128. Texts.WriteLn(W)
  1129. END;
  1130. Texts.SetFont(W, Fonts.Default);
  1131. T := TextFrames.Text(""); Texts.Append(T, W.buf);
  1132. OpenText("Active Objects", T, FALSE)
  1133. END ShowActive;
  1134. (* Halt or Terminate the selected thread. *)
  1135. PROCEDURE StopProcess(halt: BOOLEAN);
  1136. VAR
  1137. s: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT;
  1138. n : AosActive.Process;
  1139. BEGIN
  1140. Oberon.GetSelection(text, beg, end, time);
  1141. IF time # -1 THEN
  1142. Texts.OpenScanner(s, text, beg); Texts.Scan(s);
  1143. IF s.class = Texts.Int THEN
  1144. REPEAT
  1145. n := ProcessInfo.GetProcess(s.i);
  1146. IF n # NIL THEN
  1147. AosActive.TerminateThis(n, halt);
  1148. beg := s.line;
  1149. REPEAT Texts.Scan(s) UNTIL (s.class = Texts.Inval) OR ((s.class = Texts.Int) & (s.line # beg)) OR (Texts.Pos(s) > end);
  1150. IF Texts.Pos(s) > end THEN s.class := Texts.Inval END
  1151. ELSE
  1152. Texts.WriteString(W, "Object "); Texts.WriteInt(W, s.i, 1);
  1153. Texts.WriteString(W, " not found"); Texts.WriteLn(W);
  1154. Texts.Append(Oberon.Log, W.buf);
  1155. s.class := Texts.Inval
  1156. END
  1157. UNTIL s.class # Texts.Int
  1158. END
  1159. END
  1160. END StopProcess;
  1161. (** Halt selected thread. *)
  1162. PROCEDURE HaltObject*; (** non-portable *)
  1163. BEGIN
  1164. StopProcess(TRUE)
  1165. END HaltObject;
  1166. (** Terminate selected thread. *)
  1167. PROCEDURE TerminateObject*; (** non-portable *)
  1168. BEGIN
  1169. StopProcess(FALSE)
  1170. END TerminateObject;
  1171. (** Attempt to terminate all non-immune threads. *)
  1172. PROCEDURE TerminateObjects*; (** non-portable *)
  1173. VAR processes : ARRAY ProcessInfo.MaxNofProcesses OF AosActive.Process; nofProcesses, i : LONGINT;
  1174. BEGIN
  1175. ProcessInfo.GetProcesses(processes, nofProcesses);
  1176. FOR i := 0 TO nofProcesses - 1 DO
  1177. AosActive.TerminateThis(processes[i], FALSE)
  1178. END;
  1179. END TerminateObjects;
  1180. (** Start monitoring the KernelLog log for trap viewers and OpenKernelLog. *)
  1181. PROCEDURE StartLog*; (** non-portable *)
  1182. VAR cmd: PROCEDURE;
  1183. BEGIN
  1184. IF task = NIL THEN
  1185. IF AosModules.ModuleByName (LogWindow) # NIL THEN
  1186. GETPROCEDURE (LogWindow, "Close", cmd);
  1187. IF cmd # NIL THEN cmd END;
  1188. END;
  1189. IF buf = NIL THEN NEW(buf, BufSize) END; (* never reallocate existing buffer *)
  1190. IF log = NIL THEN NEW(log); Texts.Open(log, "") END;
  1191. IF KernelLog.OpenBuffer(ADDRESSOF(buf[0]), LEN(buf)) THEN
  1192. NEW(task); task.safe := TRUE; task.handle := LogHandler;
  1193. task.time := Input.Time(); Oberon.Install(task)
  1194. ELSE
  1195. buf := NIL;
  1196. Texts.WriteString(W, "Log already open elsewhere"); Texts.WriteLn(W);
  1197. Texts.Append(Oberon.Log, W.buf)
  1198. END
  1199. ELSE
  1200. Texts.WriteString(W, "Log already open"); Texts.WriteLn(W);
  1201. Texts.Append(Oberon.Log, W.buf)
  1202. END
  1203. END StartLog;
  1204. (** Stop monitoring the KernelLog log. Allows other loggers to work (e.g. LogWindow.Open) *)
  1205. PROCEDURE StopLog*; (** non-portable *)
  1206. BEGIN
  1207. IF task # NIL THEN
  1208. KernelLog.CloseBuffer;
  1209. Oberon.Remove(task); task := NIL;
  1210. END
  1211. END StopLog;
  1212. (*
  1213. (** Load the window manager and jump into it. *)
  1214. PROCEDURE LoadWM;
  1215. VAR res: LONGINT; s: ARRAY 128 OF CHAR;
  1216. BEGIN
  1217. IF Standalone() THEN
  1218. Oberon.OpenTrack(0, Display.Width); (* inhibit display updates *)
  1219. OberonInput.Remove; (* remove default Oberon input device *)
  1220. s := "";
  1221. AosFS.AppendStr("WindowManager.Install;OberonDisplay.Install Oberon ", s);
  1222. AosFS.AppendInt(Display.Width, s);
  1223. AosFS.AppendStr("x", s);
  1224. AosFS.AppendInt(Display.Height, s);
  1225. Commands.Call(s, {Commands.Wait}, res, s);
  1226. IF res = 0 THEN
  1227. Display.SetMode(0BEH, {}); (* re-initialize display *)
  1228. Input.Init(0BEH) (* re-init input *)
  1229. ELSE
  1230. Texts.WriteString(W, s); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
  1231. END;
  1232. Viewers.CloseTrack(0)
  1233. END
  1234. END LoadWM;
  1235. *)
  1236. BEGIN
  1237. init := FALSE;
  1238. Texts.OpenWriter(W);
  1239. Oberon.Log := TextFrames.Text("");
  1240. Texts.OpenWriter(LogW); fixed := Fonts.This("Courier10.Scn.Fnt");
  1241. Greetings;
  1242. task := NIL;
  1243. Modules.InstallTermHandler(StopLog)
  1244. END System.