(****************************************************************************)
(*                                                                          *)
(*                           GSX Main Module                                *)
(*                           ===============                                *)
(* This Module contains all managing GSX functions, including the basic     *)
(* variable definitions used in the whole GSX system.                       *)
(*                                                                          *)
(* 16.5.1988          Wolfgang Muees, Hagenring 22, 3300 Braunschweig       *)
(*                                                                          *)
(****************************************************************************)

TYPE
  VECTOR  = RECORD                   (* Used to specify a pixel position in arrays. *)
              X,Y : INTEGER
            END;
  Lstring = String[255];

CONST
  CRT = 1; PLOTTER = 11; PRINTER = 21;  (* Some predefined workstation identifiers. *)
  replace =   1; transparent = 2;       (* Usable draw modes.                       *)
  exor    =   3; erase     =   4;
  P_inLen =   4; P_outLen  =   4;       (* Size of default GSX arrays               *)
  I_inLen = 128; I_outLen  = 128;       (* may be altered by user                   *)

  OpenParas : ARRAY[1..10] OF INTEGER = (* default open workstation parameters      *)
  ( CRT, 1, 7, 3 , 7, 1, 7, 0, 1, 7 );

VAR
  PB    : RECORD                        (* Graphic Parameter Block used by GSX.     *)
            CTRLADD : INTEGER;
            IINADD  : INTEGER;
            PINADD  : INTEGER;
            IOUTADD : INTEGER;
            POUTADD : INTEGER;
          END;
  CB    : RECORD                        (* Control Block used by GSX.               *)
            OPCODE  : INTEGER;          (* Main function identifier.                *)
            PINLEN  : INTEGER;          (* Number of parameters for all arrays.     *)
            POUTLEN : INTEGER;
            IINLEN  : INTEGER;
            IOUTLEN : INTEGER;
            ESCID   : INTEGER;          (* Second function identifier.              *)
            CTRL7   : INTEGER;          (* Opcode dependent information.            *)
            CTRL8   : INTEGER;
            CTRL9   : INTEGER;
            CTRL10  : INTEGER;
          END;
  OpenINTs  : ARRAY[1..45] OF INTEGER;  (* INTEGER information about workstation    *)
  OpenPtrs  : ARRAY[1..6 ] OF VECTOR;   (* VECTOR information about workstation     *)
  ColorExamined : RECORD                (* Returned information from ExamineColor.  *)
                    Index, Red, Green, Blue : INTEGER
                  END;
  PTSIN         : ARRAY [1..P_inLen]  OF VECTOR;                (* input vectors    *)
  PTSOUT        : ARRAY [1..P_outLen] OF VECTOR;                (* output vectors   *)
  INTIN         : ARRAY [1..I_inLen]  OF INTEGER;               (* input INTEGERs   *)
  INTOUT        : ARRAY [1..I_outLen] OF INTEGER;               (* output INTEGERs  *)

PROCEDURE ResetAddr;                                  (* Set up parablock addresses *)
BEGIN
  WITH PB DO
    BEGIN
      CTRLADD := ADDR ( CB     );
      IINADD  := ADDR ( INTIN  );
      PINADD  := ADDR ( PTSIN  );
      IOUTADD := ADDR ( INTOUT );
      POUTADD := ADDR ( PTSOUT );
    END;
END;

PROCEDURE ResetPara;                                     (* Set no input parameters *)
BEGIN
  WITH CB DO
    BEGIN
      PINLEN := 0;
      IINLEN := 0;
    END;
END;

PROCEDURE simple ( Opcode : INTEGER );        (* some GSX calls need only an opcode *)
BEGIN
  CB.OPCODE := Opcode;
  BDOS ( 115, ADDR ( PB ) );
  ResetPara;
END;

PROCEDURE simplESC ( Opcode : INTEGER );               (* ESC calls with ESC opcode *)
BEGIN
  CB.ESCID := Opcode;
  simple ( 5 );
END;

PROCEDURE oneINT ( Opcode, Para : INTEGER );           (* calls with one INTIN para *)
BEGIN
  INTIN[1] := Para;
  CB.IINLEN := 1;
  simple ( Opcode );
END;

PROCEDURE SetText ( Text : Lstring );             (* used to transfer text -> INTIN *)
VAR i,m : INTEGER;
    c   : CHAR;
BEGIN
  i := 1;
  m := Length ( Text );
  IF m > I_inLen THEN m := I_inLen;
  WHILE i <= m DO
    BEGIN
      INTIN[i] := ord ( Text[i] );
      i := succ ( i );
    END;
  CB.IINLEN := i;
END;

PROCEDURE numPTS ( Opcode, Number : INTEGER; VAR Points );
BEGIN
  CB.PINLEN := Number;
  PB.PINADD := ADDR ( Points );
  simple ( Opcode );
  ResetAddr;
END;

PROCEDURE OpenStation ( Identifier : INTEGER );
                         (* Opens the passed workstation. MUST be used before accessing
                            other GSX procedures. *)
BEGIN
  ResetAddr;
  ResetPara;
  WITH PB DO
    BEGIN
      IINADD  := ADDR ( OpenParas );
      IOUTADD := ADDR ( OpenINTs  );
      POUTADD := ADDR ( OpenPtrs  );
    END;
  OpenParas[1] := Identifier;
  CB.IINLEN := 10;
  simple ( 1 );
  ResetAddr;
END;

PROCEDURE CloseStation;  (* Counterpart to OpenStation. MUST be called prior to returning
                            to operating system or open another workstation. *)
BEGIN
  simple ( 2 );
END;

PROCEDURE ClearStation;  (* Erase screens , insert blank paper. After OpenStation, this
                            procedure ist not needed. *)
BEGIN
  simple ( 3 );
END;

PROCEDURE UpdateStation; (* Causes all pending commands to be executed. Before closing a
                            workstation, this procedure is not needed. Mainly used for
                            printer drivers. *)
BEGIN
  simple ( 4 );
END;

PROCEDURE GraphMode;     (* Explicitly sets graphic mode. Clear screens. After OpenStation,
                            the device is already in graphic mode. *)
BEGIN
  simplESC ( 2 );
END;

PROCEDURE TextMode;      (* Turns to cursor-addressable text mode. This function is also
                            performed by CloseStation. *)
BEGIN
  simplESC ( 3 );
END;

PROCEDURE HardCopy;      (* Dumps out screen contents on printer. Only meaningfull if the
                            device is a CRT. *)
BEGIN
  simplESC ( 17 );
END;

PROCEDURE SetCursor ( X,Y : INTEGER );
                         (* Display the graphic cursor ( usualy a cross ) at the specified
                            position. Any old cursor is removed, so you don't need to use
                            the RemoveCursor procedure unless you want to display no cursor
                            at all. Only meaningfull if the device is a CRT. *)
BEGIN
  PTSIN[1].X := X;
  PTSIN[1].Y := Y;
  CB.PINLEN  := 1;
  simplESC ( 18 );
END;

PROCEDURE RemoveCursor;  (* Removes a previously displayed graphic cursor. If no cursor was
                            displayed, nothing happens. *)
BEGIN
  simplESC ( 19 );
END;

PROCEDURE DefineColor ( Index, Red, Green, Blue : INTEGER );
                         (* Defines color palette for this color index. If the index is not
                            available, nothing happens. *)
BEGIN
  INTIN[1]  := Index;
  INTIN[2]  := Red;
  INTIN[3]  := Green;
  INTIN[4]  := Blue;
  CB.IINLEN := 4;
  simple ( 14 );
END;

PROCEDURE ExamineColor ( Index : INTEGER; Realized : BOOLEAN );
                         (* Examines color palette for this color index. If Realized = TRUE,
                            color displayed on device is returned, else color defined with
                            DefineColor or OpenStation is returned in ColorExamined. If the
                            index is out of range, then the maximum index is returned ( the
                            same would be used if you try to DRAW with this out-of-range
                            index ). *)
BEGIN
  INTIN[1]  := Index;
  INTIN[2]  := ORD ( Realized );
  CB.IINLEN := 2;
  PB.IOUTADD:= ADDR ( ColorExamined );
  simple ( 26 );
  ResetAddr;
END;

PROCEDURE DrawMode ( Mode : INTEGER );
                         (* Determines the way pixels are modified. Not all devices can
                            do drawing in all modes ( for example, a PLOTTER can't do
                            xor drawing). Default DrawMode is replace. *)
BEGIN
  oneINT (