Jump to content

Oberon/A2/Oberon.Configuration.Mod

From Wikibooks, open books for an open world
(* ETH Oberon, Copyright 2001 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich.
Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *)

MODULE Configuration IN Oberon;	(** portable *)	(* jm, Configuration module/code borrowed from ET by uh **)

(*
	contains a lot of code borrowed from ET
*)

IMPORT Modules, Display, Input, Viewers, Texts, Oberon;

CONST
	CR = 0DX;
	Default = "Configuration.Text";

VAR
	W: Texts.Writer;
	sX, sY: INTEGER;	(* saved coordinates for newm viewer [used in Marker ] *)

PROCEDURE OpenScanner(VAR S: Texts.Scanner);
	VAR
		text: Texts.Text;
		beg, end, time: LONGINT;
BEGIN
	Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
	Texts.Scan(S);
	IF (S.class = Texts.Char) & (S.c = "^") THEN
		text := NIL; time := 0; Oberon.GetSelection(text, beg, end, time);
		IF (text = NIL) OR (time <= 0) THEN S.class := Texts.Inval; RETURN END;
		Texts.OpenScanner(S, text, beg); Texts.Scan(S)
	END
END OpenScanner;

(** Execute commands contained in the text. Each command must be on a separate line. *)
PROCEDURE do*(T: Texts.Text; beg, end: LONGINT);
VAR S: Texts.Scanner; pos: LONGINT; res: INTEGER;

	PROCEDURE NextCmd;
		VAR tR: Texts.Reader; ch: CHAR;
	BEGIN
		IF pos < end THEN
			Texts.OpenReader(tR, T, pos); Texts.Read(tR, ch);
			LOOP
				WHILE ~tR.eot & (ch # CR) DO Texts.Read(tR, ch) END;
				Texts.Read(tR, ch);
				IF tR.eot THEN
					EXIT
				ELSIF (ch > " ") & (ch # "!") & (ch # "#") THEN
					pos := Texts.Pos(tR)-1;
					Texts.OpenScanner(S, T, pos); Texts.Scan(S);
					RETURN
				END
			END
		END;
		S.class := Texts.Inval
	END NextCmd;

	PROCEDURE FirstCmd;
		VAR tR: Texts.Reader; ch: CHAR;
	BEGIN
		IF pos < end THEN
			Texts.OpenReader(tR, T, pos); Texts.Read(tR, ch);
			IF ~tR.eot & (ch > " ") & (ch # "!") & (ch # "#") THEN
				pos := Texts.Pos(tR)-1;
				Texts.OpenScanner(S, T, pos); Texts.Scan(S);
				RETURN
			END
		END;
		NextCmd()
	END FirstCmd;

	PROCEDURE UserInterrupt(): BOOLEAN;
	VAR ch: CHAR;
	BEGIN
		WHILE Input.Available() # 0 DO
			Input.Read(ch);
			IF ch = CHR(27) THEN RETURN TRUE END
		END;
		RETURN FALSE
	END UserInterrupt;

BEGIN
	pos := beg; FirstCmd();
	WHILE (S.class = Texts.Name) & (pos < end) & ~UserInterrupt() DO
		pos := Texts.Pos(S) - 1;
		Oberon.Par.vwr := Oberon.MarkedViewer();
		Oberon.Par.frame := Oberon.MarkedFrame();
		Oberon.Par.text := T; Oberon.Par.pos := pos;
		Oberon.Call(S.s, Oberon.Par, FALSE, res);
		IF res # 0 THEN
			Texts.WriteString(W, "Call error: ");  Texts.WriteString(W, Modules.resMsg);
			Texts.WriteLn(W);  Texts.Append(Oberon.Log, W.buf)
		END;
		NextCmd()
	END
END do;

(** Configuration.DoText ( "*" | "^" | textfile { textfile } "~" )
		Execute the commands in textfile . Each command must be written on a separate line. *)
	PROCEDURE DoText*;
	VAR S: Texts.Scanner; T: Texts.Text;
	BEGIN
		OpenScanner(S);
		IF (S.class = Texts.Char) & (S.c = "*") THEN
			T := Oberon.MarkedText()
		ELSIF S.class IN {Texts.Name, Texts.String} THEN
			NEW(T); Texts.Open(T, S.s)
		ELSE
			T := NIL
		END;
		IF T # NIL THEN
			do(T, 0, T.len)
		END
	END DoText;

(** Configuration.DoCommands ( "^" | cmd { cmd } "~" )
		Execute the commands. Each command must be written on a separate line. *)
PROCEDURE DoCommands*;
	VAR
		S: Texts.Scanner; T: Texts.Text;
		beg, end, time: LONGINT;
BEGIN
	Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
	Texts.Scan(S);
	IF (S.class = Texts.Char) & (S.c = "^") THEN
		T := NIL; time := -1; Oberon.GetSelection(T, beg, end, time);
	ELSE
		T := Oberon.Par.text; beg := Oberon.Par.pos; end := T.len
	END;
	IF T # NIL THEN
		do(T, beg, end)
	END
END DoCommands;

PROCEDURE ValidX(X: INTEGER): BOOLEAN;
BEGIN
	RETURN (Display.Left <= X) & (X < Display.Left + Display.Width)
			OR (Display.ColLeft <= X) & (X < Display.ColLeft + Display.Width)
END ValidX;

PROCEDURE ValidY(Y: INTEGER): BOOLEAN;
BEGIN
	RETURN (Display.Bottom <= Y) & (Y < Display.Bottom + Display.Height)
END ValidY;

(** Set the star marker under program control:
	Configuration.Marker set save		(* set at saved position *)
	Configuration.Marker set this		(* set to current viewer *)
	Configuration.Marker set system		(* in system track *)
	Configuration.Marker set user		(* in user track *)
	Configuration.Marker set X Y		(* at absolute pixel position X, Y *)
	Configuration.Marker set X% Y%		(* at relative pixel position X, Y *)
	Configuration.Marker save system		(* save marker in system track *)
	Configuration.Marker save user		(* save marker in user track *)
*)
PROCEDURE Marker*;
	VAR S: Texts.Scanner;	V : Viewers.Viewer;	cM: Oberon.ControlMsg;
BEGIN
	Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);  Texts.Scan(S);
	IF S.class # Texts.Name THEN RETURN END;
	IF S.s = "set" THEN
		Texts.Scan(S); cM.id := Oberon.mark + 999;
		IF (S.class = Texts.Name) & (S.s = "saved") THEN
			V := Viewers.This(sX + 1, sY - 1);
			IF (V # NIL) & (V.X = sX) & (V.Y + V.H = sY) THEN
				cM.id := Oberon.mark; cM.X := V.X + V.W DIV 2; cM.Y := V.Y + V.H DIV 2
			END
		ELSIF (S.class = Texts.Name) & (S.s = "this") THEN
			IF Oberon.Par.vwr # NIL THEN
				cM.id := Oberon.mark; cM.X := Oberon.Par.vwr.X + Oberon.Par.vwr.W DIV 2;
				cM.Y := Oberon.Par.vwr.Y + Oberon.Par.vwr.H DIV 2
			END
		ELSIF (S.class = Texts.Name) & (S.s = "system") THEN
			Oberon.AllocateSystemViewer(Oberon.SystemTrack(Oberon.Par.vwr.X), cM.X, cM.Y);
			cM.id := Oberon.mark;
		ELSIF (S.class = Texts.Name) & (S.s = "user") THEN
			Oberon.AllocateUserViewer(Oberon.UserTrack(Oberon.Par.vwr.X), cM.X, cM.Y);
			cM.id := Oberon.mark;
		ELSIF (S.class = Texts.Int) & (S.i >= 0) THEN
			cM.X := SHORT(S.i); Texts.Scan(S);
			IF (S.class = Texts.Int) & (S.i >= 0) THEN
				cM.Y := SHORT(S.i);
				IF ValidX(cM.X) & ValidY(cM.Y) THEN cM.id := Oberon.mark END
			ELSIF (S.class = Texts.Char) & (S.c = "%") THEN
				Texts.Scan(S);
				IF (S.class = Texts.Int) & (S.i >= 0) THEN
					cM.Y := SHORT(S.i*Display.Height DIV 100);
					cM.X := SHORT(LONG(Display.Width)*cM.X DIV 100);
					IF ValidX(cM.X) & ValidY(cM.Y) THEN cM.id := Oberon.mark END
				END
			END
		END;
		IF cM.id = Oberon.mark THEN
			IF cM.Y >= Display.Width THEN cM.Y := Display.Width-1 END;
			V := Viewers.This(cM.X, cM.Y); IF V # NIL THEN V.handle(V, cM) END	(* set marker *)
		END
	ELSIF S.s = "save" THEN
		Texts.Scan(S);
		IF S.class = Texts.Name THEN
			IF S.s = "system" THEN
				Oberon.AllocateSystemViewer(Oberon.SystemTrack(Oberon.Par.vwr.X), sX, sY)
			ELSIF S.s = "user" THEN
				Oberon.AllocateUserViewer(Oberon.UserTrack(Oberon.Par.vwr.X), sX, sY)
			ELSE sX := -1; sY := -1
			END
		END
	END
END Marker;

PROCEDURE Init;
	VAR
		s: Texts.Scanner;
		T: Texts.Text;
		x, y: INTEGER;
BEGIN
	Oberon.OpenScanner(s, "System.Configuration");
	IF ~(s.class IN {Texts.Name, Texts.String}) THEN
		COPY(Default, s.s)
	END;
	NEW(T); Texts.Open(T, s.s);
	IF T.len > 0 THEN
		Oberon.AllocateSystemViewer(Display.Left, x, y);
		NEW(Oberon.Par);
		Oberon.Par.vwr := Viewers.This(x+1, y-1); NEW(Oberon.Par.frame);
		do(T, 0, T.len)
	END
END Init;

BEGIN Texts.OpenWriter(W); Init()
END Configuration.