ðÛSyntax10.Scn.FntöÿÿÿSÀÔStampElemsAlloc6 Oct 93äSyntax10i.Scn.Fnt 1+Courier10.Scn.FntÍ+Syntax10b.Scn.FntòŒ¿À KLML(À-+=QTR`qIMODULE Hex; (** CAS  **) IMPORT SYSTEM, Math, Oberon, Files, Input, Display, Fonts, Viewers, Texts, TextFrames, MenuViewers; CONST Menu = "System.Close System.Copy System.Grow Hex.Search Hex.Store "; left = 2; middle = 1; right = 0; (*mouse keys*) inval = -1; ascii = -2; (*MapToModel:type - values 0.. used for num types*) MaxPat = 32; TYPE ModelText = POINTER TO ModelTextDesc; ViewText = POINTER TO ViewTextDesc; ModelTextDesc = RECORD(Texts.TextDesc) view: ViewText; adrBase, base, byteW, blocks, elemB, adrW, elemW, hiLimit, blockW, numL, numR, asciiL, asciiR, lineW: INTEGER (*derived values*) END; ViewTextDesc = RECORD(Texts.TextDesc) model: ModelText END; VAR W, WM: Texts.Writer; plen: INTEGER; pat: ARRAY MaxPat OF CHAR; (*[0..plen)*) PROCEDURE StdFont; BEGIN Texts.SetFont(W, Fonts.Default) END StdFont; PROCEDURE NormFont; BEGIN Texts.SetFont(W, Fonts.This("Courier10.Scn.Fnt")) END NormFont; PROCEDURE Ch (ch: CHAR); BEGIN Texts.Write(W, ch) END Ch; PROCEDURE Str (s: ARRAY OF CHAR); BEGIN Texts.WriteString(W, s) END Str; PROCEDURE Ln; BEGIN Texts.WriteLn(W) END Ln; PROCEDURE MarkViewer (F: Display.Frame; mark: BOOLEAN); VAR v: Viewers.Viewer; t: Texts.Text; r: Texts.Reader; ch: CHAR; BEGIN v := Viewers.This(F.X, F.Y); IF (v IS MenuViewers.Viewer) & (v.dsc IS TextFrames.Frame) THEN t := v.dsc(TextFrames.Frame).text; Texts.OpenReader(r, t, t.len-1); Texts.Read(r, ch); IF ~mark & (ch = "!") THEN Texts.Delete(t, t.len-1, t.len) ELSIF mark & (ch # "!") THEN Texts.Write(WM, "!"); Texts.Append(t, WM.buf) END END END MarkViewer; PROCEDURE ClearW; BEGIN IF W.buf.len > 0 THEN Texts.OpenBuf(W.buf) END END ClearW; PROCEDURE WrNum (n: LONGINT; base, width: INTEGER); VAR i, k: INTEGER; s: ARRAY 32 OF CHAR; BEGIN (*n >= 0*) i := 0; REPEAT k := SHORT(n MOD base); n := n DIV base; IF k < 10 THEN s[i] := CHR(k + 30H) ELSE s[i] := CHR(k + 37H) END; INC(i) UNTIL n = 0; WHILE width > i DO Ch("0"); DEC(width) END; REPEAT DEC(i); Ch(s[i]) UNTIL i = 0 END WrNum; PROCEDURE Ascii (ch: CHAR): CHAR; BEGIN IF (ch < " ") OR (7FX <= ch) THEN ch := "." END; RETURN ch END Ascii; PROCEDURE Val (ch: CHAR): INTEGER; BEGIN (*ch IN {0..9, a..z, A..Z}*) IF ch <= "9" THEN RETURN ORD(ch) - 30H ELSE RETURN ORD(CAP(ch)) - 37H END END Val; PROCEDURE Valid (MT: ModelText; type: INTEGER; ch: CHAR): BOOLEAN; VAR b: BOOLEAN; BEGIN b := FALSE; IF type # inval THEN IF type = ascii THEN b := (" " <= ch) & (ch < 7FX) ELSIF ("0" <= ch) & (ch <= "9") OR ("A" <= CAP(ch)) & (CAP(ch) <= "Z") THEN IF type > 0 THEN b := Val(ch) < MT.base ELSE b := Val(ch) < MT.hiLimit END END END; RETURN b END Valid; PROCEDURE* NullNotify (T: Texts.Text; op: INTEGER; beg, end: LONGINT); END NullNotify; PROCEDURE ComputeMetrics (MT: ModelText); VAR i: INTEGER; log, w: REAL; PROCEDURE Log2(i: LONGINT): REAL; BEGIN RETURN Math.ln(i) / Math.ln(2) END Log2; BEGIN log := Log2(MT.base); w := 8 / log; MT.elemW := SHORT(ENTIER(w)); IF w > MT.elemW THEN INC(MT.elemW, 2) ELSE INC(MT.elemW) END; w := 24 / Log2(MT.adrBase); MT.adrW := SHORT(ENTIER(w)); IF w > MT.adrW THEN INC(MT.adrW) END; IF MT.byteW MOD MT.blocks # 0 THEN MT.blocks := MT.byteW END; MT.blockW := MT.blocks * MT.elemW + 1; MT.numL := MT.adrW + 5; MT.numR := MT.numL + (MT.byteW DIV MT.blocks) * MT.blockW - 2; MT.asciiL := MT.numR + 5; MT.asciiR := MT.asciiL + MT.byteW; MT.lineW := MT.asciiR + 1; i := 8 MOD SHORT(ENTIER(log)); IF i = 0 THEN i := SHORT(ENTIER(log)) END; MT.hiLimit := 1; WHILE i > 0 DO MT.hiLimit := MT.hiLimit * 2; DEC(i) END END ComputeMetrics; PROCEDURE MapToModel (MT: ModelText; vpos: LONGINT; VAR type: INTEGER; VAR mpos: LONGINT); VAR line: LONGINT; col: INTEGER; BEGIN line := vpos DIV MT.lineW; col := SHORT(vpos MOD MT.lineW); type := inval; IF (MT.numL <= col) & (col < MT.numR) THEN DEC(col, MT.numL); IF (col + 1) MOD MT.blockW # 0 THEN DEC(col, col DIV MT.blockW); IF col MOD MT.elemW < MT.elemW-1 THEN type := col MOD MT.elemW; mpos := line * MT.byteW + col DIV MT.elemW END END ELSIF (MT.asciiL <= col) & (col < MT.asciiR) THEN type := ascii; mpos := line * MT.byteW + col - MT.asciiL END END MapToModel; PROCEDURE MapToView (MT: ModelText; mpos: LONGINT; VAR vpos: LONGINT); BEGIN (*mpos MOD MT.byteW = 0*) vpos := (mpos DIV MT.byteW) * MT.lineW END MapToView; PROCEDURE IncPos (MT: ModelText; VAR vpos: LONGINT); VAR type: INTEGER; mpos: LONGINT; BEGIN MapToModel(MT, vpos, type, mpos); IF type = inval THEN INC(vpos) ELSIF type = ascii THEN INC(vpos); IF vpos MOD MT.lineW = MT.asciiR THEN INC(vpos, LONG(MT.lineW - MT.byteW)) END ELSIF type < MT.elemW-2 THEN INC(vpos) ELSE IF vpos MOD MT.lineW = MT.numR - 1 THEN INC(vpos, LONG(MT.lineW - (MT.numR - MT.numL - 1)) ) ELSE INC(vpos, 2); IF (vpos MOD MT.lineW - MT.numL) MOD MT.blockW = MT.blockW-1 THEN INC(vpos) END END END END IncPos; PROCEDURE DecPos (MT: ModelText; VAR vpos: LONGINT); VAR type: INTEGER; mpos: LONGINT; BEGIN MapToModel(MT, vpos, type, mpos); IF type = inval THEN DEC(vpos) ELSIF type = ascii THEN DEC(vpos); IF vpos MOD MT.lineW = MT.asciiL-1 THEN DEC(vpos, LONG(MT.lineW - MT.byteW)) END ELSIF type > 0 THEN DEC(vpos) ELSE IF vpos MOD MT.lineW = MT.numL THEN DEC(vpos, LONG(MT.lineW - (MT.numR - MT.numL - 1)) ) ELSE DEC(vpos, 2); IF (vpos MOD MT.lineW - MT.numL) MOD MT.blockW = MT.blockW-2 THEN DEC(vpos) END END END END DecPos; PROCEDURE GenView (MT: ModelText; VAR beg, end: LONGINT); VAR R: Texts.Reader; adr, i, j: LONGINT; ch: CHAR; vbeg, vend: LONGINT; ascii: ARRAY 32 OF CHAR; BEGIN DEC(beg, beg MOD MT.byteW); INC(end, (MT.byteW - end) MOD MT.byteW); adr := beg; IF end > MT.len THEN end := MT.len END; Texts.OpenReader(R, MT, beg); Texts.Read(R, ch); WHILE adr < end DO WrNum(adr, MT.adrBase, MT.adrW); Str(":ŸŸŸŸ"); i := 0; WHILE (adr < end) & (i < MT.byteW) DO INC(adr); WrNum(ORD(ch), MT.base, MT.elemW-1); Ch("Ÿ"); ascii[i] := Ascii(ch); INC(i); Texts.Read(R, ch); IF i MOD MT.blocks = 0 THEN Ch("Ÿ") END; IF i = MT.byteW THEN ascii[i] := 0X; Str("ŸŸ "); Str(ascii); Ln END END END; IF (0 < i) & (i < MT.byteW) THEN ascii[i] := 0X; WHILE i < MT.byteW DO j := MT.elemW; INC(i); WHILE j > 0 DO Ch(" "); DEC(j) END; IF i MOD MT.blocks = 0 THEN Ch("Ÿ") END END; Str("ŸŸ "); Str(ascii); Ln END END GenView; PROCEDURE UpdateView (MT: ModelText; beg, end: LONGINT); VAR VT: ViewText; vbeg, vend: LONGINT; BEGIN GenView(MT, beg, end); VT := MT.view; MapToView(MT, beg, vbeg); IF end < MT.len THEN MapToView(MT, end, vend) ELSE vend := MT.view.len END; VT.notify := NullNotify; Texts.Delete(VT, vbeg, vend); Texts.Insert(VT, vbeg, W.buf); VT.notify := TextFrames.NotifyDisplay; VT.notify(VT, Texts.replace, vbeg, vend) END UpdateView; PROCEDURE Load (MT: ModelText; f: Files.File); VAR beg, end: LONGINT; r: Files.Rider; ch: CHAR; BEGIN MT.notify := TextFrames.NotifyDisplay; Texts.Open(MT, ""); IF f = NIL THEN f := Files.New("") END; Files.Set(r, f, 0); Files.Read(r, ch); WHILE ~r.eof DO Ch(ch); Files.Read(r, ch) END; Texts.Append(MT, W.buf); NEW(MT.view); MT.view.notify := TextFrames.NotifyDisplay; MT.view.model := MT; Texts.Open(MT.view, ""); beg := 0; end := MT.len; GenView(MT, beg, end); Texts.Append(MT.view, W.buf) END Load; PROCEDURE ModelReplChar (MT: ModelText; VAR vpos: LONGINT; ch: CHAR); VAR R: Texts.Reader; type, n, i: INTEGER; mpos: LONGINT; ch0: CHAR; s: ARRAY 16 OF INTEGER; BEGIN MapToModel(MT, vpos, type, mpos); IF Valid(MT, type, ch) & (mpos < MT.len) THEN IF type >= 0 THEN Texts.OpenReader(R, MT, mpos); Texts.Read(R, ch0); i := 0; n := ORD(ch0); REPEAT s[i] := n MOD MT.base; INC(i); n := n DIV MT.base UNTIL i = MT.elemW-1; s[MT.elemW-2 - type] := Val(ch); n := 0; REPEAT DEC(i); n := n * MT.base + s[i] UNTIL i = 0; ch := CHR(n) END; Ch(ch); Texts.Delete(MT, mpos, mpos + 1); Texts.Insert(MT, mpos, W.buf); IncPos(MT, vpos) END END ModelReplChar; PROCEDURE ReplChar (MT: ModelText; VAR vpos: LONGINT; ch: CHAR); VAR type: INTEGER; mpos: LONGINT; BEGIN MapToModel(MT, vpos, type, mpos); ModelReplChar(MT, vpos, ch); IF type # inval THEN UpdateView(MT, mpos, mpos + 1) END END ReplChar; PROCEDURE ReplText (MT: ModelText; VAR vpos: LONGINT; T: Texts.Text; beg, end: LONGINT); VAR R: Texts.Reader; ch: CHAR; type: INTEGER; mpos, i: LONGINT; BEGIN MapToModel(MT, vpos, type, mpos); IF type # inval THEN Texts.OpenReader(R, T, beg); Texts.Read(R, ch); i := beg; WHILE i < end DO INC(i); IF (" " <= ch) & (ch < 7FX) THEN ModelReplChar(MT, vpos, ch) END; Texts.Read(R, ch) END; UpdateView(MT, mpos, mpos + end - beg) END END ReplText; PROCEDURE Zero (MT: ModelText; vbeg, vend: LONGINT); VAR begtype, endtype: INTEGER; beg, end, i: LONGINT; ch: CHAR; BEGIN MapToModel(MT, vbeg, begtype, beg); MapToModel(MT, vend - 1, endtype, end); INC(end); IF (begtype # inval) & (endtype # inval) & ((begtype # ascii) OR (begtype = endtype)) & (end <= MT.len) THEN IF begtype = ascii THEN ch := " " ELSE ch := 0X END; i := end - beg; WHILE i > 0 DO Ch(ch); DEC(i) END; Texts.Delete(MT, beg, end); Texts.Insert(MT, beg, W.buf); UpdateView(MT, beg, end) END END Zero; PROCEDURE CopySelection (MT: ModelText; vbeg, vend: LONGINT): Texts.Text; VAR T: Texts.Text; B: Texts.Buffer; R: Texts.Reader; begtype, endtype, i: INTEGER; beg, end: LONGINT; ch: CHAR; BEGIN T := TextFrames.Text(""); MapToModel(MT, vbeg, begtype, beg); MapToModel(MT, vend-1, endtype, end); INC(end); IF (begtype = inval) OR (endtype = inval) OR (begtype = ascii) # (endtype = ascii) THEN NEW(B); Texts.OpenBuf(B); Texts.Save(MT.view, vbeg, vend, B); Texts.Append(T, B) ELSIF begtype = ascii THEN Texts.OpenReader(R, MT, beg); Texts.Read(R, ch); i := 0; WHILE beg < end DO Ch(Ascii(ch)); Texts.Read(R, ch); INC(i); INC(beg); IF i = MT.byteW THEN Ln; i := 0 END END; IF i > 0 THEN Ln END; Texts.Append(T, W.buf) ELSE Texts.OpenReader(R, MT, beg); Texts.Read(R, ch); i := 0; WHILE beg < end DO WrNum(ORD(ch), MT.base, MT.elemW-1); Texts.Read(R, ch); INC(i); INC(beg); IF i = MT.byteW THEN Ln; i := 0 ELSE Ch("Ÿ") END END; IF i > 0 THEN Ln END; Texts.Append(T, W.buf) END; RETURN T END CopySelection; PROCEDURE SetCaret (MT: ModelText; F: TextFrames.Frame; vpos: LONGINT); VAR V: Viewers.Viewer; type: INTEGER; mpos, pbeg: LONGINT; P: TextFrames.Parc; BEGIN V := Viewers.This(F.X, F.Y); IF Oberon.FocusViewer # V THEN Oberon.PassFocus(V) END; IF F.hasCar THEN TextFrames.RemoveCaret(F) END; MapToModel(MT, vpos, type, mpos); WHILE (type = inval) & (vpos < MT.view.len) DO INC(vpos); MapToModel(MT, vpos, type, mpos) END; TextFrames.ParcBefore(F.text, vpos, P, pbeg); IF (F.H > P.lsp DIV TextFrames.Unit) & (vpos < F.org) OR (TextFrames.Pos(F, F.X + F.W, F.Y) < vpos) THEN IF F.hasSel THEN TextFrames.RemoveSelection(F) END; Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); TextFrames.Show(F, vpos - 200) END; TextFrames.SetCaret(F, vpos) END SetCaret; PROCEDURE* Handle (F: Display.Frame; VAR M: Display.FrameMsg); CONST BS = 8X; TAB = 9X; LF = 0AX; CR = 0DX; DEL = 7FX; UpArrow = 0C1X; DnArrow = 0C2X; RtArrow = 0C3X; LtArrow = 0C4X; VAR MT: ModelText; vpos, mpos, pos, col, off: LONGINT; type: INTEGER; keysum: SET; text: Texts.Text; beg, end, time: LONGINT; copyOver: Oberon.CopyOverMsg; BEGIN WITH F: TextFrames.Frame DO MT := F.text(ViewText).model; vpos := F.carloc.pos; IF M IS Oberon.InputMsg THEN WITH M: Oberon.InputMsg DO IF (M.id = Oberon.track) & (M.X >= F.X + TextFrames.barW) THEN IF M.keys = {left} THEN TextFrames.RemoveCaret(F); TextFrames.TrackCaret(F, M.X, M.Y, M.keys); vpos := F.carloc.pos; SetCaret(MT, F, vpos); IF M.keys = {left, middle} THEN Oberon.GetSelection(text, beg, end, time); IF time > 0 THEN ClearW; ReplText(MT, vpos, text, beg, end); SetCaret(MT, F, vpos) END END; RETURN ELSIF M.keys = {right} THEN TextFrames.TrackSelection(F, M.X, M.Y, M.keys); F.time := Oberon.Time(); IF M.keys = {right, middle} THEN ClearW; copyOver.text := CopySelection(MT, F.selbeg.pos, F.selend.pos); copyOver.beg := 0; copyOver.end := copyOver.text.len; Oberon.FocusViewer.handle(Oberon.FocusViewer, copyOver) ELSIF M.keys = {right, left} THEN ClearW; Zero(MT, F.selbeg.pos, F.selend.pos); SetCaret(MT, F, F.selbeg.pos) END; RETURN END ELSIF (M.id = Oberon.consume) & F.hasCar THEN col := vpos MOD MT.lineW; pos := vpos - col; IF (M.ch = CR) OR (M.ch = LF) THEN IF col < 62 THEN vpos := pos + MT.lineW + MT.numL ELSE vpos := pos + MT.lineW + MT.asciiL END ELSIF M.ch = TAB THEN MapToModel(MT, vpos, type, mpos); off := mpos MOD MT.byteW; IF type = ascii THEN vpos := pos + MT.numL + MT.elemW * off + off DIV MT.blocks ELSIF type # inval THEN vpos := pos + MT.asciiL + off END ELSIF M.ch = LtArrow THEN DecPos(MT, vpos) ELSIF M.ch = RtArrow THEN IncPos(MT, vpos) ELSIF M.ch = UpArrow THEN DEC(vpos, LONG(MT.lineW)) ELSIF M.ch = DnArrow THEN INC(vpos, LONG(MT.lineW)) ELSIF (" " <= M.ch) & (M.ch < 7FX) THEN ClearW; ReplChar(MT, vpos, M.ch) END; IF (vpos < 0) OR (vpos > MT.view.len) THEN vpos := pos + col END; SetCaret(MT, F, vpos); RETURN END END ELSIF M IS Oberon.SelectionMsg THEN WITH M: Oberon.SelectionMsg DO IF F.hasSel & (F.time > M.time) THEN M.time := F.time; ClearW; M.text := CopySelection(MT, F.selbeg.pos, F.selend.pos); M.beg := 0; M.end := M.text.len; RETURN END END ELSIF M IS Oberon.CopyOverMsg THEN WITH M: Oberon.CopyOverMsg DO IF F.hasCar THEN ClearW; ReplText(MT, vpos, M.text, M.beg, M.end); SetCaret(MT, F, vpos); RETURN END END ELSIF (M IS TextFrames.UpdateMsg) & (M(TextFrames.UpdateMsg).text = F.text) THEN MarkViewer(F, TRUE) END END; TextFrames.Handle(F, M) END Handle; PROCEDURE Open*; VAR S: Texts.Scanner; text: Texts.Text; time, beg, end, fptr: LONGINT; f: Files.File; MT: ModelText; TF: TextFrames.Frame; V: MenuViewers.Viewer; x, y: INTEGER; name: ARRAY LEN(S.s) OF CHAR; opt: CHAR; val: INTEGER; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); ClearW; NEW(MT); IF (S.class # Texts.Name) & (S.class # Texts.Int) OR (S.line # 0) THEN Oberon.GetSelection(text, beg, end, time); IF time > 0 THEN Texts.OpenScanner(S, text, beg); Texts.Scan(S) END END; IF (S.class # Texts.Name) OR (S.line # 0) THEN name := "Hex.Open" ELSE COPY(S.s, name) END; IF S.class = Texts.Int THEN f := SYSTEM.VAL(Files.File, S.i) ELSE f := Files.Old(name) END; MT.adrBase := 16; MT.base := 16; MT.byteW := 16; MT.blocks := 4; MT.elemB := 1; (*defaults*) Texts.Scan(S); WHILE (S.class = Texts.Char) & (S.c = "/") DO Texts.Scan(S); IF S.class = Texts.Name THEN opt := CAP(S.s[0]); Texts.Scan(S); IF S.class = Texts.Int THEN val := SHORT(S.i); Texts.Scan(S); IF (opt = "A") & (2 <= S.i) & (S.i <= 36) THEN MT.adrBase := val (*base of addresses*) ELSIF (opt = "B") & (2 <= S.i) & (S.i <= 36) THEN MT.base := val (*base of numeric area*) ELSIF (opt = "L") & (1 <= S.i) & (S.i <= 32) THEN MT.byteW := val (*line width in bytes*) ELSIF (opt = "G") & (1 <= S.i) & (S.i <= 32) THEN MT.blocks := val (*elements per group*) ELSIF (opt = "E") & (1 <= S.i) & (S.i <= 32) THEN MT.elemB := val (*bytes per element*) ;HALT(99) END END END END; ComputeMetrics(MT); Load(MT, f); Oberon.AllocateUserViewer(Oberon.Mouse.X, x, y); TF := TextFrames.NewText(MT.view, 0); TF.handle := Handle; V := MenuViewers.New(TextFrames.NewMenu(name, Menu), TF, TextFrames.menuH, x, y); END Open; PROCEDURE Search*; VAR TF: TextFrames.Frame; MT: ModelText; text: Texts.Text; beg, end, time, vpos: LONGINT; R: Texts.Reader; ch: CHAR; type, i, j, b, e: INTEGER; ref: ARRAY MaxPat OF CHAR; (*ref [b..e) is readback buffer*) BEGIN IF Oberon.Par.vwr.dsc = Oberon.Par.frame THEN TF := Oberon.Par.vwr.dsc.next(TextFrames.Frame); Oberon.GetSelection(text, beg, end, time); IF time > 0 THEN Texts.OpenReader(R, text, beg); plen := 0; Texts.Read(R, ch); WHILE ~R.eot & (Texts.Pos(R) <= end) & (plen < MaxPat) DO pat[plen] := Ascii(ch); INC(plen); Texts.Read(R, ch) END END; IF plen > 0 THEN MT := TF.text(ViewText).model; end := MT.len; IF TF.hasCar THEN MapToModel(MT, TF.carloc.pos, type, beg) ELSE beg := 0 END; Texts.OpenReader(R, MT, beg); Texts.Read(R, ch); i := 0; ref[0] := ch; j := 0; b := 0; e := 1; WHILE (i < plen) & (beg <= end) DO IF pat[i] = Ascii(ch) THEN INC(i); j := (j + 1) MOD MaxPat ELSE i := 0; b := (b + 1) MOD MaxPat; j := b END; IF j # e THEN ch := ref[j] ELSE Texts.Read(R, ch); INC(beg); ref[j] := ch; e := (e + 1) MOD MaxPat END END; IF i = plen THEN MapToView(MT, beg - beg MOD MT.byteW, vpos); INC(vpos, MT.asciiL + beg MOD MT.byteW); SetCaret(MT, TF, vpos) END END END END Search; PROCEDURE Store*; VAR S: Texts.Scanner; F: TextFrames.Frame; MT: ModelText; R: Texts.Reader; f: Files.File; r: Files.Rider; i, res: INTEGER; ch: CHAR; name: ARRAY 64 OF CHAR; BEGIN IF Oberon.Par.vwr.dsc = Oberon.Par.frame THEN F := Oberon.Par.vwr.dsc(TextFrames.Frame); Texts.OpenScanner(S, F.text, 0); Texts.Scan(S); IF S.class = Texts.Name THEN MT := F.next(TextFrames.Frame).text(ViewText).model; ClearW; StdFont; Str("Hex.Store "); Str(S.s); Ch(" "); NormFont; Texts.OpenReader(R, MT, 0); Texts.Read(R, ch); f := Files.New(S.s); Files.Set(r, f, 0); WHILE ~R.eot DO Files.Write(r, ch); Texts.Read(R, ch) END; COPY(S.s, name); i := 0; WHILE name[i] # 0X DO INC(i) END; name[i] := "."; name[i+1] := "B"; name[i+2] := "a"; name[i+3] := "k"; name[i+4] := 0X; Files.Rename(S.s, name, res); Files.Register(f); StdFont; Texts.WriteInt(W, Files.Length(f), 0); Ln; NormFont; Texts.Append(Oberon.Log, W.buf); MarkViewer(F, FALSE) END END END Store; BEGIN Texts.OpenWriter(W); Texts.OpenWriter(WM); NormFont END Hex. (* hex view outline: (base = 16, byteW = 16, numL = 11, Blocks = 4, elemW = 3) AAAAAA:////HH/HH/HH/HH//HH/HH/HH/HH//HH/HH/HH/HH//HH/HH/HH/HH////CCCCCCCCCCCCCCCC 01234567890123456789012345678901234567890123456789012345678901234567890123456789012 1 2 3 4 5 6 7 8 address hex dump (4 blocks of 4 bytes each) ascii dump (16 characters) *)