home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / oberon / system / utils.mod (.txt) < prev    next >
Oberon Text  |  1977-12-31  |  43KB  |  1,008 lines

  1. Syntax10.Scn.Fnt
  2. Syntax10i.Scn.Fnt
  3. StampElems
  4. Alloc
  5. 10 Dec 95
  6. FoldElems
  7. Syntax10b.Scn.Fnt
  8. Syntax12b.Scn.Fnt
  9. not yet completed!!!
  10. Syntax12i.Scn.Fnt
  11. LineElems
  12. Alloc
  13. Syntax10.Scn.Fnt
  14. FoldElems
  15. Syntax10.Scn.Fnt
  16. Syntax10b.Scn.Fnt
  17.         VAR
  18.             R: Texts.Reader;
  19.             text: Texts.Text;
  20.             i, beg, end, time: LONGINT;
  21.             ch: CHAR;
  22.     BEGIN
  23.         Oberon.GetSelection(text, beg, end, time);
  24.         IF time >= 0 THEN
  25.             i := beg; Texts.SetFont(W, Fonts.This("Syntax10i.Scn.Fnt"));
  26.             Texts.SetColor(W, Oberon.CurCol); Texts.SetOffset(W, Oberon.CurOff);
  27.             LOOP
  28.                 Texts.WriteString(W, str); Texts.Insert(text, i, W.buf); INC(i, LEN(str)); INC(end, LEN(str));
  29.                 IF i < end THEN
  30.                     Texts.OpenReader(R, text, i);
  31.                     REPEAT Texts.Read(R, ch); INC(i) UNTIL (ch = 0DX) OR (i = end)
  32.                 END;
  33.                 Texts.WriteString(W, "*)");
  34.                 IF ch # 0DX THEN Texts.Insert(text, i, W.buf); EXIT END;
  35.                 Texts.Insert(text, i-1, W.buf); INC(i, 2); INC(end, 2);
  36.                 IF i = end THEN EXIT END
  37.             END;
  38.             Texts.SetFont(W, Fonts.Default)
  39.         END
  40.     END Comm;
  41. Syntax10.Scn.Fnt
  42. Syntax10b.Scn.Fnt
  43. Syntax10i.Scn.Fnt
  44.         VAR
  45.             R: Texts.Reader;
  46.             text: Texts.Text;
  47.             pos, i, beg, end, time: LONGINT;
  48.             ch: CHAR;
  49.     BEGIN
  50.         Oberon.GetSelection(text, beg, end, time);
  51.         IF time >= 0 THEN
  52.             Texts.OpenReader(R, text, beg);
  53.             i := beg;
  54.             LOOP
  55.                 Texts.OpenReader(R, text, i);
  56.                 REPEAT Texts.Read(R, ch); INC(i) UNTIL (ch = "(") OR (i = end);
  57.                 IF i+1 >= end THEN EXIT END;
  58.                 pos := i-1;
  59.                 Texts.Read(R, ch); INC(i);
  60.                 IF ch = "*" THEN
  61.                     Texts.Delete(text, pos, i+d); DEC(end, 2+d); DEC(i, 2+d);
  62.                     Texts.OpenReader(R, text, pos)
  63.                 END;
  64.                 REPEAT Texts.Read(R, ch); INC(i) UNTIL (ch = 0DX) OR (i >= end);
  65.                 IF i > pos+1 THEN
  66.                     IF i > end THEN i := end ELSIF ch = 0DX THEN DEC(i) END;
  67.                     Texts.Delete(text, i-2+d, i+d); DEC(end, 2); DEC(i, 2)
  68.                 END;
  69.                 IF i >= end THEN EXIT END
  70.             END    (*LOOP*)
  71.         END
  72.     END Uncomm;
  73. Syntax10b.Scn.Fnt
  74. Syntax10i.Scn.Fnt
  75.     PROCEDURE Comm(str: ARRAY OF CHAR);
  76.     PROCEDURE Uncomm(d: LONGINT);
  77.     PROCEDURE Comment*;    (** Comment all lines in selection  ("(* ... *)") **)
  78.     BEGIN Comm("(*")
  79.     END Comment;
  80.     PROCEDURE Comment2*;    (** Comment all lines in selection  ("(*<< ... *)") **)
  81.     BEGIN Comm("(*<<")
  82.     END Comment2;
  83.     PROCEDURE Uncomment*;    (** Remove (* ... *) comments in selection **)
  84.     BEGIN Uncomm(0)
  85.     END Uncomment;
  86.     PROCEDURE Uncomment2*;    (** Remove (*<< ... *) comments in selection **)
  87.     BEGIN Uncomm(2)
  88.     END Uncomment2;
  89. Courier10.Scn.Fnt
  90. MODULE Utils;    (** SHML 12 Dec 91, 
  91.     IMPORT
  92.         Display, Files, Modules, Input, Fonts, Texts, TF := TextFrames,
  93.         Viewers, MV := MenuViewers, Oberon;
  94.     CONST ErrorFile = "OberonErrors.Text";
  95.     VAR W: Texts.Writer; MarkedViewer: Viewers.Viewer;
  96.     PROCEDURE String(s: ARRAY OF CHAR);    BEGIN Texts.WriteString (W, s) END String;
  97.     PROCEDURE Int(i: LONGINT);    BEGIN Texts.WriteInt(W, i, 0) END Int;
  98.     PROCEDURE Ln;    BEGIN Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) END Ln;
  99.     PROCEDURE Err(s: ARRAY OF CHAR);    BEGIN String(s); Ln END Err;
  100.     PROCEDURE Setup(VAR S: Texts.Scanner; VAR end: LONGINT);    (* Set up S on parameter list *)    
  101.         VAR Sel: Texts.Text; beg, time: LONGINT;
  102.     BEGIN
  103.         Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
  104.         IF (S.class = Texts.Char) & (S.line = 0) & (S.c = "^") OR (Oberon.Par.frame = Oberon.Par.vwr.dsc) THEN
  105.             Oberon.GetSelection(Sel, beg, end, time);
  106.             IF time >= 0 THEN Texts.OpenScanner(S, Sel, beg); Texts.Scan(S) ELSE end := -1 END
  107.         ELSE end := Oberon.Par.text.len
  108.         END
  109.     END Setup;
  110.     PROCEDURE GetTextFromMarked(VAR text: Texts.Text);
  111.         VAR v: Viewers.Viewer;
  112.     BEGIN
  113.         v := Oberon.MarkedViewer();
  114.         IF (v # NIL) & (v IS MV.Viewer) & (v.dsc # NIL) & (v.dsc.next # NIL) & (v.dsc.next IS TF.Frame) THEN
  115.             text := v.dsc.next(TF.Frame).text
  116.         ELSE text := NIL
  117.         END
  118.     END GetTextFromMarked;
  119.     PROCEDURE Conv(from, to: CHAR; eat: BOOLEAN);
  120.     (* Convert from characters in a file into to characters, unless eat is TRUE *)
  121.         VAR
  122.             S: Texts.Scanner; in, out: Files.File; In, Out: Files.Rider; i, end: LONGINT; ch: CHAR;
  123.             wr: Texts.Writer; oldName: ARRAY 64 OF CHAR;
  124.     BEGIN
  125.         Texts.OpenWriter(wr); Texts.WriteString(wr, "System.RenameFiles"); Texts.WriteLn(wr);
  126.         Setup(S, end);
  127.         LOOP
  128.             IF S.class # Texts.Name THEN EXIT END;
  129.             in := Files.Old(S.s);
  130.             IF in # NIL THEN
  131.                 String(S.s); COPY(S.s, oldName);
  132.                 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;
  133.                 String(" => "); String(S.s); Ln;
  134.                 Texts.Write(wr, 9X); Texts.WriteString(wr, S.s); Texts.WriteString(wr, " => ");
  135.                 Texts.WriteString(wr, oldName); Texts.WriteLn(wr);
  136.                 out := Files.New(S.s);
  137.                 Files.Set(In, in, 0); Files.Set(Out, out, 0);
  138.                 FOR i := 1 TO Files.Length(in) DO
  139.                     Files.Read(In, ch);
  140.                     IF ch = from THEN
  141.                         IF ~eat THEN Files.Write(Out, to) END
  142.                     ELSE Files.Write(Out, ch) END
  143.                 END;
  144.                 Files.Register(out)
  145.             END;
  146.             IF Texts.Pos(S) >= end THEN EXIT END;
  147.             Texts.Scan(S)
  148.         END;
  149.         String("done"); Ln;
  150.         Texts.Write(wr, "~"); Texts.WriteLn(wr); Texts.Append(Oberon.Log, wr.buf)
  151.     END Conv;
  152.     (*PROCEDURE Convert2(from, to: CHAR);
  153.     (* Convert from characters after CR in a text into to characters *)
  154.         VAR S: Texts.Scanner; in, out: Texts.Text; In: Texts.Reader; Out: Texts.Writer; i: LONGINT; ch: CHAR;
  155.     BEGIN
  156.     (*    Setup(S);
  157.         WHILE S.class = Texts.Name DO
  158.             in := Texts.Open(S.s);
  159.             IF in # NIL THEN
  160.                 String(S.s);
  161.                 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;
  162.                 String(" => "); String(S.s); Ln;
  163.                 out := Files.New(S.s);
  164.                 Files.Set(In, in, 0); Files.Set(Out, out, 0);
  165.                 WHILE ~In.eot DO
  166.                     Texts.Read(In, ch); Texts.Write(Out, ch);
  167.                     IF ch = 0DX THEN
  168.                         Texts.Read(In, ch);
  169.                         WHILE ch = from DO
  170.                             Texts.Write(Out, to);
  171.                             Texts.Read(In, ch)
  172.                         END;
  173.                         Texts.Write(Out, ch)
  174.                     END
  175.                 END;
  176.                 Texts.Append(t, Out.buf); Texts.Store(t, out, 0, len);
  177.                 Files.Register(out)
  178.             END;
  179.             Texts.Scan(S)
  180.         END;
  181.         String("done"); Ln*)
  182.     END Convert2;
  183.     PROCEDURE ChangeCase(low, high: CHAR; diff: INTEGER);
  184.     (* Convert all chars in [low..high] in selection to chars+diff *)
  185.         VAR R: Texts.Reader; text: Texts.Text; msg: Texts.CopyMsg; i, beg, end: LONGINT; ch: CHAR;
  186.     BEGIN
  187.         Oberon.GetSelection(text, beg, end, i);
  188.         IF i >= 0 THEN
  189.             Texts.OpenReader(R, text, beg); i := beg;
  190.             REPEAT
  191.                 Texts.Read(R, ch);
  192.                 Texts.SetFont(W, R.fnt); Texts.SetColor(W, R.col); Texts.SetOffset(W, R.voff);
  193.                 IF (low <= ch) & (ch <= high) THEN Texts.Write(W, CHR(ORD(ch)+diff))
  194.                 ELSIF R.elem # NIL THEN R.elem.handle(R.elem, msg); Texts.WriteElem(W, msg.e)
  195.                 ELSE Texts.Write(W, ch)
  196.                 END;
  197.                 INC(i)
  198.             UNTIL i = end;
  199.             Texts.Delete(text, beg, end); Texts.Insert(text, beg, W.buf);
  200.             Texts.SetFont(W, Fonts.Default)
  201.         END
  202.     END ChangeCase;
  203.     PROCEDURE CloseOpen(VAR self: Viewers.Viewer; dY: INTEGER);    (* Close self and open it at old y + dY *)
  204.         VAR handler: Display.Handler; oldX, oldY: INTEGER;
  205.     BEGIN
  206.         IF dY # 0 THEN
  207.             handler := self.handle;
  208.             oldX := self.X; oldY := self.Y+self.H;
  209.             Viewers.Close(self);
  210.             self := MV.New(self.dsc, self.dsc.next, TF.menuH, oldX, oldY+dY);
  211.             self.handle := handler
  212.         END
  213.     END CloseOpen;
  214.     PROCEDURE MoveUp(self: Viewers.Viewer; VAR dY: INTEGER);    (* Move self and all viewers above up *)
  215.         VAR upper: Viewers.Viewer;
  216.     BEGIN
  217.         upper := Viewers.Next(self);
  218.         IF upper.state = 1 THEN dY := upper.H    (* filler viewer *)
  219.         ELSE MoveUp(upper, dY)
  220.         END;
  221.         CloseOpen(self, dY);    (* extend own frame by maximal extension allowed by upper *)
  222.         dY := self.H-Viewers.minH    (* own maximal reduction *)
  223.     END MoveUp;
  224.     PROCEDURE MoveDown(self: Viewers.Viewer);    (* Move self and all viewers below down *)
  225.         VAR upper: Viewers.Viewer;
  226.     BEGIN
  227.         upper := self;
  228.         REPEAT upper := Viewers.Next(upper) UNTIL upper.state = 1;    (* find filler viewer *)
  229.         upper := Viewers.Next(upper);
  230.         WHILE upper # self DO
  231.             CloseOpen(upper, -(upper.H-Viewers.minH)); upper := Viewers.Next(upper)
  232.         END;
  233.         CloseOpen(upper, -(upper.H-Viewers.minH))
  234.     END MoveDown;
  235.     (** Commands *) 
  236.     PROCEDURE Compare*;    (** ({name1 name2} "~" | "^")    Compare two files *)
  237.         CONST Size = SIZE(LONGINT); BufSize = 4096 DIV Size;
  238.         VAR
  239.             S: Texts.Scanner;
  240.             name: ARRAY 32 OF CHAR;
  241.             f1, f2: Files.File;
  242.             R1, R2: Files.Rider;
  243.             l1, l2, end, i: LONGINT;
  244.             ch1, ch2: CHAR;
  245.             buf1, buf2: ARRAY BufSize OF LONGINT;
  246.     BEGIN
  247.         Setup(S, end);    (* string comparison *)
  248.         LOOP
  249.             IF S.class # Texts.Name THEN EXIT END;
  250.             COPY(S.s, name); Texts.Scan(S);
  251.             IF S.class # Texts.Name THEN EXIT END;
  252.             f1 := Files.Old(name); f2 := Files.Old(S.s);
  253.             IF (f1 # NIL) & (f2 # NIL) THEN
  254.                 String("comparing "); String(name); String(" and "); String(S.s); Ln;
  255.                 Files.Set(R1, f1, 0); Files.Set(R2, f2, 0); l1 := Files.Length(f1); l2 := Files.Length(f2);
  256.                 IF l1 # l2 THEN String("Files differ in length"); Ln
  257.                 ELSE
  258.                     l1 := l2 MOD Size; DEC(l2, l1);
  259.                     LOOP
  260.                         IF l1 = 0 THEN EXIT END;
  261.                         Files.Read(R1, ch1); Files.Read(R2, ch2);
  262.                         IF ch1 # ch2 THEN String("pos "); Int(Files.Pos(R1)); Ln; EXIT END;
  263.                         DEC(l1)
  264.                     END;
  265.                     IF l1 = 0 THEN
  266.                         LOOP
  267.                             IF l2 = 0 THEN EXIT END;
  268.                             Files.ReadBytes(R1, buf1, BufSize); Files.ReadBytes(R2, buf2, BufSize);
  269.                             i := 0; WHILE (i < BufSize) & (buf1[i] = buf2[i]) DO INC(i) END;
  270.                             IF i < BufSize THEN String("pos "); Int(Files.Pos(R1)-BufSize*Size); Ln; EXIT END;
  271.                             DEC(l2, BufSize*Size)
  272.                         END
  273.                     END
  274.                 END;
  275.                 Files.Close(f1); Files.Close(f2)
  276.             END;
  277.             IF Texts.Pos(S) >= end THEN EXIT END;
  278.             Texts.Scan(S)
  279.         END
  280.     END Compare;
  281.     PROCEDURE FileCompare*;    (** ({name1 name2} "~" | "^")    Compare two files and report differences *)
  282.         VAR
  283.             S: Texts.Scanner;
  284.             name: ARRAY 32 OF CHAR;
  285.             f1, f2: Files.File;
  286.             R1, R2: Files.Rider;
  287.             l1, l2, end: LONGINT;
  288.             ch1, ch2: CHAR;
  289.             same: BOOLEAN;
  290.             X,Y: INTEGER; keys: SET;
  291.     BEGIN
  292.         Setup(S, end);
  293.         LOOP
  294.             IF S.class # Texts.Name THEN EXIT END;
  295.             COPY(S.s, name); Texts.Scan(S);
  296.             IF S.class # Texts.Name THEN EXIT END;
  297.             f1 := Files.Old(name); f2 := Files.Old(S.s);
  298.             IF (f1 # NIL) & (f2 # NIL) THEN
  299.                 String("comparing "); String(name); String(" and "); String(S.s); Ln;
  300.                 Files.Set(R1, f1, 0); Files.Set(R2, f2, 0); l1 := Files.Length(f1); l2 := Files.Length(f2);
  301.                 IF l1 # l2 THEN String("Files differ in length"); Ln END;
  302.                 IF l2 < l1 THEN l1 := l2 END;
  303.                 same := TRUE; l2 := 1; keys := {};
  304.                 WHILE (l2 <= l1) & (keys # {0, 1, 2}) DO
  305.                     Files.Read(R1, ch1); Files.Read(R2, ch2);
  306.                     IF ch1 # ch2 THEN same := FALSE; String("pos "); Int(Files.Pos(R1)); Ln END;
  307.                     Input.Mouse(keys, X, Y); INC(l2)
  308.                 END;
  309.                 Files.Close(f1); Files.Close(f2);
  310.                 IF same THEN String("Files are identical"); Ln END
  311.             END;
  312.             IF (keys = {0, 1, 2}) OR (Texts.Pos(S) >= end) THEN EXIT END;
  313.             Texts.Scan(S)
  314.         END
  315.     END FileCompare;
  316.     PROCEDURE TextCompare*;    (** ({name1 name2} "~" | "^")    Compare two texts and report differences *)
  317.         VAR
  318.             S: Texts.Scanner;
  319.             name: ARRAY 32 OF CHAR;
  320.             t1, t2: Texts.Text;
  321.             R1, R2: Texts.Reader;
  322.             l1, l2, end: LONGINT;
  323.             ch1, ch2: CHAR;
  324.             same: BOOLEAN;
  325.             X,Y: INTEGER; keys: SET;
  326.     BEGIN
  327.         Setup(S, end);
  328.         LOOP
  329.             IF S.class # Texts.Name THEN EXIT END;
  330.             COPY(S.s, name); Texts.Scan(S);
  331.             IF S.class # Texts.Name THEN EXIT END;
  332.             t1 := TF.Text(name); t2 := TF.Text(S.s);
  333.             String("comparing "); String(name); String(" and "); String(S.s); Ln;
  334.             Texts.OpenReader(R1, t1, 0); Texts.OpenReader(R2, t2, 0); l1 := t1.len; l2 := t2.len;
  335.             IF l1 # l2 THEN String("Texts differ in length"); Ln END;
  336.             IF l2 < l1 THEN l1 := l2 END;
  337.             same := TRUE; l2 := 1; keys := {};
  338.             WHILE (l2 <= l1) & (keys # {0, 1, 2}) DO
  339.                 Texts.Read(R1, ch1); Texts.Read(R2, ch2);
  340.                 IF ch1 # ch2 THEN same := FALSE; String("pos "); Int(Texts.Pos(R1)); Ln END;
  341.                 Input.Mouse(keys, X, Y); INC(l2)
  342.             END;
  343.             IF same THEN String("Texts are identical"); Ln END;
  344.             IF (keys = {0, 1, 2}) OR (Texts.Pos(S) >= end) THEN EXIT END;
  345.             Texts.Scan(S)
  346.         END
  347.     END TextCompare;
  348.     PROCEDURE Comment*;    (** Comment selection with "(* ... *)" *)
  349.         VAR
  350.             text: Texts.Text; r: Texts.Reader; ch: CHAR;
  351.             beg, end, time: LONGINT;
  352.             front, back: BOOLEAN;
  353.     BEGIN
  354.         Oberon.GetSelection(text, beg, end, time);
  355.         IF time >= 0 THEN
  356.             front := FALSE; back := FALSE;
  357.             IF beg = 0 THEN front := TRUE
  358.             ELSE
  359.                 Texts.OpenReader(r, text, beg-1); Texts.Read(r, ch);
  360.                 IF ch = 0DX THEN front := TRUE END
  361.             END;
  362.             IF end < text.len THEN
  363.                 Texts.OpenReader(r, text, end-1); Texts.Read(r, ch);
  364.                 IF ch = 0DX THEN back := TRUE END
  365.             END;
  366.             Texts.Write(W, "("); Texts.Write(W, "*");
  367.             IF front THEN Texts.WriteLn(W); INC(end) END;
  368.             Texts.Insert(text, beg, W.buf);
  369.             Texts.Write(W, "*"); Texts.Write(W, ")");
  370.             IF back THEN Texts.WriteLn(W) END;
  371.             Texts.Insert(text, end+2, W.buf)
  372.         END
  373.     END Comment;
  374.     PROCEDURE Comment2*;    (** Comment selection with "(*<< ... *)" *)
  375.         VAR
  376.             text: Texts.Text;
  377.             beg, end, time: LONGINT;
  378.     BEGIN
  379.         Oberon.GetSelection(text, beg, end, time);
  380.         IF time >= 0 THEN
  381.             Texts.Write(W, "("); Texts.WriteString(W, "*<<"); Texts.WriteLn(W); Texts.Insert(text, beg, W.buf);
  382.             Texts.Write(W, "*");Texts.Write(W, ")"); Texts.WriteLn(W); Texts.Insert(text, end+4, W.buf)
  383.         END
  384.     END Comment2;
  385.     PROCEDURE Uncomment*;    (** Remove (* ... *) comments around selection *)
  386.         VAR text: Texts.Text; beg, end, time: LONGINT;
  387.         PROCEDURE DelHead(pos: LONGINT): BOOLEAN;
  388.             VAR r: Texts.Reader; ch: CHAR;
  389.         BEGIN
  390.             Texts.OpenReader(r, text, pos); Texts.Read(r, ch);
  391.             IF ~r.eot & (ch = "(") THEN
  392.                 Texts.Read(r, ch);
  393.                 IF ~r.eot & (ch = "*") THEN
  394.                     Texts.Read(r, ch);
  395.                     IF ~r.eot THEN Texts.Delete(text, pos, pos+2); RETURN TRUE END
  396.                 END
  397.             END;
  398.             RETURN FALSE
  399.         END DelHead;
  400.         PROCEDURE DelTail(pos: LONGINT): BOOLEAN;
  401.             VAR r: Texts.Reader; ch: CHAR;
  402.         BEGIN
  403.             Texts.OpenReader(r, text, pos); Texts.Read(r, ch);
  404.             IF ~r.eot & (ch = "*") THEN
  405.                 Texts.Read(r, ch);
  406.                 IF ~r.eot & (ch = ")") THEN
  407.                     Texts.Read(r, ch);
  408.                     IF ~r.eot THEN Texts.Delete(text, pos, pos+2); RETURN TRUE END
  409.                 END
  410.             END;
  411.             RETURN FALSE
  412.         END DelTail;
  413.     BEGIN
  414.         Oberon.GetSelection(text, beg, end, time);
  415.         IF (time >= 0) & (DelHead(beg) OR DelHead(beg-3)) & (DelTail(end-6) OR DelTail(end-3)) THEN END
  416.     END Uncomment;
  417.     PROCEDURE Uncomment2*;    (** Remove (*<< ... *) comments around selection *)
  418.         VAR text: Texts.Text; beg, end, time: LONGINT;
  419.         PROCEDURE DelHead(pos: LONGINT): BOOLEAN;
  420.             VAR r: Texts.Reader; ch: CHAR;
  421.         BEGIN
  422.             Texts.OpenReader(r, text, pos); Texts.Read(r, ch);
  423.             IF ~r.eot & (ch = "(") THEN
  424.                 Texts.Read(r, ch);
  425.                 IF ~r.eot & (ch = "*") THEN
  426.                     Texts.Read(r, ch);
  427.                     IF ~r.eot & (ch = "<") THEN
  428.                         Texts.Read(r, ch);
  429.                         IF ~r.eot & (ch = "<") THEN
  430.                             Texts.Read(r, ch);
  431.                             IF ~r.eot THEN Texts.Delete(text, pos, pos+4); RETURN TRUE END
  432.                         END
  433.                     END
  434.                 END
  435.             END;
  436.             RETURN FALSE
  437.         END DelHead;
  438.         PROCEDURE DelTail(pos: LONGINT): BOOLEAN;
  439.             VAR r: Texts.Reader; ch: CHAR;
  440.         BEGIN
  441.             Texts.OpenReader(r, text, pos); Texts.Read(r, ch);
  442.             IF ~r.eot & (ch = "*") THEN
  443.                 Texts.Read(r, ch);
  444.                 IF ~r.eot & (ch = ")") THEN
  445.                     Texts.Read(r, ch);
  446.                     IF ~r.eot THEN Texts.Delete(text, pos, pos+2); RETURN TRUE END
  447.                 END
  448.             END;
  449.             RETURN FALSE
  450.         END DelTail;
  451.     BEGIN
  452.         Oberon.GetSelection(text, beg, end, time);
  453.         IF (time >= 0) & (DelHead(beg) OR DelHead(beg-5)) & (DelTail(end-8) OR DelTail(end-5)) THEN END
  454.     END Uncomment2;
  455.     PROCEDURE CR2LF*;    (** ({name} "~" | "^")    Convert Oberon-files to Unix-files (CR to LF) *)
  456.     BEGIN Conv(0DX, 0AX, FALSE)
  457.     END CR2LF;
  458.     PROCEDURE LF2CR*;    (** ({name} "~" | "^")    Convert Unix-files to Oberon-files (LF to CR) *)
  459.     BEGIN Conv(0AX, 0DX, FALSE)
  460.     END LF2CR;
  461.     PROCEDURE CRLF2CR*;    (** ({name} "~" | "^")    Convert PC-files to Oberon-files (CR LF to CR) *)
  462.     BEGIN Conv(0AX, 0DX, TRUE)
  463.     END CRLF2CR;
  464.     PROCEDURE LineBreak2CRLF*;    (** ({name} "~" | "^")    Convert Oberon/Unix-files to PC-files (CR/LF to CR LF) *)
  465.         VAR
  466.             S: Texts.Scanner; in, out: Files.File; In, Out: Files.Rider; i, end: LONGINT; ch: CHAR;
  467.             wr: Texts.Writer; oldName: ARRAY 64 OF CHAR;
  468.     BEGIN
  469.         Texts.OpenWriter(wr); Texts.WriteString(wr, "System.RenameFiles"); Texts.WriteLn(wr);
  470.         Setup(S, end);
  471.         LOOP
  472.             IF S.class # Texts.Name THEN EXIT END;
  473.             in := Files.Old(S.s);
  474.             IF in # NIL THEN
  475.                 String(S.s); COPY(S.s, oldName);
  476.                 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;
  477.                 String(" => "); String(S.s); Ln;
  478.                 Texts.Write(wr, 9X); Texts.WriteString(wr, S.s); Texts.WriteString(wr, " => ");
  479.                 Texts.WriteString(wr, oldName); Texts.WriteLn(wr);
  480.                 out := Files.New(S.s);
  481.                 Files.Set(In, in, 0); Files.Set(Out, out, 0);
  482.                 FOR i := 1 TO Files.Length(in) DO
  483.                     Files.Read(In, ch);
  484.                     IF (ch = 0DX) OR (ch = 0AX) THEN Files.Write(Out, 0DX); Files.Write(Out, 0AX)
  485.                     ELSE Files.Write(Out, ch)
  486.                     END
  487.                 END;
  488.                 Files.Register(out)
  489.             END;
  490.             IF Texts.Pos(S) >= end THEN EXIT END;
  491.             Texts.Scan(S)
  492.         END;
  493.         String("done"); Ln;
  494.         Texts.Write(wr, "~"); Texts.WriteLn(wr); Texts.Append(Oberon.Log, wr.buf)
  495.     END LineBreak2CRLF;
  496.     PROCEDURE Convert*;    (** from to ({name} "~" | "^")    Convert from chars into to chars in all files name *)
  497.         VAR S: Texts.Scanner; from, to: CHAR; end: LONGINT;
  498.     BEGIN
  499.         Setup(S, end);
  500.         IF S.class # Texts.Int THEN RETURN END;
  501.         from := CHR(S.i); Texts.Scan(S);
  502.         IF S.class # Texts.Int THEN RETURN END;
  503.         to := CHR(S.i); Oberon.Par.pos := Texts.Pos(S)-1;
  504.         Conv(from, to, FALSE)
  505.     END Convert;
  506.     (*PROCEDURE FromCN*;    (** ({name} "~" | "^")    Convert CN-files to SHML-files (CR {blank} to CR {tab}) *) *)
  507.     (*BEGIN Convert2(" ", 09X) *)
  508.     (*END FromCN; *)
  509.     (*PROCEDURE ToCN*;    (** ({name} "~" | "^")    Convert SHML-files to CN-files (CR {tab} to CR {blank}) *) *)
  510.     (*BEGIN Convert2(09X, " ") *)
  511.     (*END ToCN; *)
  512.     PROCEDURE NonPrintable*;    (** Set caret before (next) non_printable character in marked viewer *)
  513.         VAR
  514.             R: Texts.Reader; v: Viewers.Viewer; f: TF.Frame; text: Texts.Text;
  515.             dx, x, y, w, h: INTEGER; p, pos: LONGINT; ch: CHAR;
  516.     BEGIN
  517.         v := Oberon.MarkedViewer();
  518.         IF (v # NIL) & (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) THEN
  519.             IF v # MarkedViewer THEN MarkedViewer := v END;
  520.             f := v.dsc.next(TF.Frame);
  521.             IF f.hasCar THEN pos := f.carloc.pos+1 ELSE pos := 0 END
  522.         ELSE RETURN
  523.         END;
  524.         text := f.text; Texts.OpenReader(R, text, pos);
  525.         REPEAT Texts.Read(R, ch); Display.GetChar(Fonts.Default.raster, ch, dx, x, y, w, h, p)
  526.         UNTIL R.eot OR (dx = 0) & (ch # 0DX);
  527.         IF ~R.eot THEN
  528.             pos := Texts.Pos(R); p := pos-200;
  529.             IF p < 0 THEN p := 0 END;
  530.             TF.Show(f, p); TF.SetCaret(f, pos);
  531.             String("ASCII code = "); Int(ORD(ch)); Ln
  532.         ELSE String("none found"); Ln
  533.         END
  534.     END NonPrintable;
  535.     PROCEDURE Clean*;    (** Delete spaces and tabs at end of lines in marked viewer *)
  536.         VAR R: Texts.Reader; text: Texts.Text; del, pos: LONGINT; ch: CHAR;
  537.     BEGIN
  538.         GetTextFromMarked(text);
  539.         IF (text # NIL) & (text.len # 0) THEN
  540.             Texts.OpenReader(R, text, 0); del := 0;
  541.             LOOP
  542.                 IF Texts.Pos(R) >= text.len THEN EXIT END;
  543.                 REPEAT Texts.Read(R, ch) UNTIL (ch = " ") OR (ch = 9X) OR R.eot;
  544.                 IF R.eot THEN EXIT END;
  545.                 pos := Texts.Pos(R)-1;
  546.                 REPEAT Texts.Read(R, ch) UNTIL (ch # " ") & (ch # 9X) OR R.eot;
  547.                 IF R.eot THEN EXIT
  548.                 ELSIF ch = 0DX THEN
  549.                     INC(del, Texts.Pos(R)-pos-1); Texts.Delete(text, pos, Texts.Pos(R)-1);
  550.                     Texts.OpenReader(R, text, pos+1)
  551.                 END
  552.             END;
  553.             Int(del); String(" char"); IF del # 1 THEN String("s") END; String(" deleted"); Ln
  554.         END
  555.     END Clean;
  556.     PROCEDURE Semicolons*;    (** Delete superfluous semicolons in marked viewer *)
  557.         CONST None = 0; End = 1; EndIdent = 2;
  558.         VAR S, s1: Texts.Scanner; text: Texts.Text; del, pos: LONGINT; state: INTEGER;
  559.     BEGIN
  560.         GetTextFromMarked(text);
  561.         IF (text # NIL) & (text.len # 0) THEN
  562.             Texts.OpenScanner(S, text, 0); S.class := Texts.Inval; del := 0;
  563.             LOOP
  564.                 IF S.eot THEN EXIT END;
  565.                 state := None;
  566.                 REPEAT
  567.                     IF (state IN {None, End}) & (S.class = Texts.Name) & (S.s = "END") THEN state := End
  568.                     ELSIF (state = End) & (S.class = Texts.Name) & (S.s # "END") THEN state := EndIdent
  569.                     ELSIF (S.class # Texts.Char) OR (S.c # ";") THEN state := None
  570.                     END;
  571.                     Texts.Scan(S)
  572.                 UNTIL (S.class = Texts.Char) & (S.c = ";") OR S.eot;
  573.                 IF S.eot THEN EXIT END;
  574.                 pos := Texts.Pos(S)-2;
  575.                 (* S.c = ";" *)
  576.                 Texts.Scan(S);
  577.                 IF S.eot THEN EXIT END;
  578.                 IF (S.class = Texts.Name) & ((S.s = "END") OR (S.s = "ELSE") OR (S.s = "ELSIF") OR (S.s = "UNTIL"))
  579.                         OR (S.class = Texts.Char) & (S.c = "|") THEN
  580.                     IF (S.class = Texts.Name) & (S.s = "END") & (state = EndIdent) THEN
  581.                         (* don't delete if END ident; END ident. *)
  582.                         Texts.OpenScanner(s1, text, Texts.Pos(S)); Texts.Scan(s1);
  583.                         IF (s1.class = Texts.Name) & ((s1.s[s1.len-1] = ".") OR (s1.nextCh = ";")) THEN pos := -1 END
  584.                     END;
  585.                     IF pos >= 0 THEN
  586.                         INC(del); Texts.Delete(text, pos, pos+1);
  587.                         Texts.OpenScanner(S, text, pos)
  588.                     END
  589.                 END
  590.             END;    (* LOOP *)
  591.             Int(del); String(" semicolon"); IF del # 1 THEN String("s") END; String(" deleted"); Ln
  592.         END
  593.     END Semicolons;
  594.     PROCEDURE Format*;
  595.         (** Insert CR between (VAR | CONST | BEGIN | THEN | DO | LOOP) and following statement, if not only on one line *)
  596.         VAR s: Texts.Scanner; v: Viewers.Viewer; text: Texts.Text; del, pos: LONGINT;
  597.     BEGIN
  598.         v := Oberon.MarkedViewer();
  599.         IF (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) THEN
  600.             text := v.dsc.next(TF.Frame).text; Texts.OpenScanner(s, text, 0); repl := 0;
  601.             LOOP
  602.                 IF s.eot THEN EXIT END;
  603.                 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;
  604.                 IF s.eot THEN EXIT END;
  605.                 IF 
  606.                 IF (s.class = Texts.Char) & (s.c = "|") THEN
  607.                     startPos := Texts.Pos(s)-1;
  608.                     REPEAT Texts.Scan(s) UNTIL (s.class = Texts.Char) & (s.c = ":") OR s.eot
  609.                 ELSE startPos := Texts.Pos(s)-s.len
  610.                 END;
  611.                 IF s.eot THEN EXIT END;
  612.                 insertPos := Texts.Pos(s)-1; line := s.line;
  613.                 REPEAT Texts.Scan(s) UNTIL s.eot OR s.line = line+1 END;
  614.                 IF s.eot THEN EXIT END;
  615.                 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"))
  616.                         OR (s.class = Texts.Char) & (s.c = "|") THEN
  617.                     INC(del); Texts.Delete(text, pos, pos+1);
  618.                     Texts.OpenScanner(S, text, Texts.Pos(S))
  619.                 END
  620.             END;    (* LOOP *)
  621.             Int(del); String(" semicolon"); IF del # 1 THEN String("s") END; String(" deleted"); Ln
  622.         END
  623.     END Format;
  624.     PROCEDURE Deblank*;    (** [num] | "^"    Replace num (or 2) leading blanks in a line with 1 Tab *)
  625.         VAR
  626.             s: Texts.Scanner; v: Viewers.Viewer; r: Texts.Reader; text: Texts.Text;
  627.             i, num, rep: INTEGER; pos, end: LONGINT; ch: CHAR;
  628.     BEGIN
  629.         v := Oberon.MarkedViewer();
  630.         IF (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) & Oberon.Pointer.on THEN
  631.             Setup(s, end); IF s.class = Texts.Int THEN num := SHORT(s.i) ELSE num := 2 END;
  632.             text := v.dsc.next(TF.Frame).text; Texts.OpenReader(r, text, 0); ch := 0X; rep := 0;
  633.             LOOP
  634.                 Texts.OpenBuf(W.buf);
  635.                 WHILE (ch # 0DX) & ~r.eot DO Texts.Read(r, ch) END;
  636.                 IF r.eot THEN EXIT END;
  637.                 pos := Texts.Pos(r); Texts.Read(r, ch); i := 0;
  638.                 WHILE ~r.eot & (ch = " ") DO
  639.                     INC(i);
  640.                     IF i MOD num = 0 THEN Texts.Write(W, 9X) END;
  641.                     Texts.Read(r, ch)
  642.                 END;
  643.                 IF r.eot THEN EXIT END;
  644.                 IF (ch # 0DX) & (W.buf.len > 0) THEN
  645.                     INC(rep);
  646.                     end := Texts.Pos(r)-1;
  647.                     Texts.Delete(text, pos, end); Texts.Insert(text, pos, W.buf);
  648.                     Texts.OpenReader(r, text, end)
  649.                 END
  650.             END;
  651.             Int(rep); String(" replacement(s)"); Ln
  652.         END
  653.     END Deblank;
  654.     PROCEDURE Fold*;    (** Fold a program's procedures. Two viewers showing same text: lower viewer is marked! *)
  655.         VAR
  656.             v: Viewers.Viewer; low, up: TF.Frame; text: Texts.Text; S: Texts.Scanner;
  657.             name: ARRAY 32 OF CHAR; beg, end: LONGINT; res: INTEGER;
  658.     BEGIN
  659.         v := Oberon.MarkedViewer();
  660.         IF (v IS MV.Viewer) & (v.dsc.next IS TF.Frame) & (v.next IS MV.Viewer) & (v.next.dsc.next IS TF.Frame) &
  661.                 (v.dsc.next(TF.Frame).text = v.next.dsc.next(TF.Frame).text) THEN
  662.             low := v.dsc.next(TF.Frame); text := low.text; up := v.next.dsc.next(TF.Frame);
  663.             IF low.hasSel THEN beg := low.selbeg.pos ELSE beg := 0 END;
  664.             Texts.OpenScanner(S, text, beg);
  665.             LOOP
  666.                 IF S.eot THEN EXIT END;
  667.                 REPEAT Texts.Scan(S) UNTIL (S.class = Texts.Name) & (S.s = "PROCEDURE") OR S.eot;
  668.                 IF S.eot THEN EXIT END;
  669.                 (* S.s = "PROCEDURE" *)
  670.                 LOOP
  671.                     Texts.Scan(S);
  672.                     IF (S.class = Texts.Char) & (S.c = "*") & ~S.eot THEN Texts.Scan(S) END;    (* PROCEDURE* P *)
  673.                     IF (S.class = Texts.Name) OR S.eot THEN COPY(S.s, name); EXIT
  674.                     ELSIF S.class = Texts.Char THEN    (* receiver or forward/interrupt/code proc *)
  675.                         IF S.c = "(" THEN REPEAT Texts.Scan(S) UNTIL (S.class = Texts.Char) & (S.c = ")") OR S.eot
  676.                         ELSE REPEAT Texts.Scan(S) UNTIL (S.class = Texts.Name) & (S.s = "PROCEDURE") OR S.eot
  677.                         END;
  678.                         IF S.eot THEN EXIT END
  679.                     END
  680.                 END;    (* LOOP *)
  681.                 IF S.eot THEN EXIT END;
  682.                 (* name = Name of procedure *)
  683.                 REPEAT Texts.Scan(S) UNTIL (S.nextCh = 0DX) OR S.eot;
  684.                 IF S.eot THEN EXIT END;
  685.                 beg := Texts.Pos(S);    (* start of procedure body *)
  686.                 Texts.Scan(S);
  687.                 LOOP
  688.                     WHILE ((S.class # Texts.Name) OR (S.s # "END")) & ~S.eot DO Texts.Scan(S) END;
  689.                     IF S.eot THEN EXIT END;
  690.                     (* S.s = "END" *)
  691.                     Texts.Scan(S);
  692.                     IF (S.class = Texts.Name) & (S.s = name) THEN Texts.Scan(S); end := Texts.Pos(S)+1(*skip CR*); EXIT END
  693.                 END;    (* LOOP *)
  694.                 IF S.eot THEN EXIT END;
  695.                 Texts.Write(W, 9X); Texts.Insert(text, beg-1, W.buf);
  696.                 TF.Show(up, beg); TF.Show(low, end);
  697.                 TF.SetSelection(up, beg, end); TF.SetSelection(low, beg, end);
  698.                 up.selend.pos := end; low.selbeg.pos := beg;
  699.                 name := "FoldElems.Insert"; Oberon.Call(name, Oberon.Par, FALSE, res);
  700.                 Texts.OpenScanner(S, text, end+2)
  701.             END    (* LOOP *)
  702.         END
  703.     END Fold;
  704.     PROCEDURE Constants*;    (** Generate constant declarations a = 1; b*= 2; c = 3; from a, b*, c = 1, ..; *)
  705.         TYPE
  706.             Entry = POINTER TO RECORD name: ARRAY 32 OF CHAR; marked, newLine: BOOLEAN; next: Entry END;
  707.         VAR
  708.             S: Texts.Scanner;
  709.             e, head: Entry;
  710.             text: Texts.Text; normal, bold: Fonts.Font;
  711.             V: Viewers.Viewer; F: TF.Frame;
  712.             beg, end, cpos, len, i, time: LONGINT; line: INTEGER;
  713.     BEGIN
  714.         Oberon.GetSelection(text, beg, end, time);
  715.         IF time < 0 THEN Err("no selection!")
  716.         ELSE
  717.             V := Oberon.FocusViewer;
  718.             IF (V.dsc # NIL) & (V.dsc.next IS TF.Frame) THEN
  719.                 F := V.dsc.next(TF.Frame);
  720.                 IF F.hasCar THEN cpos := F.carloc.pos ELSE Err("no caret!"); RETURN END
  721.             ELSE Err("no viewer!"); RETURN
  722.             END;
  723.             IF (F.text = text) & (cpos < end) THEN Err("caret has to be after selected text!"); RETURN END;
  724.             Texts.OpenScanner(S, text, beg); Texts.Scan(S); line := S.line;
  725.             normal := Fonts.This("Syntax10.Scn.Fnt"); bold := Fonts.This("Syntax10b.Scn.Fnt");
  726.             NEW(head); e := head;
  727.             LOOP
  728.                 IF S.class # Texts.Name THEN EXIT END;
  729.                 e.newLine := S.line > line; line := S.line;
  730.                 NEW(e.next); e := e.next;
  731.                 COPY(S.s, e.name); e.marked := FALSE;
  732.                 Texts.Scan(S);
  733.                 IF (S.class # Texts.Char) OR (S.class = Texts.Char) & (S.c = "=") THEN EXIT END;
  734.                 (* Assert: S.class = Texts.Char *)
  735.                 IF S.c = "*" THEN e.marked := TRUE; Texts.Scan(S); IF (S.class = Texts.Char) & (S.c = "=") THEN EXIT END END;
  736.                 Texts.Scan(S)    (* read next name *)
  737.             END;
  738.             Texts.Scan(S);
  739.             IF S.class # Texts.Int THEN Err("there should be an integer after the last const!"); RETURN END;
  740.             i := S.i; e := head.next;
  741.             WHILE e # NIL DO
  742.                 IF e.marked THEN Texts.SetFont(W, bold) END;
  743.                 Texts.WriteString(W, e.name); Texts.SetFont(W, normal);
  744.                 IF e.marked THEN Texts.WriteString(W, "*= ") ELSE Texts.WriteString(W, " = ") END;
  745.                 Texts.WriteInt(W, i, 0); Texts.Write(W, ";");
  746.                 IF e.newLine THEN Texts.WriteLn(W) ELSE Texts.Write(W, " ") END;
  747.                 e := e.next; INC(i)
  748.             END;
  749.             Texts.WriteLn(W);
  750.             IF head.next # NIL THEN
  751.                 len := W.buf.len;
  752.                 Texts.Insert(F.text, cpos, W.buf); TF.SetCaret(F(TF.Frame), cpos+len)
  753.             END
  754.         END
  755.     END Constants;
  756.     (*PROCEDURE Exports*;    (** Make all exported ("*" or "-") identifiers in marked viewer bold *)
  757.         VAR R: Texts.Reader; bold: Fonts.Font; text: Texts.Text; V: Viewers.Viewer; beg, end, pos: LONGINT; ch: CHAR;
  758.     BEGIN
  759.         V := Oberon.MarkedViewer();
  760.         IF (V = NIL) OR (V.dsc = NIL) OR (V.dsc.next = NIL) OR ~(V.dsc.next IS TF.Frame) THEN RETURN END;
  761.         text := V.dsc.next(TF.Frame).text; Texts.OpenReader(R, text, 0); Texts.Read(R, ch);
  762.         IF R.fnt.name = "Syntax12.Scn.Fnt" THEN bold := Fonts.This("Syntax12b.Scn.Fnt")
  763.         ELSE bold := Fonts.This("Syntax10b.Scn.Fnt")
  764.         END;
  765.         LOOP
  766.             WHILE ((ch < "A") OR ("Z" < ch) & (ch < "a") OR ("z" < ch)) & ~R.eot DO Texts.Read(R, ch) END;
  767.             IF R.eot THEN EXIT END;
  768.             beg := Texts.Pos(R)-1;
  769.             REPEAT Texts.Read(R, ch)
  770.             UNTIL (ch < "0") OR ("9" < ch) & (ch < "A") OR ("Z" < ch) & (ch < "a") OR ("z" < ch) OR R.eot;
  771.             IF R.eot THEN EXIT END;
  772.             end := Texts.Pos(R)-1;
  773.             WHILE (ch <= " ") & ~R.eot DO Texts.Read(R, ch) END;
  774.             IF R.eot THEN EXIT END;
  775.             IF (ch = "*") OR (ch = "-") THEN
  776.                 REPEAT Texts.Read(R, ch) UNTIL (ch > " ") OR R.eot;
  777.                 IF R.eot THEN EXIT END;
  778.                 IF (ch = ":") OR (ch = "(") OR (ch = ";") OR (ch = "=") OR (ch = ",") THEN
  779.                     pos := Texts.Pos(R);
  780.                     Texts.ChangeLooks(text, beg, end, {0}, bold, 0, 0); Texts.OpenReader(R, text, pos)
  781.                 END
  782.             END
  783.         END
  784.     END Exports;
  785.     PROCEDURE Exports*;    (** Make all exported ("*" or "-") identifiers in marked viewer bold *)
  786.         VAR s: Texts.Scanner; bold: Fonts.Font; text: Texts.Text; end, idents: LONGINT; len: SHORTINT;
  787.     BEGIN
  788.         GetTextFromMarked(text);
  789.         IF (text # NIL) & (text.len # 0) THEN
  790.             Texts.OpenScanner(s, text, 0); Texts.Scan(s);
  791.             IF s.fnt.name = "Syntax12.Scn.Fnt" THEN bold := Fonts.This("Syntax12b.Scn.Fnt")
  792.             ELSE bold := Fonts.This("Syntax10b.Scn.Fnt")
  793.             END;
  794.             idents := 0;
  795.             LOOP
  796.                 WHILE ~s.eot & (s.class # Texts.Name) DO Texts.Scan(s) END;    (* get next name *)
  797.                 IF s.eot THEN EXIT END;
  798.                 IF s.s = "BEGIN" THEN    (* skip everything between BEGIN and END ident *)
  799.                     REPEAT
  800.                         REPEAT Texts.Scan(s) UNTIL s.eot OR ((s.class = Texts.Name) & (s.s = "END"));    (* get END *)
  801.                         IF s.eot THEN EXIT END;
  802.                         Texts.Scan(s);
  803.                         IF s.eot THEN EXIT END
  804.                     UNTIL s.class = Texts.Name;    (* exit only if END ident *)
  805.                     Texts.Scan(s);
  806.                     IF s.eot THEN EXIT END
  807.                 END;
  808.                 WHILE ~s.eot & (s.class # Texts.Name) DO Texts.Scan(s) END;    (* get next name *)
  809.                 IF s.eot THEN EXIT END;
  810.                 len := s.len; end := Texts.Pos(s)-1;
  811.                 Texts.Scan(s);
  812.                 IF s.eot THEN EXIT END;
  813.                 IF (s.class = Texts.Char) & ((s.c = "*") OR (s.c = "-")) THEN    (* export mark *)
  814.                     Texts.Scan(s);
  815.                     IF s.eot THEN EXIT END;
  816.                     IF (s.class = Texts.Char) & ((s.c = ":") OR (s.c = "(") OR (s.c = ";") OR (s.c = "=") OR (s.c = ",")) THEN
  817.                         INC(idents);
  818.                         Texts.ChangeLooks(text, end-len, end, {0}, bold, 0, 0); Texts.OpenScanner(s, text, end); Texts.Scan(s)
  819.                     END
  820.                 END
  821.             END;
  822.             Int(idents); String(" ident"); IF idents # 1 THEN String("s") END; String(" marked"); Ln
  823.         END
  824.     END Exports;
  825.     PROCEDURE Exits*;    (** Make all RETURN, EXIT, and HALT statements in marked viewer bold *)
  826.         VAR S: Texts.Scanner; bold: Fonts.Font; text: Texts.Text; end, exits: LONGINT;
  827.     BEGIN
  828.         GetTextFromMarked(text);
  829.         IF (text # NIL) & (text.len # 0) THEN
  830.             Texts.OpenScanner(S, text, 0); Texts.Scan(S);
  831.             IF S.fnt.name = "Syntax12.Scn.Fnt" THEN bold := Fonts.This("Syntax12b.Scn.Fnt")
  832.             ELSE bold := Fonts.This("Syntax10b.Scn.Fnt")
  833.             END;
  834.             exits := 0;
  835.             LOOP
  836.                 WHILE ~S.eot & ((S.class # Texts.Name) OR
  837.                         (S.s # "RETURN") & (S.s # "EXIT") & (S.s # "HALT") & (S.s # "ASSERT")) DO
  838.                     Texts.Scan(S)
  839.                 END;
  840.                 IF S.eot THEN EXIT END;
  841.                 IF (S.nextCh <= " ") OR (S.nextCh = "(") THEN
  842.                     end := Texts.Pos(S)-1; INC(exits);
  843.                     Texts.ChangeLooks(text, end-S.len, end, {0}, bold, 0, 0); Texts.OpenScanner(S, text, end)
  844.                 END;
  845.                 Texts.Scan(S)
  846.             END;
  847.             Int(exits); String(" exit"); IF exits # 1 THEN String("s") END; String(" marked"); Ln
  848.         END
  849.     END Exits;
  850.     PROCEDURE Comments*;    (** Make all comments in marked viewer italic iff they do not extend over several lines *)
  851.         CONST CR = 0DX;
  852.         VAR
  853.             R: Texts.Reader; italic: Fonts.Font; text: Texts.Text; beg, end, count: LONGINT; ch : CHAR;
  854.             sameLine : BOOLEAN;
  855.     BEGIN
  856.         GetTextFromMarked(text);
  857.         IF (text # NIL) & (text.len # 0) THEN
  858.             Texts.OpenReader(R, text, 0); Texts.Read (R, ch);
  859.             IF R.fnt.name = "Syntax12.Scn.Fnt" THEN italic := Fonts.This("Syntax12i.Scn.Fnt")
  860.             ELSE italic := Fonts.This("Syntax10i.Scn.Fnt")
  861.             END;
  862.             (* the following code is not fool-proof, but works for sensible comments *)
  863.             count := 0; sameLine := FALSE;
  864.             WHILE ~R.eot DO
  865.                 IF ch = "(" THEN
  866.                     Texts.Read (R, ch);
  867.                     IF ch = "*" THEN
  868.                         IF count = 0 THEN beg := Texts.Pos (R) - 2 END;
  869.                         INC (count);
  870.                         sameLine := TRUE
  871.                     END
  872.                 ELSIF ch = "*" THEN
  873.                     Texts.Read (R, ch);
  874.                     IF ch = ")" THEN
  875.                         DEC (count);
  876.                         IF (count = 0) & sameLine THEN
  877.                             end := Texts.Pos (R);
  878.                             Texts.ChangeLooks(text, beg+2, end-2, {0}, italic, 0, 0); Texts.OpenReader (R, text, Texts.Pos (R))
  879.                         END
  880.                     END
  881.                 ELSIF ch = CR THEN
  882.                     sameLine := FALSE;
  883.                     Texts.Read (R, ch)
  884.                 ELSE
  885.                     Texts.Read (R, ch)
  886.                 END;
  887.             END
  888.         END
  889.     END Comments;
  890.     PROCEDURE Lower*;    (** Convert selection to lower case *)
  891.     BEGIN ChangeCase("A", "Z", ORD("a")-ORD("A"))
  892.     END Lower;
  893.     PROCEDURE Upper*;    (** Convert selection to upper case *)
  894.     BEGIN ChangeCase("a", "z", ORD("A")-ORD("a"))
  895.     END Upper;
  896.     PROCEDURE FindMsg(keyword, msg: ARRAY OF CHAR);    (** (number) | "^"    Display message corresponding to number *)    
  897.         VAR S: Texts.Scanner; T: Texts.Text; num, end: LONGINT;
  898.         PROCEDURE Err;    BEGIN String("nothing found"); Ln END Err;
  899.     BEGIN
  900.         Setup(S, end);
  901.         WHILE ~S.eot & (S.class # Texts.Int) DO Texts.Scan(S) END;
  902.         IF S.eot THEN RETURN END;
  903.         num := S.i;
  904.         T := TF.Text(ErrorFile);
  905.         IF T.len = 0 THEN RETURN END;
  906.         Texts.OpenScanner(S, T, 0);
  907.         REPEAT Texts.Scan(S) UNTIL S.eot OR (S.class = Texts.Name) & (S.s = keyword);
  908.         IF S.eot THEN Err; RETURN END;
  909.         REPEAT Texts.Scan(S) UNTIL S.eot OR (S.class = Texts.Int) & (S.i = num);
  910.         IF S.eot THEN Err; RETURN END;
  911.         String(msg); String(" "); Int(num); String(" = "); Texts.Append(Oberon.Log, W.buf);
  912.         num := Texts.Pos(S);
  913.         REPEAT Texts.Read(S, S.nextCh) UNTIL S.eot OR (S.nextCh = 0DX);
  914.         IF S.eot THEN end := T.len ELSE end := Texts.Pos(S) END;
  915.         Texts.Save(T, num, end, W.buf); Texts.Append(Oberon.Log, W.buf)
  916.     END FindMsg;
  917.     PROCEDURE Trap*;    (** ("TRAP" number) | "^"    Display corresponding trap message of trap number *)    
  918.     BEGIN FindMsg("Trap", "TRAP")
  919.     END Trap;
  920.     PROCEDURE Error*;    (** number | "^"    Display corresponding error message *)    
  921.     BEGIN FindMsg("Incorrect", "err")
  922.     END Error;
  923.     (** Viewer management *) 
  924.     PROCEDURE Up*;        (** Move marked viewer and all above it upwards *)
  925.         VAR v: Viewers.Viewer; dY: INTEGER;
  926.     BEGIN
  927.         IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN v := Oberon.Par.vwr ELSE v := Oberon.MarkedViewer() END;
  928.         MoveUp(v, dY)
  929.     END Up;
  930.     PROCEDURE Down*;    (** Move marked viewer and all below it downwards *)
  931.         VAR v: Viewers.Viewer;
  932.     BEGIN
  933.         IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN v := Oberon.Par.vwr ELSE v := Oberon.MarkedViewer() END;
  934.         MoveDown(v)
  935.     END Down;
  936.     PROCEDURE Unfocus*;    (** Remove focus from focus viewer *)
  937.     BEGIN Oberon.FocusViewer := Viewers.This(Oberon.Mouse.X, Oberon.Mouse.Y)
  938.     END Unfocus;
  939.     PROCEDURE Close*;    (** Close marked viewer explicitly *)    
  940.         VAR V: Viewers.Viewer; U: Display.Frame; M: Viewers.ViewerMsg;
  941.     BEGIN
  942.         V := Oberon.MarkedViewer(); U := V.next;
  943.         M.id := Viewers.modify; M.Y := V.Y; M.H := V.H + U.H;
  944.         U.handle(U, M); U.Y := M.Y; U.H := M.H;
  945.         WHILE U.next # V DO U := U.next END;
  946.         U.next := V.next
  947.     END Close;
  948.     PROCEDURE Copy*;    (** Copy marked viewer explicitly *)    
  949.         VAR F: Display.Frame; name: ARRAY 32 OF CHAR; res: INTEGER;
  950.     BEGIN
  951.         F := Oberon.Par.frame; Oberon.Par.frame := Oberon.MarkedViewer();
  952.         name := "System.Copy"; Oberon.Call(name, Oberon.Par, FALSE, res);
  953.         Oberon.Par.frame := F
  954.     END Copy;
  955.     PROCEDURE Free*;    (** module | "^"    Free a module unconditionally *)    
  956.         VAR S: Texts.Scanner; end: LONGINT; m: Modules.Module;
  957.     BEGIN
  958.         Setup(S, end);
  959.         IF S.class = Texts.Name THEN
  960.             m := Modules.ThisMod(S.s); String(S.s); String(" unloading");
  961.             IF m # NIL THEN m.refcnt := 0; Modules.Free(S.s, FALSE) END;
  962.             IF (m = NIL) OR (Modules.res # 0) THEN String(" failed") END;
  963.             Ln
  964.         END
  965.     END Free;
  966. BEGIN Texts.OpenWriter(W)
  967. END Utils.
  968. Utils.FileCompare  name1  name2
  969. Utils.TextCompare  name1  name2
  970. Utils.FileCompare ^
  971. Utils.TextCompare ^
  972. Utils.Quote
  973. Utils.Comment
  974. Utils.Comment2
  975. Utils.Uncomment
  976. Utils.Uncomment2
  977. Utils.CR2LF ^
  978. Utils.LF2CR ^
  979. Utils.CRLF2CR ^
  980. Utils.FromCN ^
  981. Utils.ToCN ^
  982. Utils.Upper
  983. Utils.Lower
  984. Utils.Clean
  985. Utils.Trap ^
  986. Utils.Fold *
  987. Utils.Semicolon *
  988. Utils.Constants
  989. Utils.Exports
  990. Conversion of Amiga Umlauts to Ceres
  991. Utils.Convert 10 13 ^    LF -> CR
  992. Utils.Convert 196 128 ^    
  993. Utils.Convert 214 129 ^    
  994. Utils.Convert 220 130 ^    
  995. Utils.Convert 228 131 ^    
  996. Utils.Convert 246 132 ^    
  997. Utils.Convert 252 133 ^    
  998. Utils.Convert 223 146 ^    double s -> 
  999.  (lack of other character, use Write.Replace)
  1000. Conversion of Mac (??) Umlauts to Ceres
  1001. Utils.Convert 10 13 ^    LF -> CR
  1002. Utils.Convert 138 131 ^    
  1003. Utils.Convert 154 132 ^    
  1004. Utils.Convert 159 133 ^    
  1005. Utils.Convert 142 144
  1006. Utils.Convert 143 140 ^    
  1007. Utils.Convert 141 147 ^    
  1008.