/*----------------------------------------------------------------------------
   File   :    ToolTypeWatch.c
   Projekt:    ToolTypeWatch
   Inhalt :    LibCount1 - vor FindToolType geschaltet, dokumentiert Aufrufe
               LibCount2 - vor MatchToolValue geschaltet,dokumentiert Aufrufe
               CheckTask - eigenen Port überprüfen und ev. CTRL-C schicken
               _main     - Haupt-PRG

   Version:    0.7
   Datum  :    05. Januar 1992

   Autor  :    Uwe Röhm
   Adresse:    Auber Str. 25,  W-6209 Hohenstein 4
    (Semester) Wörthstr. 18    W-8390 Passau
   Bemerkung:
----------------------------------------------------------------------------*/
#include <exec/types.h>
#include <exec/exec.h>
#include <exec/io.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

#define HAILTEXT "\n[32mToolTypeWatch V%ld.%ld[0m   © 1991 by Uwe Röhm\nStart me again to adjust old icon.library vectors.\n\n"
#define ERROR1 "[33mToolTypeWatch[31m - Removed...\n"
#define ERROR2 "[33mERROR[31m while oppening Intuition.library V37!\n"
#define ERROR3 "[33mERROR[31m while oppening Window!\n"
#define ERROR4 "[33mERROR[31m while oppening console.device!\n"
#define ERROR5 "[33mERROR:[31m Couldn´t install new FindToolType() function!\n"
#define ERROR6 "[33mERROR:[31m Couldn´t install new MatchToolValue() function!\n"
#define DEF_PORTNAME "ToolTypeWatch.port"


/*  ---------------------   eigene Strukturen   -------------------------  */
struct MyMessage {
   struct Message m;
   char text;
   };

/*  ---------------------   Daten für cback.o   -------------------------  */
long  _stack = 4000;
char *_procname = "ToolTypeWatch";
long  _priority = 0;
long  _BackGroundIO = 1;
extern BPTR _Backstdout;

/*  ---------------------   globale Variablen   -------------------------  */
UBYTE* (* __regargs oldfunk) (UBYTE **toolTypeArray, UBYTE *typeName);
BOOL   (* __regargs oldoldfunk) ( UBYTE *typeString, UBYTE *value);
struct IntuitionBase *IntuitionBase;
struct Library *IconBase;
struct MsgPort *myport;
extern long version, revision;
/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  LibCount1
   Parameter :  UBYTE  **toolTypeArray
                UBYTE  *typeName
   Rückgabe  :  UBYTE *(entweder NULL, oder value-String)

   Aufruf von:  überall und niergends
   UnterFunks:  ---
   Autor     :  Uwe Röhm
   Datum     :  04. November 1991
   Bemerkung:
   Schickt zuerst die Übergabeparameter zu FindToolType und den Namen der
   aktuellen Task an meinen HauptTask zur Ausgabe auf meinem Con-Window und
   ruft dann die normale FindToolType-Funktion auf.
   Den Umweg mit PutMsg mache ich, weil es sonst zu Abstürzen kam, als ich
   von hier aus direkt mit DoIO arbeitete.
   ACHTUNG: Ich erwarte meine Message nicht zurück (kein ReplyMsg),
            dafür muß sie aber mit FreeMem wieder freigegeben werden (s.u.).
   ACHTUNG: Die Argumente kommen in A1 und D0 (nicht A1/A2) an!!! Deshalb
            gebe ich sie explizit per __asm und register an.
   ACHTUNG: KEINE DOS-Aufrufe hier verwenden, da diese Routine ev. von
            einfachen Tasks aufgerufen werden kann...
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
UBYTE* __saveds __regargs LibCount1(UBYTE **toolTypeArray, UBYTE *typeName)
{
   UBYTE *retcode = NULL;
   struct MyMessage *msg;
   static char str[200];

   Forbid();   /* wegen SysBase-Zugriff... */
   sprintf (str, "%s:  Find ToolType '%s'   (erstes '%s')\n",
            SysBase->ThisTask->tc_Node.ln_Name, typeName, *toolTypeArray);
   Permit();

   // Message an HauptTask für die Ausgabe auf meiner Console
   if (msg = AllocMem (sizeof(struct Message) + strlen(str) + 1, MEMF_CLEAR))
   {
      strcpy (&msg->text, str);
      msg->m.mn_Length = sizeof(struct Message) + strlen(str) + 1;
      PutMsg (myport, (struct Message *) msg);
   } // if AllocMem

   // Ur-FindToolType aufrufen
   retcode = oldfunk(toolTypeArray, typeName);
   return retcode;
}

/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  LibCount2
   Parameter :  UBYTE        *typeString (mehrere (?) Values eines ToolTypes)
                UBYTE        *value      (ist dieser Wert darin enthalten)
   Rückgabe  :  BOOL (Ja oder nein...)

   Aufruf von:  überall und niergends
   UnterFunks:  ---
   Autor     :  Uwe Röhm
   Datum     :  04. November 1991
   Bemerkung:
   Wie LibCount1, nur für die MatchToolValue-Funktion.
   ACHTUNG: KEINE DOS-Aufrufe hier verwenden, da diese Routine ev. von
            einfachen Tasks aufgerufen werden kann...
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
BOOL __saveds __regargs LibCount2(UBYTE *typeString, UBYTE *value)
{
   BOOL retcode = FALSE;
   struct MyMessage *msg;
   static char str[200];

   Forbid();   /* wegen SysBase-Zugriff... */
   sprintf (str, "%s:  Wert von '%s' in %s'?? (MatchToolValue)\n",
            SysBase->ThisTask->tc_Node.ln_Name, value, typeString);
   Permit();

   // Ausgabe auf meiner Console
   if (msg = AllocMem (sizeof(struct Message) + strlen(str) + 1, MEMF_CLEAR))
   {
      strcpy (&msg->text, str);
      msg->m.mn_Length = sizeof(struct Message) + strlen(str) + 1;
      PutMsg (myport, (struct Message *) msg);
   } // if AllocMem

   // Ur-MatchToolValue aufrufen
   retcode = oldoldfunk(typeString, value);
   return retcode;
}

/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  CheckTask
   Parameter :  ---
   Rückgabe  :  struct MsgPort * (erzeugter MsgPort)

   Aufruf von:  main (s.u.)
   UnterFunks:  ---
   Autor     :  Uwe Röhm
   Datum     :  02. November 1991
   Bemerkung:
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
struct MsgPort *CheckTask (void)
{
struct MsgPort *tmp = NULL;

   if ((tmp = (struct MsgPort *) FindPort (DEF_PORTNAME)))
   {
      Signal (tmp->mp_SigTask, SIGBREAKF_CTRL_C);
      return (NULL);
   }
   else
   {   tmp = CreatePort (DEF_PORTNAME, 0);  }

   return tmp;
}


/*  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
   Funktion  :  _main
   Parameter :  char *cmd (die einzelnen Argumente)
   Rückgabe  :  ---

   Aufruf von:  CLI / WB
   UnterFunks:
   Autor     :  Uwe Röhm
   Datum     :  04. November 1991
   Bemerkung:
   Ein Ausgabewindow wird geöffnet und dann per SetFunction die FindToolType()
   und die MatchToolValkue() Funktionen gepatched. Danach warte ich darauf,
   daß ein erneuter Aufruf dieses Programmes an meinen SystemPort ein Break-
   Signal sendet. Ausgaben werden nur von hier aus getätigt. Ich bekomme dazu
   von meinen eingepatchten Funktionen Messages mit den entspr. Texten.
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  */
void main (int argc, char *argv[])
{
   BOOL retcode;
   ULONG sigbits;
   char string[150];
   struct Message *msg;
   struct Window *mywin;
   struct IOStdReq ioreq;
   struct MyMessage *mymsg;
   WORD zoomkoords[4] = {12,12,70,12};

   sprintf (string, HAILTEXT, version, revision);
   Write (_Backstdout, string, strlen(string));

   myport = CheckTask ();
   retcode = (myport == NULL) ? FALSE : TRUE;
   if (retcode)
   {
      IntuitionBase = OpenLibrary ("intuition.library", 37L);
      retcode = (IntuitionBase == NULL) ? FALSE : TRUE;
      if (retcode)
      {
        IconBase = OpenLibrary ("icon.library", 37L);
        retcode = (IconBase == NULL) ? FALSE : TRUE;
        if (retcode)
        {
         mywin = OpenWindowTags (NULL, WA_Height,200,
                                       WA_Width, 600,
                                       WA_MinWidth, 70,
                                       WA_MinHeight, 40,
                                       WA_MaxWidth, -1,
                                       WA_MaxHeight, -1,
                                       WA_Title, "ToolTypeWatch - Output",
                                       WA_DetailPen, 1,
                                       WA_CloseGadget, TRUE,
                                       WA_DragBar, TRUE,
                                       WA_DepthGadget, TRUE,
                                       WA_Zoom, &zoomkoords,
                                       WA_SizeGadget, TRUE,
                                       WA_SimpleRefresh, TRUE,
                                       WA_IDCMP, IDCMP_CLOSEWINDOW,
                                       TAG_DONE);
         retcode = (mywin == NULL) ? FALSE : TRUE;
         if (retcode)
         {
            // Console UnitNr. 3 + SimpleRefresh (s.o.) :
            //  - autom. Updaten des Textes bei Sizing des Windows
            //  - mögliches Ausschneiden von Text ins ClipBoard
            ioreq.io_Data = (APTR) mywin;
            retcode = (OpenDevice("console.device", 3, &ioreq, NULL) == 0) ? TRUE : FALSE;
            if (retcode)
            {
               // ACHTUNG: Negativer Offset und Hexadezimal!!!
               oldfunk = SetFunction ((struct Library *)IconBase, -0x60,(APTR)LibCount1);
               retcode = (oldfunk == NULL) ? FALSE : TRUE;
               if (retcode)
               {
                  // ACHTUNG: Negativer Offset und Hexadezimal!!!
                  oldoldfunk = SetFunction ((struct Library *)IconBase, -0x66,(APTR)LibCount2);
                  retcode = (oldoldfunk == NULL) ? FALSE : TRUE;
                  if (retcode)
                  {
                     Close (_Backstdout);
                     _Backstdout = NULL;

                     do
                     {
                        sigbits = Wait (SIGBREAKF_CTRL_C | (1 << mywin->UserPort->mp_SigBit) | (1 << myport->mp_SigBit));
                        //
                        // Angefragte Ausgaben machen
                        //
                        if (sigbits & (1 << myport->mp_SigBit))
                        {
                           while (mymsg = (struct MyMessage *) GetMsg (myport))
                           {
                              ioreq.io_Command = CMD_WRITE;
                              ioreq.io_Data    = (APTR) &mymsg->text;
                              ioreq.io_Length  = -1;
                              DoIO(&ioreq);
                              FreeMem (mymsg, mymsg->m.mn_Length);
                           } /* if GetMsg */
                        } /* if myport */
                        //
                        // Close Gadget - Fenster schliessen
                        //
                        if (sigbits & (1 << mywin->UserPort->mp_SigBit))
                        {
                           while (msg = GetMsg(mywin->UserPort))
                              ReplyMsg(msg);
                           sigbits |= SIGBREAKF_CTRL_C;
                        } /* if UserPort */
                     }
                     while (!(sigbits & SIGBREAKF_CTRL_C));

                     SetFunction ((struct Library *)IconBase, -0x66, (APTR) oldoldfunk);
                  }
                  else
                  {  Write (_Backstdout, ERROR6, sizeof (ERROR6));    }

                  SetFunction ((struct Library *)IconBase, -0x60, (APTR) oldfunk);
               } // if SetFunction
               else
               {  Write (_Backstdout, ERROR5, sizeof (ERROR5));      }

               CloseDevice(&ioreq);
            } // if OpenDevice
            else
            {  Write (_Backstdout, ERROR4, sizeof (ERROR4));      }

            CloseWindow (mywin);
         } // if OpenWindow
         else
          {  Write (_Backstdout, ERROR3, sizeof (ERROR3));   }

         CloseLibrary (IconBase);
        } // if IconBase

        CloseLibrary (IntuitionBase);
      } // if IntuitionBase
      else
      {  Write (_Backstdout, ERROR2, sizeof(ERROR2));    }

   } // if CheckTask
   else
   {  Write (_Backstdout, ERROR1, sizeof (ERROR1));     }


   //
   //    meinen Port sauber schliessen
   //
   if (myport)
   {
      while (msg = GetMsg (myport))
      {
         if (msg->mn_Length == sizeof(struct Message))
            ReplyMsg (msg); // Wer immer es war, er kriegt sie wieder
         else
            FreeMem (msg, msg->mn_Length); // Nachzügler meiner AusgabeMessages
      }
      DeletePort (myport);
      myport = NULL;
   }

   if (_Backstdout != NULL)
      Close (_Backstdout);
   exit ((retcode == TRUE) ? 0 : 10);

}
