(*---------------------------------------------------------------------------
 :Program.       M2Options
 :Contents.      Lets you set m2compiler and m2linker options via menu
 :Author.        Rainer Bauer
 :Shortcut.      [rb]
 :Address.       Sandberg 6
 :Address.       D-7092 Rosenberg
 :Phone.         49-7967-6959
 :Address.       Fido : 2:244/8580.24
		 email: amiga@guru.hamm.sub.org			
 :Language.      Modula-2
 :Translator.    M2Amiga V4.0
 :Copyright.     Real Public Domain
 :Bugs.          With KickStart 2.0 the window will be a little bit too
                 long (about 24 Pixels), because there are no longer two
                 DepthGadgets! I couldn't find a solution to this problem.
                 Anybody out there who can tell me ? If you work with
                 KickStart 2.0, you may change the value xWidth in
                 InitOptWin-Procedure (see there for more details).
 :Remark.        Works with every Font! (For example with an Sapphire 20
                 proportional Font ;-).
                 The Window-positions must occur in first two lines in the
                 ENV-variable ENV:m2opt ! Only these are scanned.
 :History.       V1.0, 12-Sep-91: First release.                         [rb]
 :Update.        No further versions; I just buyed M2Apse. An enviroment
 :Update.        for the M2Amiga System!
 :Usage.         Workbench: simply doubleclick its icon
                 CLI      : run M2Options
---------------------------------------------------------------------------*)

(*$ StackChk    := FALSE
    NilChk      := FALSE
    RangeChk    := FALSE
    OverflowChk := FALSE
    CaseChk     := FALSE
    ReturnChk   := FALSE
    LongAlign   := FALSE
    Volatile    := FALSE
    LargeVars   := FALSE
    StackParms  := FALSE
*)

(*$ DEFINE German := TRUE *)


MODULE M2Options;

(*---------------------------------------------------------------------------
------                           IMPORT                                ------
---------------------------------------------------------------------------*)

IMPORT io:InOut;

FROM SYSTEM       IMPORT ADR, ADDRESS, LONGSET;

FROM IntuitionL   IMPORT OpenWindow, CloseWindow,
                         SetMenuStrip, ClearMenuStrip,
                         LockIBase, UnlockIBase, OpenIntuition;
FROM IntuitionD   IMPORT Screen, ScreenPtr, customScreen,
                         ScreenFlags, ScreenFlagSet,
                         NewWindow, WindowPtr, Window,
                         WindowFlags, WindowFlagSet,
                         MenuItem, Menu,
                         MenuItemFlags, MenuItemFlagSet,
                         IntuitionBasePtr,
                         IDCMPFlags, IDCMPFlagSet,
                         IntuiMessage, IntuiText;
FROM IntuiMacros  IMPORT MenuNum, ItemNum;
FROM ExecL        IMPORT WaitPort, GetMsg, ReplyMsg;
FROM GraphicsD    IMPORT RastPortPtr, jam1;
FROM GraphicsL    IMPORT TextLength;
FROM FileSystem   IMPORT File, Lookup, Close, ReadChar, WriteChar, done;
FROM String       IMPORT FirstPos, noOccur;
FROM Conversions  IMPORT StrToVal, ValToStr;
FROM ASCII        IMPORT eol, lf, sp, ht, nul;
FROM Arts         IMPORT Assert;

(*---------------------------------------------------------------------------
------                       TYPE & CONSTANT                           ------
---------------------------------------------------------------------------*)

TYPE   MainItems   = (Project, m2cOptionen, m2lOptionen, TargetCPU);
       ProjItems   = (Save, Cycle, Quit);
       m2cItems    = (CMeldungen, StackChk, RangeChk, OverflowChk, NilChk,
                      CaseChk, ReturnChk, LargeVars, EntryClear, LongAllign,
                      StackParms, Volatile, CDebug, Ref, CIkonen, Warnungen,
                      Profiler);
CONST  m2cItemsAnz = 16;
TYPE   m2lItems    = (LMeldungen, SmallCode, SmallData, Minimal, Reentrant,
                      LDebug, LIkonen, AskModule);
CONST  m2lItemsAnz = 7;
TYPE   CPUItems    = (CPU00, CPU10, CPU20, CPU30, CPU31, CPU40);
CONST  CPUItemsAnz = 5;

TYPE   Text        = ARRAY [0..255] OF CHAR;
       MenuText    = ARRAY [0..11]  OF CHAR;

CONST

  (*$ IF German *)

       OptWinTitle       = "Compiler und Linker Optionen";
       PMTitle           = "Projekt";
       CMTitle           = "m2c-Optionen";
       LMTitle           = "m2l-Optionen";
       UMTitle           = "Prozessor";

  (*$ ELSE      *)  (* English *)

       OptWinTitle       = "compiler and linker options";
       PMTitle           = "Project";
       CMTitle           = "m2c - options";
       LMTitle           = "m2l - options";
       UMTitle           = "Processor";

  (*$ ENDIF     *)

       Plus        = "+";
       Minus       = "-";
       m2cENV      = "ENV:m2c";
       m2lENV      = "ENV:m2l";
       optENV      = "ENV:m2opt";

(*---------------------------------------------------------------------------
------                              VAR                                ------
---------------------------------------------------------------------------*)


VAR   OptWinPtr    : WindowPtr;        (* Pointer to window                *)
      OptWin       : NewWindow;        (* Data for window                  *)
      OptWinTitleChars : INTEGER;      (* Chars in windowtitle             *)
      ActualRPPtr  : RastPortPtr;      (* To get Font-Data                 *)
      ActualScrPtr,
      HScrPtr      : ScreenPtr;        (* For cycling on other screens     *)
      WBenchScr    : BOOLEAN;          (* Workbenchscreen ?                *)
      ActualSWidth,
      ActualSHeight: INTEGER;          (* For right position of window     *)
      TextxSize,
      TextySize    : CARDINAL;         (* You may use every Font           *)
      WinlEdge,
      WintEdge     : INTEGER;          (* Position after Cycling           *)
      Class        : IDCMPFlagSet;     (* To find out what user wants      *)
      Code         : CARDINAL;         (* To find out what user wants      *)
      IntuiMsg     : POINTER TO IntuiMessage; (* What command was sent ?   *)
      MenuStrip    : ARRAY [Project..TargetCPU] OF Menu; (* The menues     *)
      MaxPMChars,
      MaxCMChars,
      MaxLMChars,
      MaxUMChars   : INTEGER;          (* To handle different fonts        *)
      ok           : BOOLEAN;          (* The result of the installed menu *)
      CZ           : m2cItems;         (* 3 counter for comfortable use of *)
      LZ           : m2lItems;         (* the menues                       *)
      UZ           : CPUItems;         (* The third one ;-)                *)
                   (* ?Items for MenuItems                        *)
                   (* ?IText for ItuiTextstructures for Items     *)
                   (* ?OText for Characters for each Option       *)
                   (* ?MText for MenuItemsText                    *)
      PItems       : ARRAY [Save..Quit] OF MenuItem;
      PIText       : ARRAY [Save..Quit] OF IntuiText;
      PMText       : ARRAY [Save..Quit] OF MenuText;
      CItems       : ARRAY [CMeldungen..Profiler] OF MenuItem;
      CIText       : ARRAY [CMeldungen..Profiler] OF IntuiText;
      COText       : ARRAY [CMeldungen..Profiler] OF CHAR;
      CMText       : ARRAY [CMeldungen..Profiler] OF MenuText;
      LItems       : ARRAY [LMeldungen..AskModule] OF MenuItem;
      LIText       : ARRAY [LMeldungen..AskModule] OF IntuiText;
      LOText       : ARRAY [LMeldungen..AskModule] OF CHAR;
      LMText       : ARRAY [LMeldungen..AskModule] OF MenuText;
      UItems       : ARRAY [CPU00..CPU40] OF MenuItem;
      UIText       : ARRAY [CPU00..CPU40] OF IntuiText;
      UOText       : ARRAY [CPU00..CPU40] OF CHAR;
      UMText       : ARRAY [CPU00..CPU40] OF MenuText;

(*---------------------------------------------------------------------------
------                         InitMenuText                            ------
---------------------------------------------------------------------------*)

PROCEDURE InitMenuText();

BEGIN

  OptWinTitleChars := SIZE(OptWinTitle);
  MaxPMChars       := SIZE(PMTitle);
  MaxCMChars       := SIZE(CMTitle);
  MaxLMChars       := SIZE(LMTitle);
  MaxUMChars       := SIZE(UMTitle);

  PMText[Save]     := " Save";
  PMText[Cycle]    := " Cycle";
  PMText[Quit]     := " Quit";

  COText[StackChk]      := "S"; CMText[StackChk]      := "StackChk";
  COText[RangeChk]      := "R"; CMText[RangeChk]      := "RangeChk";
  COText[OverflowChk]   := "V"; CMText[OverflowChk]   := "OverflowChk";
  COText[NilChk]        := "N"; CMText[NilChk]        := "NilChk";
  COText[CaseChk]       := "C"; CMText[CaseChk]       := "CaseChk";
  COText[ReturnChk]     := "F"; CMText[ReturnChk]     := "ReturnChk";
  COText[LargeVars]     := "Y"; CMText[LargeVars]     := "LargeVars";
  COText[EntryClear]    := "E"; CMText[EntryClear]    := "EntryClear";
  COText[LongAllign]    := "L"; CMText[LongAllign]    := "LonAllign";
  COText[StackParms]    := "Z"; CMText[StackParms]    := "StackParms";
  COText[Volatile]      := "H"; CMText[Volatile]      := "Volatile";
  COText[CDebug]        := "D"; CMText[CDebug]        := "Debug";
  COText[Ref]           := "@"; CMText[Ref]           := "Ref";
  COText[Profiler]      := "P"; CMText[Profiler]      := "Profiler";
  COText[CMeldungen]    := "Q";
  COText[CIkonen]       := "I";
  COText[Warnungen]     := "W";

  LOText[SmallCode]     := "C"; LMText[SmallCode]     := "SmallCode";
  LOText[SmallData]     := "D"; LMText[SmallData]     := "SmallData";
  LOText[Minimal]       := "M"; LMText[Minimal]       := "Minimal";
  LOText[Reentrant]     := "R"; LMText[Reentrant]     := "Reentrant";
  LOText[LDebug]        := "X"; LMText[LDebug]        := "Debug";
  LOText[AskModule]     := "A"; LMText[AskModule]     := "AskModule";
  LOText[LMeldungen]    := "Q";
  LOText[LIkonen]       := "I";

  UOText[CPU00]         := "0";   UMText[CPU00]       := "68000";
  UOText[CPU10]         := "1";   UMText[CPU10]       := "68010";
  UOText[CPU20]         := "2";   UMText[CPU20]       := "68020";
  UOText[CPU30]         := "3";   UMText[CPU30]       := "68030";
  UOText[CPU31]         := "8";   UMText[CPU31]       := "'30+81";
  UOText[CPU40]         := "4";   UMText[CPU40]       := "68040";

  (*$ IF German *)

  CMText[CMeldungen]    := "Meldungen";
  CMText[CIkonen]       := "Ikonen";
  CMText[Warnungen]     := "Warnungen";

  LMText[LMeldungen]    := "Meldungen";
  LMText[LIkonen]       := "Ikonen";

  (*$ ELSE      *)  (* English *)

  CMText[CMeldungen]    := "Information";
  CMText[CIkonen]       := "Icons";
  CMText[Warnungen]     := "Warnings";

  LMText[LMeldungen]    := "Information";
  LMText[LIkonen]       := "Icons";

  (*$ ENDIF     *)

END InitMenuText;

(*---------------------------------------------------------------------------
------                            InitMenu                             ------
---------------------------------------------------------------------------*)

PROCEDURE InitMenu();

CONST  xBorder   = 6;                   (* Border of the menu              *)
       yBorder   = 4;                   (* dito                            *)
       MenuDist  = 10;                  (* Distance between each menu      *)

VAR    PMBreite, CMBreite,
       LMBreite, UMBreite   : INTEGER;  (* To handle different fonts       *)
       i, j                 : CARDINAL; (* To setup the Menustructure      *)
       HUZ                  : CPUItems; (* To realize mutual exlude in
                                           processor menu                  *)


BEGIN

  (* Get width of menues in the actuall font: *)

  PMBreite := TextLength(ActualRPPtr, ADR(PMTitle),   MaxPMChars) + xBorder;
  CMBreite := TextLength(ActualRPPtr, ADR(CMTitle),   MaxCMChars) + xBorder;
  LMBreite := TextLength(ActualRPPtr, ADR(LMTitle),   MaxLMChars) + xBorder;
  UMBreite := TextLength(ActualRPPtr, ADR(UMTitle),   MaxUMChars) + xBorder;

  (* Set them up.                             *)

  WITH MenuStrip[Project] DO
    nextMenu := ADR(MenuStrip[m2cOptionen]);
    leftEdge := MenuDist;
    topEdge  := 0;
    width    := PMBreite; height   := 0;
    flags    := {0};      menuName := ADR(PMTitle);
    firstItem := ADR(PItems[Save]);
  END; (* WITH *)

  WITH MenuStrip[m2cOptionen] DO
    nextMenu := ADR(MenuStrip[m2lOptionen]);
    leftEdge := PMBreite + 2 * MenuDist;
    topEdge  := 0;
    width    := CMBreite; height   := 0;
    flags    := {0};      menuName := ADR(CMTitle);
    firstItem := ADR(CItems[CMeldungen]);
  END; (* WITH *)

  WITH MenuStrip[m2lOptionen] DO
    nextMenu := ADR(MenuStrip[TargetCPU]);
    leftEdge := PMBreite + CMBreite + 3 * MenuDist;
    topEdge  := 0;
    width    := LMBreite; height   := 0;
    flags    := {0};      menuName := ADR(LMTitle);
    firstItem := ADR(LItems[LMeldungen]);
  END; (* WITH *)

  WITH MenuStrip[TargetCPU] DO
    nextMenu := NIL;
    leftEdge := PMBreite + CMBreite + LMBreite + 4 * MenuDist;
    topEdge  := 0;
    width    := UMBreite; height   := 0;
    flags    := {0};      menuName := ADR(UMTitle);
    firstItem := NIL;
    firstItem := ADR(UItems[CPU00]);
  END; (* WITH *)

  (* Set the first Item up:                   *)

  WITH PItems[Save] DO
    nextItem := ADR(PItems[Cycle]); subItem  := NIL;
    leftEdge := -5;       topEdge := 0;
    width    := PMBreite; height  := TextySize + yBorder - 1;
    flags    := MenuItemFlagSet{highBox, itemText, itemEnabled};
    mutualExclude := LONGSET{};
    itemFill      := ADR(PIText[Save]); selectFill := NIL;
  END; (* WITH *)
  WITH PIText[Save] DO
    frontPen := 1; backPen := 2;
    leftEdge := 0; topEdge := 2;
    iText    := ADR(PMText[Save]);
    drawMode := jam1; iTextFont := NIL;
    nextText := NIL;
  END; (* WITH *)

  (* and copy the same information in all other. *)

  PItems[Cycle] := PItems[Save];
    WITH PItems[Cycle] DO
      nextItem := ADR(PItems[Quit]);
      topEdge  := TextySize + yBorder;
      itemFill := ADR(PIText[Cycle]);
    END; (* WITH *)
  PIText[Cycle] := PIText[Save];
  WITH PIText[Cycle] DO
    iText    := ADR(PMText[Cycle]);
  END; (* WITH *)

  PItems[Quit] := PItems[Save];
    WITH PItems[Quit] DO
      nextItem := NIL;
      topEdge  := 2 * (TextySize + yBorder);
      itemFill := ADR(PIText[Quit]);
    END; (* WITH *)
  PIText[Quit] := PIText[Save];
  WITH PIText[Quit] DO
    iText    := ADR(PMText[Quit]);
  END; (* WITH *)


  WITH CItems[CMeldungen] DO
    nextItem      := ADR(CItems[StackChk]); subItem := NIL;
    leftEdge      := -5; topEdge := 0;
    width         := CMBreite; height := TextySize + yBorder - 1;
    flags         := MenuItemFlagSet{highBox, itemText, itemEnabled, checkIt,
                                menuToggle, checked};
    mutualExclude := LONGSET{};
    itemFill      := ADR(CIText[CMeldungen]); selectFill := NIL;
    END; (* WITH *)
  WITH CIText[CMeldungen] DO
    frontPen := 1; backPen := 2;
    leftEdge := 21; topEdge := 2;
    iText    := ADR(CMText[CMeldungen]);
    drawMode := jam1; iTextFont := NIL;
    nextText := NIL;
  END; (* WITH *)

  (* Here they are all the same ...           *)

  i := 0;
  FOR CZ := StackChk TO Profiler DO
    INC(i);
    CItems[CZ]       := CItems[CMeldungen];
    CIText[CZ]       := CIText[CMeldungen];
    CIText[CZ].iText := ADR(CMText[CZ]);
    WITH CItems[CZ] DO
      topEdge    := i * (TextySize + yBorder);
      itemFill   := ADR(CIText[CZ]);
      IF i # m2cItemsAnz THEN
        nextItem := ADR(CItems[VAL(m2cItems, i+1)]);
      ELSE
        nextItem := NIL;
      END; (* IF *)
    END; (* WITH *)
  END; (* FOR *)

  CItems[CDebug].mutualExclude := LONGSET{ORD(Ref)};
  CItems[Ref].mutualExclude    := LONGSET{ORD(CDebug)};

  i := 0;
  FOR LZ := LMeldungen TO AskModule DO
    LItems[LZ]       := CItems[CMeldungen];
    LIText[LZ]       := CIText[CMeldungen];
    LIText[LZ].iText := ADR(LMText[LZ]);
    WITH LItems[LZ] DO
      width      := LMBreite;
      topEdge    := i * (TextySize + yBorder);
      itemFill   := ADR(LIText[LZ]);
      IF i # m2lItemsAnz THEN
        nextItem := ADR(LItems[VAL(m2lItems, i+1)]);
      ELSE
        nextItem := NIL;
      END; (* IF *)
    END; (* WITH *)
    INC(i);
  END; (* FOR *)

  i := 0;
  FOR UZ := CPU00 TO CPU40 DO
    UItems[UZ]       := CItems[CMeldungen];
    UIText[UZ]       := CIText[CMeldungen];
    UIText[UZ].iText := ADR(UMText[UZ]);
    WITH UItems[UZ] DO
      EXCL(flags, checked);
      width      := UMBreite;
      topEdge    := i * (TextySize + yBorder);
      itemFill   := ADR(UIText[UZ]);
      IF i # CPUItemsAnz THEN
        nextItem := ADR(UItems[VAL(CPUItems, i+1)]);
      ELSE
        nextItem := NIL;
      END; (* IF *)
    END; (* WITH *)
    INC(i);
  END; (* FOR *)

  FOR UZ := CPU00 TO CPU40  DO
    FOR HUZ := CPU00 TO CPU40 DO
      IF UZ # HUZ THEN
        INCL(UItems[UZ].mutualExclude,ORD(HUZ));
      END; (* IF *)
    END; (* FOR *)
  END; (* FOR *)

END InitMenu;

(*---------------------------------------------------------------------------
------                          InitOptWin                             ------
---------------------------------------------------------------------------*)

PROCEDURE InitOptWin();

CONST  GadgetWidth = 24; (* Width of an DepthGadget *)
       xBorder     = 6;  (* Border of the Window    *)
       yBorder     = 1;  (* dito                    *)


VAR    TextLen,
       xWidth, yHeigth    : INTEGER; (* To handle fonts *)

BEGIN
  TextLen := TextLength(ActualRPPtr, ADR(OptWinTitle),
                        OptWinTitleChars);
  xWidth  := TextLen + 3 * GadgetWidth + 2 * xBorder;


  (* xWidth  := TextLen + 2 * GadgetWidth + xBorder;
                          ^--- for Kick 2.0          *)

  IF (WinlEdge + xWidth) >= ActualSWidth THEN
    WinlEdge := ActualSWidth - xWidth;
  END; (* IF *)

  yHeigth := TextySize + 2 * yBorder;

  IF (WintEdge + yHeigth) >= ActualSHeight THEN
    WintEdge := ActualSHeight - yHeigth;
  END; (* IF *)

  WITH OptWin DO
    leftEdge    := WinlEdge; topEdge  := WintEdge;
    width       := xWidth;   height   := yHeigth;
    detailPen   := 1;        blockPen := 0;
    idcmpFlags  := IDCMPFlagSet{closeWindow, menuPick, menuVerify};
    flags       := WindowFlagSet{windowDrag, windowDepth, windowClose,
                                activate};
    firstGadget := NIL;
    checkMark   := NIL;
    screen      := ActualScrPtr;
    title       := ADR(OptWinTitle);
    bitMap      := NIL;
    IF (wbenchScreen IN ActualScrPtr^.flags) AND
       (publicScreen IN ActualScrPtr^.flags) AND
       (sf2          IN ActualScrPtr^.flags) AND
       (sf3          IN ActualScrPtr^.flags) THEN
      type      := customScreen;
    ELSE
      type      := ScreenFlagSet{wbenchScreen};
    END; (* IF *)

  END; (* WITH *)

END InitOptWin;

(*---------------------------------------------------------------------------
------                            ReadENV                              ------
---------------------------------------------------------------------------*)

PROCEDURE ReadENVs();

  PROCEDURE ClearStr(VAR Str: ARRAY OF CHAR);
  VAR  i: INTEGER;
  BEGIN
    FOR i := 0 TO HIGH(Str) DO Str[i] := nul END;
  END ClearStr;


  PROCEDURE Parsem2c(ENVText : ARRAY OF CHAR);

  VAR   NewPos      : LONGCARD; (* The new position of "+" or "-" *)
        Posi        : LONGINT;  (* The actual position            *)

  BEGIN
    NewPos := 0;
    REPEAT
      Posi := FirstPos(ENVText, NewPos, Plus);
      NewPos := LONGCARD(Posi+1);
      IF Posi # noOccur THEN
        REPEAT
          FOR CZ := CMeldungen TO Profiler DO
            IF CAP(ENVText[NewPos]) = COText[CZ] THEN
              INCL(CItems[CZ].flags, checked)
            END; (* IF *)
          END; (* FOR *)
          INC(NewPos);
        UNTIL (ENVText[NewPos] = sp) OR
              (ENVText[NewPos] = ht) OR
              (ENVText[NewPos] = Plus) OR
              (ENVText[NewPos] = Minus) OR
              (ENVText[NewPos] = nul);
      END; (* IF *)
    UNTIL Posi = noOccur;
    NewPos := 0;
    REPEAT
      Posi := FirstPos(ENVText, NewPos, Minus);
      NewPos := LONGCARD(Posi+1);
      IF Posi # noOccur THEN
        REPEAT
          FOR CZ := CMeldungen TO Profiler DO
            IF CAP(ENVText[NewPos]) = COText[CZ] THEN
              EXCL(CItems[CZ].flags, checked)
            END; (* IF *)
          END; (* FOR *)
          INC(NewPos);
        UNTIL (ENVText[NewPos] = sp) OR
              (ENVText[NewPos] = ht) OR
              (ENVText[NewPos] = Plus) OR
              (ENVText[NewPos] = Minus) OR
              (ENVText[NewPos] = nul);
      END; (* IF *)
    UNTIL Posi = noOccur;
  END Parsem2c;


  PROCEDURE Parsem2l(ENVText: ARRAY OF CHAR);

  VAR   NewPos      : LONGCARD; (* Look the procedure above *)
        Posi        : LONGINT;

  BEGIN
    NewPos := 0;
    REPEAT
      Posi := FirstPos(ENVText, NewPos, Plus);
      NewPos := LONGCARD(Posi+1);
      IF Posi # noOccur THEN
        REPEAT
          FOR LZ := LMeldungen TO AskModule DO
            IF CAP(ENVText[NewPos]) = LOText[LZ] THEN
              INCL(LItems[LZ].flags, checked)
            END; (* IF *)
          END; (* FOR *)
          INC(NewPos);
        UNTIL (ENVText[NewPos] = sp) OR
              (ENVText[NewPos] = ht) OR
              (ENVText[NewPos] = Plus) OR
              (ENVText[NewPos] = Minus) OR
              (ENVText[NewPos] = nul);
      END; (* IF *)
    UNTIL Posi = noOccur;
    NewPos := 0;
    REPEAT
      Posi := FirstPos(ENVText, NewPos, Minus);
      NewPos := LONGCARD(Posi+1);
      IF Posi # noOccur THEN
        REPEAT
          FOR LZ := LMeldungen TO AskModule DO
            IF CAP(ENVText[NewPos]) = LOText[LZ] THEN
              EXCL(LItems[LZ].flags, checked)
            END; (* IF *)
          END; (* FOR *)
          INC(NewPos);
        UNTIL (ENVText[NewPos] = sp) OR
              (ENVText[NewPos] = ht) OR
              (ENVText[NewPos] = Plus) OR
              (ENVText[NewPos] = Minus) OR
              (ENVText[NewPos] = nul);
      END; (* IF *)
    UNTIL Posi = noOccur;
  END Parsem2l;


  PROCEDURE CheckCPU(ENVText: ARRAY OF CHAR);

  VAR   Posi : INTEGER;
        ok   : BOOLEAN;

  BEGIN
    Posi := 0;
    REPEAT
      CASE ENVText[Posi] OF
        "0": ok := TRUE; INCL(UItems[CPU00].flags, checked);|
        "1": ok := TRUE; INCL(UItems[CPU10].flags, checked);|
        "2": ok := TRUE; INCL(UItems[CPU20].flags, checked);|
        "3": ok := TRUE; INCL(UItems[CPU30].flags, checked);|
        "8": ok := TRUE; INCL(UItems[CPU31].flags, checked);|
        "4": ok := TRUE; INCL(UItems[CPU40].flags, checked);
      ELSE
      END; (* CASE *)
      INC(Posi);
    UNTIL (ENVText[Posi] = nul) OR ok;
  END CheckCPU;


  PROCEDURE Parsem2opt(ENVText: ARRAY OF CHAR): INTEGER;

  VAR     PosText     : ARRAY [0..3] OF CHAR; (* With MegaWB your screen may
                                                 be 1024 * 1024 pixel...   *)
          NewPos,z    : SHORTCARD;            (* For scanning              *)
          WinPos      : LONGINT;              (* Returned position         *)
          signed, err : BOOLEAN;              (* For convertion StrToVal   *)

  BEGIN
    NewPos := 0;
    WHILE (ENVText[NewPos] = sp) OR (ENVText[NewPos] = ht) DO
      INC(NewPos)
    END; (* WHILE *)
    IF ENVText[NewPos] # eol THEN
      z := 0;
      REPEAT
        PosText[z] := ENVText[NewPos];
        INC(NewPos); INC(z);
      UNTIL (ENVText[NewPos] = sp)  OR (ENVText[NewPos] = ht) OR
            (ENVText[NewPos] = eol) OR (z = 4) ;
      IF z < 4 THEN
        PosText[z] := nul
      ELSE
        RETURN 0;
      END; (* IF *)
      StrToVal(PosText, WinPos, signed , 10, err);
      IF ~err AND (WinPos >= 0) THEN
        RETURN INTEGER(WinPos);
      ELSE
        RETURN 0;
      END; (* IF *)
    ELSE
      RETURN 0;
    END; (* IF *)
  END Parsem2opt;


VAR    ENVVar                 : File;      (* File-IO                      *)
       z                      : SHORTCARD; (* counter                      *)
       ENVText                : Text;      (* For incoming text            *)
       Check                  : BOOLEAN;   (* Handling mutual Exclude      *)

BEGIN

        (* At first: ENV:m2c ... *)

  ClearStr(ENVText);
  Lookup(ENVVar, m2cENV, 0, FALSE);
  IF ENVVar.res = done THEN
    z := 0;
    REPEAT
      ReadChar(ENVVar, ENVText[z]); INC(z);
    UNTIL ((ENVText[z-1] = eol) OR ENVVar.eof);
    Close(ENVVar);
    Parsem2c(ENVText);
    IF (checked IN CItems[Ref].flags) AND (checked IN CItems[CDebug].flags) THEN
      EXCL(CItems[Ref].flags,      checked);
    END; (* IF *)
    CheckCPU(ENVText);
  ELSE
    (* standart settings : *)
    INCL(UItems[CPU00].flags,    checked);
    EXCL(CItems[Ref].flags,      checked);
    EXCL(CItems[CIkonen].flags,  checked);
    EXCL(CItems[Profiler].flags, checked);
  END; (* IF *)

        (* then ENV:m2l ... *)

  ClearStr(ENVText);
  Lookup(ENVVar, m2lENV, 0, FALSE);
  IF ENVVar.res = done THEN
    z := 0;
    REPEAT
      ReadChar(ENVVar, ENVText[z]); INC(z);
    UNTIL ((ENVText[z-1] = eol) OR ENVVar.eof);
    Close(ENVVar);
    ENVText[z-1] := nul;
    Parsem2l(ENVText);

    Check := TRUE; UZ := CPU00;
    LOOP
      IF checked IN UItems[UZ].flags THEN Check := FALSE; EXIT END;
      IF ORD(UZ) = CPUItemsAnz THEN EXIT END;
      UZ := VAL(CPUItems, (ORD(UZ) + 1));
    END; (* LOOP *)
    IF Check THEN CheckCPU(ENVText) END;
  ELSE
    (* standart settings : *)
    EXCL(LItems[Minimal].flags,   checked);
    EXCL(LItems[Reentrant].flags, checked);
    EXCL(LItems[LIkonen].flags,   checked);
    EXCL(LItems[AskModule].flags, checked);

    Check := TRUE; UZ := CPU00;
    LOOP
      IF checked IN UItems[UZ].flags THEN Check := FALSE; EXIT END;
      IF ORD(UZ) = CPUItemsAnz THEN EXIT END;
      UZ := VAL(CPUItems, (ORD(UZ) + 1));
    END; (* LOOP *)
    IF Check THEN CheckCPU(ENVText) END;
  END; (* IF *)

        (* last, but not least ENV:m2opt ... *)

  ClearStr(ENVText);
  Lookup(ENVVar, optENV, 0, FALSE);
  IF ENVVar.res = done THEN
    z := 0;
    REPEAT
      ReadChar(ENVVar, ENVText[z]); INC(z);
    UNTIL ((ENVText[z-1] = eol) OR ENVVar.eof);
    IF ENVVar.eof THEN
      WinlEdge := 0; WintEdge := 0;
    ELSE
      WinlEdge :=  Parsem2opt(ENVText);
      z := 0;
      REPEAT
        ReadChar(ENVVar, ENVText[z]); INC(z);
      UNTIL ((ENVText[z-1] = eol) OR ENVVar.eof);
      WintEdge :=  Parsem2opt(ENVText);
    END; (* IF *)
    Close(ENVVar);
  ELSE
    WinlEdge := 0; WintEdge := 0;
  END; (* IF *)

END ReadENVs;

(*---------------------------------------------------------------------------
------                            WriteENV                             ------
---------------------------------------------------------------------------*)

PROCEDURE WriteENVs();

VAR    ENVVar                 : File;       (* File-IO                     *)
       z, hz                  : SHORTCARD;  (* counter                     *)
       DummyText, ENVText     : Text;       (* for outgoing text           *)
       TextLen                : SHORTCARD;  (* name says everything        *)
       signed, err            : BOOLEAN;    (* To handle ValToStr          *)

BEGIN

        (* At first: ENV:m2c ... *)

  z := 0;

  ENVText[z] := Plus; INC(z);
  FOR UZ := CPU00 TO CPU40 DO
    IF checked IN UItems[UZ].flags THEN ENVText[z] := UOText[UZ]; INC(z) END;
  END; (* FOR *)
  IF ENVText[z-1] = Plus THEN ENVText[z] := UOText[CPU00]; INC(z) END;

  FOR CZ := CMeldungen TO Profiler DO
    IF checked IN CItems[CZ].flags THEN ENVText[z] := COText[CZ]; INC(z) END;
  END; (* FOR *)

  ENVText[z] := Minus; INC(z);
  FOR CZ := CMeldungen TO Profiler DO
    IF ~(checked IN CItems[CZ].flags) THEN ENVText[z] := COText[CZ]; INC(z) END;
  END; (* FOR *)
  IF ENVText[z-1] = Minus THEN ENVText[z-1] := nul; DEC(z) END;

  ENVText[z] := eol;
  TextLen := z;

  Lookup(ENVVar, m2cENV, 0, TRUE);
  IF ENVVar.res = done THEN
    FOR z := 0 TO TextLen DO
      WriteChar(ENVVar, ENVText[z]);
    END; (* FOR *)
    Close(ENVVar);
  END; (* IF *)

        (* then ENV:m2l ... *)

  z := 0;

  ENVText[z] := Plus; INC(z);
  FOR UZ := CPU00 TO CPU40 DO
    IF checked IN UItems[UZ].flags THEN ENVText[z] := UOText[UZ]; INC(z) END;
  END; (* FOR *)
  IF ENVText[z-1] = Plus THEN ENVText[z] := UOText[CPU00]; INC(z) END;

  FOR LZ := LMeldungen TO AskModule DO
    IF checked IN LItems[LZ].flags THEN ENVText[z] := LOText[LZ]; INC(z) END;
  END; (* FOR *)

  ENVText[z] := Minus; INC(z);
  FOR LZ := LMeldungen TO AskModule DO
    IF ~(checked IN LItems[LZ].flags) THEN ENVText[z] := LOText[LZ]; INC(z) END;
  END; (* FOR *)
  IF ENVText[z-1] = Minus THEN ENVText[z-1] := nul; DEC(z) END;

  ENVText[z] := eol;
  TextLen := z;

  Lookup(ENVVar, m2lENV, 0, TRUE);
  IF ENVVar.res = done THEN
    FOR z := 0 TO TextLen DO
      WriteChar(ENVVar, ENVText[z]);
    END; (* FOR *)
    Close(ENVVar);
  END; (* IF *)

        (* last, but not least ENV:m2opt ... *)

  WinlEdge := OptWinPtr^.leftEdge;
  ValToStr(WinlEdge, signed, DummyText, 10, -6, nul, err);
  ENVText := DummyText;

  z := 0; hz := 0;
  REPEAT INC(z); UNTIL ENVText[z] = nul;
  ENVText[z] := lf; INC(z);

  WintEdge := OptWinPtr^.topEdge;
  ValToStr(WintEdge, signed, DummyText, 10, -6, nul, err);

  REPEAT
    ENVText[z] := DummyText[hz];
    INC(z); INC(hz);
  UNTIL DummyText[hz] = nul;
  ENVText[z] := lf;

  Lookup(ENVVar, optENV, 0, TRUE);
  IF ENVVar.res = done THEN
    FOR z := 0 TO TextLen DO
      WriteChar(ENVVar, ENVText[z]);
    END; (* FOR *)
    Close(ENVVar);
  END; (* IF *)

END WriteENVs;

(*---------------------------------------------------------------------------
------                         GetActiveScreen                         ------
---------------------------------------------------------------------------*)

PROCEDURE GetActiveScreen();

VAR Lock      : LONGCARD;         (* for unlocking ...                *)
    IBasePtr  : IntuitionBasePtr; (* To get data of other screens     *)

BEGIN
  IBasePtr := OpenIntuition();
  Lock     := LockIBase(0);
    ActualScrPtr   := IBasePtr^.activeScreen;
  UnlockIBase(Lock);
END GetActiveScreen;

(*---------------------------------------------------------------------------
------                          GetActualData                          ------
---------------------------------------------------------------------------*)

PROCEDURE GetActualData();

(* VAR  LScrPtr        : ScreenPtr;
        ActualScrTitle : ADDRESS;                for V36 and higher *)


BEGIN
  (* ActualScrTitle := ActualScrPtr^.title;      for V36 and higher *)
  (* LScrPtr := LockPubScreen(ActualScrTitle);   for V36 and higher *)

  ActualRPPtr  := ADR(ActualScrPtr^.rastPort);
  ActualSWidth := ActualScrPtr^.width;
  ActualSHeight:= ActualScrPtr^.height;
  TextxSize    := ActualScrPtr^.rastPort.font^.xSize;
  TextySize    := ActualScrPtr^.rastPort.font^.ySize;

  (* IF LScrPtr # NIL THEN UnlockPubScreen(ActualScrTitle, LScrPtr) END;
                                                   for V36 and higher *)
END GetActualData;

(*---------------------------------------------------------------------------
------                            CycleScreen                          ------
---------------------------------------------------------------------------*)

PROCEDURE CycleScreen();

      (* to find out which flags where set (when reinstalling the menu)! *)
VAR   COSet        : ARRAY [CMeldungen..Profiler] OF BOOLEAN;
      LOSet        : ARRAY [LMeldungen..AskModule] OF BOOLEAN;
      UOSet        : ARRAY [CPU00..CPU40] OF BOOLEAN;

BEGIN
  WinlEdge := OptWinPtr^.leftEdge;
  WintEdge := OptWinPtr^.topEdge;
  FOR CZ := CMeldungen TO Profiler  DO  COSet[CZ] := FALSE END;
  FOR LZ := LMeldungen TO AskModule DO  LOSet[LZ] := FALSE END;
  FOR UZ := CPU00      TO CPU40     DO  UOSet[UZ] := FALSE END;
  FOR CZ := CMeldungen TO Profiler DO
    IF checked IN CItems[CZ].flags THEN COSet[CZ] := TRUE  END;
  END; (* FOR *)
  FOR LZ := LMeldungen TO AskModule DO
    IF checked IN LItems[LZ].flags THEN LOSet[LZ] := TRUE  END;
  END; (* FOR *)
  FOR UZ := CPU00 TO CPU40 DO
    IF checked IN UItems[UZ].flags THEN UOSet[UZ] := TRUE  END;
  END; (* FOR *)
  IF ActualScrPtr^.nextScreen # NIL THEN
    ClearMenuStrip(OptWinPtr);
    CloseWindow(OptWinPtr); OptWinPtr := NIL;
    ActualScrPtr := ActualScrPtr^.nextScreen;
    GetActualData;
    InitOptWin;
    OptWinPtr := OpenWindow(OptWin);
    Assert(OptWinPtr#NIL, ADR("Konnte Window nicht öffnen"));
    InitMenu;
    FOR CZ := CMeldungen TO Profiler DO
      IF COSet[CZ] = FALSE THEN EXCL(CItems[CZ].flags, checked) END;
    END; (* FOR *)
    FOR LZ := LMeldungen TO AskModule DO
      IF LOSet[LZ] = FALSE THEN EXCL(LItems[LZ].flags, checked) END;
    END; (* FOR *)
    FOR UZ := CPU00 TO CPU40 DO
      IF UOSet[UZ] = TRUE THEN INCL(UItems[UZ].flags, checked) END;
    END; (* FOR *)
    ok := SetMenuStrip(OptWinPtr, ADR(MenuStrip));
    Assert(ok#FALSE, ADR("Konnte Menu nicht installieren"));
  END; (* IF *)
END CycleScreen;


(*---------------------------------------------------------------------------
------                              MAIN                               ------
---------------------------------------------------------------------------*)

BEGIN
  InitMenuText;
  GetActiveScreen;
  GetActualData;
  InitMenu;
  ReadENVs;
  InitOptWin;
  OptWinPtr := OpenWindow(OptWin);
  Assert(OptWinPtr#NIL, ADR("Konnte Window nicht öffnen"));
  ok := SetMenuStrip(OptWinPtr, ADR(MenuStrip));
  Assert(ok#FALSE, ADR("Konnte Menu nicht installieren"));
  LOOP
    WaitPort(OptWinPtr^.userPort);
    IntuiMsg := GetMsg(OptWinPtr^.userPort);
    WHILE IntuiMsg # NIL DO
      Class := IntuiMsg^.class;
      Code := IntuiMsg^.code;
      ReplyMsg(IntuiMsg);
      IF closeWindow IN Class THEN EXIT;
      ELSIF menuPick IN Class THEN
        IF (MenuNum(Code) = 0) AND (ItemNum(Code) = 0) THEN
          WriteENVs
        ELSIF (MenuNum(Code) = 0) AND (ItemNum(Code) = 1) THEN
          CycleScreen
        ELSIF (MenuNum(Code) = 0) AND (ItemNum(Code) = 2) THEN
          EXIT
        END; (* IF *)
      END; (* IF *)
      IntuiMsg := GetMsg(OptWinPtr^.userPort);
    END; (* WHILE *)
  END; (* LOOP *)
  ClearMenuStrip(OptWinPtr);
  CloseWindow(OptWinPtr); OptWinPtr := NIL;

CLOSE
  IF OptWinPtr # NIL THEN
    ClearMenuStrip(OptWinPtr);
    CloseWindow(OptWinPtr);    OptWinPtr := NIL;
  END; (* IF *)
END M2Options.
