123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332 |
- (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
- MODULE System IN Oberon; (** portable, except where noted *) (* pjm *)
- (**
- * Based on System.Mod by jg, nw, ard, nm, jm, ejz et al.
- * Aos Native Oberon
- *
- * History:
- *
- * 16.03.2007 Activate SystemTools.FreeDownTo instead of AosTools.FreeDownTo in procedure FreeOberon (staubesv)
- *)
- IMPORT SYSTEM, Kernel, AosFS := Files IN A2, Files, Modules, Objects, Display, Input, Fonts, Viewers, Texts, Oberon, TextFrames,
- KernelLog IN A2, Streams IN A2, Machine IN A2, Heaps IN A2, AosModules := Modules IN A2, AosActive := Objects IN A2,
- ProcessInfo IN A2, Commands IN A2;
- CONST
- OberonBaseModule = "Oberon-Kernel";
- WMWindowManager = "WMWindowManager";
- LogWindow = "LogWindow"; (* must have a Close command *)
- MaxString = 64;
- MaxArray = 10;
- LogTime = Input.TimeUnit DIV 2;
- BufSize = 8192;
- TYPE
- Bytes = AosModules.Bytes;
- OberonRunner = OBJECT
- VAR exception : BOOLEAN;
- BEGIN {ACTIVE, SAFE, PRIORITY(AosActive.Normal)}
- IF ~exception THEN
- exception := TRUE;
- KernelLog.Enter; KernelLog.String("Oberon started"); KernelLog.Exit;
- Oberon.Loop;
- ELSE
- KernelLog.Enter; KernelLog.String("Oberon restarted due to an exception"); KernelLog.Exit;
- Oberon.Loop;
- END;
- KernelLog.Enter; KernelLog.String("Oberon stopped"); KernelLog.Exit;
- END OberonRunner;
- VAR
- W, LogW: Texts.Writer;
- init: BOOLEAN;
- count: LONGINT;
- task: Oberon.Task;
- fixed: Fonts.Font;
- buf: POINTER TO ARRAY OF CHAR;
- log: Texts.Text;
- oberonRunner : OberonRunner;
- time0, date0: LONGINT;
- PROCEDURE OpenText(title: ARRAY OF CHAR; T: Texts.Text; system: BOOLEAN);
- VAR W: INTEGER;
- BEGIN
- IF system THEN W := Display.Width DIV 8*3 ELSE W := 400 END;
- Oberon.OpenText(title, T, W, 240)
- END OpenText;
- (* --- Toolbox for system control *)
- PROCEDURE SetFont*;
- VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner; f: Fonts.Font;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN
- Texts.OpenScanner(S, T, beg); Texts.Scan(S);
- IF S.class = Texts.Name THEN
- f := Fonts.This(S.s);
- IF f # NIL THEN Oberon.SetFont(f) END
- END
- END
- ELSIF S.class = Texts.Name THEN
- f := Fonts.This(S.s);
- IF f # NIL THEN Oberon.SetFont(f) END
- END
- END SetFont;
- PROCEDURE SetColor*;
- VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner; ch: CHAR;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN
- Texts.OpenReader(S, T, beg); Texts.Read(S, ch); Oberon.SetColor(S.col)
- END
- ELSIF S.class = Texts.Int THEN Oberon.SetColor(SHORT(SHORT(S.i)))
- END
- END SetColor;
- PROCEDURE SetOffset*;
- VAR beg, end, time: LONGINT; T: Texts.Text;S: Texts.Scanner; ch: CHAR;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN
- Texts.OpenReader(S, T, beg); Texts.Read(S, ch); Oberon.SetOffset(S.voff)
- END
- ELSIF S.class = Texts.Int THEN Oberon.SetOffset(SHORT(SHORT(S.i)))
- END
- END SetOffset;
- PROCEDURE Time*;
- VAR par: Oberon.ParList; S: Texts.Scanner; t, d, hr, min, sec, yr, mo, day: LONGINT;
- PROCEDURE WritePair(ch: CHAR; x: LONGINT);
- BEGIN Texts.Write(W, ch);
- Texts.Write(W, CHR(x DIV 10 + 30H)); Texts.Write(W, CHR(x MOD 10 + 30H))
- END WritePair;
- BEGIN
- par := Oberon.Par;
- Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
- IF S.class = Texts.Int THEN (*set date*)
- day := S.i; Texts.Scan(S); mo := S.i; Texts.Scan(S); yr := S.i; Texts.Scan(S);
- hr := S.i; Texts.Scan(S); min := S.i; Texts.Scan(S); sec := S.i;
- IF yr > 1900 THEN DEC(yr, 1900) END; (* compatible with old two-digit format *)
- t := (hr*64 + min)*64 + sec; d := (yr*16 + mo)*32 + day;
- Oberon.SetClock(t, d)
- ELSE (*read date*)
- Texts.WriteString(W, "System.Time");
- Oberon.GetClock(t, d); Texts.WriteDate(W, t, d);
- IF (S.class = Texts.Name) & (S.s = "start") THEN
- Texts.WriteString(W, ", started");
- time0 := t; date0 := d
- ELSIF (S.class = Texts.Name) & (S.s = "lap") THEN
- hr := t DIV 4096 MOD 32; min := t DIV 64 MOD 64; sec := t MOD 64;
- DEC(sec, time0 MOD 64);
- IF sec < 0 THEN INC(sec, 60); DEC(min) END;
- DEC(min, time0 DIV 64 MOD 64);
- IF min < 0 THEN INC(min, 60); DEC(hr) END;
- DEC(hr, time0 DIV 4096 MOD 32);
- IF hr < 0 THEN INC(hr, 24) END; (* assume one day passed *)
- Texts.WriteString(W, ", "); WritePair(" ", hr);
- WritePair(":", min); WritePair(":", sec);
- Texts.WriteString(W, " elapsed");
- IF d # date0 THEN
- Texts.WriteString(W, " (may be incorrect due to date change)")
- END
- END;
- Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf)
- END
- END Time;
- (* Perform an immediate garbage collection. *)
- PROCEDURE Collect*;
- BEGIN
- Heaps.GC; (* force garbage collection *)
- Kernel.GC (* call Oberon finalizers *)
- END Collect;
- (* --- Toolbox for standard display *)
- PROCEDURE Open*;
- VAR par: Oberon.ParList; T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
- BEGIN
- par := Oberon.Par;
- Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") OR (S.line # 0) THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END
- END;
- IF S.class IN {Texts.Name, Texts.String} THEN
- OpenText(S.s, TextFrames.Text(S.s), TRUE)
- END
- END Open;
- PROCEDURE OpenLog*;
- BEGIN
- OpenText("System.Log", Oberon.Log, TRUE);
- END OpenLog;
- PROCEDURE Clear*;
- VAR S: Texts.Scanner; par: Oberon.ParList; F: Display.Frame; L: Objects.LinkMsg; A: Objects.AttrMsg;
- BEGIN
- par := Oberon.Par; F := NIL;
- L.id := Objects.get; L.name := "Model"; L.obj := NIL;
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "*") THEN
- F := Oberon.MarkedFrame()
- ELSIF (par.vwr # NIL) & (par.vwr.dsc # NIL) THEN
- F := par.vwr.dsc.next;
- F.handle(F, L);
- IF (L.obj # NIL) & (L.obj IS Display.Frame) THEN
- A.id := Objects.get; A.name := "Gen"; L.obj.handle(L.obj, A);
- IF A.s = "PanelDocs.NewDoc" THEN (* Desktop *)
- F := Oberon.Par.obj(Display.Frame);
- F := F.dlink(Display.Frame);
- F := F.next.dsc
- ELSE
- F := L.obj(Display.Frame)
- END
- END
- END;
- IF F # NIL THEN
- F.handle(F, L);
- IF (L.obj # NIL) & (L.obj IS Texts.Text) THEN
- Texts.Delete(L.obj(Texts.Text), 0, L.obj(Texts.Text).len)
- END
- END
- END Clear;
- PROCEDURE Close*;
- VAR par: Oberon.ParList; V: Viewers.Viewer;
- BEGIN
- par := Oberon.Par;
- IF par.frame = par.vwr.dsc THEN V := par.vwr
- ELSE V := Oberon.MarkedViewer()
- END;
- Viewers.Close(V)
- END Close;
- PROCEDURE CloseTrack*;
- VAR V: Viewers.Viewer;
- BEGIN
- V := Oberon.MarkedViewer(); Viewers.CloseTrack(V.X)
- END CloseTrack;
- PROCEDURE Recall*;
- VAR V: Viewers.Viewer; M: Display.ControlMsg;
- BEGIN
- Viewers.Recall(V);
- IF (V # NIL) & (V.state = 0) THEN
- Viewers.Open(V, V.X, V.Y + V.H); M.F := NIL; M.id := Display.restore; V.handle(V, M)
- END
- END Recall;
- PROCEDURE Copy*;
- VAR V, V1: Viewers.Viewer; M: Objects.CopyMsg; N: Display.ControlMsg;
- BEGIN
- M.id := Objects.shallow;
- V := Oberon.Par.vwr; V.handle(V, M); V1 := M.obj(Viewers.Viewer);
- Viewers.Open(V1, V.X, V.Y + V.H DIV 2);
- N.F := NIL; N.id := Display.restore; V1.handle(V1, N)
- END Copy;
- PROCEDURE Grow*;
- VAR par: Oberon.ParList; V, V1: Viewers.Viewer; M: Objects.CopyMsg; N: Display.ControlMsg; DW, DH: INTEGER;
- BEGIN
- par := Oberon.Par;
- IF par.frame = par.vwr.dsc THEN V := par.vwr
- ELSE V := Oberon.MarkedViewer()
- END;
- DW := Oberon.DisplayWidth(V.X); DH := Oberon.DisplayHeight(V.X);
- IF V.H < DH - Viewers.minH THEN Oberon.OpenTrack(V.X, V.W)
- ELSIF V.W < DW THEN Oberon.OpenTrack(Oberon.UserTrack(V.X), DW)
- END;
- IF (V.H < DH - Viewers.minH) OR (V.W < DW) THEN
- M.id := Objects.shallow;
- V.handle(V, M); V1 := M.obj(Viewers.Viewer);
- Viewers.Open(V1, V.X, DH);
- N.F := NIL; N.id := Display.restore; V1.handle(V1, N)
- END
- END Grow;
- (* --- Toolbox for module management *)
- PROCEDURE Free*;
- VAR par: Oberon.ParList; S: Texts.Scanner; F: TextFrames.Frame; time, beg, end, pos: LONGINT; T: Texts.Text;
- PROCEDURE FreeFile;
- (*VAR i: LONGINT;*)
- BEGIN
- (*IF S.nextCh # "*" THEN Modules.Free(S.s, FALSE)
- ELSE Modules.Free(S.s, TRUE); Texts.Scan(S)
- END*)
- (*i := 0; WHILE (S.s[i] # 0X) & (S.s[i] # ".") DO INC(i) END;
- S.s[i] := 0X;*)
- Modules.Free(S.s, FALSE);
- IF Modules.res = 0 THEN
- Texts.WriteString(W, S.s); Texts.WriteString(W, " unloaded")
- ELSE
- Texts.WriteString(W, Modules.resMsg)
- END;
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END FreeFile;
- BEGIN
- par := Oberon.Par;
- Oberon.GetSelection(T, beg, end, time);
- Texts.WriteString(W, "System.Free"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
- IF (par.vwr.dsc = NIL) OR (par.vwr.dsc # par.frame) OR ~(par.vwr.dsc.next IS TextFrames.Frame) THEN
- Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") OR (S.class = Texts.Inval) THEN
- IF time # -1 THEN
- Texts.OpenScanner(S, T, beg); pos := Texts.Pos(S)-1; Texts.Scan(S);
- WHILE ~S.eot & (S.class = Texts.Name) & (pos < end) DO
- FreeFile; pos := Texts.Pos(S); Texts.Scan(S);
- WHILE ~S.eot & (S.class = Texts.Int) DO pos := Texts.Pos(S); Texts.Scan(S) END
- END
- END
- ELSE
- WHILE S.class = Texts.Name DO FreeFile; Texts.Scan(S) END
- END
- ELSE
- F := par.vwr.dsc.next(TextFrames.Frame);
- IF F.sel > 0 THEN
- Texts.OpenScanner(S, F.text, F.selbeg.pos);
- WHILE ~S.eot & (Texts.Pos(S) < F.selend.pos) DO
- Texts.Scan(S);
- IF S.class = Texts.Name THEN FreeFile;
- IF Modules.res = 0 THEN
- Texts.OpenReader(S, F.text, F.selbeg.pos);
- REPEAT Texts.Read(S, S.nextCh) UNTIL S.eot OR (S.nextCh = 0DX);
- Texts.Delete(F.text, F.selbeg.pos, Texts.Pos(S));
- DEC(F.selend.pos, Texts.Pos(S) - F.selbeg.pos);
- Texts.OpenScanner(S, F.text, F.selbeg.pos);
- END
- ELSE F.selbeg.pos := Texts.Pos(S)
- END
- END
- END
- END
- END Free;
- PROCEDURE WriteK(VAR W: Texts.Writer; k: LONGINT);
- VAR suffix: CHAR;
- BEGIN
- IF k < 100*1024 THEN suffix := "K"
- ELSIF k < 100*1024*1024 THEN suffix := "M"; k := k DIV 1024
- ELSE suffix := "G"; k := k DIV (1024*1024)
- END;
- Texts.WriteInt(W, k, 1); Texts.Write(W, suffix); Texts.Write(W, "B")
- END WriteK;
- PROCEDURE ShowModules*;
- VAR T: Texts.Text; M: Modules.Module; n, t: LONGINT; size: SIZE; tag: ADDRESS;
- BEGIN
- T := TextFrames.Text("");
- M := AosModules.root; n := 0; t := 0;
- WHILE M # NIL DO
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, M.code)- SIZEOF (ADDRESS), tag); (* indirect tag *)
- SYSTEM.GET(tag, size);
- Texts.WriteString(W, M.name); Texts.WriteInt(W, LONGINT (size), 8);
- Texts.WriteInt(W, M.refcnt, 4);
- Texts.WriteLn(W); M := M.next;
- INC(n); INC(t, LONGINT (size))
- END;
- IF n > 1 THEN
- Texts.WriteLn(W); Texts.WriteInt(W, n, 1); Texts.WriteString(W, " modules use ");
- WriteK(W, (t+512) DIV 1024)
- END;
- M := AosModules.freeRoot;
- IF M # NIL THEN
- Texts.WriteLn(W); Texts.WriteLn(W);
- WHILE M # NIL DO
- Texts.WriteString(W, M.name); Texts.WriteLn(W); M := M.next
- END
- END;
- Texts.WriteLn(W); Texts.Append(T, W.buf);
- OpenText("Modules|System.Close System.Free Edit.Search Edit.Store", T, TRUE)
- END ShowModules;
- (* --- Toolbox for library management *)
- PROCEDURE ListLibrary (L: Objects.Library);
- BEGIN
- Texts.WriteString(W, L.name); Texts.WriteLn(W); INC(count)
- END ListLibrary;
- PROCEDURE ShowLibraries*;
- VAR t: Texts.Text;
- BEGIN
- t := TextFrames.Text(""); count := 0;
- Objects.Enumerate(ListLibrary);
- IF count > 1 THEN
- Texts.WriteLn(W); Texts.WriteInt(W, count, 1); Texts.WriteString(W, " public libraries")
- END;
- Texts.WriteLn(W); Texts.Append(t, W.buf);
- OpenText("Libraries", t, TRUE)
- END ShowLibraries;
- PROCEDURE FreeLibraries*;
- VAR par: Oberon.ParList; T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
- BEGIN
- par := Oberon.Par;
- Texts.WriteString(W, "System.FreeLibraries "); Texts.WriteLn(W);
- Texts.OpenScanner(S, par.text, par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S)
- ELSE S.class := Texts.Inval
- END
- ELSE end := MAX(LONGINT)
- END;
- WHILE (S.class = Texts.Name) & (Texts.Pos(S) <= end) DO
- Objects.FreeLibrary(S.s); Texts.WriteString(W,S.s); Texts.WriteLn(W);
- Texts.Scan(S)
- END;
- Texts.Append(Oberon.Log, W.buf)
- END FreeLibraries;
- (* --- Toolbox of file system *)
- PROCEDURE Directory*;
- VAR
- beg, end, time, date, size, count, total: LONGINT; enum: AosFS.Enumerator;
- par: Oberon.ParList; R: Texts.Reader; T, t: Texts.Text; flags, fileflags: SET;
- diroption, ch: CHAR; pat: ARRAY 32 OF CHAR;
- name: AosFS.FileName;
- PROCEDURE ReadString(VAR s: ARRAY OF CHAR);
- VAR i, m: LONGINT;
- BEGIN
- Texts.Read(R, ch);
- WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch <= " ") & (ch # 0DX) DO Texts.Read(R, ch) END;
- i := 0; m := LEN(s)-1;
- IF ch = 22X THEN
- Texts.Read(R, ch);
- WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch # 22X) & (ch # 0DX) & (i # m) DO
- s[i] := ch; INC(i); Texts.Read(R, ch)
- END;
- IF ~R.eot & (ch = 22X) THEN Texts.Read(R, ch) END
- ELSE
- WHILE ~R.eot & (R.lib IS Fonts.Font) & (ch > " ") & (ch # Oberon.OptionChar) & (i # m) DO
- s[i] := ch; INC(i); Texts.Read(R, ch)
- END
- END;
- s[i] := 0X
- END ReadString;
- BEGIN
- par := Oberon.Par;
- Texts.OpenReader(R, par.text, par.pos); ReadString(pat);
- IF (pat[0] = "^") OR (pat[0] = 0X) THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN
- Texts.OpenReader(R, T, beg); ReadString(pat)
- END
- END;
- IF ch = Oberon.OptionChar THEN Texts.Read(R, diroption) ELSE diroption := 0X END;
- IF diroption = "d" THEN flags := {AosFS.EnumSize, AosFS.EnumTime} ELSE flags := {} END;
- NEW(enum);
- enum.Open(pat, flags);
- count := 0; total := 0;
- WHILE enum.GetEntry(name, fileflags, time, date, size) DO
- INC(count);
- Texts.WriteString(W, name);
- IF AosFS.EnumTime IN flags THEN
- Texts.Write(W, 9X); Texts.WriteDate(W, time, date)
- END;
- IF AosFS.EnumSize IN flags THEN
- Texts.Write(W, 9X); Texts.WriteInt(W, size, 1);
- INC(total, size)
- END;
- Texts.WriteLn(W)
- END;
- enum.Close;
- NEW(t); Texts.Open(t, "");
- IF count > 1 THEN
- Texts.WriteLn(W); Texts.WriteInt(W, count, 1); Texts.WriteString(W, " files");
- IF AosFS.EnumSize IN flags THEN
- Texts.WriteString(W, " use "); WriteK(W, (total+1023) DIV 1024)
- END
- END;
- Texts.Append(t, W.buf);
- OpenText("Directory", t, TRUE)
- END Directory;
- PROCEDURE CopyFile(name: ARRAY OF CHAR; VAR S: Texts.Scanner);
- CONST BufLen = 8192;
- VAR f, g: Files.File; Rf, Rg: Files.Rider; buf : ARRAY BufLen OF CHAR; i: LONGINT;
- BEGIN
- Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "=") THEN
- Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = ">") THEN
- Texts.Scan(S);
- IF S.class IN {Texts.Name, Texts.String} THEN
- Texts.WriteString(W, name); Texts.WriteString(W, " => "); Texts.WriteString(W, S.s);
- Texts.WriteString(W, " copying"); Texts.Append(Oberon.Log, W.buf);
- f := Files.Old(name);
- IF f # NIL THEN g := Files.New(S.s) END;
- IF (f # NIL) & (g # NIL) THEN
- Files.Set(Rf, f, 0); Files.Set(Rg, g, 0);
- i := 0;
- WHILE i < Files.Length(f) DIV BufLen DO
- Files.ReadBytes(Rf,buf,BufLen); Files.WriteBytes(Rg,buf,BufLen); INC(i)
- END;
- Files.ReadBytes(Rf, buf, Files.Length(f) MOD BufLen);
- Files.WriteBytes(Rg, buf, Files.Length(f) MOD BufLen);
- Files.Register(g)
- ELSE
- Texts.WriteString(W, " failed"); S.eot := TRUE
- END;
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END
- END
- END
- END CopyFile;
- PROCEDURE CopyFiles*;
- VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- Texts.WriteString(W, "System.CopyFiles"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN
- Texts.OpenScanner(S, T, beg); Texts.Scan(S);
- IF S.class IN {Texts.Name, Texts.String} THEN CopyFile(S.s, S) END
- END
- ELSE
- WHILE ~S.eot & (S.class IN {Texts.Name, Texts.String}) DO
- CopyFile(S.s, S); IF ~S.eot THEN Texts.Scan(S) END
- END
- END
- END CopyFiles;
- PROCEDURE RenameFile (name: ARRAY OF CHAR; VAR S: Texts.Scanner);
- VAR res: INTEGER;
- BEGIN
- Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "=") THEN
- Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = ">") THEN
- Texts.Scan(S);
- IF S.class IN {Texts.Name, Texts.String} THEN
- Texts.WriteString(W, name); Texts.WriteString(W, " => "); Texts.WriteString(W, S.s);
- Texts.WriteString(W, " renaming"); Texts.Append(Oberon.Log, W.buf);
- Files.Rename(name, S.s, res);
- IF (res < 0) OR (res > 1) THEN Texts.WriteString(W, " failed"); S.eot := TRUE END;
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END
- END
- END
- END RenameFile;
- PROCEDURE RenameFiles*;
- VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- Texts.WriteString(W, "System.RenameFiles"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN
- Texts.OpenScanner(S, T, beg); Texts.Scan(S);
- IF S.class IN {Texts.Name, Texts.String} THEN RenameFile(S.s, S) END
- END
- ELSE
- WHILE ~S.eot & (S.class IN {Texts.Name, Texts.String}) DO
- RenameFile(S.s, S); IF ~S.eot THEN Texts.Scan(S) END
- END
- END
- END RenameFiles;
- PROCEDURE DeleteFile(VAR name: ARRAY OF CHAR; VAR S: Texts.Scanner);
- VAR res: INTEGER;
- BEGIN
- Texts.WriteString(W, name); Texts.WriteString(W, " deleting");
- Texts.Append(Oberon.Log, W.buf); Files.Delete(name, res);
- IF res # 0 THEN Texts.WriteString(W, " failed"); S.eot := TRUE END;
- Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END DeleteFile;
- PROCEDURE DeleteFiles*;
- VAR beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner;
- BEGIN
- Oberon.GetSelection(T, beg, end, time);
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- Texts.WriteString(W, "System.DeleteFiles"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- IF time # -1 THEN
- Texts.OpenScanner(S, T, beg); Texts.Scan(S);
- IF S.class IN {Texts.Name, Texts.String} THEN DeleteFile(S.s, S) END
- END
- ELSE
- WHILE ~S.eot & (S.class IN {Texts.Name, Texts.String}) DO
- DeleteFile(S.s, S); IF ~S.eot THEN Texts.Scan(S) END
- END
- END
- END DeleteFiles;
- (* --- Toolbox for system inspection *)
- PROCEDURE Watch*;
- VAR free, total, largest, low, high, i: SIZE; list: AosFS.FileSystemTable; fs: AosFS.FileSystem;
- BEGIN
- Texts.WriteString(W, "System.Watch"); Texts.WriteLn(W);
- AosFS.GetList(list);
- IF list # NIL THEN
- FOR i := 0 TO LEN(list)-1 DO
- fs := list[i];
- Texts.Write(W, 9X); Texts.WriteString(W, fs.prefix); Texts.WriteString(W, ": ");
- IF fs.vol # NIL THEN
- free := ENTIER(fs.vol.Available()/1024.0D0 * fs.vol.blockSize);
- total := ENTIER(fs.vol.size/1024.0D0 * fs.vol.blockSize);
- WriteK(W, LONGINT(free)); Texts.WriteString(W, " of ");
- WriteK(W, LONGINT(total)); Texts.WriteString(W, " free")
- ELSE
- Texts.WriteString(W, fs.desc)
- END;
- Texts.WriteLn(W)
- END
- END;
- (* heap info *)
- Heaps.GetHeapInfo(total, free, largest);
- (*total := (total+512) DIV 1024;*)
- free := (free+512) DIV 1024;
- largest := (largest+512) DIV 1024;
- Machine.GetFreeK(total, low, high);
- INC(free, low+high);
- IF high > largest THEN largest := high END;
- IF low > largest THEN largest := low END;
- Texts.Write(W, 9X); Texts.WriteString(W, "Heap has ");
- WriteK(W, LONGINT(free)); Texts.WriteString(W, " of ");
- WriteK(W, LONGINT(total)); Texts.WriteString(W, " free (");
- WriteK(W, LONGINT(largest)); Texts.WriteString(W, " contiguous)"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf)
- END Watch;
- PROCEDURE GetNum(refs: Bytes; VAR i, num: LONGINT);
- VAR n, s: LONGINT; x: CHAR;
- BEGIN
- s := 0; n := 0; x := refs[i]; INC(i);
- WHILE ORD(x) >= 128 DO
- INC(n, ASH(ORD(x) - 128, s)); INC(s, 7); x := refs[i]; INC(i)
- END;
- num := n + ASH(ORD(x) MOD 64 - ORD(x) DIV 64 * 64, s)
- END GetNum;
- (*
- Reference = {OldRef | ProcRef} .
- OldRef = 0F8X offset/n name/s {Variable} .
- ProcRef = 0F9X offset/n nofPars/n RetType procLev/1 slFlag/1 name/s {Variable} .
- RetType = 0X | Var | ArrayType | Record .
- ArrayType = 12X | 14X | 15X . (* static array, dynamic array, open array *)
- Record = 16X .
- Variable = VarMode (Var | ArrayVar | RecordVar ) offset/n name/s .
- VarMode = 1X | 3X . (* direct, indirect *)
- Var = 1X .. 0FX . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc, string *)
- ArrayVar = (81X .. 8EX) dim/n . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc *)
- RecordVar = (16X | 1DX) tdadr/n . (* record, recordpointer *)
- *)
- (* FindProc - Find a procedure in the reference block. Return index of name, or -1 if not found. *)
- PROCEDURE FindProc(refs: Bytes; ofs: LONGINT): LONGINT;
- VAR i, m, t, proc: LONGINT; ch: CHAR;
- BEGIN
- proc := -1; i := 0; m := LEN(refs^);
- ch := refs[i]; INC(i);
- WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
- GetNum(refs, i, t); (* pofs *)
- IF t > ofs THEN (* previous procedure was the one *)
- ch := 0X (* stop search *)
- ELSE (* ~found *)
- IF ch = 0F9X THEN
- GetNum(refs, i, t); (* nofPars *)
- INC(i, 3) (* RetType, procLev, slFlag *)
- END;
- proc := i; (* remember this position, just before the name *)
- REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* pname *)
- IF i < m THEN
- ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
- WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
- ch := refs[i]; INC(i); (* type *)
- IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
- GetNum(refs, i, t) (* dim/tdadr *)
- END;
- GetNum(refs, i, t); (* vofs *)
- REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
- IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
- END
- END
- END
- END;
- IF (proc = -1) & (i # 0) THEN proc := i END; (* first procedure *)
- RETURN proc
- END FindProc;
- PROCEDURE WriteProc(mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Bytes; VAR refpos, base: LONGINT);
- VAR ch: CHAR;
- BEGIN
- refpos := -1;
- IF mod = NIL THEN
- Texts.WriteString(W, "Unknown EIP ="); Texts.WriteHex(W, LONGINT(pc)); Texts.Write(W, "H");
- IF fp # -1 THEN
- Texts.WriteString(W, " EBP ="); Texts.WriteHex(W, LONGINT(fp)); Texts.Write(W, "H")
- END
- ELSE
- Texts.WriteString(W, mod.name);
- DEC(pc, LONGINT(ADDRESSOF(mod.code[0])));
- refs := SYSTEM.VAL(Bytes, mod.refs);
- IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
- refpos := FindProc(refs, LONGINT(pc));
- IF refpos # -1 THEN
- Texts.Write(W, ".");
- ch := refs[refpos]; INC(refpos);
- IF ch = "$" THEN base := LONGINT(mod.sb) ELSE base := LONGINT(fp) END; (* for variables *)
- WHILE ch # 0X DO Texts.Write(W, ch); ch := refs[refpos]; INC(refpos) END
- END
- END;
- Texts.WriteString(W, " PC = "); Texts.WriteInt(W, LONGINT(pc), 1)
- END
- END WriteProc;
- PROCEDURE Variables(refs: Bytes; i, base: LONGINT);
- VAR
- mode, ch: CHAR; m, adr, type, n, lval, size, tmp1, tmp2, tdadr: LONGINT; etc: BOOLEAN;
- sval: SHORTINT; ival: INTEGER; tmp: Bytes; set: SET;
- rval: REAL; lrval: LONGREAL;
- BEGIN
- m := LEN(refs^); mode := refs[i]; INC(i);
- WHILE (i < m) & (mode >= 1X) & (mode <= 3X) DO (* var *)
- type := ORD(refs[i]); INC(i); etc := FALSE;
- IF type > 80H THEN
- IF type = 83H THEN type := 15 ELSE DEC(type, 80H) END;
- GetNum(refs, i, n)
- ELSIF (type = 16H) OR (type = 1DH) THEN
- GetNum(refs, i, tdadr); n := 1
- ELSE
- IF type = 15 THEN n := MaxString (* best guess *) ELSE n := 1 END
- END;
- GetNum(refs, i, adr);
- Texts.Write(W, 9X); ch := refs[i]; INC(i);
- WHILE ch # 0X DO Texts.Write(W, ch); ch := refs[i]; INC(i) END;
- Texts.WriteString(W, " = ");
- INC(adr, base);
- IF n = 0 THEN (* open array *)
- SYSTEM.GET(adr+4, n) (* real LEN from stack *)
- END;
- IF type = 15 THEN
- IF n > MaxString THEN etc := TRUE; n := MaxString END
- ELSE
- IF n > MaxArray THEN etc := TRUE; n := MaxArray END
- END;
- IF mode # 1X THEN SYSTEM.GET(adr, adr) END; (* indirect *)
- IF (adr >= -4) & (adr < 4096) THEN
- Texts.WriteString(W, "NIL reference ("); Texts.WriteHex(W, adr); Texts.WriteString(W, "H )")
- ELSE
- IF type = 15 THEN
- Texts.Write(W, 22X);
- LOOP
- IF n = 0 THEN EXIT END;
- SYSTEM.GET(adr, ch); INC(adr);
- IF (ch < " ") OR (ch > "~") THEN EXIT END;
- Texts.Write(W, ch); DEC(n)
- END;
- Texts.Write(W, 22X); etc := (ch # 0X)
- ELSE
- CASE type OF
- 1..4: size := 1
- |5: size := 2
- |6..7,9,13,14,29: size := 4
- |8, 16: size := 8
- |22: size := 0; ASSERT(n <= 1)
- ELSE
- Texts.WriteString(W, "bad type "); Texts.WriteInt(W, type, 1); n := 0
- END;
- WHILE n > 0 DO
- CASE type OF
- 1,3: (* BYTE, CHAR *)
- SYSTEM.GET(adr, ch);
- IF (ch > " ") & (ch <= "~") THEN Texts.Write(W, ch)
- ELSE Texts.WriteHex(W, ORD(ch)); Texts.Write(W, "X")
- END
- |2: (* BOOLEAN *)
- SYSTEM.GET(adr, ch);
- IF ch = 0X THEN Texts.WriteString(W, "FALSE")
- ELSIF ch = 1X THEN Texts.WriteString(W, "TRUE")
- ELSE Texts.WriteInt(W, ORD(ch), 1)
- END
- |4: (* SHORTINT *)
- SYSTEM.GET(adr, sval); Texts.WriteInt(W, sval, 1)
- |5: (* INTEGER *)
- SYSTEM.GET(adr, ival); Texts.WriteInt(W, ival, 1)
- |6: (* LONGINT *)
- SYSTEM.GET(adr, lval); Texts.WriteInt(W, lval, 1)
- |7: (* REAL *)
- SYSTEM.GET(adr, rval); Texts.WriteReal(W, rval, 15)
- |8: (* LONGREAL *)
- SYSTEM.GET(adr, lrval); Texts.WriteLongReal(W, lrval, 24)
- |9: (* SET *)
- SYSTEM.GET(adr, set); Texts.WriteSet(W, set)
- |13, 29: (* POINTER *)
- SYSTEM.GET(adr, lval); Texts.WriteHex(W, lval); Texts.Write(W, "H")
- |14: (* PROC *)
- SYSTEM.GET(adr, lval);
- IF lval = 0 THEN Texts.WriteString(W, "NIL")
- ELSE WriteProc(AosModules.ThisModuleByAdr(lval), lval, -1, tmp, tmp1, tmp2)
- END
- |16: (* HUGEINT *)
- Texts.WriteHex(W, SYSTEM.GET32(adr+4));
- Texts.WriteHex(W, SYSTEM.GET32(adr))
- |22: (* RECORD *)
- Texts.WriteHex(W, tdadr); Texts.Write(W, "H")
- END;
- DEC(n); INC(adr, size);
- IF n > 0 THEN Texts.WriteString(W, ", ") END
- END
- END
- END;
- IF etc THEN Texts.WriteString(W, " ...") END;
- Texts.WriteLn(W);
- IF i < m THEN mode := refs[i]; INC(i) END
- END
- END Variables;
- PROCEDURE OutState (VAR name: ARRAY OF CHAR; t: Texts.Text);
- VAR mod: Modules.Module; refpos, i: LONGINT; refs: Bytes; ch: CHAR;
- BEGIN
- i := 0; WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END;
- name[i] := 0X;
- Texts.WriteString(W, name); mod := AosModules.root;
- WHILE (mod # NIL) & (mod.name # name) DO mod := mod.next END;
- IF mod # NIL THEN
- Texts.WriteString(W, " SB ="); Texts.WriteHex(W, LONGINT(mod.sb)); Texts.Write(W, "H"); Texts.WriteLn(W);
- refs := SYSTEM.VAL(Bytes, mod.refs);
- IF (refs # NIL) & (LEN(mod.refs) # 0) THEN
- refpos := FindProc(refs, 0); (* assume module body is at PC = 0 (not true for OMI) *)
- IF refpos # -1 THEN
- REPEAT ch := refs[refpos]; INC(refpos) UNTIL ch = 0X;
- Variables(refs, refpos, LONGINT(mod.sb))
- END
- END
- ELSE
- Texts.WriteString(W, " not loaded"); Texts.WriteLn(W)
- END;
- Texts.Append(t, W.buf)
- END OutState;
- PROCEDURE State*;
- VAR T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END
- END;
- IF S.class = Texts.Name THEN
- T := TextFrames.Text(""); OutState(S.s, T);
- OpenText("State", T, TRUE)
- END
- END State;
- PROCEDURE ShowCommands*;
- VAR M: Modules.Module; beg, end, time: LONGINT; T: Texts.Text; S: Texts.Scanner; i: INTEGER;
- BEGIN
- Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
- IF (S.class = Texts.Char) & (S.c = "^") THEN
- Oberon.GetSelection(T, beg, end, time);
- IF time # -1 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END
- END;
- IF S.class = Texts.Name THEN
- i := 0; WHILE (S.s[i] # 0X) & (S.s[i] # ".") DO INC(i) END; S.s[i] := 0X;
- M := Modules.ThisMod(S.s);
- IF M # NIL THEN
- T := TextFrames.Text("");
- i := 0;
- WHILE i < LEN(M.command) DO
- IF M.command[i].entryAdr # Heaps.NilVal THEN (* only show Oberon commands *)
- Texts.WriteString(W, S.s); Texts.Write(W, ".");
- Texts.WriteString(W, M.command[i].name);
- Texts.WriteLn(W)
- END;
- INC(i)
- END;
- Texts.Append(T, W.buf);
- OpenText("Commands", T, TRUE)
- ELSE
- Texts.WriteString(W, Modules.resMsg); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf)
- END
- END
- END ShowCommands;
- PROCEDURE ShowTasks*;
- VAR T: Texts.Text; n: Oberon.Task; ofs: ADDRESS; t: LONGINT; m: Modules.Module;
- BEGIN
- n := Oberon.NextTask; t := Input.Time();
- REPEAT
- ofs := SYSTEM.VAL(ADDRESS, n.handle); m := AosModules.ThisModuleByAdr(ofs);
- Texts.WriteString(W, m.name); Texts.WriteString(W, " PC = ");
- Texts.WriteInt(W, LONGINT(ofs-ADDRESSOF(m.code[0])), 1);
- IF n.safe THEN Texts.WriteString(W, " safe ")
- ELSE Texts.WriteString(W, " unsafe ")
- END;
- Texts.WriteInt(W, n.time, 1);
- IF n.time - t <= 0 THEN
- Texts.WriteString(W, " ready")
- ELSE
- Texts.WriteString(W, " waiting "); Texts.WriteInt(W, (n.time-t)*1000 DIV Input.TimeUnit, 1);
- Texts.WriteString(W, "ms")
- END;
- Texts.WriteLn(W);
- n := n.next
- UNTIL n = Oberon.NextTask;
- T := TextFrames.Text("");
- Texts.Append(T, W.buf);
- OpenText("Tasks", T, TRUE)
- END ShowTasks;
- (*
- PROCEDURE WriteTrap(VAR W: Texts.Writer; error, page: LONGINT);
- BEGIN
- Texts.WriteString(W, "TRAP "); Texts.WriteInt(W, error, 1);
- Texts.WriteString(W, " ");
- IF error > 0 THEN
- CASE error OF
- 1: Texts.WriteString(W, "WITH guard failed")
- |2: Texts.WriteString(W, "CASE invalid")
- |3: Texts.WriteString(W, "RETURN missing")
- |5: Texts.WriteString(W, "Implicit type guard failed")
- |6: Texts.WriteString(W, "Type guard failed")
- |7: Texts.WriteString(W, "Index out of range")
- |8: Texts.WriteString(W, "ASSERT failed")
- |9: Texts.WriteString(W, "Array dimension error")
- |13: Texts.WriteString(W, "Keyboard interrupt")
- |14: Texts.WriteString(W, "Out of memory")
- |15: Texts.WriteString(W, "Bad sector number")
- |16: Texts.WriteString(W, "Disk full")
- |17: Texts.WriteString(W, "Disk error")
- |18: Texts.WriteString(W, "File too large")
- |19: Texts.WriteString(W, "Buffer overflow")
- (* for NCFS/OFS *)
- |20: Texts.WriteString(W, "Volume full")
- |21: Texts.WriteString(W, "Volume write-protected")
- |22: Texts.WriteString(W, "Volume not found")
- |23: Texts.WriteString(W, "Illegal Access")
- |24: Texts.WriteString(W, "Volume in use")
- |25: Texts.WriteString(W, "Volume modified")
- |26: Texts.WriteString(W, "Not a valid volume")
- |27: Texts.WriteString(W, "Cannot contact server ")
- ELSE
- IF error = MAX(INTEGER) THEN Texts.WriteString(W, "Trace "); Texts.WriteInt(W, trap, 1); INC(trap)
- ELSE Texts.WriteString(W, "HALT statement")
- END
- END
- ELSE
- error := -error;
- IF (error >= 32) & (error <= 39) THEN Texts.WriteString(W, "Floating-point ") END;
- CASE error OF
- 0,32: Texts.WriteString(W, "Division by zero")
- |4,33: Texts.WriteString(W, "Overflow")
- |6: Texts.WriteString(W, "Invalid instruction")
- |12: Texts.WriteString(W, "Stack overflow")
- |13: Texts.WriteString(W, "General protection fault")
- |14: (* page fault *)
- IF (page >= -4) & (page < 4096) THEN Texts.WriteString(W, "NIL reference (")
- (*ELSIF (page >= 100000H) & (page < Kernel.StackOrg) THEN Texts.WriteString(W, "Stack overflow (")*)
- ELSE Texts.WriteString(W, "Page fault (")
- END;
- Texts.WriteHex(W, page); Texts.WriteString(W, "H )")
- |34: Texts.WriteString(W, "operation invalid")
- |35: Texts.WriteString(W, "stack fault")
- ELSE Texts.WriteString(W, "CPU exception")
- END
- END
- END WriteTrap;
- PROCEDURE Trap*(error, fp, pc, page: LONGINT); (** non-portable *) (* exported for Debug debugger *)
- VAR
- T: Texts.Text; refpos: LONGINT;
- mod: Modules.Module; lastfp, base: LONGINT; refs: Bytes;
- BEGIN
- IF trapped = 0 THEN
- trapped := 1;
- Display.ResetClip;
- IF Kernel.copro THEN Reals.SetFCR(Reals.DefaultFCR) ELSE resetfp() END;
- IF error # MAX(INTEGER) THEN Viewers.Close(NIL) END; (* close offending viewer, if any *)
- T := TextFrames.Text("");
- mod := AosModules.ThisModuleByAdr(pc);
- WriteTrap(W, error, page); Texts.WriteLn(W);
- LOOP
- WriteProc(mod, pc, fp, refs, refpos, base); Texts.WriteLn(W);
- IF refpos # -1 THEN Variables(refs, refpos, base) END;
- lastfp := fp;
- SYSTEM.GET(fp+4, pc); SYSTEM.GET(fp, fp); (* return addr from stack *)
- (*IF (fp < lastfp) OR (fp >= Kernel.StackOrg) THEN EXIT END; (* not called from stack *)*)
- IF fp = 0 THEN EXIT END;
- mod := AosModules.ThisModuleByAdr(pc)
- END;
- Texts.Append(T, W.buf);
- OpenText("Trap", T, TRUE)
- ELSIF trapped = 1 THEN
- trapped := 2;
- T := TextFrames.Text(""); Texts.WriteLn(W);
- Texts.WriteString(W, "TRAP "); Texts.WriteInt(W, error, 3); Texts.WriteString(W, " (recursive)");
- Texts.WriteLn(W); Texts.Append(T, W.buf);
- OpenText("Trap", T, TRUE)
- ELSIF trapped = 2 THEN
- trapped := 3;
- Texts.WriteLn(W); Texts.WriteString(W, "TRAP "); Texts.WriteInt(W, error, 3);
- Texts.WriteString(W, " (recursive)"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- ELSE (* skip *)
- END;
- trapped := 0
- END Trap;
- *)
- (* Returns TRUE iff Oberon is running in "stand-alone" mode. *)
- PROCEDURE Standalone(): BOOLEAN;
- BEGIN
- RETURN AosModules.ModuleByName(WMWindowManager) = NIL
- END Standalone;
- PROCEDURE FreeOberon;
- VAR context : Commands.Context; arg : Streams.StringReader; res: LONGINT; msg: ARRAY 128 OF CHAR;
- BEGIN
- Oberon.OpenTrack(0, Display.Width); (* inhibit display updates *)
- COPY(OberonBaseModule, msg);
- NEW(arg, LEN(msg)); arg.SetRaw(msg, 0, LEN(msg));
- NEW(context, NIL, arg, NIL, NIL, NIL);
- Commands.Activate("SystemTools.FreeDownTo", context, {}, res, msg);
- Kernel.UnlockOberon;
- AosActive.Terminate (* kill Oberon process in an unclean way (race with above! workaround in SystemTools.Mod) *)
- END FreeOberon;
- PROCEDURE Quit*;
- BEGIN
- IF Standalone() THEN
- AosModules.Shutdown(AosModules.PowerDown)
- ELSE
- FreeOberon
- END
- END Quit;
- PROCEDURE Reboot*; (** non-portable *)
- BEGIN
- IF Standalone() THEN
- AosModules.Shutdown(AosModules.Reboot)
- ELSE
- FreeOberon
- END
- END Reboot;
- PROCEDURE LogHandler(me: Oberon.Task);
- VAR i: LONGINT; t: Texts.Text; ch: CHAR; s: ARRAY 512 OF CHAR;
- BEGIN
- t := log;
- REPEAT
- KernelLog.GetBuffer(s);
- i := 0;
- LOOP
- ch := s[i];
- IF ch = 0X THEN EXIT END;
- IF (ch < 20X) & (ORD(ch) IN {01H, 02H, 03H, 0DH, 0AH, 0EH, 0FH}) THEN
- IF ch = 01X THEN (* start trap *)
- IF t = log THEN (* flush buffer to kernel log text *)
- Texts.Append(t, LogW.buf);
- t := TextFrames.Text("");
- OpenText("Trap", t, TRUE)
- END
- ELSIF ch = 02X THEN (* stop trap *)
- IF t # log THEN (* flush buffer to trap text *)
- Texts.Append(t, LogW.buf); t := log
- END
- ELSIF ch = 03X THEN
- Texts.WriteString(LogW, " **overflow**"); Texts.WriteLn(LogW)
- ELSIF ch = 0DX THEN Texts.WriteLn(LogW)
- ELSIF ch = 0EX THEN Texts.SetFont(LogW, fixed)
- ELSIF ch = 0FX THEN Texts.SetFont(LogW, Fonts.Default)
- ELSE (* skip *)
- END
- ELSE
- Texts.Write(LogW, ch)
- END;
- INC(i)
- END
- UNTIL i = 0;
- IF LogW.buf.len # 0 THEN (* flush buffer to kernel log or trap text *)
- Texts.Append(t, LogW.buf)
- END;
- me.time := Input.Time() + LogTime
- END LogHandler;
- PROCEDURE OpenKernelLog*; (** non-portable *)
- BEGIN
- IF log = NIL THEN NEW(log); Texts.Open(log, "") END;
- IF task = NIL THEN
- Texts.WriteString(W, "Execute System.StartLog to enable logging"); Texts.WriteLn(W);
- Texts.Append(log, W.buf)
- END;
- OpenText("Kernel.Log|System.Close System.Copy Edit.Search System.Clear", log, TRUE)
- END OpenKernelLog;
- PROCEDURE Init*; (** non-portable, for internal use *)
- VAR S: Texts.Scanner; Wt: Texts.Writer; T: Texts.Text; F: TextFrames.Frame; ok: BOOLEAN;
- BEGIN
- IF ~Machine.AtomicTestSet(init) THEN (* avoid user call and ignore restart due to exception *)
- Texts.OpenWriter(Wt);
- Oberon.OpenScanner(S, "System.InitCommands");
- IF S.class = Texts.Inval THEN
- OpenLog;
- OpenText("System.Tool", TextFrames.Text("System.Tool"), TRUE);
- StartLog
- ELSE
- WHILE ~S.eot & (S.class = Texts.Char) & (S.c = "{") DO
- ok := FALSE; Texts.Scan(S);
- IF S.class = Texts.Name THEN
- ok := TRUE; Texts.WriteString(Wt, S.s)
- END;
- IF ~((S.class = Texts.Char) & (S.c = "}")) THEN
- WHILE ~S.eot & (S.nextCh # "}") DO
- IF ok THEN Texts.Write(Wt, S.nextCh) END;
- Texts.Read(S, S.nextCh)
- END
- END;
- IF ok THEN
- Texts.WriteLn(Wt); T := TextFrames.Text(""); Texts.Append(T, Wt.buf);
- F := TextFrames.NewText(T, 0); TextFrames.Call(F, 0, FALSE)
- END;
- Texts.Scan(S); Texts.Scan(S)
- END
- END;
- NEW(oberonRunner);
- ELSE
- KernelLog.Enter; KernelLog.String("Only one instance of Oberon can be started"); KernelLog.Exit
- END;
- END Init;
- PROCEDURE Greetings;
- BEGIN
- Oberon.GetClock(time0, date0); Texts.WriteString(W, "System.Time");
- Texts.WriteDate(W, time0, date0); Texts.WriteLn(W);
- Texts.WriteString(W, "ETH Oberon / ");
- Texts.WriteString(W, Kernel.version); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf)
- END Greetings;
- PROCEDURE WriteType(VAR W: Texts.Writer; adr: LONGINT);
- VAR m: AosModules.Module; t: AosModules.TypeDesc;
- BEGIN
- AosModules.ThisTypeByAdr(adr, m, t);
- IF m # NIL THEN
- Texts.WriteString(W, m.name); Texts.Write(W, ".");
- IF t.name = "" THEN Texts.WriteString(W, "TYPE") ELSE Texts.WriteString(W, t.name) END
- ELSE
- Texts.WriteString(W, "NIL")
- END
- END WriteType;
- (** Display the approximate state of all threads in the system. *)
- PROCEDURE ShowActive*; (** non-portable *)
- VAR
- processes : ARRAY ProcessInfo.MaxNofProcesses OF AosActive.Process; nofProcesses : LONGINT;
- t: AosActive.Process; i, mode, adr: LONGINT; T: Texts.Text;
- pc, tmp1, tmp2: LONGINT; refs: Bytes;
- BEGIN
- ProcessInfo.GetProcesses(processes, nofProcesses);
- ProcessInfo.Sort(processes, nofProcesses, ProcessInfo.SortByID);
- (* display the threads *)
- Texts.SetFont(W, fixed);
- FOR i := 0 TO nofProcesses - 1 DO
- t := processes[i];
- Texts.WriteInt(W, t.id, 4); Texts.Write(W, " ");
- mode := t.mode;
- CASE mode OF
- AosActive.Ready: Texts.WriteString(W, "rdy")
- |AosActive.Running: Texts.WriteString(W, "run")
- |AosActive.AwaitingLock: Texts.WriteString(W, "awl")
- |AosActive.AwaitingCond: Texts.WriteString(W, "awc")
- |AosActive.AwaitingEvent: Texts.WriteString(W, "awe")
- |AosActive.Terminated: Texts.WriteString(W, "rip")
- ELSE Texts.WriteInt(W, mode, 3)
- END;
- Texts.WriteInt(W, t.procID, 2); Texts.WriteInt(W, t.priority, 2);
- (*Texts.WriteHex(W, SYSTEM.VAL(LONGINT, t)); Texts.Write(W, "H");*)
- adr := SYSTEM.VAL(LONGINT, t.obj);
- IF adr # 0 THEN
- Texts.WriteHex(W, adr); Texts.Write(W, "H");
- SYSTEM.GET(adr-4, adr); Texts.Write(W, ":"); WriteType(W, adr)
- ELSE
- Texts.WriteString(W, " SYSTEM")
- END;
- (*Texts.WriteHex(W, t.state.EIP); Texts.Write(W, "H");*)
- IF mode = AosActive.AwaitingLock THEN
- adr := SYSTEM.VAL(LONGINT, t.waitingOn);
- Texts.WriteHex(W, adr); Texts.Write(W, "H");
- IF adr # 0 THEN
- SYSTEM.GET(adr-4, adr); Texts.Write(W, ":"); WriteType(W, adr)
- END
- ELSIF mode = AosActive.AwaitingCond THEN
- Texts.Write(W, " ");
- pc := SYSTEM.VAL(LONGINT, t.condition);
- WriteProc(AosModules.ThisModuleByAdr(pc), pc, t.condFP, refs, tmp1, tmp2);
- (*Texts.WriteHex(W, SYSTEM.VAL(LONGINT, t.condition)); Texts.Write(W, "H");*)
- (*Texts.WriteHex(W, t.condFP); Texts.Write(W, "H")*)
- END;
- IF AosActive.Restart IN t.flags THEN Texts.WriteString(W, " rst") END;
- IF AosActive.PleaseHalt IN t.flags THEN Texts.WriteString(W, " hlt") END;
- IF AosActive.Unbreakable IN t.flags THEN Texts.WriteString(W, " unb"); END;
- IF AosActive.SelfTermination IN t.flags THEN Texts.WriteString(W, " slf"); END;
- IF AosActive.Preempted IN t.flags THEN Texts.WriteString(W, " pre"); END;
- IF AosActive.Resistant IN t.flags THEN Texts.WriteString(W, " res") END;
- Texts.WriteLn(W)
- END;
- Texts.SetFont(W, Fonts.Default);
- T := TextFrames.Text(""); Texts.Append(T, W.buf);
- OpenText("Active Objects", T, FALSE)
- END ShowActive;
- (* Halt or Terminate the selected thread. *)
- PROCEDURE StopProcess(halt: BOOLEAN);
- VAR
- s: Texts.Scanner; text: Texts.Text; beg, end, time: LONGINT;
- n : AosActive.Process;
- BEGIN
- Oberon.GetSelection(text, beg, end, time);
- IF time # -1 THEN
- Texts.OpenScanner(s, text, beg); Texts.Scan(s);
- IF s.class = Texts.Int THEN
- REPEAT
- n := ProcessInfo.GetProcess(s.i);
- IF n # NIL THEN
- AosActive.TerminateThis(n, halt);
- beg := s.line;
- REPEAT Texts.Scan(s) UNTIL (s.class = Texts.Inval) OR ((s.class = Texts.Int) & (s.line # beg)) OR (Texts.Pos(s) > end);
- IF Texts.Pos(s) > end THEN s.class := Texts.Inval END
- ELSE
- Texts.WriteString(W, "Object "); Texts.WriteInt(W, s.i, 1);
- Texts.WriteString(W, " not found"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf);
- s.class := Texts.Inval
- END
- UNTIL s.class # Texts.Int
- END
- END
- END StopProcess;
- (** Halt selected thread. *)
- PROCEDURE HaltObject*; (** non-portable *)
- BEGIN
- StopProcess(TRUE)
- END HaltObject;
- (** Terminate selected thread. *)
- PROCEDURE TerminateObject*; (** non-portable *)
- BEGIN
- StopProcess(FALSE)
- END TerminateObject;
- (** Attempt to terminate all non-immune threads. *)
- PROCEDURE TerminateObjects*; (** non-portable *)
- VAR processes : ARRAY ProcessInfo.MaxNofProcesses OF AosActive.Process; nofProcesses, i : LONGINT;
- BEGIN
- ProcessInfo.GetProcesses(processes, nofProcesses);
- FOR i := 0 TO nofProcesses - 1 DO
- AosActive.TerminateThis(processes[i], FALSE)
- END;
- END TerminateObjects;
- (** Start monitoring the KernelLog log for trap viewers and OpenKernelLog. *)
- PROCEDURE StartLog*; (** non-portable *)
- VAR cmd: PROCEDURE;
- BEGIN
- IF task = NIL THEN
- IF AosModules.ModuleByName (LogWindow) # NIL THEN
- GETPROCEDURE (LogWindow, "Close", cmd);
- IF cmd # NIL THEN cmd END;
- END;
- IF buf = NIL THEN NEW(buf, BufSize) END; (* never reallocate existing buffer *)
- IF log = NIL THEN NEW(log); Texts.Open(log, "") END;
- IF KernelLog.OpenBuffer(ADDRESSOF(buf[0]), LEN(buf)) THEN
- NEW(task); task.safe := TRUE; task.handle := LogHandler;
- task.time := Input.Time(); Oberon.Install(task)
- ELSE
- buf := NIL;
- Texts.WriteString(W, "Log already open elsewhere"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf)
- END
- ELSE
- Texts.WriteString(W, "Log already open"); Texts.WriteLn(W);
- Texts.Append(Oberon.Log, W.buf)
- END
- END StartLog;
- (** Stop monitoring the KernelLog log. Allows other loggers to work (e.g. LogWindow.Open) *)
- PROCEDURE StopLog*; (** non-portable *)
- BEGIN
- IF task # NIL THEN
- KernelLog.CloseBuffer;
- Oberon.Remove(task); task := NIL;
- END
- END StopLog;
- (*
- (** Load the window manager and jump into it. *)
- PROCEDURE LoadWM;
- VAR res: LONGINT; s: ARRAY 128 OF CHAR;
- BEGIN
- IF Standalone() THEN
- Oberon.OpenTrack(0, Display.Width); (* inhibit display updates *)
- OberonInput.Remove; (* remove default Oberon input device *)
- s := "";
- AosFS.AppendStr("WindowManager.Install;OberonDisplay.Install Oberon ", s);
- AosFS.AppendInt(Display.Width, s);
- AosFS.AppendStr("x", s);
- AosFS.AppendInt(Display.Height, s);
- Commands.Call(s, {Commands.Wait}, res, s);
- IF res = 0 THEN
- Display.SetMode(0BEH, {}); (* re-initialize display *)
- Input.Init(0BEH) (* re-init input *)
- ELSE
- Texts.WriteString(W, s); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
- END;
- Viewers.CloseTrack(0)
- END
- END LoadWM;
- *)
- BEGIN
- init := FALSE;
- Texts.OpenWriter(W);
- Oberon.Log := TextFrames.Text("");
- Texts.OpenWriter(LogW); fixed := Fonts.This("Courier10.Scn.Fnt");
- Greetings;
- task := NIL;
- Modules.InstallTermHandler(StopLog)
- END System.
|