(***************************************************************************

    :Program.    ObCED.mod
    :Contents.   Communication with CED
    :Author.     Achim Siebert
    :Address.    Nobileweg 67 , 7000 Stuttgart 40
    :Copyright.  Public Domain
    :Language.   Oberon
    :Translator. AmigaOberon A+L
    :Imports.    CED, Req
    :History.    Dec-1990; V1.2
    :Usage.      ObCED [c][l][e][opt] | [next] | [prev] | [first] | [quit]

****************************************************************************)

MODULE ObCED;

IMPORT
       Req,
       ExecSupport,
       FileSystem,
       I:Intuition,
       ol:OberonLib,
       Conversions,
       Dos,
       SecureDos,
       s:SYSTEM,
       Exec,
       Strings,
       Arguments,
       CED;

VAR OldFile,PathFile: ARRAY Req.dsize+Req.fchars+8 OF CHAR;
    ThisFile,ExecuteFile,EFile : ARRAY Req.fchars+8 OF CHAR;
    doscommand : ARRAY Req.dsize+6 OF CHAR;
    compoptions,linkoptions : ARRAY 20 OF CHAR;
    tfile,errfile : FileSystem.File;
    same,errfileopen : BOOLEAN;
    Ausgabefenster : Dos.FileHandlePtr;
    i,fehleraktuell,fehlergesamt : INTEGER;
    numlines : LONGINT;
    msp, foundmsp, replmsp : Exec.MsgPortPtr;
    OldDir,NewDir,DummyDir : Dos.FileLockPtr;
    mymess : CED.CEDMsg;
    mymessPtr : POINTER TO CED.CEDMsg;
    msgstring : ARRAY 8 OF CHAR;
    msgstringPtr : POINTER TO ARRAY 8 OF CHAR;
    optionen : SHORTSET;
    
CONST  c = 0; l = 1; e = 2; opt = 3; next = 4; prev = 5;
       first = 6; quit = 7;
       fehleranzahl = 168;
       
       myportname = "OB_CED";
       myreplyname = "ObRxReplyPort";
       tfilename = "T:ObCED.Workfile";
      
VAR  Fehler : ARRAY fehleranzahl OF ARRAY 65 OF CHAR;

PROCEDURE Halt;

BEGIN

 HALT(20);

END Halt;

PROCEDURE PutCED(command : ARRAY OF CHAR);

BEGIN
   IF NOT CED.PutMsg(command) THEN Halt END;
END PutCED;

PROCEDURE GetArgs():BOOLEAN;

BEGIN

   i := Arguments.NumArgs();
   IF i = 1 THEN
      Arguments.GetArg(1,msgstring);
      Strings.Upper(msgstring);
      RETURN TRUE;
   END;
   RETURN FALSE;

END GetArgs;

PROCEDURE Auswertung():BOOLEAN;

BEGIN

   optionen := SHORTSET{};
   IF    Strings.Occurs(msgstring,"NEXT")  # -1 THEN INCL(optionen,next); RETURN TRUE;
   ELSIF Strings.Occurs(msgstring,"FIRST") # -1 THEN INCL(optionen,first);RETURN TRUE;
   ELSIF Strings.Occurs(msgstring,"PREV")  # -1 THEN INCL(optionen,prev); RETURN TRUE;
   ELSIF Strings.Occurs(msgstring,"QUIT")  # -1 THEN INCL(optionen,quit); RETURN TRUE;
   ELSE  IF Strings.Occurs(msgstring,"OPT")# -1 THEN INCL(optionen,opt);  END;
         IF Strings.Occurs(msgstring,"C")  # -1 THEN INCL(optionen,c); END;
         IF Strings.Occurs(msgstring,"L")  # -1 THEN INCL(optionen,l); END;
         IF Strings.Occurs(msgstring,"E")  # -1 THEN INCL(optionen,e); END;
         IF (c IN optionen) OR (l IN optionen) OR (e IN optionen) THEN RETURN TRUE;
         ELSE RETURN FALSE END;
   END;

END Auswertung;

PROCEDURE LadeFehler();

CONST fehlerfilename = "OBERON:Fehler-Meldungen";

BEGIN

   IF NOT FileSystem.Open(errfile,fehlerfilename,FALSE) THEN
      IF CED.PutMsg("Okay1 OBERON:Fehler-Meldungen nicht gefunden!") THEN END;
   ELSE
      errfileopen := TRUE;
      i := 0;
      LOOP
         IF NOT FileSystem.ReadString(errfile,Fehler[i]) THEN EXIT;
         END;
         INC(i); IF i = fehleranzahl THEN EXIT END;
      END;
      IF NOT FileSystem.Close(errfile) THEN Halt END;
      errfileopen := FALSE;
   END;

END LadeFehler;

PROCEDURE ZeigeFehler(fnp:INTEGER);

TYPE Fehlerblock = STRUCT
                     nummer,zeile,spalte : INTEGER;
                   END;

VAR  fehlrec : Fehlerblock;
     intstring : ARRAY 12 OF CHAR;

PROCEDURE ShowErr();

VAR stellen : INTEGER;

   PROCEDURE WievieleStellen(wovon:INTEGER);

   BEGIN
      IF wovon < 10 THEN stellen := 1;
      ELSIF wovon < 100 THEN stellen := 2;
      ELSIF wovon < 1000 THEN stellen := 3;
      ELSE stellen := 4;
      END;
   END WievieleStellen;

BEGIN

   doscommand := "Jumpto ";
   IF Conversions.IntToString(fehlrec.zeile,intstring,8) THEN END;
   Strings.Append(doscommand,intstring);
   Strings.AppendChar(doscommand," ");
   IF Conversions.IntToString(fehlrec.spalte,intstring,8) THEN END;
   Strings.Append(doscommand,intstring);
   PutCED(doscommand);
   PutCED("left");
   doscommand := "okay1 Fehler Nr.";
   WievieleStellen(fehleraktuell);
   IF Conversions.IntToString(fehleraktuell,intstring,stellen) THEN END;
   Strings.Append(doscommand,intstring);
   Strings.Append(doscommand," von");
   WievieleStellen(fehlergesamt);
   IF Conversions.IntToString(fehlergesamt,intstring,stellen) THEN END;
   Strings.Append(doscommand,intstring);
   Strings.Append(doscommand,":\n");
   Strings.Append(doscommand,Fehler[fehlrec.nummer]);
   PutCED(doscommand);

END ShowErr;

BEGIN

IF fnp = first THEN
   IF errfileopen THEN
      IF NOT FileSystem.Close(errfile) THEN Halt; END;
      errfileopen := FALSE;
   END;
   IF FileSystem.Open(errfile,EFile,FALSE) THEN
      errfileopen := TRUE;
      fehlergesamt := SHORT(FileSystem.Size(errfile) DIV 6);
   ELSE
      Halt;
   END;
END;
IF CED.GetNumber("Status 17") # numlines THEN
   PutCED("okay1 Anzahl der Zeilen im File hat sich geändert!\nKorrekte Fehleranzeige nicht mehr möglich.");
   RETURN;
END;
CASE fnp OF
   first : fehleraktuell := 1;
           IF FileSystem.Move(errfile,0) AND FileSystem.Read(errfile,fehlrec) THEN
              ShowErr();
           ELSE Halt;
           END;
   |next : INC(fehleraktuell);
           IF fehleraktuell <= fehlergesamt THEN
              IF NOT FileSystem.Read(errfile,fehlrec) THEN Halt END;
              ShowErr();
           ELSE
              PutCED("okay1 Keine weiteren Fehler!");
              DEC(fehleraktuell);
           END;
   |prev : DEC(fehleraktuell);
           IF fehleraktuell <= 0 THEN
              PutCED("okay1 Keine vorausgehenden Fehler!");
              IF NOT FileSystem.Move(errfile,0) THEN Halt END;
              fehleraktuell := 0;
           ELSE
              IF FileSystem.Move(errfile,(fehleraktuell-1)*6) THEN
                 IF NOT FileSystem.Read(errfile,fehlrec) THEN Halt END;
                 ShowErr();
              ELSE Halt;
              END;
           END;
ELSE
END;

END ZeigeFehler;

PROCEDURE MakeExecuteTFile();

VAR Eingabe : Dos.FileHandlePtr;

BEGIN

   IF NOT (FileSystem.Open(tfile,tfilename,TRUE) AND
      FileSystem.WriteString(tfile,"Path OBERON: add") AND
      FileSystem.WriteString(tfile,"Stack 30000") AND
      FileSystem.WriteString(tfile,doscommand) AND
      FileSystem.WriteString(tfile,"Stack 4000") AND
      FileSystem.Close(tfile)) THEN Halt END;
   Eingabe := Dos.Open(tfilename,Dos.oldFile);
   IF Eingabe = NIL THEN Halt; END;
   IF NOT Dos.Execute("",Eingabe,Ausgabefenster) THEN Dos.Close(Eingabe); Halt; END;
   Dos.Close(Eingabe);
   IF Dos.DeleteFile(tfilename) THEN END;

END MakeExecuteTFile;

PROCEDURE Action();

   PROCEDURE FensterZu();

   BEGIN

     PutCED("cedtofront");
     Dos.Close(Ausgabefenster); Ausgabefenster := NIL;

   END FensterZu;

BEGIN

IF quit IN optionen THEN HALT(0);END;
IF c IN optionen THEN
   OldFile := "";
   IF errfileopen THEN
      IF NOT FileSystem.Close(errfile) THEN Halt; END;
      errfileopen := FALSE;
   END;
   IF CED.GetNumber("Save") # 0 THEN END;
END;
same := FALSE;
CED.GetString("Status 19",PathFile);
IF (Strings.Occurs(PathFile,".mod") = -1) THEN RETURN END;
IF PathFile = OldFile THEN same := TRUE ELSE OldFile := PathFile END;
IF NOT same THEN
   numlines := CED.GetNumber("Status 17"); IF numlines = 0 THEN RETURN END;
   CED.GetString("Status 21",ThisFile); IF ThisFile = "" THEN Halt END;
   PathFile := "";
   CED.GetString("Status 20",PathFile);
   EFile := ThisFile;
   Strings.AppendChar(EFile,"E");
   IF Strings.Occurs(PathFile,":") = -1 THEN
      CED.GetString("Status 75",doscommand);
      Strings.Insert(PathFile,0,doscommand);
   END;
   IF Strings.OccursPos(PathFile,"/txt",Strings.Length(PathFile)-4) # -1 THEN
      Strings.Delete(PathFile,Strings.Length(PathFile)-4,4);
      Strings.Insert(EFile,0,"txt/");
   ELSE
      IF Strings.OccursPos(PathFile,":txt",Strings.Length(PathFile)-4) # -1 THEN
         Strings.Delete(PathFile,Strings.Length(PathFile)-3,3);
         Strings.Insert(EFile,0,"txt/");
      END;
   END;
   IF errfileopen THEN
      IF NOT FileSystem.Close(errfile) THEN Halt; END;
      errfileopen := FALSE;
   END;
   DummyDir := Dos.CurrentDir(OldDir);
   IF NewDir # NIL THEN SecureDos.UnLock(NewDir);END;
   NewDir := SecureDos.Lock(PathFile,Dos.sharedLock);
   IF NewDir = NIL THEN Halt END;
   DummyDir := Dos.CurrentDir(NewDir);
END;
IF (c IN optionen) OR (l IN optionen) OR (e IN optionen) THEN
   compoptions := "-md "; linkoptions := "-md ";
   IF (c IN optionen) AND (opt IN optionen) THEN
      compoptions := "";
      PutCED("cedtofront");
      CED.GetString("getstring 'svbcrntmdi' 'Compiler-Optionen:'",compoptions);
      IF compoptions # "" THEN
         Strings.Insert(compoptions,0,"-");
         Strings.AppendChar(compoptions," ");
      END;
   END;
   IF (l IN optionen) AND (opt IN optionen) THEN
      linkoptions := "";
      IF (c IN optionen) AND (compoptions # "") THEN
         Strings.Upper(compoptions);
         IF Strings.Occurs(compoptions,"M") # -1 THEN
            linkoptions := "m";
         END;
         IF Strings.Occurs(compoptions,"D") # -1 THEN
            Strings.AppendChar(linkoptions,"d");
         END;
         IF Strings.Occurs(compoptions,"I") # -1 THEN
            Strings.AppendChar(linkoptions,"i");
         END;
      END;
      IF linkoptions = "" THEN linkoptions := "bs" END;
      doscommand := "getstring ";
      Strings.Append(doscommand,linkoptions);
      Strings.Append(doscommand," Linker-Optionen:");
      CED.GetString(doscommand,linkoptions);
      IF linkoptions # "" THEN
         Strings.Insert(linkoptions,0,"-");
         Strings.AppendChar(linkoptions," ");
      END;
   END;
   Ausgabefenster := Dos.Open("CON:20/0/600/200/OBCed<->CED",Dos.newFile);
   IF Ausgabefenster = NIL THEN Halt END;
   IF I.WBenchToFront() THEN END;
   IF (c IN optionen) THEN
      doscommand := "Oberon ";
      Strings.Append(doscommand,compoptions);
      Strings.Append(doscommand,ThisFile);
      MakeExecuteTFile();
      IF FileSystem.Exists(EFile) THEN
         FensterZu();
         ZeigeFehler(first); RETURN;
      END;
   END;
   IF (l IN optionen) OR (e IN optionen) THEN
      ExecuteFile := ThisFile; (*COPY(ThisFile,ExecuteFile);*)
      Strings.Delete(ExecuteFile,Strings.Length(ExecuteFile)-4,4);
      IF (l IN optionen) THEN
         doscommand := "OLink ";
         Strings.Append(doscommand,linkoptions);
         Strings.Append(doscommand,ExecuteFile);
         MakeExecuteTFile();
      END;
      IF (e IN optionen) THEN
         IF (opt IN optionen) THEN
            doscommand := "getstring ";
            Strings.Append(doscommand,ExecuteFile);
            Strings.Append(doscommand," Programm-Aufruf:");
            PutCED("cedtofront");
            CED.GetString(doscommand,doscommand);
            IF doscommand # "" THEN
               IF I.WBenchToFront() THEN END;
               IF Dos.Execute(doscommand,NIL,Ausgabefenster) THEN
                  FensterZu(); RETURN;
               ELSE Halt;
               END;
            ELSE FensterZu(); RETURN;
            END;
         ELSE
            IF Dos.Execute(ExecuteFile,NIL,Ausgabefenster) THEN
               FensterZu(); RETURN;
            ELSE Halt;
            END;
         END;
      ELSE FensterZu(); RETURN;
      END;
   ELSE
      FensterZu(); RETURN;
   END;
ELSE
   IF FileSystem.Exists(EFile) THEN
     IF (next IN optionen) AND same THEN ZeigeFehler(next);
     ELSIF (prev IN optionen) AND same THEN ZeigeFehler(prev);
     ELSE ZeigeFehler(first);
     END;
   ELSE
     PutCED("cedtofront");
     PutCED("okay1 Keine Fehlerdatei gefunden!");RETURN;
   END;
END;

END Action;

BEGIN
   optionen := SHORTSET{};
   foundmsp := Exec.FindPort(myportname);
   IF foundmsp=NIL THEN
      msp := ExecSupport.CreatePort(s.ADR(myportname),0);
      IF msp = NIL THEN Halt END;
      OldDir := SecureDos.oldCurrentDir;
      IF OldDir = NIL THEN Halt END;
      errfileopen := FALSE;
      LadeFehler();
      fehleraktuell := 1;
      IF GetArgs() THEN
         IF Auswertung() THEN
            Action();
         END;
      END;
      LOOP
         msgstring := "";
         REPEAT
            Exec.WaitPort(msp);
            mymessPtr := Exec.GetMsg(msp);
         UNTIL mymessPtr # NIL;
         IF mymessPtr^.args[0] # NIL THEN
            msgstringPtr := mymessPtr.args[0];
            IF msgstringPtr # NIL THEN
               COPY(msgstringPtr^,msgstring);
            END;
         END;
         Exec.ReplyMsg(mymessPtr);
         IF Auswertung() THEN
            Action();
         END;
      END;
   ELSE
      replmsp := ExecSupport.CreatePort(s.ADR(myreplyname),0);
      IF replmsp = NIL THEN Halt END;
      mymess.cmNode.node.type:=Exec.message;
      mymess.cmNode.length:=s.SIZE(CED.CEDMsg);
      mymess.cmNode.replyPort:=replmsp;
      IF NOT GetArgs() THEN msgstring := "QUIT";END;
      NEW(msgstringPtr);
      IF msgstringPtr = NIL THEN Halt END;
      mymess.args[0] := msgstringPtr;
      COPY(msgstring,msgstringPtr^);
      Exec.PutMsg(foundmsp,s.ADR(mymess));
      Exec.WaitPort(replmsp);
      IF Exec.GetMsg(replmsp) = NIL THEN END;
      ExecSupport.DeletePort(replmsp);
      DISPOSE(msgstringPtr);
   END;

CLOSE
 
   IF errfileopen THEN IF FileSystem.Close(errfile) THEN END;END;
   IF NewDir # NIL THEN SecureDos.UnLock(NewDir);END;
   IF msp # NIL THEN ExecSupport.DeletePort(msp);END;
   IF Ausgabefenster # NIL THEN Dos.Close(Ausgabefenster) END;

END ObCED.
