text:
Oberon/A2/Oberon.TextFrames.Mod

(* 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 TextFrames IN Oberon;	(** portable *) (* JG / pjm *)   IMPORT Input, Modules, Objects, Display, Viewers, Fonts, Texts, Oberon, MenuViewers;   CONST CR = 0DX;     replace = Display.replace; paint = Display.paint; invert = Display.invert;     extend = Display.extend; reduce = Display.reduce; 	StandardMenu = "System.Close System.Copy System.Grow Edit.Search Edit.Store"; 	LogMenu = "System.Clear Edit.Locate Edit.Search Edit.Store"; 	OpenCmd = "ET.Open"; 	Modern = FALSE;	(* enable "modern" look *) 	SmallDisplay = TRUE;	(* enable PDR's support for narrow displays *) 	MoveArea = TRUE;	(* show "move" icon at top left, and use clipping for caret *)   TYPE   	Line = POINTER TO LineDesc;   	LineDesc = RECORD     	len: SIGNED32;         wid: SIGNED16;         eot: BOOLEAN;         next: Line   	END;   	Location* = RECORD         org*, pos*: SIGNED32;         dx*, x*, y*: SIGNED16;         lin: Line   	END;   	Frame* = POINTER TO FrameDesc;   	FrameDesc* = RECORD         (Display.FrameDesc)         text*: Texts.Text;         org*: SIGNED32;         col*: SIGNED16;         lsp*: SIGNED16;         left*, right*, top*, bot*: SIGNED16;         markH*: SIGNED16;         time*: SIGNED32;         mark*, car*, sel*: SIGNED16;         carloc*: Location;         selbeg*, selend*: Location;         trailer: Line   	END;   	(*mark < 0: arrow mark         mark = 0: no mark         mark > 0: position mark*)   VAR     menuH*, barW*, left*, right*, top*, bot*, lsp*: SIGNED16; (*standard sizes*)     MarkColor, BarColor, MenuBG, TextBG, FullColor, mode: SIGNED16;     asr, dsr, selH, markW, eolW: SIGNED16;     ch: CHAR;     W, KW: Texts.Writer; (*keyboard writer*)     box: Fonts.Char;     BoxPat: ARRAY 12 OF SET;     hintPos: SIGNED32;     saved: Oberon.CaretMsg;   PROCEDURE Min (i, j: SIGNED16): SIGNED16;   BEGIN IF i >= j THEN RETURN j ELSE RETURN i END   END Min;   PROCEDURE Max (i, j: SIGNED32): SIGNED32;   BEGIN IF i >= j THEN RETURN i ELSE RETURN j END   END Max;   (*--display support*)   PROCEDURE ReplConst (col: SIGNED16; F: Frame; X, Y, W, H: SIGNED16; mode: SIGNED16);   BEGIN     IF X + W <= F.X + F.W THEN Display.ReplConst(col, X, Y, W, H, mode)       ELSIF X < F.X + F.W THEN Display.ReplConst(col, X, Y, F.X + F.W - X, H, mode)     END   END ReplConst;   PROCEDURE UpdateMark (F: Frame);     VAR oldH: SIGNED16;   BEGIN     oldH := F.markH; F.markH := SHORT(F.org * F.H DIV (F.text.len + 1));     IF (F.mark > 0) & (F.left >= barW) & (F.markH # oldH) THEN       Display.ReplConst(F.col, F.X, F.Y + F.H - 1 - oldH, markW, 1, replace);       Display.ReplConst(MarkColor, F.X, F.Y + F.H - 1 - F.markH, markW, 1, replace)     END   END UpdateMark;   PROCEDURE Width (VAR R: Texts.Reader; len: SIGNED32): SIGNED16;     VAR pos: SIGNED32; ox: SIGNED16; obj: Objects.Object;   BEGIN pos := 0; ox := 0;     WHILE pos # len DO       R.lib.GetObj(R.lib, ORD(ch), obj);       IF ~(obj IS Fonts.Char) THEN obj := box END;       ox := ox + obj(Fonts.Char).dx; INC(pos); Texts.Read(R, ch)     END;     RETURN ox   END Width;   PROCEDURE DisplayLine (F: Frame; L: Line;     VAR R: Texts.Reader; X, Y: SIGNED16; len: SIGNED32);     VAR NX: SIGNED16; obj: Objects.Object;   BEGIN NX := F.X + F.W;     WHILE (ch # CR) & (R.lib # NIL) DO       IF R.lib IS Fonts.Font THEN R.lib.GetObj(R.lib, ORD(ch), obj)         ELSE obj := box       END;       WITH obj: Fonts.Char DO         IF X + obj.x + obj.w <= NX THEN           Display.CopyPattern(R.col, obj.pat, X + obj.x, Y + obj.y, mode);           X := X + obj.dx         ELSE           X := NX         END;       END;       INC(len); Texts.Read(R, ch)     END;     L.len := len + 1; L.wid := X + eolW - (F.X + F.left);     L.eot := R.eot; Texts.Read(R, ch)   END DisplayLine;   PROCEDURE Validate (T: Texts.Text; VAR org: SIGNED32);     VAR R: Texts.Reader; pos: SIGNED32;   BEGIN     IF org > T.len THEN org := T.len     ELSIF org > 0 THEN Texts.OpenReader(R, T, org - 1); Texts.Read(R, ch);       IF ch # CR THEN         pos := Max(org - 100, 0); Texts.OpenReader(R, T, pos);         REPEAT Texts.Read(R, ch); INC(pos) UNTIL (pos = org) OR (ch = CR);         org := pos       END     ELSE org := 0     END   END Validate;   PROCEDURE Mark* (F: Frame; mark: SIGNED16);   BEGIN     IF (mark >= 0) & (F.mark < 0) & (F.H >= 16) THEN       Display.CopyPattern(F.col, Display.downArrow, F.X, F.Y, paint)     ELSIF (mark <= 0) & (F.mark > 0) & (F.H > 0) & (F.left >= barW) THEN       Display.ReplConst(F.col, F.X, F.Y + F.H - 1 - F.markH, markW, 1, replace)     END;     IF (mark > 0) & (F.H > 0) & (F.left >= barW) & (F.mark <= 0) THEN       Display.ReplConst(MarkColor, F.X, F.Y + F.H - 1 - F.markH, markW, 1, replace)     ELSIF (mark < 0) & (F.H >= 16) & (F.mark >= 0) THEN       Display.CopyPattern(MarkColor, Display.downArrow, F.X, F.Y, paint)     END;     F.mark := mark   END Mark;   PROCEDURE DrawIcon(F: Frame);   BEGIN     Display.ReplConst(MarkColor, F.X+3, F.Y+F.H-9, 6, 6, replace);     IF Oberon.New THEN       Display.ReplConst(F.col, F.X+5, F.Y+F.H-7, 2, 2, replace)     END   END DrawIcon;   PROCEDURE Restore* (F: Frame);     VAR R: Texts.Reader; L: Line; curY, botY: SIGNED16;   BEGIN (*F.mark = 0*)     Display.ReplConst(F.col, F.X, F.Y, F.W, F.H, replace);     IF F.left >= barW THEN       Display.ReplConst(BarColor, F.X + barW - 1, F.Y, 1, F.H, replace)     ELSIF MoveArea THEN       DrawIcon(F)     END;     Validate(F.text, F.org);     botY := F.Y + F.bot + dsr;     Texts.OpenReader(R, F.text, F.org); Texts.Read(R, ch);     L := F.trailer; curY := F.Y + F.H - F.top - asr;     WHILE ~L.eot & (curY >= botY) DO       NEW(L.next); L := L.next;       DisplayLine(F, L, R, F.X + F.left, curY, 0);       curY := curY - lsp     END;     L.next := F.trailer;     F.markH := SHORT(F.org * F.H DIV (F.text.len + 1))   END Restore;   PROCEDURE Suspend* (F: Frame);   BEGIN (*F.mark = 0*)     F.trailer.next := F.trailer   END Suspend;   PROCEDURE Extend* (F: Frame; newY: SIGNED16);     VAR R: Texts.Reader; L: Line;     org: SIGNED32; curY, botY: SIGNED16;   BEGIN (*F.mark = 0*)     Display.ReplConst(F.col, F.X, newY, F.W, F.Y - newY, replace);     IF F.left >= barW THEN       Display.ReplConst(BarColor, F.X + barW - 1, newY, 1, F.Y - newY, replace)     ELSIF MoveArea THEN       DrawIcon(F)     END;     F.H := F.H + F.Y - newY; F.Y := newY;     IF F.trailer.next = F.trailer THEN Validate(F.text, F.org) END;     L := F.trailer; org := F.org; curY := F.Y + F.H - F.top - asr;     WHILE L.next # F.trailer DO       L := L.next; org := org + L.len; curY := curY - lsp     END;     botY := F.Y + F.bot + dsr;     Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);     WHILE ~L.eot & (curY >= botY) DO       NEW(L.next); L := L.next;       DisplayLine(F, L, R, F.X + F.left, curY, 0);       curY := curY - lsp     END;     L.next := F.trailer;     F.markH := SHORT(F.org * F.H DIV (F.text.len + 1))   END Extend;   PROCEDURE Reduce* (F: Frame; newY: SIGNED16);     VAR L: Line; curY, botY: SIGNED16;   BEGIN (*F.mark = 0*)     F.H := F.H + F.Y - newY; F.Y := newY;     botY := F.Y + F.bot + dsr;     L := F.trailer; curY := F.Y + F.H - F.top - asr;     WHILE (L.next # F.trailer) & (curY >= botY) DO       L := L.next; curY := curY - lsp     END;     L.next := F.trailer;     IF curY + asr > F.Y THEN       Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, curY + asr - F.Y, replace)     END;     F.markH := SHORT(F.org * F.H DIV (F.text.len + 1));     Mark(F, 1)   END Reduce;   PROCEDURE Show* (F: Frame; pos: SIGNED32);     VAR R: Texts.Reader; L: Line;       org: SIGNED32; curY, botY, Y0: SIGNED16;   BEGIN     IF F.trailer.next # F.trailer THEN Validate(F.text, pos);       IF pos < F.org THEN Mark(F, 0);         Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, F.H, replace);         botY := F.Y; F.Y := F.Y + F.H; F.H := 0;         F.org := pos; F.trailer.next := F.trailer; Extend(F, botY);         Mark(F, 1)       ELSIF pos > F.org THEN         org := F.org; L := F.trailer.next; curY := F.Y + F.H - F.top - asr;         WHILE (L.next # F.trailer) & (org # pos) DO           org := org + L.len; L := L.next; curY := curY - lsp;         END;         IF org = pos THEN           F.org := org; F.trailer.next := L; Y0 := curY;           WHILE L.next # F.trailer DO             org := org + L.len; L := L.next; curY := curY - lsp           END;           Display.CopyBlock             (F.X + F.left, curY - dsr, F.W - F.left, Y0 + asr - (curY - dsr),             F.X + F.left, curY - dsr + F.Y + F.H - F.top - asr - Y0, replace);           curY := curY + F.Y + F.H - F.top - asr - Y0;           Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, curY - dsr - F.Y, replace);           botY := F.Y + F.bot + dsr;           org := org + L.len; curY := curY - lsp;           Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);           WHILE ~L.eot & (curY >= botY) DO             NEW(L.next); L := L.next;             DisplayLine(F, L, R, F.X + F.left, curY, 0);             curY := curY - lsp           END;           L.next := F.trailer;           UpdateMark(F)         ELSE Mark(F, 0);           Display.ReplConst(F.col, F.X + F.left, F.Y, F.W - F.left, F.H, replace);           botY := F.Y; F.Y := F.Y + F.H; F.H := 0;           F.org := pos; F.trailer.next := F.trailer; Extend(F, botY);           Mark(F, 1)         END       END     END   END Show;   PROCEDURE LocateLine (F: Frame; y: SIGNED16; VAR loc: Location);     VAR L: Line; org: SIGNED32; cury: SIGNED16;   BEGIN     org := F.org; L := F.trailer.next; cury := F.H - F.top - asr;     WHILE (L.next # F.trailer) & (cury > y + dsr) DO       org := org + L.len; L := L.next; cury := cury - lsp     END;     loc.org := org; loc.lin := L; loc.y := cury   END LocateLine;   PROCEDURE LocateString (F: Frame; x, y: SIGNED16; VAR loc: Location);     VAR R: Texts.Reader;       bpos, pos, lim: SIGNED32;       bx, ex, ox: SIGNED16;       obj: Objects.Object;       continue (* outer loop *): BOOLEAN;   BEGIN     LocateLine(F, y, loc);     lim := loc.org + loc.lin.len - 1;     bpos := loc.org; bx := F.left;     pos := loc.org; ox := F.left;     Texts.OpenReader(R, F.text, loc.org); Texts.Read(R, ch);     continue := TRUE;     (* LOOP *) WHILE continue DO       (* LOOP *) (*scan string*)       WHILE (pos # lim) & (" " < ch) DO         R.lib.GetObj(R.lib, ORD(ch), obj);         IF ~(obj IS Fonts.Char) THEN obj := box END;         INC(pos); ox := ox + obj(Fonts.Char).dx; Texts.Read(R, ch)       END;       ex := ox;       (* LOOP *) (*scan gap*)       WHILE (pos # lim) & (ch <= " ") DO         R.lib.GetObj(R.lib, ORD(ch), obj);         IF ~(obj IS Fonts.Char) THEN obj := box END;         INC(pos); ox := ox + obj(Fonts.Char).dx; Texts.Read(R, ch)       END;       IF (pos = lim) OR (ox > x) THEN         (* EXIT *) continue := FALSE       ELSE         R.lib.GetObj(R.lib, ORD(ch), obj);         IF ~(obj IS Fonts.Char) THEN obj := box END;         bpos := pos; bx := ox;         INC(pos); ox := ox + obj(Fonts.Char).dx; Texts.Read(R, ch)       END     END;     loc.pos := bpos; loc.dx := ex - bx; loc.x := bx   END LocateString;   PROCEDURE LocateChar (F: Frame; x, y: SIGNED16; VAR loc: Location);     VAR R: Texts.Reader;       pos, lim: SIGNED32;       ox, dx: SIGNED16;       obj: Objects.Object;       continue (* one loop *): BOOLEAN;   BEGIN     LocateLine(F, y, loc);     lim := loc.org + loc.lin.len - 1;     pos := loc.org; ox := F.left;     Texts.OpenReader(R, F.text, loc.org); Texts.Read(R, ch);     continue := TRUE;     (* LOOP *) WHILE continue DO       IF pos = lim THEN         dx := eolW; (* EXIT *) continue := FALSE       ELSE         R.lib.GetObj(R.lib, ORD(ch), obj);         IF ~(obj IS Fonts.Char) THEN obj := box END;         dx := obj(Fonts.Char).dx;         IF ox + dx > x THEN           (* EXIT *) continue := FALSE         ELSE           INC(pos); ox := ox + dx; Texts.Read(R, ch)         END       END     END (* LOOP *);     loc.pos := pos; loc.dx := dx; loc.x := ox   END LocateChar;   PROCEDURE LocatePos (F: Frame; pos: SIGNED32; VAR loc: Location);     VAR R: Texts.Reader; L: Line; org: SIGNED32; cury: SIGNED16;   BEGIN     org := F.org; L := F.trailer.next; cury := F.H - F.top - asr;     WHILE (L.next # F.trailer) & (pos >= org + L.len) DO       org := org + L.len; L := L.next; cury := cury - lsp     END;     IF pos < org THEN pos := org       ELSIF pos >= org + L.len THEN pos := org + L.len - 1     END;     Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);     loc.org := org; loc.pos := pos; loc.lin := L;     loc.x := F.left + Width(R, pos - org); loc.y := cury   END LocatePos;   PROCEDURE Pos* (F: Frame; X, Y: SIGNED16): SIGNED32;     VAR loc: Location;   BEGIN LocateChar(F, X - F.X, Y - F.Y, loc);     RETURN loc.pos   END Pos;   PROCEDURE FlipCaret (F: Frame);   VAR ox, oy, ow, oh: SIGNED16;   BEGIN     IF MoveArea THEN       Display.GetClip(ox, oy, ow, oh);       Display.SetClip(F.X, F.Y, F.W, F.H);       Display.CopyPattern(FullColor, Display.hook, F.X + F.carloc.x, F.Y + F.carloc.y - 10, invert);       Display.SetClip(ox, oy, ow, oh)     ELSE       IF (F.carloc.y >= 10) & (F.carloc.x + 12 < F.W) THEN         Display.CopyPattern(FullColor, Display.hook, F.X + F.carloc.x, F.Y + F.carloc.y - 10, invert)       END     END   END FlipCaret;   PROCEDURE SetCaret* (F: Frame; pos: SIGNED32);   BEGIN     IF F.car # 0 THEN FlipCaret(F); F.car := 0 END;     LocatePos(F, pos, F.carloc);     IF F.carloc.pos = pos THEN FlipCaret(F); F.car := 1     ELSE       RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);       Show(F, pos - 100); LocatePos(F, pos, F.carloc);       IF F.carloc.pos = pos THEN FlipCaret(F); F.car := 1 END     END   END SetCaret;   PROCEDURE TrackCaret* (F: Frame; X, Y: SIGNED16; VAR keysum: SET);     VAR loc: Location; keys: SET;   BEGIN     IF F.trailer.next # F.trailer THEN       LocateChar(F, X - F.X, Y - F.Y, F.carloc);       FlipCaret(F);       keysum := {};       REPEAT         Input.Mouse(keys, X, Y);         keysum := keysum + keys;         Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y);         LocateChar(F, X - F.X, Y - F.Y, loc);         IF loc.pos # F.carloc.pos THEN FlipCaret(F); F.carloc := loc; FlipCaret(F) END       UNTIL keys = {};       F.car := 1     END   END TrackCaret;   PROCEDURE RemoveCaret* (F: Frame);   BEGIN IF F.car # 0 THEN FlipCaret(F); F.car := 0 END   END RemoveCaret;   PROCEDURE FlipSelection (F: Frame; VAR beg, end: Location);     VAR L: Line; Y: SIGNED16;     continue (* one loop *): BOOLEAN;   BEGIN     L := beg.lin; Y := F.Y + beg.y - 2;     IF L = end.lin THEN       ReplConst(FullColor, F, F.X + beg.x, Y, end.x - beg.x, selH, invert)     ELSE       ReplConst(FullColor, F, F.X + beg.x, Y, F.left + L.wid - beg.x, selH, invert);       continue := TRUE;       (* LOOP *) WHILE continue DO         L := L.next; Y := Y - lsp;         IF L = end.lin THEN           (* EXIT *) continue := FALSE         ELSE           ReplConst(FullColor, F, F.X + F.left, Y, L.wid, selH, invert)         END       END;       ReplConst(FullColor, F, F.X + F.left, Y, end.x - F.left, selH, invert)     END   END FlipSelection;   PROCEDURE SetSelection* (F: Frame; beg, end: SIGNED32);   BEGIN     IF end <= beg THEN end := beg + 1 END;     IF F.sel # 0 THEN FlipSelection(F, F.selbeg, F.selend) END;     LocatePos(F, beg, F.selbeg);     IF F.selbeg.pos # beg THEN Show(F, beg); LocatePos(F, beg, F.selbeg) END;     LocatePos(F, end, F.selend);     FlipSelection(F, F.selbeg, F.selend); F.time := Input.Time; F.sel := 1   END SetSelection;   PROCEDURE TrackSelection* (F: Frame; X, Y: SIGNED16; VAR keysum: SET);     VAR loc: Location; modKeys, keys: SET; M: Oberon.SelectMsg;   BEGIN       IF F.trailer.next # F.trailer THEN     	IF F.sel # 0 THEN FlipSelection(F, F.selbeg, F.selend) END;     	LocateChar(F, X - F.X, Y - F.Y, loc);     	IF (F.sel # 0) & (loc.pos = F.selbeg.pos) & (F.selend.pos = F.selbeg.pos + 1) THEN       	LocateChar(F, F.left, Y - F.Y, F.selbeg)     	ELSE F.selbeg := loc     	END;     	F.sel := 0;     	INC(loc.pos); loc.x := loc.x + loc.dx; F.selend := loc;     	FlipSelection(F, F.selbeg, F.selend);         keysum := {};     	REPEAT           Input.Mouse(keys, X, Y);       	keysum := keysum + keys;       	Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y);     	  LocateChar(F, X - F.X, Y - F.Y, loc);       	IF loc.pos < F.selbeg.pos THEN loc := F.selbeg END;       	INC(loc.pos); loc.x := loc.x + loc.dx;       	IF loc.pos < F.selend.pos THEN FlipSelection(F, loc, F.selend); F.selend := loc         	ELSIF loc.pos > F.selend.pos THEN FlipSelection(F, F.selend, loc); F.selend := loc       	END   	  UNTIL keys = {};        (* ps - 3.4.98 *)         Input.KeyState(modKeys);         IF Input.SHIFT IN modKeys THEN           M.id := Oberon.get; M.F := NIL; M.sel := NIL; M.text := NIL; M.time := -1; Display.Broadcast(M);           IF (M.time # -1) & (M.text = F.text) & (M.sel IS Frame) THEN             IF M.beg > F.selbeg.pos THEN M.beg := F.selbeg.pos END;             IF M.end < F.selend.pos THEN M.end := F.selend.pos END;             FlipSelection(F, F.selbeg, F.selend);             LocatePos(F, M.beg, F.selbeg); LocatePos(F, M.end, F.selend);             FlipSelection(F, F.selbeg, F.selend);             M.F := M.sel; M.id := Oberon.set; Display.Broadcast(M)           END         END;         F.time := Input.Time; F.sel := 1       END   END TrackSelection;   PROCEDURE RemoveSelection* (F: Frame);   BEGIN IF F.sel # 0 THEN FlipSelection(F, F.selbeg, F.selend); F.sel := 0 END   END RemoveSelection;   PROCEDURE TrackLine* (F: Frame; X, Y: SIGNED16; VAR org: SIGNED32; VAR keysum: SET);     VAR old, new: Location; keys: SET;   BEGIN         IF F.trailer.next # F.trailer THEN     	  LocateLine(F, Y - F.Y, old);     	  ReplConst(FullColor, F, F.X + F.left, F.Y + old.y - dsr, old.lin.wid, 2, invert);           keysum := {};       	REPEAT       	  Input.Mouse(keys, X, Y);       	  keysum := keysum + keys;             Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y);         	LocateLine(F, Y - F.Y, new);         	IF new.org # old.org THEN         	  ReplConst(FullColor, F, F.X + F.left, F.Y + old.y - dsr, old.lin.wid, 2, invert);        	   ReplConst(FullColor, F, F.X + F.left, F.Y + new.y - dsr, new.lin.wid, 2, invert);         	  old := new       	  END     	  UNTIL keys = {};     	  ReplConst(FullColor, F, F.X + F.left, F.Y + new.y - dsr, new.lin.wid, 2, invert);     	  org := new.org         ELSE org := -1         END   END TrackLine;   PROCEDURE TrackWord* (F: Frame; X, Y: SIGNED16; VAR pos: SIGNED32; VAR keysum: SET);     VAR old, new: Location; keys: SET;   BEGIN     IF F.trailer.next # F.trailer THEN 	  LocateString(F, X - F.X, Y - F.Y, old);   	ReplConst(FullColor, F, F.X + old.x, F.Y + old.y - dsr, old.dx, 2, invert);       keysum := {};       REPEAT     	Input.Mouse(keys, X, Y); 		keysum := keysum + keys;     	Oberon.DrawCursor(Oberon.Mouse, Oberon.Mouse.marker, X, Y);     	LocateString(F, X - F.X, Y - F.Y, new);     	IF new.pos # old.pos THEN       	ReplConst(FullColor, F, F.X + old.x, F.Y + old.y - dsr, old.dx, 2, invert);       	ReplConst(FullColor, F, F.X + new.x, F.Y + new.y - dsr, new.dx, 2, invert);       	old := new     	END   	UNTIL keys = {};   	ReplConst(FullColor, F, F.X + new.x, F.Y + new.y - dsr, new.dx, 2, invert);   	pos := new.pos; hintPos := new.org     ELSE pos := -1     END   END TrackWord;   (*--message handling*)   PROCEDURE RemoveMarks (F: Frame);   BEGIN RemoveCaret(F); RemoveSelection(F)   END RemoveMarks;   PROCEDURE GetAttr* (F: Frame; VAR s: ARRAY OF CHAR);     VAR S: Texts.Scanner;   BEGIN Texts.OpenScanner(S, F.text, 0); Texts.Scan(S); COPY(S.s, s)   END GetAttr;   PROCEDURE CallCmd (cmd: ARRAY OF CHAR; F: Frame; pos: SIGNED32; new: BOOLEAN);     VAR res: SIGNED16; par: Oberon.ParList;   BEGIN     NEW(par); par.vwr := Viewers.This(F.X, F.Y);     par.frame := F; par.text := F.text; par.pos := pos;     Oberon.Call(cmd, par, new, 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   END CallCmd;   PROCEDURE Call* (F: Frame; pos: SIGNED32; new: BOOLEAN);     VAR S: Texts.Scanner; i, h: SIGNED16; hint: ARRAY 32 OF CHAR;   BEGIN     IF SmallDisplay THEN       Texts.OpenScanner(S, F.text, pos); Texts.Scan(S); h := 0;       IF ((S.class = Texts.Char) & (S.c = ".") OR (S.class = Texts.Name) & (S.s[0] = ".")) THEN         (*find hint*)         Texts.OpenScanner(S, F.text, hintPos);         REPEAT           Texts.Scan(S);           IF S.class = Texts.Name THEN             i := 0; WHILE (i < S.len) & (S.s[i] # ".") DO INC(i) END;             IF (0 < i) & (i < S.len) THEN               h := 0; REPEAT hint[h] := S.s[h]; INC(h) UNTIL h > i             END           END         UNTIL Texts.Pos(S) > pos;         IF (S.class = Texts.Char) & (S.c = ".") THEN Texts.Scan(S) END       END;       IF S.class = Texts.Name THEN         IF h > 1 THEN (*use hint*)           i := S.len; IF S.s[0] = "." THEN DEC(h) END;           REPEAT S.s[i+h] := S.s[i]; DEC(i) UNTIL (i = -1) OR (S.s[i+1] = ".");           REPEAT DEC(h); S.s[h] := hint[h] UNTIL h = 0         END;         CallCmd(S.s, F, pos + S.len, new)       END     ELSE       Texts.OpenScanner(S, F.text, pos); Texts.Scan(S);       IF (S.line = 0) & (S.class = Texts.Name) THEN CallCmd(S.s, F, pos + S.len, new) END     END   END Call;   PROCEDURE Write* (F: Frame; ch: CHAR; lib: Objects.Library; col, voff: SIGNED8);   BEGIN (*F.car # 0*)     IF ch = 7FX THEN       IF F.carloc.pos > F.org THEN         Texts.Delete(F.text, F.carloc.pos - 1, F.carloc.pos);         SetCaret(F, F.carloc.pos - 1)       END     ELSIF ch = 0C3X THEN (* right *)       IF F.carloc.pos < F.text.len THEN         RemoveCaret(F); SetCaret(F, F.carloc.pos + 1)       END     ELSIF ch = 0C4X THEN (* left *)       IF F.carloc.pos > 0 THEN         RemoveCaret(F); SetCaret(F, F.carloc.pos - 1)       END     ELSIF (ch >= 0C1X) & (ch <= 0C4X) THEN     ELSIF (ch >= 0A0X) & (ch <= 0A9X) THEN     ELSIF (ch >= 0F0X) & (ch <= 0FFX) THEN     ELSE       KW.lib := lib; KW.col := col; KW.voff := voff; Texts.Write(KW, ch);       Texts.Insert(F.text, F.carloc.pos, KW.buf);       SetCaret(F, F.carloc.pos + 1)     END   END Write;   PROCEDURE Defocus* (F: Frame);   BEGIN RemoveCaret(F)   END Defocus;   PROCEDURE Neutralize* (F: Frame);   BEGIN RemoveMarks(F)   END Neutralize;   PROCEDURE Modify* (F: Frame; id, dY, Y, H: SIGNED16);   BEGIN     Mark(F, 0); RemoveMarks(F);     IF id = extend THEN       IF dY > 0 THEN         Display.CopyBlock(F.X, F.Y, F.W, F.H, F.X, F.Y + dY, replace); F.Y := F.Y + dY       END;       Extend(F, Y)     ELSIF id = reduce THEN       Reduce(F, Y + dY);       IF dY > 0 THEN Display.CopyBlock(F.X, F.Y, F.W, F.H, F.X, Y, replace); F.Y := Y END;     END;     IF F.H > 0 THEN Mark(F, 1) END   END Modify;   PROCEDURE Open* (         F: Frame; H: Objects.Handler; T: Texts.Text; org: SIGNED32;         col, left, right, top, bot, lsp: SIGNED16);     VAR L: Line;   BEGIN NEW(L);     L.len := 0; L.wid := 0; L.eot := FALSE; L.next := L;     F.handle := H; F.text := T; F.org := org; F.trailer := L;     F.left := left; F.right := right; F.top := top; F.bot := bot;     F.lsp := lsp; F.col := col; F.mark := 0; F.car := 0; F.sel := 0   END Open;   PROCEDURE Copy* (F: Frame; VAR F1: Frame);   BEGIN NEW(F1);     Open(F1, F.handle, F.text, F.org, F.col, F.left, F.right, F.top, F.bot, F.lsp)   END Copy;   PROCEDURE CopyOver* (F: Frame; text: Texts.Text; beg, end: SIGNED32);     VAR buf: Texts.Buffer;   BEGIN     IF F.car > 0 THEN       NEW(buf); Texts.OpenBuf(buf);       Texts.Save(text, beg, end, buf);       Texts.Insert(F.text, F.carloc.pos, buf);       SetCaret(F, F.carloc.pos + (end - beg))     END   END CopyOver;   PROCEDURE GetSelection* (F: Frame; VAR M: Oberon.SelectMsg);   BEGIN     IF F.sel > 0 THEN       IF (F.time - M.time > 0) OR (M.time = -1) THEN M.sel := F; M.time := F.time;         M.text := F.text; M.beg := F.selbeg.pos; M.end := F.selend.pos;         IF M.end > M.text.len THEN M.end := M.text.len END (*        ELSIF (F.text = M.text) & (F.selbeg.pos < M.beg) & (M.sel IS Frame) THEN         IF (M.beg <= M.sel(Frame).org) & (F.selend.pos >= Pos(F, F.X+F.W, F.Y)) THEN         	M.beg := F.selbeg.pos         END *)      ELSIF F.text = M.text THEN	(* extend selection over frame boundaries *)         (* 7.4.98 - ps *)         IF (F.selbeg.pos < M.beg) & (F.selend.pos >= Pos(F, F.X+F.W, F.Y)) THEN M.beg := F.selbeg.pos END;         IF (F.selend.pos > M.end) & (F.selbeg.pos = F.org) THEN M.end := F.selend.pos END;         IF M.end > F.text.len THEN M.end := F.text.len END       END     END   END GetSelection;   PROCEDURE GetCaret* (F: Frame; VAR M: Oberon.CaretMsg);   BEGIN IF F.car > 0 THEN M.text := F.text; M.pos := F.carloc.pos; M.car := F; M.res := 0 END   END GetCaret;   PROCEDURE LineLen (VAR R: Texts.Reader): SIGNED32;     VAR len: SIGNED32;   BEGIN len := 0;     WHILE (ch # CR) & (R.lib # NIL) DO INC(len); Texts.Read(R, ch) END;     Texts.Read(R, ch);     RETURN len + 1   END LineLen;   PROCEDURE Update* (F: Frame; beg, end, len: SIGNED32);     VAR R: Texts.Reader; L, LB, LR, LS: Line; done: BOOLEAN;       org, orgB, orgS, off, Llen: SIGNED32;       botY, Y, YB, YL, YR, YS, wid, H: SIGNED16;   BEGIN     IF end < F.org THEN F.org := F.org - (end - beg) + len;     ELSE       IF beg < F.org THEN         F.trailer.next.len := F.trailer.next.len + (F.org - beg);         F.org := beg       END;       botY := F.Y + F.bot + dsr;       org := F.org; Y := F.Y + F.H - F.top - asr; L := F.trailer.next;       WHILE (L # F.trailer) & (org + L.len <= beg) DO         org := org + L.len; Y := Y - lsp; L := L.next       END;       IF L # F.trailer THEN done := FALSE;         RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);         orgB := org; YB := Y; LB := L;         WHILE (L # F.trailer) & (org + L.len <= end) DO           org := org + L.len; Y := Y - lsp; L := L.next         END;         IF L # F.trailer THEN           org := org + L.len; Y := Y - lsp; L := L.next;           IF L # F.trailer THEN             YR := Y; LR := L; org := orgB; Y := YB;             Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);             Llen := LineLen(R);             WHILE (org + Llen <= beg + len) & (botY + lsp <= Y) DO               org := org + Llen; Y := Y - lsp; Llen := LineLen(R)             END;             org := org + Llen; Y := Y - lsp;             IF botY <= Y THEN (* update with reusing lines *)               YL := Y; L := LR;               WHILE (L.next # F.trailer) & (botY + lsp <= Y) DO                 org := org + L.len; Y := Y - lsp; L := L.next               END;               orgS := org; YS := Y; LS := L;               Display.CopyBlock (                 F.X + F.left, YS - dsr + (YR - YL), F.W - F.left, YL + lsp - YS, F.X + F.left, YS - dsr, replace);               org := orgB; Y := YB; L := LB;               Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);               off := beg - org; wid := Width(R, off);               ReplConst (F.col, F, F.X + F.left + wid, Y - dsr, L.wid - wid, lsp, 0);               DisplayLine(F, L, R, F.X + F.left + wid, Y, off);               WHILE org + L.len <= beg + len DO                 org := org + L.len; Y := Y - lsp; NEW(L.next); L := L.next;                 Display.ReplConst(F.col, F.X + F.left, Y - dsr, F.W - F.left, lsp, replace);                 DisplayLine(F, L, R, F.X + F.left, Y, 0)               END;               L.next := LR;               org := orgS; Y := YS; L := LS; org := org + L.len; Y := Y - lsp;               Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);               WHILE ~L.eot & (botY <= Y) DO                 NEW(L.next); L := L.next;                 Display.ReplConst(F.col, F.X + F.left, Y - dsr, F.W - F.left, lsp, replace);                 DisplayLine(F, L, R, F.X + F.left, Y, 0);                 org := org + L.len; Y := Y - lsp               END;               L.next := F.trailer;               IF YR < YL THEN H := Min(YL- YR, Y + lsp - dsr - F.Y);                 Display.ReplConst(F.col, F.X + F.left, Y + lsp - dsr - H, F.W - F.left, H, replace)               END;               done := TRUE             END           END         END;         IF ~done THEN (* update without reusing lines *)           YR := Y; org := orgB; Y := YB; L := LB;           Texts.OpenReader(R, F.text, org); Texts.Read(R, ch);           off := beg - org; wid := Width(R, off);           ReplConst (F.col, F, F.X + F.left + wid, Y - dsr, L.wid - wid, lsp, 0);           DisplayLine(F, L, R, F.X + F.left + wid, Y, off);           WHILE ~L.eot & (botY + lsp <= Y) DO             org := org + L.len; Y := Y - lsp; NEW(L.next); L := L.next;             Display.ReplConst(F.col, F.X + F.left, Y - dsr, F.W - F.left, lsp, replace);             DisplayLine(F, L, R, F.X + F.left, Y, 0)           END;           org := org + L.len; Y := Y - lsp;           IF (Y < botY) & (org <= beg + len) & (beg + len < org + 500) THEN (*autoscroll*)             REPEAT               Display.CopyBlock               (F.X + F.left, Y + lsp - dsr, F.W - F.left, F.Y + F.H - F.top - asr - Y - lsp,                   F.X + F.left, Y + lsp - dsr + lsp,               replace);               F.org := F.org + F.trailer.next.len;               L.next := F.trailer.next; F.trailer.next := F.trailer.next.next;               L := L.next;               Display.ReplConst(F.col, F.X + F.left, Y + lsp - dsr, F.W - F.left, lsp, replace);               DisplayLine(F, L, R, F.X + F.left, Y + lsp, 0);               org := org + L.len             UNTIL org > beg + len           END;           L.next := F.trailer;           IF YR < Y THEN             Display.ReplConst (F.col, F.X + F.left, YR + lsp - dsr, F.W - F.left, Y - YR, replace)           END         END       END     END;     UpdateMark(F)   END Update;   PROCEDURE Recall (F: Frame);     VAR buf: Texts.Buffer; pos: SIGNED32;   BEGIN     IF F.car > 0 THEN 	  NEW(buf); Texts.OpenBuf(buf);       Texts.Recall(buf); pos := F.carloc.pos + buf.len; 	  Texts.Insert(F.text, F.carloc.pos, buf);       SetCaret(F, pos)     END   END Recall;   PROCEDURE SaveCaret;   BEGIN     saved.car := NIL; saved.text := NIL;     saved.id := Oberon.get; Display.Broadcast(saved)   END SaveCaret;   PROCEDURE RestoreCaret;   BEGIN     IF (saved.car # NIL) & (saved.text # NIL) THEN       saved.id := Oberon.set; Display.Broadcast(saved)     END   END RestoreCaret;   PROCEDURE Edit* (F: Frame; X, Y: SIGNED16; Keys: SET);     VAR       M: Oberon.ConsumeMsg;       R: Texts.Reader;       text: Texts.Text; buf: Texts.Buffer;       time, pos, beg, end: SIGNED32;       keysum: SET;       ch: CHAR;   BEGIN     Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y);     IF X < F.X + Min(F.left, barW) THEN       IF (0 IN Keys) OR (1 IN Keys) THEN keysum := Keys;         REPEAT           Input.Mouse(Keys, X, Y);           keysum := keysum + Keys;           Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y)         UNTIL Keys = {};         IF ~(2 IN keysum) THEN           RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);           IF (0 IN keysum) OR (F.Y + F.H < Y) THEN             IF 1 IN keysum THEN pos := 0             ELSE pos := Max(F.org - LONG(F.H * 25) DIV lsp, 0)             END           ELSE             pos := (F.Y + F.H - Y) * (F.text.len) DIV F.H           END;           RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);           Show(F, pos)         ELSIF ~(0 IN keysum) THEN           RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);           Show(F, F.text.len)         END       ELSIF 2 IN Keys THEN         TrackLine(F, X, Y, pos, keysum);         IF (pos >= 0) & ~(0 IN keysum) THEN           RemoveMarks(F); Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);           Show(F, pos)         END       END     ELSE       IF 0 IN Keys THEN         TrackSelection(F, X, Y, keysum);         IF F.sel # 0 THEN           IF (2 IN keysum) & ~(1 IN keysum) THEN (*delete text*)             Oberon.GetSelection(text, beg, end, time);             Texts.Delete(text, beg, end);             Oberon.Defocus; SetCaret(F, beg)           ELSIF (1 IN keysum) & ~(2 IN keysum) THEN (*copy to focus*)             Oberon.GetSelection(text, beg, end, time);             M.F := NIL; M.text := text; M.beg := beg; M.end := end;             Display.Broadcast(M)     	  END         END       ELSIF 1 IN Keys THEN         TrackWord(F, X, Y, pos, keysum);         IF 0 IN keysum THEN           IF (pos >= 0) & ~(2 IN keysum) THEN CallCmd(OpenCmd, F, pos, FALSE) END         ELSE           IF pos >= 0 THEN Call(F, pos, 2 IN keysum) END         END       ELSIF 2 IN Keys THEN         IF Oberon.New & (F.car # 0) & (Pos(F, X, Y) = F.carloc.pos) THEN (*click on caret*)           Oberon.Defocus; RestoreCaret; TrackWord(F, X, Y, pos, keysum);           IF 0 IN keysum THEN             IF (pos >= 0) & ~(1 IN keysum) THEN CallCmd(OpenCmd, F, pos, FALSE) END           ELSE             IF pos >= 0 THEN Call(F, pos, FALSE) END           END         ELSE           IF Oberon.New THEN SaveCaret END;           Oberon.Defocus; TrackCaret(F, X, Y, keysum);           IF F.car # 0 THEN             IF (1 IN keysum) & ~(0 IN keysum) THEN (*copy from selection*)               Oberon.GetSelection(text, beg, end, time);               IF time # -1 THEN                  NEW(buf); Texts.OpenBuf(buf);                  Texts.Save(text, beg, end, buf);                  Texts.Insert(F.text, F.carloc.pos, buf);                  SetCaret(F, F.carloc.pos + (end - beg))                ELSE (*copy from delete buffer*)                  NEW(buf); Texts.OpenBuf(buf);                  Texts.Recall(buf);                  end := F.carloc.pos + buf.len;                  Texts.Insert(F.text, F.carloc.pos, buf);                  SetCaret(F, end)                END             ELSIF (0 IN keysum) & ~(1 IN keysum) THEN (*copy font*)               Oberon.GetSelection(text, beg, end, time);               IF time # -1 THEN                 Texts.OpenReader(R, F.text, F.carloc.pos); Texts.Read(R, ch);                 IF (R.lib # NIL) & (R.lib IS Fonts.Font) THEN                   Texts.ChangeLooks(text, beg, end, {0, 1, 2}, R.lib, R.col, R.voff)                 END               END             END           END         END       END     END   END Edit;   PROCEDURE Handle* (F: Objects.Object; VAR M: Objects.ObjMsg);   	VAR F1: Frame;   BEGIN     WITH F: Frame DO   	IF M IS Texts.UpdateMsg THEN   	  WITH M: Texts.UpdateMsg DO           IF F.text = M.text THEN Update(F, M.beg, M.end, M.len) END   	  END       ELSIF M IS Oberon.InputMsg THEN          WITH M: Oberon.InputMsg DO           IF M.id = Oberon.track THEN Edit(F, M.X, M.Y, M.keys)           ELSIF M.id = Oberon.consume THEN   	      IF F.car # 0 THEN Write(F, M.ch, M.fnt, M.col, M.voff) END           END          END       ELSIF M IS Oberon.ControlMsg THEN         WITH M: Oberon.ControlMsg DO   	    IF M.id = Oberon.defocus THEN Defocus(F)   	    ELSIF M.id = Oberon.neutralize THEN Neutralize(F)           END         END       ELSIF M IS Oberon.CaretMsg THEN         WITH M: Oberon.CaretMsg DO           IF M.id = Oberon.get THEN GetCaret(F, M)           ELSIF (M.car = F) & (M.text = F.text) THEN             IF M.id = Oberon.set THEN SetCaret(F, M.pos)               ELSIF M.id = Oberon.reset THEN RemoveCaret(F)             END           END         END       ELSIF M IS Oberon.SelectMsg THEN         WITH M: Oberon.SelectMsg DO           IF M.id = Oberon.get THEN GetSelection(F, M)           ELSIF (M.sel = F) & (M.text = F.text) THEN             IF M.id = Oberon.set THEN SetSelection(F, M.beg, M.end)               ELSIF M.id = Oberon.reset THEN RemoveSelection(F)             END           END         END       ELSIF M IS Oberon.ConsumeMsg THEN         WITH M: Oberon.ConsumeMsg DO           CopyOver(F, M.text, M.beg, M.end)         END       ELSIF M IS Oberon.RecallMsg THEN         WITH M: Oberon.RecallMsg DO Recall(F) END       ELSIF M IS Display.ModifyMsg THEN         WITH M: Display.ModifyMsg DO           IF M.F = F THEN Modify(F, M.id, M.dY, M.Y, M.H) END         END       ELSIF M IS Display.LocateMsg THEN         WITH M: Display.LocateMsg DO           IF (F.X <= M.X) & (M.X < F.X + F.W) & (F.Y <= M.Y) & (M.Y < F.Y + F.H) THEN             M.loc := F; M.res := 0           END         END       ELSIF M IS Objects.AttrMsg THEN         WITH M: Objects.AttrMsg DO GetAttr(F, M.s); M.class := Objects.String; M.res := 0 END       ELSIF M IS Objects.CopyMsg THEN         WITH M: Objects.CopyMsg DO Copy(F, F1); M.obj := F1 END       ELSIF M IS Objects.LinkMsg THEN         WITH M: Objects.LinkMsg DO M.obj := F.text; M.res := 0 END   	END     END   END Handle;   (*creation*)   PROCEDURE Menu (name, commands: ARRAY OF CHAR): Texts.Text;     VAR T: Texts.Text; mb, me, m, s, d, i: SIGNED16; ch: CHAR;     continueOuter, continueInner: BOOLEAN;   BEGIN     IF SmallDisplay & (Display.Width < 1024) THEN (*adjust commands*)       mb := 0; me := 0; s := 0; d := 0;       continueOuter := TRUE;       (* outer LOOP *) WHILE continueOuter DO         (*position to beginning of word*)         continueInner := TRUE;         (* LOOP 0 *) WHILE continueInner DO           IF s >= LEN(commands) THEN             (* EXIT *) continueInner := FALSE           ELSE             ch := commands[s]; INC(s);             IF ch = 0X THEN               (* EXIT *) continueInner := FALSE             ELSE               commands[d] := ch; INC(d);               IF ("A" <= CAP(ch)) & (CAP(ch) <= "Z") THEN (* EXIT *) continueInner := FALSE END             END           END         END (* LOOP 0 *);         IF (s >= LEN(commands)) OR (ch = 0X) THEN           (* EXIT *) continueInner := FALSE         ELSE           (*scan first part of word, checking against last module name*)           m := mb; i := 0;           continueInner := TRUE;           (* LOOP 1 *) WHILE continueInner DO             INC(i); IF (m < me) & (commands[m] = ch) THEN INC(m) END;             IF s >= LEN(commands) THEN               (* EXIT *) continueInner := FALSE             ELSE               ch := commands[s]; INC(s);               IF ch = 0X THEN                 (* EXIT *) continueInner := FALSE               ELSE                 commands[d] := ch; INC(d);                 IF (ch < "0") OR ("9" < ch) & (CAP(ch) < "A") OR (CAP(ch) > "Z") THEN                   (* EXIT *) continueInner := FALSE                 END               END             END           END (* LOOP 1 *);              (*check for match*)           IF (s < LEN(commands)) & (ch = ".") THEN             IF m = mb + i THEN (*matches previous module name - compress*)               DEC(d, i); commands[d-1] := "."             ELSE (*set new module name*)               mb := d - (i+1); me := d-1             END;                          (*and do last part of word*)             continueInner := TRUE;             (* LOOP 2 *) WHILE continueInner DO               IF s >= LEN(commands) THEN                 (* EXIT *) continueInner := FALSE               ELSE                 ch := commands[s]; INC(s);                 IF ch = 0X THEN                   (* EXIT *) continueInner := FALSE                 ELSE                   commands[d] := ch; INC(d);                   IF (ch < "0") OR ("9" < ch) & (CAP(ch) < "A") OR (CAP(ch) > "Z") THEN                     (* EXIT *) continueInner := FALSE                   END                 END               END             END (* LOOP 2 *)                        END;           IF (s >= LEN(commands)) OR (ch = 0X) THEN (* EXIT *) continueOuter := FALSE END         END       END (* outer LOOP *);       IF d < LEN(commands) THEN commands[d] := 0X END     END;     NEW(T); Texts.Open(T, "");     Texts.WriteString(W, name); Texts.WriteString(W, " | "); Texts.WriteString(W, commands);     Texts.Append(T, W.buf);     RETURN T  END Menu;   PROCEDURE Text* (name: ARRAY OF CHAR): Texts.Text;     VAR T: Texts.Text;   BEGIN NEW(T); Texts.Open(T, name); RETURN T   END Text;   PROCEDURE NewMenu* (name, commands: ARRAY OF CHAR): Frame;     VAR F: Frame; l: SIGNED16;   BEGIN NEW(F);     IF MoveArea THEN l := barW-1 ELSE l := left DIV 4 END;     IF Modern THEN Open(F, Handle, Menu(name, commands), 0, MenuBG, l, 0, 3, 1, lsp)     ELSE Open(F, Handle, Menu(name, commands), 0, MenuBG, l, 0, 1, 0, lsp)     END;     RETURN F   END NewMenu;   PROCEDURE NewText* (text: Texts.Text; pos: SIGNED32): Frame;     VAR F: Frame;   BEGIN NEW(F);     Open(F, Handle, text, pos, TextBG, left, right, top, bot, lsp);     RETURN F   END NewText; PROCEDURE ShowText(title: ARRAY OF CHAR; T: Texts.Text; W, H: SIGNED16); 	VAR X, Y: SIGNED16; V: Viewers.Viewer; menu: ARRAY 100 OF CHAR; BEGIN 	X := 0; WHILE (title[X] # 0X) & (title[X] # "|") DO INC(X) END; 	IF title[X] = "|" THEN 		title[X] := 0X; INC(X);  Y := 0; 		WHILE title[X] # 0X DO menu[Y] := title[X]; INC(X);  INC(Y) END; 		menu[Y] := 0X 	ELSE 		menu := "" 	END; 	IF T = Oberon.Log THEN 		Oberon.AllocateSystemViewer(0, X, Y); 		IF menu = "" THEN menu := LogMenu END; 		V := MenuViewers.New(NewMenu(title, menu), NewText(T, Max(T.len-200, 0)), menuH, X, Y) 	ELSE 		IF W > LONG(Display.Width * 3) DIV 8 THEN Oberon.AllocateUserViewer(0, X, Y) 		ELSE Oberon.AllocateSystemViewer(0, X, Y) 		END; 		IF menu = "" THEN menu := StandardMenu END; 		V := MenuViewers.New(NewMenu(title, menu), NewText(T, 0), menuH, X, Y) 	END END ShowText; (** Replace the default system editor with a textframe. *) PROCEDURE ReplaceSystemEditor*; BEGIN 	Oberon.OpenText := ShowText END ReplaceSystemEditor; BEGIN   IF Oberon.OpenText = NIL THEN     Oberon.OpenText := ShowText   END;   IF Display.Depth(0) # 1 THEN     MarkColor := 12; MenuBG := 13; TextBG := 14;     IF Modern THEN BarColor := 12; FullColor := Display.FG - TextBG     ELSE BarColor := 13; FullColor := Display.FG     END;     mode := paint   ELSE     MarkColor := Display.FG; BarColor := Display.FG; MenuBG := Display.FG; TextBG:= Display.BG;     FullColor := Display.FG; mode := invert   END;   IF Modern THEN menuH := Fonts.Default.height + 8   ELSE menuH := Fonts.Default.height + 2   END;   barW := Fonts.Default.height + 2;   left := barW + Fonts.Default.height DIV 2;   right := Fonts.Default.height DIV 2;   IF Modern THEN top := Fonts.Default.height DIV 2 * 2 DIV 3   ELSE top := Fonts.Default.height DIV 2   END;   bot := Fonts.Default.height DIV 2;   asr := Fonts.Default.maxY;   dsr := -Fonts.Default.minY;   lsp := Fonts.Default.height;   selH := Fonts.Default.height;   markW := Fonts.Default.height DIV 3 * 2;   eolW := Fonts.Default.height DIV 2;   Texts.OpenWriter(W); Texts.OpenWriter(KW);   BoxPat[0] := {0..11};   BoxPat[1] := {0, 11}; BoxPat[2] := {0, 11}; BoxPat[3] := {0, 11}; BoxPat[4] := {0, 11};   BoxPat[5] := {0, 11}; BoxPat[6] := {0, 11}; BoxPat[7] := {0, 11}; BoxPat[8] := {0, 11};   BoxPat[9] := {0, 11}; BoxPat[10] := {0, 11}; BoxPat[11] := {0.. 11};   NEW(box);   box.dx := 12; box.x := 0; box.y := -3; box.w := 12; box.h := 12;   box.pat := Display.NewPattern(12, 12, BoxPat) END TextFrames.

title: Oberon/A2/Oberon.TextFrames.Mod


text:
Chess Opening Theory/1. e4/1...e5/2. Nf3/2...Nc6/3. Nc3/3...f5

=Winawer Defense=

3...f5
The Winawer Defense, also known as the Gothic Defense, is an excellent response by Black instead of transposing into a Four Knight's Game. Black gambits the pawn on f5; if white accepts, the gambit creates an equalizing position for black and black often plays 4...Nf6.

Theory table
'''1. e4 e5 2. Nf3 Nc6 3. Nc3 f5'''

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Talk:Programming Gambas from Zip/SQLite

Untitled
I Cant get the finance program to work. Any help ? — Preceding unsigned comment added by Frasselio (talk • contribs) 17:19, 6 January 2021 (UTC)

title: Talk:Programming Gambas from Zip/SQLite


text:
Vietnamese/Predicative Adjective

When an adjetive modifies a noun funtioning as an attribute of the noun modified, it follows the noun.
 * Cô Hà có nhà đẹp
 * Miss Hà has a beautiful House.
 * Tôi thấy.... : I'm...
 * rấ vui. : so happy.
 * buốn. : sad.
 * ngạc nhiên. : suprise.
 * xấu nổ. : shy.
 * tức giận. : angry.
 * lo lắng. : worried.
 * đáng yêu. : cute.
 * buốn ngủ. : asleep.
 * chán. : boring.

title: Vietnamese/Predicative Adjective


text:
Vietnamese/Lesson 3

 * Chi là người nưốc nào?
 * Where are you from?
 * Tôi là ...
 * I'm...
 * người việt.
 * Vietnamese.
 * người anh.
 * English.
 * người mỹ.
 * American.
 * người pháp.
 * French.
 * người bra xin.
 * Brazilian.
 * người nga.
 * Russian.
 * người ấn độ.
 * Indian.
 * người thái.
 * Thailandian.
 * người úc.
 * Australian.

title: Vietnamese/Lesson 3


text:
Vietnamese/Verb index

 * To want : muốn
 * To go : đi
 * To write : viết
 * To be : là
 * To have : có
 * To do : làm
 * To speak : nói
 * To use : dùng, sử dụng
 * To find : tìm thấy
 * To buy : mua

title: Vietnamese/Verb index


text:
Vietnamese/Demonstratives

 * Cái này là cái gì?
 * What is this?
 * Cái này là sàch
 * This is a book
 * Cái kia là cài gì?
 * What is that?
 * Cái kia là vó
 * That is a note
 * Cái đó là cài gì?
 * What is that?
 * Cái đó là mày tính
 * That is a computer
 * Người đó là em của tôi
 * That is my younger Sister
 * Đây là số điện tho ại của tôi
 * This is my phone number

title: Vietnamese/Demonstratives


text:
User:Milenioscuro

For any comments or suggestions please go to my main account Milenioscuro in the Spanish Wikipedia

title: User:Milenioscuro


text:
History of video games/Platforms/Moranbong

History
As early as the year 2000 concerns about using North Korea using games consoles as guidance computers for weapons platforms lead to export restrictions of gaming hardware to North Korea. Additionally there is a high poverty rate in the North Korean general population, as well as a state controlled and censored entertainment industry which has contributed to a rather small video game industry in the country. However by the late 2010's there was high demand for foreign entertainment products in the country, especially by the elite of North Korea.

The Moranbong is perhaps the only game console to see an official release in North Korea. The system caught the attention of gaming media outlets following a press release by a North Korean website on September 9th, 2019. The console is marketed as a way to improve physical fitness through exergaming, which it achieves with motion controls. The North Korean cartoon character Clever Raccoon Dog was apparently used in console promotions.

Due to the closed nature of North Korea, little more is known about the console outside the country. Still the console is historically significant, as it not only is likely the first game console made for the North Korean market, it is also a sign that the North Korean government views video games as an entertainment medium it can use to further its policies, as this console is focused on making the population more fit. Such explicit political involvement in a game console is rare, and provides a fascinating insight to the priorities of the North Korean government.

Technology
The game console uses camera based motion controls, remotes, and a floor mat to allow for exergaming experiences. The game console also doubles as an general multimedia device, and has edutainment software. The Moranbong appears to be a localized version of either the Subor G80, or the Cdragon Cassidy G80 both game consoles from China.

Again, due to the closed nature of North Korea, little more is known about the technology used by the console, or what games it can play.


text: Category:Book:Fatida

title: Category:Book:Fatida


text:
History of wireless telegraphy and broadcasting in Australia/Topical/Biographies/Alfred Harold Masters/Research

To date all research has been very largely limited to NLA's Trove, and further to Trove, Newspapers & Gazettes

In the National Library of Australia's Trove website, more than 960 articles (Newspapers & Gazettes) have been tagged as "Alfred Harold Masters" (search publictag:Alfred Harold Masters)

The main searches used to identify articles for tagging are as follows:
 * With phrase "A. H. Masters", without "Shipping", State "Tasmania", Category "Article" (554 hits)
 * With phrase "Harold Masters", without "Shipping", State "Tasmania", Category "Article"

Key articles relating to Masters and wireless, also Masters' family history, have been identified for text correcting and inclusion in Transcriptions and Notes - Alfred Harold Masters. Articles transcribed for Notes are tagged: "!Wikibooks AH Masters" (66 articles). Articles reviewed and considered either duplicates of other articles or not of sufficient importance for inclusion are tagged: "!Wikibooks AH Masters Not" (38 articles).


text:
Category talk:Book:C++ Programming

Write a C++ program that declares an array of 10 components of type int, and then use the array to do the following:  Fill the array components with integers from the user.  Count and print the number of components that are divisible by the first element in the array.  Print the array elements, one element in each line followed by ‘*’ depends on the number

title: Category talk:Book:C++ Programming


text:
History of wireless telegraphy and broadcasting in Australia/Topical/Biographies/Alfred Harold Masters/Wikipedia

Alfred Harold "Harold" Masters (7 Nov 1875 - 27 Apr 1951) was one of Tasmania's earliest wireless and X-ray experimenters. He was for many years councillor and superintendent of Launceston Technical School. A prominent Launceston architect and electrical engineer, he designed several of Launceston and district's major buildings. He planned and oversighted commissioning of electric light systems in several towns in northern Tasmania. He was an early advocate for adoption of hydro-electric power. Masters represented the Tasmanian Chapter of the Royal Australian Institute of Architects and actively promoted adoption of town planning principles in the Launceston community where he lived his entire adult life.

Early life
Alfred Harold "Harold" Masters was the second child of Joseph Masters (1845 - 1925) and Ann Auchterlonie Masters nee Anderson (1843 - 1904). Harold was born 7 November 1875 at Kew, Victoria. His father, Joseph Masters received a Master of Arts at Melbourne University and was a Congregational minister in Victoria, New South Wales and Tasmania. In 1887 he was appointed Inspector of Schools in Northern Tasmania, then Director of Education, finally Secretary of Education, retiring in 1918. He married Ann Aucherlonie Anderson at St Kilda, Victoria 13 March 1872. They had six children together:
 * William Edward Masters (1873 - 1952) BA, LL.B Melbourne University, barrister at Hobart, Hobart historian m. Rowena Ella "Ella" Masters nee Spong
 * Alfred Harold Masters (1875 - 1951) architect, Launceston, the subject of this article
 * Annie Lillian Masters (1876 - 1877) died as a baby
 * Rosa Masters (1878 - 1954) never married, Artist
 * Arthur Murray Masters (1880 - 1929) M.D. Edinburgh University
 * Herbert Masters (1884 - 1900) died of typhoid, age 15

Architecture
Masters commenced his architectural career in the late 1880s in the architectural department of J. and T. Gunn, a business which had been established in Launceston in the mid 1870s as timber merchants and progressively expanded its operations into all classes of building supplies. In late 1897 he commenced as a sole trader, advertising as Architect and Electrician, with premises at A.M.P. Chambers, Cameron St., Launceston. The business developed rapidly, early major appointments were to the new wing of the Queen Victoria Hospital (Launceston) in 1900, the new Devon Cottage Hospital in 1902 , a further new wing (Dunorlan-Noake) of the Queen Victoria Hospital in 1903 , the Saddler's Arms Hotel (Elizabeth Town) in 1903 and extensive alterations to St. Andrew's Church (Launceston). For a time Masters partnered with Alexander (Eric) North

Architecture Institute
The Tasmanian Association of Architects was formed in 1903 and Masters was involved at an early stage, holding the position of Hon. Secretary for several years. In 1908 Masters was elected president of the association and continued in various roles thereafter. About 1910 the association was renamed the Tasmanian Institute of Architects and in 1915 a Federal Council of Australian Architects was formed and the institute affiliated with that group. In 1919 Masters was again elected president and also to represent the institute at national conference. In 1922 Masters was in a delegation of architects urging the government to seek input from the council in the design and planning for the national capital, Canberra. Throughout the 1920s and 1930s Masters continued in various roles with the Tasmanian Institute (eg vice-president 1934 ; president 1935 ; past-president 1936 ).

Electrical Engineer
Masters was a strong advocate for the use hydro-electric power in northern Tasmania where the multiplicity of local councils tended to favour control of their own smaller plants. In February 1925 he published an opinion piece immediately prior to a referendum on the subject in Longford.

Launceston Technical School
The Launceston Technical School (later Technical College) was established in 1888 and Masters was amongst the first pupils. He was awarded a prize in Art at the first exhibition in early 1890. His association with the school continued his entire life. As a student he undertook instruction in Building Construction, Art and Perspective, Magnetism and Electricity. In late 1896 Masters commenced as instructor in electricity, that class having lapsed for a time.

Wireless Experiments
There do not appear to be contemporaneous reports of Masters experimenting in wireless prior to 1900, however he was lecturing in electricity and magnetism from the late 1890s at the Launceston Technical School. Thomas Edward Self was the first to demonstrate wireless (to the Royal Society) in Tasmania in July 1898 and his experiments were widely reported. Likely Masters' experiments followed in 1899 and were limited to indoors rather than long distance. Masters' gave a lecture and demonstration of X-rays at the Victoria Museum in September 1901 and promised a further lecture on wireless telegraphy. Finally, in October 1905 (post Wireless Telegraphy Act 1905 and apparently unlicensed), he gave a lecture and demonstration of wireless to the Launceston Branch of the Australian Natives' Association. In November 1905 a further lecture and demonstration was given by Masters to some 400 persons at the Victoria Museum. For this demonstration, Masters supplemented his own equipment by arranging the loan of low power Telefunken equipment from their Melbourne agency. This is believed to be the first land use of Telefunken equipment in Australia. Masters was aided in the demonstration by Post Office telegraphists G. Braithwaite and T. P. Richardson. In February 1906, HMS Pioneer anchored at Rosevears near Launceston and Masters was part of the official party. He inspected the Pioneer's wireless equipment and scheduled experiments using his own equipment. Masters, Richardson and Braithwaite set up the equipment the Albert Hall with an antenna attached to the flagstaff. In the following days, they successfully transmitted to the HMS Pioneer, at anchor and en route to Devonport, however the receiving was less satisfactory. Masters continued with lecturing in wireless telegraphy and in May 1906 lectured on that topic to the St. John's Young Men's Club. When the temporary AWA wireless telegraphy link was about to be established between Queenscliff and Devonport, local Launceston reporters sought out Masters for expert advice on wireless telegraphy principles and practice. There is no record of a licence under the Wireless Telegraphy Act 1905 having been issued for any of these experiments. Masters continued to promote wireless telegraphy in Launceston up to the start of World War I. Twin brothers Cyril Wilson Monk (later callsign: 7BR) and Alfred Brendon Monk who became telegraphists in the Naval Wireless Service in 1911 were pupils of Masters at the Launceston Technical School.

Amateur Radio
Masters is not reported as playing a part in the initial formation of the Launceston Wireless Club from August 1923 in the excitement of the commencement of the Wireless Regulations 1923. However, when the club soon restructured into the Launceston Branch of the Wireless Institute of Australia (Tasmanian Division), Masters was elected as one of the vice-presidents. In January 1924, he lectured to a meeting of the branch on the "Advance of Radio Science" and again in April 1924 on "Magnetic Induction as applied to Wireless" The first annual meeting of the club in September 1924 reflected general apathy of the members, the widespread man-made interference ("the Roar") being experienced in Launceston a major factor. Masters was thanked for his contributions and elected Chairman of the Council. He published a detailed hypothesis on causation of the Roar, and set the resources of the club to locate and identify. However a competing club had been established in October 1924, the Launceston Radio Experimenters' Club, in response to beaurocracy and lack of actual wireless experimenting activities. The new club comprised the majority of Launceston's active experimenters and took up the investigation into the roar. Despite all efforts the roar remained for several years and progressively diminished as better power distribution equipment was implemented. In September 1925, the Wireless Institute of Australia (Tasmanian Division) was formed with a view to meeting the needs of all Tasmanian experimenters and Masters was elected first president. From 1927, he withdrew from administrative activities in amateur radio, though his interest continued. In September 1933 the Launceston Technical College decided to commence a course in radio engineering and Masters was instrumental in this. In 1935 the College supplemented the radio engineering course with with a one year course specifically focussed on the award of the Postmaster-General's Department Amateur Operators Certificate of Proficiency. In the lead up to World War I, in April 1939, the Launceston Technical College made available its facilities to the Royal Australian Air Force Selection Board for the examination of candidates as fitters and wireless operators.

Family
Masters married Alice Weymouth on 29 November 1899 at Launceston. At the time of her marriage, Alice was employed as a milliner, but subsequently devoted herself to her family. She was the third daughter in a large family of 10, her parents being Alfred Weymouth (carpenter, 1842 - 1925) and Martha Elizabeth nee Cooper (1853 - 1910). Harold and Alice had 5 children together:
 * Muriel Frances Masters (1900 - 1979) librarian, never married
 * Thelma Francis Masters (1902 - 1960) never married
 * Alma Jean "Jean" Masters (1905 - 1933) never married
 * Alan Ewan Masters (1907 - 1977) married Katherine Jean Will
 * Enid Joyce Masters (1911 - 2002) married Edney Herbert Forward


text:
User:Shenlebantongying/deleted

What i deleted:

= From Ruby_Programming/Installing_Ruby =

Terminal emulators
Knowing how to use a terminal emulator is very useful if you are programming. Usually it will provide the most straightforward access to commands and applications instead of hiding it behind graphical interfaces. On the other hand they are often daunting to beginners since they are often perceived to require a deep understanding of a computer when in fact often only knowing the very basics is already enough to get started.

Unix-like operating systems

One of the most commonly used shells in the Unix-like operating systems (i.e. macOS, GNU/Linux, BSD) is the Bash shell, in fact it is very often the default shell. To start a session you will often use a terminal emulator, which allow you to use a terminal session at the same time as other graphical applications. It doesn't really matter, which terminal emulator you use, generally you want one that has color and Unicode support. In macOS you can use Terminal.app which you can find under Applications > Utilities. A popular alternative is iTerm. On most Linux distributions you will usually be provided with at least one terminal emulator by default, otherwise you might want to try Terminator, Konsole, rxvt-unicode or something different.

When you open a new window or tab in your terminal emulator of choice you will be shown your prompt. What it looks like exactly depends a lot on configuration, which can vary greatly from OS to OS (you can configure everything to your likings, however this exceeds the scope of this short introduction). Generally it will indicate your current working directory, username and hostname. When working in the shell your session always has current working directory. Commands that accept relative filenames will use that directory as the base directory to look for files. By default you are in your user's home folder, which is often abbreviated with a tilde.

To execute a command you just type it into the shell and press enter.

At first we want to look at the command  . If you type it in just like that it will print the files and directories in your current working directory. You can also provide a relative path to a directory you want to list, e.g. . If you want more detailed information about the files you can use , if you instead want to also include invisible entries (i.e. names starting with a dot) use. Of course it is possible to combine them both by running  or the short form. Note that this kind of concatenating multiple arguments into one is only possible with single character parameters. Parameters can also come in long form, for example the equivalent of  is. Which forms are available depends on the individual command.

Now you might be thinking how to remember all parameters for every command you will ever use. Thankfully you only want to remember the most important ones, which are the ones you use most frequently, otherwise there is a nice way to look them up. You can either use the   command. For example run  to find more information about the   command. Oftentimes you can find a more concise summary by trying to run the command in question followed by the parameter, however this is not something you can expect to work well with every command, whereas manual pages should be always available.

Back to the topic of current working directories. If you want to change your directory you can use   followed by the directory you want to change to. There are two special virtual directories '.' and '..'. The single dot refers to the current directory while the double dot refers to a dir's parent directory. So executing  changes into the parent directory of the current working directory.

A very brief summary of other useful commands:

Windows
Windows doesn't use the Bash shell and in the past it was hard to get Bash to work on Windows. Users of Windows 10 Anniversary Update build 14393 or later however now have the ability to install a Ubuntu subsystem which will essentially provide them with a working Bash shell and access to many commands found in the Ubuntu Linux distribution. Users wishing to use Bash on Windows 10 are advised to follow the official installation instructions from Microsoft. After the installation you can basically follow the instructions for Ubuntu/Debian.

If you don't want to do that you have two options:

 * 1) Go with another non-Microsoft project providing a Bash environment for Windows. For example you can install Cygwin, a collection of free software tools available for Windows. During the install, make sure that you select the "ruby" package, located in the "Devel, Interpreters" category.
 * 2) Use the Windows Powershell. You might sometimes have to write something different than in this book, but for basic examples this might still be enough and safe you the time you would otherwise need for installation. However if you are serious about learning a shell, learning Bash has the advantage that it is not exclusive to Windows, unlike Powershell, which prevents you from being locked in into a platform should you one day decide to switch to Unix-like operating systems or use a non-Windows server.

title: User:Shenlebantongying/deleted


text:
User:Kepler-1229b/sandbox

βħʒɱ t͡ɕt͡sʎʢhβqɒ̃‖ɚɝʢhβqɒ̃‖ɚɝ$$6rx23y=we$$

title: User:Kepler-1229b/sandbox


text:
User:Kepler-1229b

t̪

title: User:Kepler-1229b


text:
User:Account569/sandbox

How to make old 1915-1922 old fashioned oatmeal. Warm up hot bowl of water in microwave for 5 minutes.

Cautiously take out bowl, and put in scoops of rolled oats.

Mix.

Enjoy old fashioned rolled oatmeal.

title: User:Account569/sandbox


text:
User talk:Simangele Mgaga

Hi it me with the anger English got my friend who is telling me how to spell English words si don't worry got a story for u guys 😶

title: User talk:Simangele Mgaga


text:
Cookbook talk:Cabbage Kimchi

Very sorry

title: Cookbook talk:Cabbage Kimchi


text:
User talk:Fanhp2021

--Pi zero (discuss • contribs) 19:08, 8 January 2021 (UTC)

title: User talk:Fanhp2021


text: User talk:61.245.171.184

title: User talk:61.245.171.184


text:
User:Rawaa roumieh

انا اسمي روعة رومية من مدينة الميناء شمال لبنان انا معلمة خاصة بحب الكتابة والتصوير والأعلام

title: User:Rawaa roumieh


text:
Rexx Programming/How to Rexx/boolean

Boolean values are logical truth values that are considered either true or false. Rexx uses 1 to mean "true" and 0 to mean "false". Some programming languages have many different kinds of values that could be treated as Boolean, depending on the context. The Rexx programming language itself only recognizes 0 and 1 for this purpose.

/* Some Boolean variables */ raining = 1 freezing = 1 snowing = 0 hailing = 0 /* Boolean values affect control structures... */ /* The computer will say we might need an umbrella. */ select when raining then say "You might need an umbrella." when snowing then say "Let's build a snowman!" when hailing then say "Ouch! There's hail." otherwise say "There might not be any precipitation." end /* The computer will tell us to watch out for ice. */ if freezing then say "Watch out for ice!" else say "At least it's not freezing outside." /* This loop will never start because it isn't snowing. */ do while snowing say "It'll just keep snowing forever!" end

Logical Operators
Operators exist to combine Boolean values into new Boolean values. The ampersand (&) means "and", the pipe symbol (|) means "or" and the backslash (\) means "not".

if raining | snowing then say "It's either raining or snowing--maybe both." if raining & freezing then say "Expect freezing rain." if \ snowing then say "No snow today." if \ (raining | snowing) then say "It's neither raining nor snowing."

Relational Operators
Some other operations combine other kinds of values to make true or false statements. They will always result in 0 or 1. You can read about them in the comparative operators section. The remainder when an integer is divided by 2 will technically result in a Boolean value, but other kinds of remainders will not.

say 2 < 3            /* says 1 */ say "happy" = "sad"  /* says 0 */ /* We can use Booleans to validate input: */ do until positive & even say "Enter a positive even number:" pull number positive = number > 0 odd = number // 2 even = \ odd end

title: Rexx Programming/How to Rexx/boolean


text:
Rexx Programming/How to Rexx/backslash

The backslash character (\), an alternative to Not (¬), is a logical operator for a Boolean value. It represents negation. Many other programming languages use either an exclamation mark or the word "not" for the same purpose. It precedes a value of 0 or 1 to produce the other value. Backslash has the advantage that it is an ASCII character and thus not subject to the code page issue of not, e.g., X'AA' versus X'AC'.

/* Boolean values are 0 and 1 */ false = 0 true = 1 /* Backslash means "not" */ say \ false  /* same as: say true; same as: say ¬ false */ say \ true   /* same as: say false */

The backslash can also be combined with loose and strict equality to produce "not equal" operators.

/* Loose unequal says false (0) */ say 'ok ' \= 'ok' /* Strict unequal says true (1) */ say 'ok ' \== 'ok'

title: Rexx Programming/How to Rexx/backslash