Syntax10.Scn.Fnt Syntax10i.Scn.Fnt StampElems Alloc 10 Dec 95 FoldElems Syntax10b.Scn.Fnt Syntax12b.Scn.Fnt not yet completed!!! Syntax12i.Scn.Fnt LineElems Alloc Syntax10.Scn.Fnt FoldElems Syntax10.Scn.Fnt Syntax10b.Scn.Fnt VAR R: Texts.Reader; text: Texts.Text; i, beg, end, time: LONGINT; ch: CHAR; BEGIN Oberon.GetSelection(text, beg, end, time); IF time >= 0 THEN i := beg; Texts.SetFont(W, Fonts.This("Syntax10i.Scn.Fnt")); Texts.SetColor(W, Oberon.CurCol); Texts.SetOffset(W, Oberon.CurOff); LOOP Texts.WriteString(W, str); Texts.Insert(text, i, W.buf); INC(i, LEN(str)); INC(end, LEN(str)); IF i < end THEN Texts.OpenReader(R, text, i); REPEAT Texts.Read(R, ch); INC(i) UNTIL (ch = 0DX) OR (i = end) END; Texts.WriteString(W, "*)"); IF ch # 0DX THEN Texts.Insert(text, i, W.buf); EXIT END; Texts.Insert(text, i-1, W.buf); INC(i, 2); INC(end, 2); IF i = end THEN EXIT END END; Texts.SetFont(W, Fonts.Default) END END Comm; Syntax10.Scn.Fnt Syntax10b.Scn.Fnt Syntax10i.Scn.Fnt VAR R: Texts.Reader; text: Texts.Text; pos, i, beg, end, time: LONGINT; ch: CHAR; BEGIN Oberon.GetSelection(text, beg, end, time); IF time >= 0 THEN Texts.OpenReader(R, text, beg); i := beg; LOOP Texts.OpenReader(R, text, i); REPEAT Texts.Read(R, ch); INC(i) UNTIL (ch = "(") OR (i = end); IF i+1 >= end THEN EXIT END; pos := i-1; Texts.Read(R, ch); INC(i); IF ch = "*" THEN Texts.Delete(text, pos, i+d); DEC(end, 2+d); DEC(i, 2+d); Texts.OpenReader(R, text, pos) END; REPEAT Texts.Read(R, ch); INC(i) UNTIL (ch = 0DX) OR (i >= end); IF i > pos+1 THEN IF i > end THEN i := end ELSIF ch = 0DX THEN DEC(i) END; Texts.Delete(text, i-2+d, i+d); DEC(end, 2); DEC(i, 2) END; IF i >= end THEN EXIT END END (*LOOP*) END END Uncomm; Syntax10b.Scn.Fnt Syntax10i.Scn.Fnt PROCEDURE Comm(str: ARRAY OF CHAR); PROCEDURE Uncomm(d: LONGINT); PROCEDURE Comment*; (** Comment all lines in selection ("(* ... *)") **) BEGIN Comm("(*") END Comment; PROCEDURE Comment2*; (** Comment all lines in selection ("(*<< ... *)") **) BEGIN Comm("(*<<") END Comment2; PROCEDURE Uncomment*; (** Remove (* ... *) comments in selection **) BEGIN Uncomm(0) END Uncomment; PROCEDURE Uncomment2*; (** Remove (*<< ... *) comments in selection **) BEGIN Uncomm(2) END Uncomment2; Courier10.Scn.Fnt MODULE Utils; (** SHML 12 Dec 91, IMPORT Display, Files, Modules, Input, Fonts, Texts, TF := TextFrames, Viewers, MV := MenuViewers, Oberon; CONST ErrorFile = "OberonErrors.Text"; VAR W: Texts.Writer; MarkedViewer: Viewers.Viewer; PROCEDURE String(s: ARRAY OF CHAR); BEGIN Texts.WriteString (W, s) END String; PROCEDURE Int(i: LONGINT); BEGIN Texts.WriteInt(W, i, 0) END Int; PROCEDURE Ln; BEGIN Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) END Ln; PROCEDURE Err(s: ARRAY OF CHAR); BEGIN String(s); Ln END Err; PROCEDURE Setup(VAR S: Texts.Scanner; VAR end: LONGINT); (* Set up S on parameter list *) VAR Sel: Texts.Text; beg, time: LONGINT; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF (S.class = Texts.Char) & (S.line = 0) & (S.c = "^") OR (Oberon.Par.frame = Oberon.Par.vwr.dsc) THEN Oberon.GetSelection(Sel, beg, end, time); IF time >= 0 THEN Texts.OpenScanner(S, Sel, beg); Texts.Scan(S) ELSE end := -1 END ELSE end := Oberon.Par.text.len END END Setup; PROCEDURE GetTextFromMarked(VAR text: Texts.Text); VAR v: Viewers.Viewer; BEGIN v := Oberon.MarkedViewer(); IF (v # NIL) & (v IS MV.Viewer) & (v.dsc # NIL) & (v.dsc.next # NIL) & (v.dsc.next IS TF.Frame) THEN text := v.dsc.next(TF.Frame).text ELSE text := NIL END END GetTextFromMarked; PROCEDURE Conv(from, to: CHAR; eat: BOOLEAN); (* Convert from characters in a file into to characters, unless eat is TRUE *) VAR S: Texts.Scanner; in, out: Files.File; In, Out: Files.Rider; i, end: LONGINT; ch: CHAR; wr: Texts.Writer; oldName: ARRAY 64 OF CHAR; BEGIN Texts.OpenWriter(wr); Texts.WriteString(wr, "System.RenameFiles"); Texts.WriteLn(wr); Setup(S, end); LOOP IF S.class # Texts.Name THEN EXIT END; in := Files.Old(S.s); IF in # NIL THEN String(S.s); COPY(S.s, oldName); S.s[S.len] := "."; S.s[S.len+1] := "C"; S.s[S.len+2] := "n"; S.s[S.len+3] := "v"; S.s[S.len+4] := 0X; String(" => "); String(S.s); Ln; Texts.Write(wr, 9X); Texts.WriteString(wr, S.s); Texts.WriteString(wr, " => "); Texts.WriteString(wr, oldName); Texts.WriteLn(wr); out := Files.New(S.s); Files.Set(In, in, 0); Files.Set(Out, out, 0); FOR i := 1 TO Files.Length(in) DO Files.Read(In, ch); IF ch = from THEN IF ~eat THEN Files.Write(Out, to) END ELSE Files.Write(Out, ch) END END; Files.Register(out) END; IF Texts.Pos(S) >= end THEN EXIT END; Texts.Scan(S) END; String("done"); Ln; Texts.Write(wr, "~"); Texts.WriteLn(wr); Texts.Append(Oberon.Log, wr.buf) END Conv; (*PROCEDURE Convert2(from, to: CHAR); (* Convert from characters after CR in a text into to characters *) VAR S: Texts.Scanner; in, out: Texts.Text; In: Texts.Reader; Out: Texts.Writer; i: LONGINT; ch: CHAR; BEGIN (* Setup(S); WHILE S.class = Texts.Name DO in := Texts.Open(S.s); IF in # NIL THEN String(S.s); S.s[S.len] := "."; S.s[S.len+1] := "C"; S.s[S.len+2] := "n"; S.s[S.len+3] := "v"; S.s[S.len+4] := 0X; String(" => "); String(S.s); Ln; out := Files.New(S.s); Files.Set(In, in, 0); Files.Set(Out, out, 0); WHILE ~In.eot DO Texts.Read(In, ch); Texts.Write(Out, ch); IF ch = 0DX THEN Texts.Read(In, ch); WHILE ch = from DO Texts.Write(Out, to); Texts.Read(In, ch) END; Texts.Write(Out, ch) END END; Texts.Append(t, Out.buf); Texts.Store(t, out, 0, len); Files.Register(out) END; Texts.Scan(S) END; String("done"); Ln*) END Convert2; PROCEDURE ChangeCase(low, high: CHAR; diff: INTEGER); (* Convert all chars in [low..high] in selection to chars+diff *) VAR R: Texts.Reader; text: Texts.Text; msg: Texts.CopyMsg; i, beg, end: LONGINT; ch: CHAR; BEGIN Oberon.GetSelection(text, beg, end, i); IF i >= 0 THEN Texts.OpenReader(R, text, beg); i := beg; REPEAT Texts.Read(R, ch); Texts.SetFont(W, R.fnt); Texts.SetColor(W, R.col); Texts.SetOffset(W, R.voff); IF (low <= ch) & (ch <= high) THEN Texts.Write(W, CHR(ORD(ch)+diff)) ELSIF R.elem # NIL THEN R.elem.handle(R.elem, msg); Texts.WriteElem(W, msg.e) ELSE Texts.Write(W, ch) END; INC(i) UNTIL i = end; Texts.Delete(text, beg, end); Texts.Insert(text, beg, W.buf); Texts.SetFont(W, Fonts.Default) END END ChangeCase; PROCEDURE CloseOpen(VAR self: Viewers.Viewer; dY: INTEGER); (* Close self and open it at old y + dY *) VAR handler: Display.Handler; oldX, oldY: INTEGER; BEGIN IF dY # 0 THEN handler := self.handle; oldX := self.X; oldY := self.Y+self.H; Viewers.Close(self); self := MV.New(self.dsc, self.dsc.next, TF.menuH, oldX, oldY+dY); self.handle := handler END END CloseOpen; PROCEDURE MoveUp(self: Viewers.Viewer; VAR dY: INTEGER); (* Move self and all viewers above up *) VAR upper: Viewers.Viewer; BEGIN upper := Viewers.Next(self); IF upper.state = 1 THEN dY := upper.H (* filler viewer *) ELSE MoveUp(upper, dY) END; CloseOpen(self, dY); (* extend own frame by maximal extension allowed by upper *) dY := self.H-Viewers.minH (* own maximal reduction *) END MoveUp; PROCEDURE MoveDown(self: Viewers.Viewer); (* Move self and all viewers below down *) VAR upper: Viewers.Viewer; BEGIN upper := self; REPEAT upper := Viewers.Next(upper) UNTIL upper.state = 1; (* find filler viewer *) upper := Viewers.Next(upper); WHILE upper # self DO CloseOpen(upper, -(upper.H-Viewers.minH)); upper := Viewers.Next(upper) END; CloseOpen(upper, -(upper.H-Viewers.minH)) END MoveDown; (** Commands *) PROCEDURE Compare*; (** ({name1 name2} "~" | "^") Compare two files *) CONST Size = SIZE(LONGINT); BufSize = 4096 DIV Size; VAR S: Texts.Scanner; name: ARRAY 32 OF CHAR; f1, f2: Files.File; R1, R2: Files.Rider; l1, l2, end, i: LONGINT; ch1, ch2: CHAR; buf1, buf2: ARRAY BufSize OF LONGINT; BEGIN Setup(S, end); (* string comparison *) LOOP IF S.class # Texts.Name THEN EXIT END; COPY(S.s, name); Texts.Scan(S); IF S.class # Texts.Name THEN EXIT END; f1 := Files.Old(name); f2 := Files.Old(S.s); IF (f1 # NIL) & (f2 # NIL) THEN String("comparing "); String(name); String(" and "); String(S.s); Ln; Files.Set(R1, f1, 0); Files.Set(R2, f2, 0); l1 := Files.Length(f1); l2 := Files.Length(f2); IF l1 # l2 THEN String("Files differ in length"); Ln ELSE l1 := l2 MOD Size; DEC(l2, l1); LOOP IF l1 = 0 THEN EXIT END; Files.Read(R1, ch1); Files.Read(R2, ch2); IF ch1 # ch2 THEN String("pos "); Int(Files.Pos(R1)); Ln; EXIT END; DEC(l1) END; IF l1 = 0 THEN LOOP IF l2 = 0 THEN EXIT END; Files.ReadBytes(R1, buf1, BufSize); Files.ReadBytes(R2, buf2, BufSize); i := 0; WHILE (i < BufSize) & (buf1[i] = buf2[i]) DO INC(i) END; IF i < BufSize THEN String("pos "); Int(Files.Pos(R1)-BufSize*Size); Ln; EXIT END; DEC(l2, BufSize*Size) END END END; Files.Close(f1); Files.Close(f2) END; IF Texts.Pos(S) >= end THEN EXIT END; Texts.Scan(S) END END Compare; PROCEDURE FileCompare*; (** ({name1 name2} "~" | "^") Compare two files and report differences *) VAR S: Texts.Scanner; name: ARRAY 32 OF CHAR; f1, f2: Files.File; R1, R2: Files.Rider; l1, l2, end: LONGINT; ch1, ch2: CHAR; same: BOOLEAN; X,Y: INTEGER; keys: SET; BEGIN Setup(S, end); LOOP IF S.class # Texts.Name THEN EXIT END; COPY(S.s, name); Texts.Scan(S); IF S.class # Texts.Name THEN EXIT END; f1 := Files.Old(name); f2 := Files.Old(S.s); IF (f1 # NIL) & (f2 # NIL) THEN String("comparing "); String(name); String(" and "); String(S.s); Ln; Files.Set(R1, f1, 0); Files.Set(R2, f2, 0); l1 := Files.Length(f1); l2 := Files.Length(f2); IF l1 # l2 THEN String("Files differ in length"); Ln END; IF l2 < l1 THEN l1 := l2 END; same := TRUE; l2 := 1; keys := {}; WHILE (l2 <= l1) & (keys # {0, 1, 2}) DO Files.Read(R1, ch1); Files.Read(R2, ch2); IF ch1 # ch2 THEN same := FALSE; String("pos "); Int(Files.Pos(R1)); Ln END; Input.Mouse(keys, X, Y); INC(l2) END; Files.Close(f1); Files.Close(f2); IF same THEN String("Files are identical"); Ln END END; IF (keys = {0, 1, 2}) OR (Texts.Pos(S) >= end) THEN EXIT END; Texts.Scan(S) END END FileCompare; PROCEDURE TextCompare*; (** ({name1 name2} "~" | "^") Compare two texts and report differences *) VAR S: Texts.Scanner; name: ARRAY 32 OF CHAR; t1, t2: Texts.Text; R1, R2: Texts.Reader; l1, l2, end: LONGINT; ch1, ch2: CHAR; same: BOOLEAN; X,Y: INTEGER; keys: SET; BEGIN Setup(S, end); LOOP IF S.class # Texts.Name THEN EXIT END; COPY(S.s, name); Texts.Scan(S); IF S.class # Texts.Name THEN EXIT END; t1 := TF.Text(name); t2 := TF.Text(S.s); String("comparing "); String(name); String(" and "); String(S.s); Ln; Texts.OpenReader(R1, t1, 0); Texts.OpenReader(R2, t2, 0); l1 := t1.len; l2 := t2.len; IF l1 # l2 THEN String("Texts differ in length"); Ln END; IF l2 < l1 THEN l1 := l2 END; same := TRUE; l2 := 1; keys := {}; WHILE (l2 <= l1) & (keys # {0, 1, 2}) DO Texts.Read(R1, ch1); Texts.Read(R2, ch2); IF ch1 # ch2 THEN same := FALSE; String("pos "); Int(Texts.Pos(R1)); Ln END; Input.Mouse(keys, X, Y); INC(l2) END; IF same THEN String("Texts are identical"); Ln END; IF (keys = {0, 1, 2}) OR (Texts.Pos(S) >= end) THEN EXIT END; Texts.Scan(S) END END TextCompare; PROCEDURE Comment*; (** Comment selection with "(* ... *)" *) VAR text: Texts.Text; r: Texts.Reader; ch: CHAR; beg, end, time: LONGINT; front, back: BOOLEAN; BEGIN Oberon.GetSelection(text, beg, end, time); IF time >= 0 THEN front := FALSE; back := FALSE; IF beg = 0 THEN front := TRUE ELSE Texts.OpenReader(r, text, beg-1); Texts.Read(r, ch); IF ch = 0DX THEN front := TRUE END END; IF end < text.len THEN Texts.OpenReader(r, text, end-1); Texts.Read(r, ch); IF ch = 0DX THEN back := TRUE END END; Texts.Write(W, "("); Texts.Write(W, "*"); IF front THEN Texts.WriteLn(W); INC(end) END; Texts.Insert(text, beg, W.buf); Texts.Write(W, "*"); Texts.Write(W, ")"); IF back THEN Texts.WriteLn(W) END; Texts.Insert(text, end+2, W.buf) END END Comment; PROCEDURE Comment2*; (** Comment selection with "(*<< ... *)" *) VAR text: Texts.Text; beg, end, time: LONGINT; BEGIN Oberon.GetSelection(text, beg, end, time); IF time >= 0 THEN Texts.Write(W, "("); Texts.WriteString(W, "*<<"); Texts.WriteLn(W); Texts.Insert(text, beg, W.buf); Texts.Write(W, "*");Texts.Write(W, ")"); Texts.WriteLn(W); Texts.Insert(text, end+4, W.buf) END END Comment2; PROCEDURE Uncomment*; (** Remove (* ... *) comments around selection *) VAR text: Texts.Text; beg, end, time: LONGINT; PROCEDURE DelHead(pos: LONGINT): BOOLEAN; VAR r: Texts.Reader; ch: CHAR; BEGIN Texts.OpenReader(r, text, pos); Texts.Read(r, ch); IF ~r.eot & (ch = "(") THEN Texts.Read(r, ch); IF ~r.eot & (ch = "*") THEN Texts.Read(r, ch); IF ~r.eot THEN Texts.Delete(text, pos, pos+2); RETURN TRUE END END END; RETURN FALSE END DelHead; PROCEDURE DelTail(pos: LONGINT): BOOLEAN; VAR r: Texts.Reader; ch: CHAR; BEGIN Texts.OpenReader(r, text, pos); Texts.Read(r, ch); IF ~r.eot & (ch = "*") THEN Texts.Read(r, ch); IF ~r.eot & (ch = ")") THEN Texts.Read(r, ch); IF ~r.eot THEN Texts.Delete(text, pos, pos+2); RETURN TRUE END END END; RETURN FALSE END DelTail; BEGIN Oberon.GetSelection(text, beg, end, time); IF (time >= 0) & (DelHead(beg) OR DelHead(beg-3)) & (DelTail(end-6) OR DelTail(end-3)) THEN END END Uncomment; PROCEDURE Uncomment2*; (** Remove (*<< ... *) comments around selection *) VAR text: Texts.Text; beg, end, time: LONGINT; PROCEDURE DelHead(pos: LONGINT): BOOLEAN; VAR r: Texts.Reader; ch: CHAR; BEGIN Texts.OpenReader(r, text, pos); Texts.Read(r, ch); IF ~r.eot & (ch = "(") THEN Texts.Read(r, ch); IF ~r.eot & (ch = "*") THEN Texts.Read(r, ch); IF ~r.eot & (ch = "<") THEN Texts.Read(r, ch); IF ~r.eot & (ch = "<") THEN Texts.Read(r, ch); IF ~r.eot THEN Texts.Delete(text, pos, pos+4); RETURN TRUE END END END END END; RETURN FALSE END DelHead; PROCEDURE DelTail(pos: LONGINT): BOOLEAN; VAR r: Texts.Reader; ch: CHAR; BEGIN Texts.OpenReader(r, text, pos); Texts.Read(r, ch); IF ~r.eot & (ch = "*") THEN Texts.Read(r, ch); IF ~r.eot & (ch = ")") THEN Texts.Read(r, ch); IF ~r.eot THEN Texts.Delete(text, pos, pos+2); RETURN TRUE END END END; RETURN FALSE END DelTail; BEGIN Oberon.GetSelection(text, beg, end, time); IF (time >= 0) & (DelHead(beg) OR DelHead(beg-5)) & (DelTail(end-8) OR DelTail(end-5)) THEN END END Uncomment2; PROCEDURE CR2LF*; (** ({name} "~" | "^") Convert Oberon-files to Unix-files (CR to LF) *) BEGIN Conv(0DX, 0AX, FALSE) END CR2LF; PROCEDURE LF2CR*; (** ({name} "~" | "^") Convert Unix-files to Oberon-files (LF to CR) *) BEGIN Conv(0AX, 0DX, FALSE) END LF2CR; PROCEDURE CRLF2CR*; (** ({name} "~" | "^") Convert PC-files to Oberon-files (CR LF to CR) *) BEGIN Conv(0AX, 0DX, TRUE) END CRLF2CR; PROCEDURE LineBreak2CRLF*; (** ({name} "~" | "^") Convert Oberon/Unix-files to PC-files (CR/LF to CR LF) *) VAR S: Texts.Scanner; in, out: Files.File; In, Out: Files.Rider; i, end: LONGINT; ch: CHAR; wr: Texts.Writer; oldName: ARRAY 64 OF CHAR; BEGIN Texts.OpenWriter(wr); Texts.WriteString(wr, "System.RenameFiles"); Texts.WriteLn(wr); Setup(S, end); LOOP IF S.class # Texts.Name THEN EXIT END; in := Files.Old(S.s); IF in # NIL THEN String(S.s); COPY(S.s, oldName); S.s[S.len] := "."; S.s[S.len+1] := "C"; S.s[S.len+2] := "n"; S.s[S.len+3] := "v"; S.s[S.len+4] := 0X; String(" => "); String(S.s); Ln; Texts.Write(wr, 9X); Texts.WriteString(wr, S.s); Texts.WriteString(wr, " => "); Texts.WriteString(wr, oldName); Texts.WriteLn(wr); out := Files.New(S.s); Files.Set(In, in, 0); Files.Set(Out, out, 0); FOR i := 1 TO Files.Length(in) DO Files.Read(In, ch); IF (ch = 0DX) OR (ch = 0AX) THEN Files.Write(Out, 0DX); Files.Write(Out, 0AX) ELSE Files.Write(Out, ch) END END; Files.Register(out) END; IF Texts.Pos(S) >= end THEN EXIT END; Texts.Scan(S) END; String("done"); Ln; Texts.Write(wr, "~"); Texts.WriteLn(wr); Texts.Append(Oberon.Log, wr.buf) END LineBreak2CRLF; PROCEDURE Convert*; (** from to ({name} "~" | "^") Convert from chars into to chars in all files name *) VAR S: Texts.Scanner; from, to: CHAR; end: LONGINT; BEGIN Setup(S, end); IF S.class # Texts.Int THEN RETURN END; from := CHR(S.i); Texts.Scan(S); IF S.class # Texts.Int THEN RETURN END; to := CHR(S.i); Oberon.Par.pos := Texts.Pos(S)-1; Conv(from, to, FALSE) END Convert; (*PROCEDURE FromCN*; (** ({name} "~" | "^") Convert CN-files to SHML-files (CR {blank} to CR {tab}) *) *) (*BEGIN Convert2(" ", 09X) *) (*END FromCN; *) (*PROCEDURE ToCN*; (** ({name} "~" | "^") Convert SHML-files to CN-files (CR {tab} to CR {blank}) *) *) (*BEGIN Convert2(09X, " ") *) (*END ToCN; *) PROCEDURE NonPrintable*; (** Set caret before (next) non_printable character in marked viewer *) VAR R: Texts.Reader; v: Viewers.Viewer; f: TF.Frame; text: Texts.Text; dx, x, y, w, h: INTEGER; p, pos: LONGINT; ch: CHAR; BEGIN v := Oberon.MarkedViewer(); IF (v # NIL) & (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) THEN IF v # MarkedViewer THEN MarkedViewer := v END; f := v.dsc.next(TF.Frame); IF f.hasCar THEN pos := f.carloc.pos+1 ELSE pos := 0 END ELSE RETURN END; text := f.text; Texts.OpenReader(R, text, pos); REPEAT Texts.Read(R, ch); Display.GetChar(Fonts.Default.raster, ch, dx, x, y, w, h, p) UNTIL R.eot OR (dx = 0) & (ch # 0DX); IF ~R.eot THEN pos := Texts.Pos(R); p := pos-200; IF p < 0 THEN p := 0 END; TF.Show(f, p); TF.SetCaret(f, pos); String("ASCII code = "); Int(ORD(ch)); Ln ELSE String("none found"); Ln END END NonPrintable; PROCEDURE Clean*; (** Delete spaces and tabs at end of lines in marked viewer *) VAR R: Texts.Reader; text: Texts.Text; del, pos: LONGINT; ch: CHAR; BEGIN GetTextFromMarked(text); IF (text # NIL) & (text.len # 0) THEN Texts.OpenReader(R, text, 0); del := 0; LOOP IF Texts.Pos(R) >= text.len THEN EXIT END; REPEAT Texts.Read(R, ch) UNTIL (ch = " ") OR (ch = 9X) OR R.eot; IF R.eot THEN EXIT END; pos := Texts.Pos(R)-1; REPEAT Texts.Read(R, ch) UNTIL (ch # " ") & (ch # 9X) OR R.eot; IF R.eot THEN EXIT ELSIF ch = 0DX THEN INC(del, Texts.Pos(R)-pos-1); Texts.Delete(text, pos, Texts.Pos(R)-1); Texts.OpenReader(R, text, pos+1) END END; Int(del); String(" char"); IF del # 1 THEN String("s") END; String(" deleted"); Ln END END Clean; PROCEDURE Semicolons*; (** Delete superfluous semicolons in marked viewer *) CONST None = 0; End = 1; EndIdent = 2; VAR S, s1: Texts.Scanner; text: Texts.Text; del, pos: LONGINT; state: INTEGER; BEGIN GetTextFromMarked(text); IF (text # NIL) & (text.len # 0) THEN Texts.OpenScanner(S, text, 0); S.class := Texts.Inval; del := 0; LOOP IF S.eot THEN EXIT END; state := None; REPEAT IF (state IN {None, End}) & (S.class = Texts.Name) & (S.s = "END") THEN state := End ELSIF (state = End) & (S.class = Texts.Name) & (S.s # "END") THEN state := EndIdent ELSIF (S.class # Texts.Char) OR (S.c # ";") THEN state := None END; Texts.Scan(S) UNTIL (S.class = Texts.Char) & (S.c = ";") OR S.eot; IF S.eot THEN EXIT END; pos := Texts.Pos(S)-2; (* S.c = ";" *) Texts.Scan(S); IF S.eot THEN EXIT END; IF (S.class = Texts.Name) & ((S.s = "END") OR (S.s = "ELSE") OR (S.s = "ELSIF") OR (S.s = "UNTIL")) OR (S.class = Texts.Char) & (S.c = "|") THEN IF (S.class = Texts.Name) & (S.s = "END") & (state = EndIdent) THEN (* don't delete if END ident; END ident. *) Texts.OpenScanner(s1, text, Texts.Pos(S)); Texts.Scan(s1); IF (s1.class = Texts.Name) & ((s1.s[s1.len-1] = ".") OR (s1.nextCh = ";")) THEN pos := -1 END END; IF pos >= 0 THEN INC(del); Texts.Delete(text, pos, pos+1); Texts.OpenScanner(S, text, pos) END END END; (* LOOP *) Int(del); String(" semicolon"); IF del # 1 THEN String("s") END; String(" deleted"); Ln END END Semicolons; PROCEDURE Format*; (** Insert CR between (VAR | CONST | BEGIN | THEN | DO | LOOP) and following statement, if not only on one line *) VAR s: Texts.Scanner; v: Viewers.Viewer; text: Texts.Text; del, pos: LONGINT; BEGIN v := Oberon.MarkedViewer(); IF (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) THEN text := v.dsc.next(TF.Frame).text; Texts.OpenScanner(s, text, 0); repl := 0; LOOP IF s.eot THEN EXIT END; REPEAT Texts.Scan(S) UNTIL (s.class = Texts.Name) & ((s.s = "CONST") OR (s.s = "VAR") OR (s.s = "BEGIN") OR (s.s = "DO") OR (s.s = "THEN") OR (s.s = "LOOP") OR (s.s = "REPEAT")) OR (s.class = Texts.Char) & (s.c = "|") OR s.eot; IF s.eot THEN EXIT END; IF IF (s.class = Texts.Char) & (s.c = "|") THEN startPos := Texts.Pos(s)-1; REPEAT Texts.Scan(s) UNTIL (s.class = Texts.Char) & (s.c = ":") OR s.eot ELSE startPos := Texts.Pos(s)-s.len END; IF s.eot THEN EXIT END; insertPos := Texts.Pos(s)-1; line := s.line; REPEAT Texts.Scan(s) UNTIL s.eot OR s.line = line+1 END; IF s.eot THEN EXIT END; IF (s.class = Texts.Name) & ((s.s = "END") OR (s.s = "ELSE") OR (s.s = "ELSIF") OR (s.s = "UNTIL") OR (s.s = "TYPE") OR (s.s = "VAR") OR (s.s = "BEGIN")) OR (s.class = Texts.Char) & (s.c = "|") THEN INC(del); Texts.Delete(text, pos, pos+1); Texts.OpenScanner(S, text, Texts.Pos(S)) END END; (* LOOP *) Int(del); String(" semicolon"); IF del # 1 THEN String("s") END; String(" deleted"); Ln END END Format; PROCEDURE Deblank*; (** [num] | "^" Replace num (or 2) leading blanks in a line with 1 Tab *) VAR s: Texts.Scanner; v: Viewers.Viewer; r: Texts.Reader; text: Texts.Text; i, num, rep: INTEGER; pos, end: LONGINT; ch: CHAR; BEGIN v := Oberon.MarkedViewer(); IF (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) & Oberon.Pointer.on THEN Setup(s, end); IF s.class = Texts.Int THEN num := SHORT(s.i) ELSE num := 2 END; text := v.dsc.next(TF.Frame).text; Texts.OpenReader(r, text, 0); ch := 0X; rep := 0; LOOP Texts.OpenBuf(W.buf); WHILE (ch # 0DX) & ~r.eot DO Texts.Read(r, ch) END; IF r.eot THEN EXIT END; pos := Texts.Pos(r); Texts.Read(r, ch); i := 0; WHILE ~r.eot & (ch = " ") DO INC(i); IF i MOD num = 0 THEN Texts.Write(W, 9X) END; Texts.Read(r, ch) END; IF r.eot THEN EXIT END; IF (ch # 0DX) & (W.buf.len > 0) THEN INC(rep); end := Texts.Pos(r)-1; Texts.Delete(text, pos, end); Texts.Insert(text, pos, W.buf); Texts.OpenReader(r, text, end) END END; Int(rep); String(" replacement(s)"); Ln END END Deblank; PROCEDURE Fold*; (** Fold a program's procedures. Two viewers showing same text: lower viewer is marked! *) VAR v: Viewers.Viewer; low, up: TF.Frame; text: Texts.Text; S: Texts.Scanner; name: ARRAY 32 OF CHAR; beg, end: LONGINT; res: INTEGER; BEGIN v := Oberon.MarkedViewer(); IF (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) & (v.next IS MV.Viewer) & (v.next.dsc.next IS TF.Frame) & (v.dsc.next(TF.Frame).text = v.next.dsc.next(TF.Frame).text) THEN low := v.dsc.next(TF.Frame); text := low.text; up := v.next.dsc.next(TF.Frame); IF low.hasSel THEN beg := low.selbeg.pos ELSE beg := 0 END; Texts.OpenScanner(S, text, beg); LOOP IF S.eot THEN EXIT END; REPEAT Texts.Scan(S) UNTIL (S.class = Texts.Name) & (S.s = "PROCEDURE") OR S.eot; IF S.eot THEN EXIT END; (* S.s = "PROCEDURE" *) LOOP Texts.Scan(S); IF (S.class = Texts.Char) & (S.c = "*") & ~S.eot THEN Texts.Scan(S) END; (* PROCEDURE* P *) IF (S.class = Texts.Name) OR S.eot THEN COPY(S.s, name); EXIT ELSIF S.class = Texts.Char THEN (* receiver or forward/interrupt/code proc *) IF S.c = "(" THEN REPEAT Texts.Scan(S) UNTIL (S.class = Texts.Char) & (S.c = ")") OR S.eot ELSE REPEAT Texts.Scan(S) UNTIL (S.class = Texts.Name) & (S.s = "PROCEDURE") OR S.eot END; IF S.eot THEN EXIT END END END; (* LOOP *) IF S.eot THEN EXIT END; (* name = Name of procedure *) REPEAT Texts.Scan(S) UNTIL (S.nextCh = 0DX) OR S.eot; IF S.eot THEN EXIT END; beg := Texts.Pos(S); (* start of procedure body *) Texts.Scan(S); LOOP WHILE ((S.class # Texts.Name) OR (S.s # "END")) & ~S.eot DO Texts.Scan(S) END; IF S.eot THEN EXIT END; (* S.s = "END" *) Texts.Scan(S); IF (S.class = Texts.Name) & (S.s = name) THEN Texts.Scan(S); end := Texts.Pos(S)+1(*skip CR*); EXIT END END; (* LOOP *) IF S.eot THEN EXIT END; Texts.Write(W, 9X); Texts.Insert(text, beg-1, W.buf); TF.Show(up, beg); TF.Show(low, end); TF.SetSelection(up, beg, end); TF.SetSelection(low, beg, end); up.selend.pos := end; low.selbeg.pos := beg; name := "FoldElems.Insert"; Oberon.Call(name, Oberon.Par, FALSE, res); Texts.OpenScanner(S, text, end+2) END (* LOOP *) END END Fold; PROCEDURE Constants*; (** Generate constant declarations a = 1; b*= 2; c = 3; from a, b*, c = 1, ..; *) TYPE Entry = POINTER TO RECORD name: ARRAY 32 OF CHAR; marked, newLine: BOOLEAN; next: Entry END; VAR S: Texts.Scanner; e, head: Entry; text: Texts.Text; normal, bold: Fonts.Font; V: Viewers.Viewer; F: TF.Frame; beg, end, cpos, len, i, time: LONGINT; line: INTEGER; BEGIN Oberon.GetSelection(text, beg, end, time); IF time < 0 THEN Err("no selection!") ELSE V := Oberon.FocusViewer; IF (V.dsc # NIL) & (V.dsc.next IS TF.Frame) THEN F := V.dsc.next(TF.Frame); IF F.hasCar THEN cpos := F.carloc.pos ELSE Err("no caret!"); RETURN END ELSE Err("no viewer!"); RETURN END; IF (F.text = text) & (cpos < end) THEN Err("caret has to be after selected text!"); RETURN END; Texts.OpenScanner(S, text, beg); Texts.Scan(S); line := S.line; normal := Fonts.This("Syntax10.Scn.Fnt"); bold := Fonts.This("Syntax10b.Scn.Fnt"); NEW(head); e := head; LOOP IF S.class # Texts.Name THEN EXIT END; e.newLine := S.line > line; line := S.line; NEW(e.next); e := e.next; COPY(S.s, e.name); e.marked := FALSE; Texts.Scan(S); IF (S.class # Texts.Char) OR (S.class = Texts.Char) & (S.c = "=") THEN EXIT END; (* Assert: S.class = Texts.Char *) IF S.c = "*" THEN e.marked := TRUE; Texts.Scan(S); IF (S.class = Texts.Char) & (S.c = "=") THEN EXIT END END; Texts.Scan(S) (* read next name *) END; Texts.Scan(S); IF S.class # Texts.Int THEN Err("there should be an integer after the last const!"); RETURN END; i := S.i; e := head.next; WHILE e # NIL DO IF e.marked THEN Texts.SetFont(W, bold) END; Texts.WriteString(W, e.name); Texts.SetFont(W, normal); IF e.marked THEN Texts.WriteString(W, "*= ") ELSE Texts.WriteString(W, " = ") END; Texts.WriteInt(W, i, 0); Texts.Write(W, ";"); IF e.newLine THEN Texts.WriteLn(W) ELSE Texts.Write(W, " ") END; e := e.next; INC(i) END; Texts.WriteLn(W); IF head.next # NIL THEN len := W.buf.len; Texts.Insert(F.text, cpos, W.buf); TF.SetCaret(F(TF.Frame), cpos+len) END END END Constants; (*PROCEDURE Exports*; (** Make all exported ("*" or "-") identifiers in marked viewer bold *) VAR R: Texts.Reader; bold: Fonts.Font; text: Texts.Text; V: Viewers.Viewer; beg, end, pos: LONGINT; ch: CHAR; BEGIN V := Oberon.MarkedViewer(); IF (V = NIL) OR (V.dsc = NIL) OR (V.dsc.next = NIL) OR ~(V.dsc.next IS TF.Frame) THEN RETURN END; text := V.dsc.next(TF.Frame).text; Texts.OpenReader(R, text, 0); Texts.Read(R, ch); IF R.fnt.name = "Syntax12.Scn.Fnt" THEN bold := Fonts.This("Syntax12b.Scn.Fnt") ELSE bold := Fonts.This("Syntax10b.Scn.Fnt") END; LOOP WHILE ((ch < "A") OR ("Z" < ch) & (ch < "a") OR ("z" < ch)) & ~R.eot DO Texts.Read(R, ch) END; IF R.eot THEN EXIT END; beg := Texts.Pos(R)-1; REPEAT Texts.Read(R, ch) UNTIL (ch < "0") OR ("9" < ch) & (ch < "A") OR ("Z" < ch) & (ch < "a") OR ("z" < ch) OR R.eot; IF R.eot THEN EXIT END; end := Texts.Pos(R)-1; WHILE (ch <= " ") & ~R.eot DO Texts.Read(R, ch) END; IF R.eot THEN EXIT END; IF (ch = "*") OR (ch = "-") THEN REPEAT Texts.Read(R, ch) UNTIL (ch > " ") OR R.eot; IF R.eot THEN EXIT END; IF (ch = ":") OR (ch = "(") OR (ch = ";") OR (ch = "=") OR (ch = ",") THEN pos := Texts.Pos(R); Texts.ChangeLooks(text, beg, end, {0}, bold, 0, 0); Texts.OpenReader(R, text, pos) END END END END Exports; PROCEDURE Exports*; (** Make all exported ("*" or "-") identifiers in marked viewer bold *) VAR s: Texts.Scanner; bold: Fonts.Font; text: Texts.Text; end, idents: LONGINT; len: SHORTINT; BEGIN GetTextFromMarked(text); IF (text # NIL) & (text.len # 0) THEN Texts.OpenScanner(s, text, 0); Texts.Scan(s); IF s.fnt.name = "Syntax12.Scn.Fnt" THEN bold := Fonts.This("Syntax12b.Scn.Fnt") ELSE bold := Fonts.This("Syntax10b.Scn.Fnt") END; idents := 0; LOOP WHILE ~s.eot & (s.class # Texts.Name) DO Texts.Scan(s) END; (* get next name *) IF s.eot THEN EXIT END; IF s.s = "BEGIN" THEN (* skip everything between BEGIN and END ident *) REPEAT REPEAT Texts.Scan(s) UNTIL s.eot OR ((s.class = Texts.Name) & (s.s = "END")); (* get END *) IF s.eot THEN EXIT END; Texts.Scan(s); IF s.eot THEN EXIT END UNTIL s.class = Texts.Name; (* exit only if END ident *) Texts.Scan(s); IF s.eot THEN EXIT END END; WHILE ~s.eot & (s.class # Texts.Name) DO Texts.Scan(s) END; (* get next name *) IF s.eot THEN EXIT END; len := s.len; end := Texts.Pos(s)-1; Texts.Scan(s); IF s.eot THEN EXIT END; IF (s.class = Texts.Char) & ((s.c = "*") OR (s.c = "-")) THEN (* export mark *) Texts.Scan(s); IF s.eot THEN EXIT END; IF (s.class = Texts.Char) & ((s.c = ":") OR (s.c = "(") OR (s.c = ";") OR (s.c = "=") OR (s.c = ",")) THEN INC(idents); Texts.ChangeLooks(text, end-len, end, {0}, bold, 0, 0); Texts.OpenScanner(s, text, end); Texts.Scan(s) END END END; Int(idents); String(" ident"); IF idents # 1 THEN String("s") END; String(" marked"); Ln END END Exports; PROCEDURE Exits*; (** Make all RETURN, EXIT, and HALT statements in marked viewer bold *) VAR S: Texts.Scanner; bold: Fonts.Font; text: Texts.Text; end, exits: LONGINT; BEGIN GetTextFromMarked(text); IF (text # NIL) & (text.len # 0) THEN Texts.OpenScanner(S, text, 0); Texts.Scan(S); IF S.fnt.name = "Syntax12.Scn.Fnt" THEN bold := Fonts.This("Syntax12b.Scn.Fnt") ELSE bold := Fonts.This("Syntax10b.Scn.Fnt") END; exits := 0; LOOP WHILE ~S.eot & ((S.class # Texts.Name) OR (S.s # "RETURN") & (S.s # "EXIT") & (S.s # "HALT") & (S.s # "ASSERT")) DO Texts.Scan(S) END; IF S.eot THEN EXIT END; IF (S.nextCh <= " ") OR (S.nextCh = "(") THEN end := Texts.Pos(S)-1; INC(exits); Texts.ChangeLooks(text, end-S.len, end, {0}, bold, 0, 0); Texts.OpenScanner(S, text, end) END; Texts.Scan(S) END; Int(exits); String(" exit"); IF exits # 1 THEN String("s") END; String(" marked"); Ln END END Exits; PROCEDURE Comments*; (** Make all comments in marked viewer italic iff they do not extend over several lines *) CONST CR = 0DX; VAR R: Texts.Reader; italic: Fonts.Font; text: Texts.Text; beg, end, count: LONGINT; ch : CHAR; sameLine : BOOLEAN; BEGIN GetTextFromMarked(text); IF (text # NIL) & (text.len # 0) THEN Texts.OpenReader(R, text, 0); Texts.Read (R, ch); IF R.fnt.name = "Syntax12.Scn.Fnt" THEN italic := Fonts.This("Syntax12i.Scn.Fnt") ELSE italic := Fonts.This("Syntax10i.Scn.Fnt") END; (* the following code is not fool-proof, but works for sensible comments *) count := 0; sameLine := FALSE; WHILE ~R.eot DO IF ch = "(" THEN Texts.Read (R, ch); IF ch = "*" THEN IF count = 0 THEN beg := Texts.Pos (R) - 2 END; INC (count); sameLine := TRUE END ELSIF ch = "*" THEN Texts.Read (R, ch); IF ch = ")" THEN DEC (count); IF (count = 0) & sameLine THEN end := Texts.Pos (R); Texts.ChangeLooks(text, beg+2, end-2, {0}, italic, 0, 0); Texts.OpenReader (R, text, Texts.Pos (R)) END END ELSIF ch = CR THEN sameLine := FALSE; Texts.Read (R, ch) ELSE Texts.Read (R, ch) END; END END END Comments; PROCEDURE Lower*; (** Convert selection to lower case *) BEGIN ChangeCase("A", "Z", ORD("a")-ORD("A")) END Lower; PROCEDURE Upper*; (** Convert selection to upper case *) BEGIN ChangeCase("a", "z", ORD("A")-ORD("a")) END Upper; PROCEDURE FindMsg(keyword, msg: ARRAY OF CHAR); (** (number) | "^" Display message corresponding to number *) VAR S: Texts.Scanner; T: Texts.Text; num, end: LONGINT; PROCEDURE Err; BEGIN String("nothing found"); Ln END Err; BEGIN Setup(S, end); WHILE ~S.eot & (S.class # Texts.Int) DO Texts.Scan(S) END; IF S.eot THEN RETURN END; num := S.i; T := TF.Text(ErrorFile); IF T.len = 0 THEN RETURN END; Texts.OpenScanner(S, T, 0); REPEAT Texts.Scan(S) UNTIL S.eot OR (S.class = Texts.Name) & (S.s = keyword); IF S.eot THEN Err; RETURN END; REPEAT Texts.Scan(S) UNTIL S.eot OR (S.class = Texts.Int) & (S.i = num); IF S.eot THEN Err; RETURN END; String(msg); String(" "); Int(num); String(" = "); Texts.Append(Oberon.Log, W.buf); num := Texts.Pos(S); REPEAT Texts.Read(S, S.nextCh) UNTIL S.eot OR (S.nextCh = 0DX); IF S.eot THEN end := T.len ELSE end := Texts.Pos(S) END; Texts.Save(T, num, end, W.buf); Texts.Append(Oberon.Log, W.buf) END FindMsg; PROCEDURE Trap*; (** ("TRAP" number) | "^" Display corresponding trap message of trap number *) BEGIN FindMsg("Trap", "TRAP") END Trap; PROCEDURE Error*; (** number | "^" Display corresponding error message *) BEGIN FindMsg("Incorrect", "err") END Error; (** Viewer management *) PROCEDURE Up*; (** Move marked viewer and all above it upwards *) VAR v: Viewers.Viewer; dY: INTEGER; BEGIN IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN v := Oberon.Par.vwr ELSE v := Oberon.MarkedViewer() END; MoveUp(v, dY) END Up; PROCEDURE Down*; (** Move marked viewer and all below it downwards *) VAR v: Viewers.Viewer; BEGIN IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN v := Oberon.Par.vwr ELSE v := Oberon.MarkedViewer() END; MoveDown(v) END Down; PROCEDURE Unfocus*; (** Remove focus from focus viewer *) BEGIN Oberon.FocusViewer := Viewers.This(Oberon.Mouse.X, Oberon.Mouse.Y) END Unfocus; PROCEDURE Close*; (** Close marked viewer explicitly *) VAR V: Viewers.Viewer; U: Display.Frame; M: Viewers.ViewerMsg; BEGIN V := Oberon.MarkedViewer(); U := V.next; M.id := Viewers.modify; M.Y := V.Y; M.H := V.H + U.H; U.handle(U, M); U.Y := M.Y; U.H := M.H; WHILE U.next # V DO U := U.next END; U.next := V.next END Close; PROCEDURE Copy*; (** Copy marked viewer explicitly *) VAR F: Display.Frame; name: ARRAY 32 OF CHAR; res: INTEGER; BEGIN F := Oberon.Par.frame; Oberon.Par.frame := Oberon.MarkedViewer(); name := "System.Copy"; Oberon.Call(name, Oberon.Par, FALSE, res); Oberon.Par.frame := F END Copy; PROCEDURE Free*; (** module | "^" Free a module unconditionally *) VAR S: Texts.Scanner; end: LONGINT; m: Modules.Module; BEGIN Setup(S, end); IF S.class = Texts.Name THEN m := Modules.ThisMod(S.s); String(S.s); String(" unloading"); IF m # NIL THEN m.refcnt := 0; Modules.Free(S.s, FALSE) END; IF (m = NIL) OR (Modules.res # 0) THEN String(" failed") END; Ln END END Free; BEGIN Texts.OpenWriter(W) END Utils. Utils.FileCompare name1 name2 Utils.TextCompare name1 name2 Utils.FileCompare ^ Utils.TextCompare ^ Utils.Quote Utils.Comment Utils.Comment2 Utils.Uncomment Utils.Uncomment2 Utils.CR2LF ^ Utils.LF2CR ^ Utils.CRLF2CR ^ Utils.FromCN ^ Utils.ToCN ^ Utils.Upper Utils.Lower Utils.Clean Utils.Trap ^ Utils.Fold * Utils.Semicolon * Utils.Constants Utils.Exports Conversion of Amiga Umlauts to Ceres Utils.Convert 10 13 ^ LF -> CR Utils.Convert 196 128 ^ Utils.Convert 214 129 ^ Utils.Convert 220 130 ^ Utils.Convert 228 131 ^ Utils.Convert 246 132 ^ Utils.Convert 252 133 ^ Utils.Convert 223 146 ^ double s -> (lack of other character, use Write.Replace) Conversion of Mac (??) Umlauts to Ceres Utils.Convert 10 13 ^ LF -> CR Utils.Convert 138 131 ^ Utils.Convert 154 132 ^ Utils.Convert 159 133 ^ Utils.Convert 142 144 Utils.Convert 143 140 ^ Utils.Convert 141 147 ^